[jboss-cvs] JBoss Messaging SVN: r1970 - in trunk: src/etc/server/default/deploy and 19 other directories.

jboss-cvs-commits at lists.jboss.org jboss-cvs-commits at lists.jboss.org
Tue Jan 16 15:59:22 EST 2007


Author: timfox
Date: 2007-01-16 15:58:56 -0500 (Tue, 16 Jan 2007)
New Revision: 1970

Added:
   trunk/src/etc/server/default/deploy/bridge-service.xml
   trunk/src/etc/xmdesc/Bridge-xmbean.xml
   trunk/src/main/org/jboss/jms/recovery/BridgeXAResourceRecovery.java
   trunk/src/main/org/jboss/jms/server/bridge/BridgeMBean.java
   trunk/src/main/org/jboss/jms/server/bridge/BridgeService.java
   trunk/tests/etc/bridge-recovery.properties
   trunk/tests/etc/jbossjta-properties.xml
   trunk/tests/src/org/jboss/test/messaging/jms/bridge/BridgeMBeanTest.java
   trunk/tests/src/org/jboss/test/messaging/jms/bridge/BridgeTestBase.java
   trunk/tests/src/org/jboss/test/messaging/jms/bridge/ReconnectTest.java
Removed:
   trunk/lib/jbossts/
   trunk/src/main/org/jboss/jms/recovery/MessagingXAResourceRecovery.java
   trunk/tests/src/org/jboss/test/messaging/util/TransactionManagerLocator.java
Modified:
   trunk/src/etc/server/default/deploy/remoting-service.xml
   trunk/src/main/org/jboss/jms/client/container/ClosedInterceptor.java
   trunk/src/main/org/jboss/jms/client/container/ExceptionInterceptor.java
   trunk/src/main/org/jboss/jms/message/MessageIdGeneratorFactory.java
   trunk/src/main/org/jboss/jms/recovery/JMSProviderXAResourceRecovery.java
   trunk/src/main/org/jboss/jms/server/ServerPeer.java
   trunk/src/main/org/jboss/jms/server/bridge/Bridge.java
   trunk/src/main/org/jboss/jms/server/bridge/JNDIConnectionFactoryFactory.java
   trunk/src/main/org/jboss/jms/server/endpoint/ServerConnectionEndpoint.java
   trunk/src/main/org/jboss/messaging/core/plugin/postoffice/DefaultPostOffice.java
   trunk/tests/bin/runtest
   trunk/tests/bin/start-rmi-server
   trunk/tests/etc/log4j.xml
   trunk/tests/etc/poison.xml
   trunk/tests/src/org/jboss/test/messaging/MessagingTestCase.java
   trunk/tests/src/org/jboss/test/messaging/jms/XATest.java
   trunk/tests/src/org/jboss/test/messaging/jms/bridge/BridgeTest.java
   trunk/tests/src/org/jboss/test/messaging/jms/clustering/base/ClusteringTestBase.java
   trunk/tests/src/org/jboss/test/messaging/tools/ServerManagement.java
   trunk/tests/src/org/jboss/test/messaging/tools/aop/PoisonInterceptor.java
   trunk/tests/src/org/jboss/test/messaging/tools/jmx/ServiceContainer.java
   trunk/tests/src/org/jboss/test/messaging/tools/jmx/rmi/LocalTestServer.java
Log:
More bridge work



Added: trunk/src/etc/server/default/deploy/bridge-service.xml
===================================================================
--- trunk/src/etc/server/default/deploy/bridge-service.xml	2007-01-16 14:25:37 UTC (rev 1969)
+++ trunk/src/etc/server/default/deploy/bridge-service.xml	2007-01-16 20:58:56 UTC (rev 1970)
@@ -0,0 +1,63 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+     Example Message Bridge configurations
+
+     $Id: destinations-service.xml 1930 2007-01-09 18:16:04Z timfox $
+ -->
+
+<server>
+
+   <mbean code="org.jboss.jms.server.bridge.BridgeService"
+      name="jboss.messaging:service=Bridge,name=exampleBridge"
+      xmbean-dd="xmdesc/Bridge-xmbean.xml">
+      
+      <attribute name="SourceConnectionFactoryLookup">/ConnectionFactory</attribute>
+      
+      <attribute name="TargetConnectionFactoryLookup">/ConnectionFactory</attribute>
+      
+      <attribute name="SourceDestinationLookup">/topic/sourceTopic</attribute>
+      
+      <attribute name="TargetDestinationLookup">/queue/targetQueue</attribute>
+      
+      <attribute name="SourceUsername">bob</attribute>
+      
+      <attribute name="SourcePassword">pwd1</attribute>
+      
+      <attribute name="TargetUsername">jane</attribute>
+      
+      <attribute name="TargetPassword">pwd2</attribute>
+      
+      <attribute name="QualityOfServiceMode">2</attribute>
+      
+      <attribute name="Selector">vegetable='marrow'</attribute>
+      
+      <attribute name="MaxBatchSize">100</attribute>      
+      
+      <attribute name="MaxBatchTime">5000</attribute>
+      
+      <attribute name="SubName">mySubscription</attribute>
+      
+      <attribute name="ClientID">clientid-123</attribute>
+      
+      <attribute name="FailureRetryInterval">5000</attribute>
+      
+      <attribute name="MaxRetries">-1</attribute>
+      
+      <attribute name="SourceJNDIProperties"><![CDATA[
+java.naming.factory.initial=org.jnp.interfaces.NamingContextFactory
+java.naming.provider.url=jnp://server1:1099
+java.naming.factory.url.pkgs=org.jboss.naming:org.jnp.interfaces
+      ]]>
+      </attribute>
+      
+      <attribute name="TargetJNDIProperties"><![CDATA[
+java.naming.factory.initial=org.jnp.interfaces.NamingContextFactory
+java.naming.provider.url=jnp://server2:1099
+java.naming.factory.url.pkgs=org.jboss.naming:org.jnp.interfaces            
+      ]]>
+      </attribute>
+   </mbean>   
+
+
+</server>
\ No newline at end of file

Modified: trunk/src/etc/server/default/deploy/remoting-service.xml
===================================================================
--- trunk/src/etc/server/default/deploy/remoting-service.xml	2007-01-16 14:25:37 UTC (rev 1969)
+++ trunk/src/etc/server/default/deploy/remoting-service.xml	2007-01-16 20:58:56 UTC (rev 1970)
@@ -27,6 +27,8 @@
                <attribute name="callbackStore">org.jboss.remoting.callback.CallbackStore</attribute>
                <attribute name="clientSocketClass" isParam="true">org.jboss.jms.client.remoting.ClientSocketWrapper</attribute>
                <attribute name="serverSocketClass">org.jboss.jms.server.remoting.ServerSocketWrapper</attribute>
+               <attribute name="NumberOfRetries">1</attribute>
+               <attribute name="NumberOfCallRetries">1</attribute>
             </invoker>
             <handlers>
                <handler subsystem="JMS">org.jboss.jms.server.remoting.JMSServerInvocationHandler</handler>

Added: trunk/src/etc/xmdesc/Bridge-xmbean.xml
===================================================================
--- trunk/src/etc/xmdesc/Bridge-xmbean.xml	2007-01-16 14:25:37 UTC (rev 1969)
+++ trunk/src/etc/xmdesc/Bridge-xmbean.xml	2007-01-16 20:58:56 UTC (rev 1970)
@@ -0,0 +1,157 @@
+<?xml version="1.0" encoding="UTF-8"?>
+   <!DOCTYPE mbean PUBLIC
+      "-//JBoss//DTD JBOSS XMBEAN 1.2//EN"
+      "http://www.jboss.org/j2ee/dtd/jboss_xmbean_1_2.dtd">
+
+<mbean>
+   <description>A JMS Message Bridge</description>
+   <class>org.jboss.server.bridge.BridgeService</class>
+
+   <!-- Managed constructors -->
+
+   <!-- Managed attributes -->
+
+   <attribute access="read-only" getMethod="getInstance">
+      <description>Gets the underlying instance</description>
+      <name>Instance</name>
+      <type>org.jboss.messaging.core.plugin.contract.MessagingComponent</type>
+   </attribute>
+
+	<attribute access="read-write" getMethod="getSourceConnectionFactoryLookup"
+	   setMethod="setSourceConnectionFactoryLookup">
+	   <description>The source connection factory lookup</description>
+	   <name>SourceConnectionFactoryLookup</name>
+	   <type>java.lang.String</type>
+	</attribute>
+	
+	<attribute access="read-write" getMethod="getDestConnectionFactoryLookup"
+	   setMethod="setDestConnectionFactoryLookup">
+	   <description>The destination connection factory lookup</description>
+	   <name>DestConnectionFactoryLookup</name>
+	   <type>java.lang.String</type>
+	</attribute>	
+	
+	<attribute access="read-write" getMethod="getSourceUsername"
+	   setMethod="setSourceUsername">
+	   <description>The source username</description>
+	   <name>SourceUsername</name>
+	   <type>java.lang.String</type>
+	</attribute>	
+	
+	<attribute access="read-write" getMethod="getSourcePassword"
+	   setMethod="setSourcePassword">
+	   <description>The source username</description>
+	   <name>SourcePassword</name>
+	   <type>java.lang.String</type>
+	</attribute>		
+	
+	<attribute access="read-write" getMethod="getDestUsername"
+	   setMethod="setDestUsername">
+	   <description>The destination username</description>
+	   <name>DestUsername</name>
+	   <type>java.lang.String</type>
+	</attribute>	
+	
+	<attribute access="read-write" getMethod="getQualityOfServiceMode"
+	   setMethod="setQualityOfServiceMode">
+	   <description>The quality of service mode. 0 = at most once. 1 = duplicates ok, 2 = once and only once</description>
+	   <name>QualitOfServiceMode</name>
+	   <type>int</type>
+	</attribute>	
+	 
+	<attribute access="read-write" getMethod="getSelector"
+	   setMethod="setSelector">
+	   <description>The JMS selector to use when consuming messages from the source destination</description>
+	   <name>Selector</name>
+	   <type>java.lang.String</type>
+	</attribute>
+	
+	<attribute access="read-write" getMethod="getMaxBatchSize"
+	   setMethod="setMaxBatchSize">
+	   <description>The maximum number of messages to forward at a time, must be >= 1</description>
+	   <name>MaxBatchSize</name>
+	   <type>int</type>
+	</attribute>	
+	
+	<attribute access="read-write" getMethod="getMaxBatchTime"
+	   setMethod="setMaxBatchTime">
+	   <description>Number of milliseconds to wait after no messages arrive to forward batch of messages</description>
+	   <name>MaxBatchTime</name>
+	   <type>int</type>
+	</attribute>	
+	
+	<attribute access="read-write" getMethod="getSubName"
+	   setMethod="setSubName">
+	   <description>If consuming from a durable subscription, this is the name of the durable subscrition</description>
+	   <name>SubName</name>
+	   <type>java.lang.String</type>
+	</attribute>
+	
+	<attribute access="read-write" getMethod="getClientID"
+	   setMethod="setClientID">
+	   <description>If consuming from a durable subscription, this is the client id to use</description>
+	   <name>ClientID</name>
+	   <type>java.lang.String</type>
+	</attribute>		
+	
+	<attribute access="read-write" getMethod="getFailureRetryInterval"
+	   setMethod="setFailureRetryInterval">
+	   <description>The amount of time to wait in milliseconds before retrying connection creation, after connection failure is detected, or -1 if no retries will be attempted</description>
+	   <name>FailureRetryInterval</name>
+	   <type>long</type>
+	</attribute>	
+	
+	<attribute access="read-write" getMethod="getMaxRetries"
+	   setMethod="setMaxRetries">
+	   <description>The maximum number of attempts to retry connection creation after connection failure is detected</description>
+	   <name>MaxRetries</name>
+	   <type>int</type>
+	</attribute>		
+	
+	<attribute access="read-only" getMethod="isFailed">
+	   <description>Has the bridge failed?</description>
+	   <name>Failed</name>
+	   <type>boolean</type>
+	</attribute>
+	
+	<attribute access="read-only" getMethod="isPaused">
+	   <description>Is the bridge paused?</description>
+	   <name>Paused</name>
+	   <type>boolean</type>
+	</attribute>	
+	
+	<attribute access="read-write" getMethod="getSourceJNDIProperties" setMethod="setSourceJNDIProperties>
+	   <description>The JNDI properties to use to lookup the source destination, or null if a local JNDI initial context should be used</description>
+	   <name>SourceJNDIProperties</name>
+	   <type>java.lang.String</type>
+	</attribute>	
+	
+	<attribute access="read-write" getMethod="getDestNDIProperties" setMethod="setDestJNDIProperties>
+	   <description>The JNDI properties to use to lookup the destination destination, or null if a local JNDI initial context should be used</description>
+	   <name>DestJNDIProperties</name>
+	   <type>java.lang.String</type>
+	</attribute>			
+
+   <!-- Managed operations -->
+
+   <operation>
+      <description>JBoss Service lifecycle operation</description>
+      <name>create</name>
+   </operation>
+
+   <operation>
+      <description>JBoss Service lifecycle operation</description>
+      <name>start</name>
+   </operation>
+
+   <operation>
+      <description>JBoss Service lifecycle operation</description>
+      <name>stop</name>
+   </operation>
+
+   <operation>
+      <description>JBoss Service lifecycle operation</description>
+      <name>destroy</name>
+   </operation>   
+
+</mbean>
\ No newline at end of file

Modified: trunk/src/main/org/jboss/jms/client/container/ClosedInterceptor.java
===================================================================
--- trunk/src/main/org/jboss/jms/client/container/ClosedInterceptor.java	2007-01-16 14:25:37 UTC (rev 1969)
+++ trunk/src/main/org/jboss/jms/client/container/ClosedInterceptor.java	2007-01-16 20:58:56 UTC (rev 1970)
@@ -298,7 +298,7 @@
          catch (Throwable ignored)
          {
             // Add a log interceptor to the child if you want the error
-            ignored.printStackTrace();
+         //   ignored.printStackTrace();
          }
       }
       

Modified: trunk/src/main/org/jboss/jms/client/container/ExceptionInterceptor.java
===================================================================
--- trunk/src/main/org/jboss/jms/client/container/ExceptionInterceptor.java	2007-01-16 14:25:37 UTC (rev 1969)
+++ trunk/src/main/org/jboss/jms/client/container/ExceptionInterceptor.java	2007-01-16 20:58:56 UTC (rev 1970)
@@ -73,7 +73,7 @@
       catch(JMSException e)
       {
          // JMSException should not be logged unless trace is on
-         if (trace) { log.trace("Caught JMSException", e); }
+        // if (trace) { log.trace("Caught JMSException", e); }
          throw e;
       }
       catch (Throwable t)

Modified: trunk/src/main/org/jboss/jms/message/MessageIdGeneratorFactory.java
===================================================================
--- trunk/src/main/org/jboss/jms/message/MessageIdGeneratorFactory.java	2007-01-16 14:25:37 UTC (rev 1969)
+++ trunk/src/main/org/jboss/jms/message/MessageIdGeneratorFactory.java	2007-01-16 20:58:56 UTC (rev 1970)
@@ -90,7 +90,6 @@
       log.debug("checked out MessageIdGenerator for " + serverId +
                 ", reference count is " + h.refCount);
 
-
       return h.generator;
    }
 

Added: trunk/src/main/org/jboss/jms/recovery/BridgeXAResourceRecovery.java
===================================================================
--- trunk/src/main/org/jboss/jms/recovery/BridgeXAResourceRecovery.java	2007-01-16 14:25:37 UTC (rev 1969)
+++ trunk/src/main/org/jboss/jms/recovery/BridgeXAResourceRecovery.java	2007-01-16 20:58:56 UTC (rev 1970)
@@ -0,0 +1,230 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2005, JBoss Inc., and individual contributors as indicated
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jboss.jms.recovery;
+
+import java.io.InputStream;
+import java.sql.SQLException;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Properties;
+import java.util.StringTokenizer;
+
+import javax.jms.XAConnection;
+import javax.jms.XAConnectionFactory;
+import javax.jms.XASession;
+import javax.naming.InitialContext;
+import javax.transaction.xa.XAResource;
+
+import org.jboss.logging.Logger;
+
+import com.arjuna.ats.jta.recovery.XAResourceRecovery;
+
+/**
+ * A BridgeXAResourceRecovery
+ * 
+ *
+ * @author <a href="mailto:tim.fox at jboss.com">Tim Fox</a>
+ * @version <tt>$Revision: 1.1 $</tt>
+ *
+ * $Id$
+ *
+ */
+public class BridgeXAResourceRecovery implements XAResourceRecovery
+{
+   private static final Logger log = Logger.getLogger(BridgeXAResourceRecovery.class);
+   
+   private Hashtable jndiProperties;
+   
+   private String connectionFactoryLookup;
+   
+   private boolean returnedXAResource;
+   
+   private XAConnection conn;
+
+   public synchronized XAResource getXAResource() throws SQLException
+   {
+      InitialContext ic = null;
+      
+      if (log.isTraceEnabled()) { log.trace(this + " getting XAResource"); }
+      
+      try
+      {         
+         if (jndiProperties.isEmpty())
+         {
+            //Local initial context
+            
+            ic = new InitialContext();
+         }
+         else
+         {
+            ic = new InitialContext(jndiProperties);
+         }
+         
+         XAConnectionFactory cf = (XAConnectionFactory)ic.lookup(connectionFactoryLookup);
+         
+         conn = cf.createXAConnection();
+         
+         XASession sess = conn.createXASession();
+         
+         XAResource res = sess.getXAResource();
+         
+         returnedXAResource = true;
+         
+         if (log.isTraceEnabled()) { log.trace(this + " returning " + res); }
+         
+         return res;
+      }     
+      catch (Exception e)
+      {
+         log.warn("Failed to get XAResource", e);
+         
+         return null;
+      }
+      finally
+      {
+         if (ic != null)
+         {
+            try
+            {
+               ic.close();
+            }
+            catch (Exception ignore)
+            {               
+               //Ignore
+            }
+         }
+      }
+      
+   }
+
+   public synchronized boolean hasMoreResources()
+   {
+      return !returnedXAResource;
+   }
+
+   public synchronized boolean initialise(String config)
+   {
+      if (log.isTraceEnabled()) { log.trace(this + " intialise: " + config); }
+      
+      StringTokenizer tok = new StringTokenizer(config, ",");
+      
+      if (tok.countTokens() != 2)
+      {
+         log.error("Invalid config: " + config);
+         return false;
+      }
+      
+      String provider = tok.nextToken();
+      
+      String propsFile = tok.nextToken();
+      
+      try
+      {
+         //The config should point to a properties file on the classpath that holds the actual config
+         InputStream is = Thread.currentThread().getContextClassLoader().getResourceAsStream(propsFile);
+         
+         Properties props = new Properties();
+         
+         props.load(is);
+         
+         /*
+          * provider1.jndi.prop1=xxxx
+          * provider1.jndi.prop2=yyyy
+          * provider1.jndi.prop3=zzzz
+          * 
+          * provider1.xaconnectionfactorylookup=xyz
+          * 
+          * provider2.jndi.prop1=xxxx
+          * provider2.jndi.prop2=yyyy
+          * provider2.jndi.prop3=zzzz
+          * 
+          * provider2.xaconnectionfactorylookup=xyz
+          *           
+          */
+         
+         Iterator iter = props.entrySet().iterator();
+         
+         String jndiPrefix = provider + ".jndi.";
+         
+         String cfKey = provider + ".xaconnectionfactorylookup";
+         
+         jndiProperties = new Hashtable();
+         
+         while (iter.hasNext())
+         {
+            Map.Entry entry = (Map.Entry)iter.next();
+            
+            String key = (String)entry.getKey();
+            String value = (String)entry.getValue();
+            
+            if (key.startsWith(jndiPrefix))
+            {
+               String actualKey = key.substring(jndiPrefix.length());
+               
+               jndiProperties.put(actualKey, value);
+            }
+            else if (key.equals(cfKey))
+            {
+               connectionFactoryLookup = value;
+            }
+         }
+         
+         if (connectionFactoryLookup == null)
+         {
+            log.error("Key " + cfKey + " does not exist in config");
+            return false;
+         }
+         
+         if (log.isTraceEnabled()) { log.trace(this + " initialised"); }
+         
+         return true;
+      }
+      catch (Exception e)
+      {
+         log.error("Failed to load config file: " + config, e);
+         
+         return false;
+      }
+   }
+   
+   protected void finalize()
+   {
+      if (log.isTraceEnabled()) { log.trace(this + " finalizing"); }
+      
+      //I'd rather have some lifecycle method that gets called on this class by the recovery manager
+      //but there doesn't seem to be one.
+      //Therefore the only place I can close the connection is in the finalizer
+      if (conn != null)
+      {
+         try
+         {
+            conn.close();
+         }
+         catch (Exception ignore)
+         {
+            //Ignore
+         }
+      }
+   }
+
+}

Modified: trunk/src/main/org/jboss/jms/recovery/JMSProviderXAResourceRecovery.java
===================================================================
--- trunk/src/main/org/jboss/jms/recovery/JMSProviderXAResourceRecovery.java	2007-01-16 14:25:37 UTC (rev 1969)
+++ trunk/src/main/org/jboss/jms/recovery/JMSProviderXAResourceRecovery.java	2007-01-16 20:58:56 UTC (rev 1970)
@@ -29,6 +29,10 @@
 
 /**
  * JMS Provider Adapter based recovery.
+ * 
+ * This should be done when recovery is being driven from a transaction manager deployed with JBoss AS
+ * since it relies on JMSProviderLoader instances being deployed that correspond to the JMS providers
+ * to recover for.
  *
  * @author <a href="adrian at jboss.com">Adrian Brock</a>
  * @author <a href="juha at jboss.com">Juha Lindfors</a>

Deleted: trunk/src/main/org/jboss/jms/recovery/MessagingXAResourceRecovery.java
===================================================================
--- trunk/src/main/org/jboss/jms/recovery/MessagingXAResourceRecovery.java	2007-01-16 14:25:37 UTC (rev 1969)
+++ trunk/src/main/org/jboss/jms/recovery/MessagingXAResourceRecovery.java	2007-01-16 20:58:56 UTC (rev 1970)
@@ -1,152 +0,0 @@
-package org.jboss.jms.recovery;
-
-import java.sql.SQLException;
-import javax.jms.XAConnection;
-import javax.jms.XAConnectionFactory;
-import javax.jms.XASession;
-import javax.naming.Context;
-import javax.naming.InitialContext;
-import javax.transaction.xa.XAResource;
-
-import org.jboss.logging.Logger;
-
-import com.arjuna.ats.jta.recovery.XAResourceRecovery;
-
-/**
- * 
- * A MessagingXAResourceRecovery
- *
- * @version <tt>$Revision$</tt>
- *
- * $Id$
- *
- */
-public class MessagingXAResourceRecovery implements XAResourceRecovery
-{   
-   private boolean trace = log.isTraceEnabled();
-   
-   private static final Logger log = Logger.getLogger(MessagingXAResourceRecovery.class);
-   
-   private boolean working = false;
-   
-   private XAResource xaRes = null;
-   
-   private String xaConnFactory = null;
-   
-   public MessagingXAResourceRecovery()
-   {
-   }
-   
-   public XAResource getXAResource() throws SQLException
-   {
-      if (trace) { log.trace("returning the xaresource " + xaRes); }
-      return xaRes;
-   }
-   
-   /**
-    * This method returns the Messaging XAResource reference.
-    * You have to pass the jndi name of the XAConnectionFactory
-    * via the JBossTS RecoveryManager's properties
-    * @return
-    */
-   public XAResource initXAResource()
-   {
-      if(trace)
-      {
-         log.trace("Initialising xaresource..");
-      }
-      try
-      {
-         Context ctx = new InitialContext();
-         
-         XAConnectionFactory cf = (XAConnectionFactory) ctx
-         .lookup(xaConnFactory);
-         
-         XAConnection xaConn = cf.createXAConnection();
-         
-         XASession session = xaConn.createXASession();
-         xaRes = session.getXAResource();
-         
-         if(trace)
-            log.trace("Found the xares: "+xaRes);
-         
-      }
-      catch (Exception e)
-      {
-         // You may get this exception when the messaging server
-         // is not fully booted up. Nothing to worry, it'll keep
-         // trying until successful.
-         log.warn("XAConnectionFactory is not found. \n" +
-                  "The messaging server is not yet initialized.\n" +
-         "we'll try again once server is fully back");
-         
-      }
-      
-      return xaRes;
-   }
-   
-   /**
-    * This method is used to pass any
-    * intialisation parameters to this
-    * class
-    * @param param
-    * @return
-    * @throws SQLException
-    */
-   public boolean initialise(String param) throws SQLException
-   {
-      if(trace) { log.trace("Passed in parameter: " + param); }
-      
-      if (param != null)
-      {
-         // param is in the form of name=value
-         String value = param.substring(param.indexOf("=") + 1);
-         
-         if(trace) { log.trace("The connection factory is " + value); }
-         
-         xaConnFactory = value;
-      }
-      else
-      {
-         log.debug("The XA connection factory parameter is null. " +
-         "Using the default 'XAConnectionFactory'");
-         
-         xaConnFactory = "XAConnectionFactory";
-      }
-      return true;
-   }
-   
-   /**
-    * This method checks whether there's an xa resource available
-    *
-    * @return
-    */
-   public boolean hasMoreResources()
-   {      
-      if (working)
-      {
-         return false;
-      }
-      
-      if (xaRes == null)
-      {
-         xaRes = initXAResource();
-      }
-      
-      // test the resource
-      try
-      {
-         
-         xaRes.getTransactionTimeout();
-         
-         working = true;         
-      }
-      catch (Exception ignored)
-      {
-         
-         // ignore this exception
-      }
-      
-      return working;
-   }
-}

Modified: trunk/src/main/org/jboss/jms/server/ServerPeer.java
===================================================================
--- trunk/src/main/org/jboss/jms/server/ServerPeer.java	2007-01-16 14:25:37 UTC (rev 1969)
+++ trunk/src/main/org/jboss/jms/server/ServerPeer.java	2007-01-16 20:58:56 UTC (rev 1970)
@@ -185,6 +185,8 @@
       {
          throw new IllegalArgumentException("ID cannot be negative");
       }
+      
+      log.info(this + " creating serverpeer with id " + serverPeerID);
 
       this.serverPeerID = serverPeerID;
       this.defaultQueueJNDIContext = defaultQueueJNDIContext;

Modified: trunk/src/main/org/jboss/jms/server/bridge/Bridge.java
===================================================================
--- trunk/src/main/org/jboss/jms/server/bridge/Bridge.java	2007-01-16 14:25:37 UTC (rev 1969)
+++ trunk/src/main/org/jboss/jms/server/bridge/Bridge.java	2007-01-16 20:58:56 UTC (rev 1970)
@@ -42,6 +42,7 @@
 
 import org.jboss.logging.Logger;
 import org.jboss.messaging.core.plugin.contract.MessagingComponent;
+import org.jboss.tm.TxManager;
 
 /**
  * 
@@ -128,9 +129,9 @@
    
    private String sourcePassword;
    
-   private String destUsername;
+   private String targetUsername;
    
-   private String destPassword;
+   private String targetPassword;
    
    private TransactionManager tm;
    
@@ -156,21 +157,21 @@
    
    private Object lock;
    
-   private ConnectionFactoryFactory sourceCfFactory;
+   private ConnectionFactoryFactory sourceCff;
    
-   private ConnectionFactoryFactory destCfFactory;
+   private ConnectionFactoryFactory targetCff;
    
-   private Connection connSource; 
+   private Connection sourceConn; 
    
-   private Connection connDest;
+   private Connection targetConn;
    
-   private Destination destSource;
+   private Destination sourceDestination;
    
-   private Destination destDest;
+   private Destination targetDestination;
    
-   private Session sessSource;
+   private Session sourceSession;
    
-   private Session sessDest;
+   private Session targetSession;
    
    private MessageConsumer consumer;
    
@@ -186,79 +187,47 @@
    
    private Transaction tx;  
    
-   private boolean manualAck;
+   private boolean failed;
    
-   private boolean manualCommit;
-      
+   private boolean usingXA;
+   
+   
    /*
+    * Constructor for MBean
+    */
+   public Bridge()
+   {      
+   }
+   
+   
+   /*
     * This constructor is used when source and destination are on different servers
     */
-   public Bridge(ConnectionFactoryFactory sourceCfFactory, ConnectionFactoryFactory destCfFactory,
-                 Destination destSource, Destination destDest,         
+   public Bridge(ConnectionFactoryFactory sourceCff, ConnectionFactoryFactory destCff,
+                 Destination sourceDestination, Destination targetDestination,         
                  String sourceUsername, String sourcePassword,
-                 String destUsername, String destPassword,
+                 String targetUsername, String targetPassword,
                  String selector, long failureRetryInterval,
                  int maxRetries,
                  int qosMode,
                  int maxBatchSize, long maxBatchTime,
                  String subName, String clientID)
-   {
-      if (sourceCfFactory == null)
-      {
-         throw new IllegalArgumentException("sourceCfFactory cannot be null");
-      }
-      if (destCfFactory == null)
-      {
-         throw new IllegalArgumentException("destCfFactory cannot be null");
-      }
-      if (destSource == null)
-      {
-         throw new IllegalArgumentException("destSource cannot be null");
-      }
-      if (destDest == null)
-      {
-         throw new IllegalArgumentException("destDest cannot be null");
-      }
-      if (failureRetryInterval < 0 && failureRetryInterval != -1)
-      {
-         throw new IllegalArgumentException("failureRetryInterval must be > 0 or -1 to represent no retry");
-      }
-      if (maxRetries < 0)
-      {
-         throw new IllegalArgumentException("maxRetries must be >= 0");
-      }
-      if (failureRetryInterval == -1 && maxRetries > 0)
-      {
-         throw new IllegalArgumentException("If failureRetryInterval == -1 maxRetries must be 0");
-      }
-      if (maxBatchSize < 1)
-      {
-         throw new IllegalArgumentException("maxBatchSize must be >= 1");
-      }
-      if (maxBatchTime < 1 && maxBatchTime != -1)
-      {
-         throw new IllegalArgumentException("maxBatchTime must be >= 1 or -1 to represent unlimited batch time");
-      }
-      if (qosMode != QOS_AT_MOST_ONCE && qosMode != QOS_DUPLICATES_OK && qosMode != QOS_ONCE_AND_ONLY_ONCE)
-      {
-         throw new IllegalArgumentException("Invalid QoS mode " + qosMode);
-      }
+   {            
+      this.sourceCff = sourceCff;
       
-      this.sourceCfFactory = sourceCfFactory;
+      this.targetCff = destCff;
       
-      this.destCfFactory = destCfFactory;
+      this.sourceDestination = sourceDestination;
       
-      this.destSource = destSource;
+      this.targetDestination = targetDestination;
       
-      this.destDest = destDest;
-      
       this.sourceUsername = sourceUsername;
       
       this.sourcePassword = sourcePassword;
       
-      this.destUsername = destUsername;
+      this.targetUsername = targetUsername;
       
-      this.destPassword = destPassword;
+      this.targetPassword = targetPassword;
       
       this.selector = selector;
       
@@ -275,6 +244,8 @@
       this.subName = subName;
       
       this.clientID = clientID;
+            
+      checkParams();
       
       this.messages = new LinkedList();      
       
@@ -325,6 +296,8 @@
       else
       {
          log.warn("Failed to start bridge");
+         
+         failed = true;
       }
    }
    
@@ -359,9 +332,12 @@
          if (trace) { log.trace("Checker thread has finished"); }
       }
       
-      connSource.close();
+      sourceConn.close();
       
-      connDest.close();
+      if (targetConn != null)
+      {
+         targetConn.close();
+      }
 
       if (tx != null)
       {
@@ -386,7 +362,7 @@
       {
          paused = true;
          
-         connSource.stop();
+         sourceConn.stop();
       }
       
       if (trace) { log.trace("Paused " + this); }
@@ -400,23 +376,328 @@
       {
          paused = false;
          
-         connSource.start();
+         sourceConn.start();
       }
       
       if (trace) { log.trace("Resumed " + this); }
    }
    
+   public Destination getSourceDestination()
+   {
+      return sourceDestination;
+   }
+   
+   public void setSourceDestination(Destination dest)
+   {
+      if (started)
+      {
+         log.warn("Cannot set SourceDestination while bridge is started");
+         return;
+      }
+      this.sourceDestination = dest;
+      checkParams();
+   }
+   
+   public Destination getTargetDestination()
+   {
+      return targetDestination;
+   }
+   
+   public void setTargetDestination(Destination dest)
+   {
+      if (started)
+      {
+         log.warn("Cannot set TargetDestination while bridge is started");
+         return;
+      }
+      this.targetDestination = dest;
+      checkParams();
+   }
+   
+   public String getSourceUsername()
+   {
+      return sourceUsername;
+   }
+   
+   public synchronized void setSourceUserName(String name)
+   {
+      if (started)
+      {
+         log.warn("Cannot set SourceUsername while bridge is started");
+         return;
+      }
+      sourceUsername = name;
+      checkParams();
+   }
+   
+   public synchronized String getSourcePassword()
+   {
+      return sourcePassword;
+   }
+   
+   public synchronized void setSourcePassword(String pwd)
+   {
+      if (started)
+      {
+         log.warn("Cannot set SourcePassword while bridge is started");
+         return;
+      }
+      sourcePassword = pwd;
+      checkParams();
+   }
+      
+   public synchronized String getDestUsername()
+   {
+      return targetUsername;
+   }
+   
+   public synchronized void setDestUserName(String name)
+   {
+      if (started)
+      {
+         log.warn("Cannot set DestUserName while bridge is started");
+         return;
+      }
+      this.targetUsername = name;
+      checkParams();
+   }
+   
+   public synchronized String getDestPassword()
+   {
+      return this.targetPassword;
+   }
+   
+   public synchronized void setDestPassword(String pwd)
+   {
+      if (started)
+      {
+         log.warn("Cannot set DestPassword while bridge is started");
+         return;
+      }
+      this.targetPassword = pwd;
+      checkParams();
+   }
+      
+   public synchronized String getSelector()
+   {
+      return selector;
+   }
+   
+   public synchronized void setSelector(String selector)
+   {
+      if (started)
+      {
+         log.warn("Cannot set Selector while bridge is started");
+         return;
+      }
+      this.selector = selector;
+      checkParams();
+   }
+   
+   public synchronized long getFailureRetryInterval()
+   {
+      return failureRetryInterval;
+   }
+   
+   public synchronized void setFailureRetryInterval(long interval)
+   {
+      if (started)
+      {
+         log.warn("Cannot set FailureRetryInterval while bridge is started");
+         return;
+      }
+      
+      this.failureRetryInterval = interval;
+      checkParams();
+   }    
+   
+   public synchronized int getMaxRetries()
+   {
+      return maxRetries;
+   }
+   
+   public synchronized void setMaxRetries(int retries)
+   {
+      if (started)
+      {
+         log.warn("Cannot set MaxRetries while bridge is started");
+         return;
+      }
+      
+      this.maxRetries = retries;
+      checkParams();
+   }
+      
+   public synchronized int getQualityOfServiceMode()
+   {
+      return qualityOfServiceMode;
+   }
+   
+   public synchronized void setQualityOfServiceMode(int mode)
+   {
+      if (started)
+      {
+         log.warn("Cannot set QualityOfServiceMode while bridge is started");
+         return;
+      }
+      
+      qualityOfServiceMode = mode;
+      checkParams();
+   }   
+   
+   public synchronized int getMaxBatchSize()
+   {
+      return maxBatchSize;
+   }
+   
+   public synchronized void setMaxBatchSize(int size)
+   {
+      if (started)
+      {
+         log.warn("Cannot set MaxBatchSize while bridge is started");
+         return;
+      }
+      
+      maxBatchSize = size;
+      checkParams();
+   }
+   
+   public synchronized long getMaxBatchTime()
+   {
+      return maxBatchTime;
+   }
+   
+   public synchronized void setMaxBatchTime(long time)
+   {
+      if (started)
+      {
+         log.warn("Cannot set MaxBatchTime while bridge is started");
+         return;
+      }
+      
+      maxBatchTime = time;
+      checkParams();
+   }
+      
+   public synchronized String getSubName()
+   {
+      return this.subName;
+   }
+   
+   public synchronized void setSubName(String subname)
+   {
+      if (started)
+      {
+         log.warn("Cannot set SubName while bridge is started");
+         return;
+      }
+      
+      this.subName = subname; 
+      checkParams();
+   }
+      
+   public synchronized String getClientID()
+   {
+      return clientID;
+   }
+   
+   public synchronized void setClientID(String clientID)
+   {
+      if (started)
+      {
+         log.warn("Cannot set ClientID while bridge is started");
+         return;
+      }
+      
+      this.clientID = clientID; 
+      checkParams();
+   }
+      
+   public synchronized boolean isPaused()
+   {
+      return paused;
+   }
+   
+   public synchronized boolean isFailed()
+   {
+      return failed;
+   }
+   
+   public synchronized void setSourceConnectionFactoryFactory(ConnectionFactoryFactory cff)
+   {
+      if (started)
+      {
+         log.warn("Cannot set SourceConnectionFactoryFactory while bridge is started");
+         return;
+      }
+      this.sourceCff = cff;
+   }
+   
+   public synchronized void setDestConnectionFactoryFactory(ConnectionFactoryFactory cff)
+   {
+      if (started)
+      {
+         log.warn("Cannot set DestConnectionFactoryFactory while bridge is started");
+         return;
+      }
+      this.targetCff = cff;
+   }
+   
    // Private -------------------------------------------------------------------
    
+   private void checkParams()
+   {
+      if (sourceCff == null)
+      {
+         throw new IllegalArgumentException("sourceCfFactory cannot be null");
+      }
+      if (targetCff == null)
+      {
+         throw new IllegalArgumentException("destCfFactory cannot be null");
+      }
+      if (sourceDestination == null)
+      {
+         throw new IllegalArgumentException("destSource cannot be null");
+      }
+      if (targetDestination == null)
+      {
+         throw new IllegalArgumentException("destDest cannot be null");
+      }
+      if (failureRetryInterval < 0 && failureRetryInterval != -1)
+      {
+         throw new IllegalArgumentException("failureRetryInterval must be > 0 or -1 to represent no retry");
+      }
+      if (maxRetries < 0 && maxRetries != -1)
+      {
+         throw new IllegalArgumentException("maxRetries must be >= 0 or -1 to represent infinite retries");
+      }
+      if (failureRetryInterval == -1 && maxRetries > 0)
+      {
+         throw new IllegalArgumentException("If failureRetryInterval == -1 maxRetries must be 0");
+      }
+      if (maxBatchSize < 1)
+      {
+         throw new IllegalArgumentException("maxBatchSize must be >= 1");
+      }
+      if (maxBatchTime < 1 && maxBatchTime != -1)
+      {
+         throw new IllegalArgumentException("maxBatchTime must be >= 1 or -1 to represent unlimited batch time");
+      }
+      if (this.qualityOfServiceMode != QOS_AT_MOST_ONCE && qualityOfServiceMode != QOS_DUPLICATES_OK && qualityOfServiceMode != QOS_ONCE_AND_ONLY_ONCE)
+      {
+         throw new IllegalArgumentException("Invalid quality of service mode " + qualityOfServiceMode);
+      }
+   }
+   
    private void enlistResources(Transaction tx) throws Exception
    {
       if (trace) { log.trace("Enlisting resources in tx"); }
       
-      XAResource resSource = ((XASession)sessSource).getXAResource();
+      XAResource resSource = ((XASession)sourceSession).getXAResource();
       
       tx.enlistResource(resSource);
       
-      XAResource resDest = ((XASession)sessDest).getXAResource();
+      XAResource resDest = ((XASession)targetSession).getXAResource();
       
       tx.enlistResource(resDest);
       
@@ -427,11 +708,11 @@
    {
       if (trace) { log.trace("Delisting resources from tx"); }
       
-      XAResource resSource = ((XASession)sessSource).getXAResource();
+      XAResource resSource = ((XASession)sourceSession).getXAResource();
       
       tx.delistResource(resSource, XAResource.TMSUCCESS);
       
-      XAResource resDest = ((XASession)sessDest).getXAResource();
+      XAResource resDest = ((XASession)targetSession).getXAResource();
       
       tx.delistResource(resDest, XAResource.TMSUCCESS);
       
@@ -462,14 +743,22 @@
    {
       if (tm == null)
       {
-//         tm = TransactionManagerLocator.getInstance().locate();
-//         
-//         if (tm == null)
-//         {
-//            throw new IllegalStateException("Cannot locate a transaction manager");
-//         }
+         //tm = TransactionManagerLocator.getInstance().locate();
          
          tm = com.arjuna.ats.jta.TransactionManager.transactionManager();
+         
+         if (tm == null)
+         {
+            throw new IllegalStateException("Cannot locate a transaction manager");
+         }
+         
+         //Sanity check
+         if (tm instanceof TxManager)
+         {
+            log.warn("WARNING! The old JBoss transaction manager is being used. " +
+                     "This does not have XA transaction recovery functionality. " +
+                     "For XA transaction recovery please deploy the JBoss Transactions JTA/JTS implementation.");
+         }
       }
       
       return tm;
@@ -516,73 +805,128 @@
       }
       return conn;
    }
-   
+    
+   /*
+    * Source and target on same server
+    * --------------------------------
+    * If the source and target destinations are on the same server (same resource manager) then,
+    * in order to get QOS_ONCE_AND_ONLY_ONCE, we simply need to consuming and send in a single
+    * local JMS transaction.
+    * 
+    * We actually use a single local transacted session for the other QoS modes too since this
+    * is more performant than using DUPS_OK_ACKNOWLEDGE or AUTO_ACKNOWLEDGE session ack modes, so effectively
+    * the QoS is upgraded.
+    * 
+    * Source and target on different server
+    * -------------------------------------
+    * If the source and target destinations are on a different servers (different resource managers) then:
+    * 
+    * If desired QoS is QOS_ONCE_AND_ONLY_ONCE, then we start a JTA transaction and enlist the consuming and sending
+    * XAResources in that.
+    * 
+    * If desired QoS is QOS_DUPLICATES_OK then, we use CLIENT_ACKNOWLEDGE for the consuming session and
+    * AUTO_ACKNOWLEDGE (this is ignored) for the sending session if the maxBatchSize == 1, otherwise we
+    * use a local transacted session for the sending session where maxBatchSize > 1, since this is more performant
+    * When bridging a batch, we make sure to manually acknowledge the consuming session, if it is CLIENT_ACKNOWLEDGE
+    * *after* the batch has been sent
+    * 
+    * If desired QoS is QOS_AT_MOST_ONCE then, if maxBatchSize == 1, we use AUTO_ACKNOWLEDGE for the consuming session,
+    * and AUTO_ACKNOWLEDGE for the sending session.
+    * If maxBatchSize > 1, we use CLIENT_ACKNOWLEDGE for the consuming session and a local transacted session for the
+    * sending session.
+    * 
+    * When bridging a batch, we make sure to manually acknowledge the consuming session, if it is CLIENT_ACKNOWLEDGE
+    * *before* the batch has been sent
+    * 
+    */
    private boolean setupJMSObjects()
    {
       try
-      {
-         connSource = createConnection(sourceUsername, sourcePassword, sourceCfFactory);
+      {  
+         //Are source and target destinations on the server? If so we can get once and only once
+         //just using a local transacted session
+         boolean sourceAndTargetSameServer = sourceCff == targetCff;
          
-         connDest = createConnection(destUsername, destPassword, destCfFactory);
+         sourceConn = createConnection(sourceUsername, sourcePassword, sourceCff);
          
+         if (!sourceAndTargetSameServer)
+         {
+            targetConn = createConnection(targetUsername, targetPassword, targetCff);
+         }
+                  
          if (clientID != null)
          {
-            connSource.setClientID(clientID);
+            sourceConn.setClientID(clientID);
          }
           
          Session sess;
          
-         if (qualityOfServiceMode == QOS_ONCE_AND_ONLY_ONCE)
+         if (sourceAndTargetSameServer)
          {
-            //Create an XASession for consuming from the source
-            if (trace) { log.trace("Creating XA source session"); }
-            sessSource = ((XAConnection)connSource).createXASession();
+            //We simply use a single local transacted session for consuming and sending      
             
-            sess = ((XASession)sessSource).getSession();
+            sourceSession = sourceConn.createSession(true, Session.SESSION_TRANSACTED);
+            
+            sess = sourceSession;
          }
          else
          {
-            if (trace) { log.trace("Creating non XA source session"); }
+            //Source and destination are on different resource managers
             
-            //Create a standard session for consuming from the source
-            
-            //If the QoS is at_most_once, and max batch size is 1 then we use AUTO_ACKNOWLEDGE
-            //If the QoS is at_most_once, and max batch size > 1 or -1, then we use CLIENT_ACKNOWLEDGE
-            //We could use CLIENT_ACKNOWLEDGE for both the above but AUTO_ACKNOWLEGE may be slightly more
-            //performant in some implementations that manually acking every time but it really depends
-            //on the implementation.
-            //We could also use local transacted for both the above but don't for the same reasons.
-            
-            //If the QoS is duplicates_ok, we use CLIENT_ACKNOWLEDGE
-            //We could use local transacted, whether one is faster than the other probably depends on the
-            //messaging implementation but there's probably not much in it
-            
-            int ackMode;
-            if (qualityOfServiceMode == QOS_AT_MOST_ONCE && maxBatchSize == 1)
+            if (qualityOfServiceMode == QOS_ONCE_AND_ONLY_ONCE)
             {
-               ackMode = Session.AUTO_ACKNOWLEDGE;
+               //Create an XASession for consuming from the source
+               if (trace) { log.trace("Creating XA source session"); }
+               
+               sourceSession = ((XAConnection)sourceConn).createXASession();
+               
+               sess = ((XASession)sourceSession).getSession();
+               
+               usingXA = true;
             }
             else
             {
-               ackMode = Session.CLIENT_ACKNOWLEDGE;
+               if (trace) { log.trace("Creating non XA source session"); }
                
-               manualAck = true;
+               //Create a standard session for consuming from the source
+               
+               //If the QoS is at_most_once, and max batch size is 1 then we use AUTO_ACKNOWLEDGE
+               //If the QoS is at_most_once, and max batch size > 1 or -1, then we use CLIENT_ACKNOWLEDGE
+               //We could use CLIENT_ACKNOWLEDGE for both the above but AUTO_ACKNOWLEGE may be slightly more
+               //performant in some implementations that manually acking every time but it really depends
+               //on the implementation.
+               //We could also use local transacted for both the above but don't for the same reasons.
+               
+               //If the QoS is duplicates_ok, we use CLIENT_ACKNOWLEDGE
+               //We could use local transacted, whether one is faster than the other probably depends on the
+               //messaging implementation but there's probably not much in it
+               
+               int ackMode;
+               if (qualityOfServiceMode == QOS_AT_MOST_ONCE && maxBatchSize == 1)
+               {
+                  ackMode = Session.AUTO_ACKNOWLEDGE;
+               }
+               else
+               {
+                  ackMode = Session.CLIENT_ACKNOWLEDGE;
+ 
+               }
+               
+               sourceSession = sourceConn.createSession(false, ackMode);
+               
+               sess = sourceSession;
             }
-            
-            sessSource = connSource.createSession(false, ackMode);
-            
-            sess = sessSource;
          }
             
          if (subName == null)
          {
             if (selector == null)
             {
-               consumer = sess.createConsumer(destSource);
+               consumer = sess.createConsumer(sourceDestination);
             }
             else
             {
-               consumer = sess.createConsumer(destSource, selector, false);
+               consumer = sess.createConsumer(sourceDestination, selector, false);
             }
          }
          else
@@ -590,42 +934,47 @@
             //Durable subscription
             if (selector == null)
             {
-               consumer = sess.createDurableSubscriber((Topic)destSource, subName);
+               consumer = sess.createDurableSubscriber((Topic)sourceDestination, subName);
             }
             else
             {
-               consumer = sess.createDurableSubscriber((Topic)destSource, subName, selector, false);
+               consumer = sess.createDurableSubscriber((Topic)sourceDestination, subName, selector, false);
             }
          }
          
-         if (qualityOfServiceMode == QOS_ONCE_AND_ONLY_ONCE)
-         {
-            if (trace) { log.trace("Creating XA dest session"); }
-            
-            //Create an XA sesion for sending to the destination
-            
-            sessDest = ((XAConnection)connDest).createXASession();
-            
-            sess = ((XASession)sessDest).getSession();
+         //Now the sending session
+         
+         if (!sourceAndTargetSameServer)
+         {            
+            if (usingXA)
+            {
+               if (trace) { log.trace("Creating XA dest session"); }
+               
+               //Create an XA sesion for sending to the destination
+               
+               targetSession = ((XAConnection)targetConn).createXASession();
+               
+               sess = ((XASession)targetSession).getSession();
+            }
+            else
+            {
+               if (trace) { log.trace("Creating non XA dest session"); }
+               
+               //Create a standard session for sending to the destination
+               
+               //If maxBatchSize == 1 we just create a non transacted session, otherwise we
+               //create a transacted session for the send, since sending the batch in a transaction
+               //is likely to be more efficient than sending messages individually
+               
+               boolean manualCommit = maxBatchSize == 1;
+               
+               targetSession = targetConn.createSession(manualCommit, manualCommit ? Session.SESSION_TRANSACTED : Session.AUTO_ACKNOWLEDGE);
+               
+               sess = targetSession;
+            }       
          }
-         else
-         {
-            if (trace) { log.trace("Creating non XA dest session"); }
-            
-            //Create a standard session for sending to the destination
-            
-            //If maxBatchSize == 1 we just create a non transacted session, otherwise we
-            //create a transacted session for the send, since sending the batch in a transaction
-            //is likely to be more efficient than sending messages individually
-            
-            manualCommit = maxBatchSize == 1;
-            
-            sessDest = connDest.createSession(manualCommit, manualCommit ? Session.SESSION_TRANSACTED : Session.AUTO_ACKNOWLEDGE);
-            
-            sess = sessDest;
-         }
          
-         if (qualityOfServiceMode == QOS_ONCE_AND_ONLY_ONCE)
+         if (usingXA)
          {
             if (trace) { log.trace("Starting JTA transaction"); }
             
@@ -634,11 +983,11 @@
             enlistResources(tx);                  
          }
          
-         producer = sess.createProducer(destDest);
+         producer = sess.createProducer(targetDestination);
                           
          consumer.setMessageListener(new SourceListener());
          
-         connSource.start();
+         sourceConn.start();
          
          return true;
       }
@@ -678,14 +1027,17 @@
       //Close the old objects
       try
       {
-         connSource.close();
+         sourceConn.close();
       }
       catch (Throwable ignore)
       {            
       }
       try
       {
-         connDest.close();
+         if (targetConn != null)
+         {
+            targetConn.close();
+         }
       }
       catch (Throwable ignore)
       {            
@@ -746,138 +1098,161 @@
    {
       if (trace) { log.trace("Sending batch of " + messages.size() + " messages"); }
         
-      synchronized (lock)
+      if (paused)
       {
-         try
+         //Don't send now
+         if (trace) { log.trace("Paused, so not sending now"); }
+         
+         return;            
+      }
+         
+      try
+      {         
+         if (qualityOfServiceMode == QOS_AT_MOST_ONCE)
          {
-            if (paused)
+            //We ack *before* we send
+            if (sourceSession.getAcknowledgeMode() == Session.CLIENT_ACKNOWLEDGE)
             {
-               //Don't send now
-               if (trace) { log.trace("Paused, so not sending now"); }
-               
-               return;            
+               //Ack on the last message
+               ((Message)messages.getLast()).acknowledge();       
             }
+         }
+         
+         //Now send the message(s)   
             
-            if (qualityOfServiceMode == QOS_AT_MOST_ONCE)
-            {
-               //We ack before we send
-               if (manualAck)
-               {
-                  //Ack on the last message
-                  ((Message)messages.getLast()).acknowledge();       
-               }
-            }
+         Iterator iter = messages.iterator();
+         
+         Message msg = null;
+         
+         while (iter.hasNext())
+         {
+            msg = (Message)iter.next();
             
-            //Now send the message(s)   
-               
-            Iterator iter = messages.iterator();
+            if (trace) { log.trace("Sending message " + msg); }
             
-            Message msg = null;
+            producer.send(msg);
             
-            while (iter.hasNext())
-            {
-               msg = (Message)iter.next();
-               
-               if (trace) { log.trace("Sending message " + msg); }
-               
-               producer.send(msg);
-               
-               if (trace) { log.trace("Sent message " + msg); }                    
-            }
+            if (trace) { log.trace("Sent message " + msg); }                    
+         }
+         
+         if (qualityOfServiceMode == QOS_DUPLICATES_OK)
+         {
+            //We ack the source message(s) after sending
             
-            if (qualityOfServiceMode == QOS_DUPLICATES_OK)
-            {
-               //We ack the source message(s) after sending
-               
-               if (manualAck)
-               {               
-                  //Ack on the last message
-                  ((Message)messages.getLast()).acknowledge();
-               }                  
-            }
+            if (sourceSession.getAcknowledgeMode() == Session.CLIENT_ACKNOWLEDGE)
+            {               
+               //Ack on the last message
+               ((Message)messages.getLast()).acknowledge();
+            }                  
+         }
+         
+         //Now we commit the sending session if necessary
+         if (targetSession != null && targetSession.getTransacted() && !usingXA)
+         {
+            if (trace) { log.trace("Committing target session"); }
             
-            //Now we commit the sending session if necessary
-            if (manualCommit)
-            {
-               sessDest.commit();            
-            }
+            targetSession.commit();    
             
-            if (qualityOfServiceMode == QOS_ONCE_AND_ONLY_ONCE)
-            {
-               //Commit the JTA transaction and start another
-                                       
-               delistResources(tx);
-                  
-               if (trace) { log.trace("Committing JTA transaction"); }
+            if (trace) { log.trace("Committed target session"); }
+         }
+         
+         //And commit the consuming session if necessary
+         if (sourceSession.getTransacted() && !usingXA)
+         {
+            if (trace) { log.trace("Committing source session"); }
+            
+            sourceSession.commit();
+            
+            if (trace) { log.trace("Committed source session"); }
+         }
+         
+         if (usingXA)
+         {
+            //Commit the JTA transaction and start another
+                                    
+            delistResources(tx);
                
-               tx.commit();
-               
-               if (trace) { log.trace("Committed JTA transaction"); }
-               
-               tx = startTx();  
-               
-               enlistResources(tx);
-            }
+            if (trace) { log.trace("Committing JTA transaction"); }
             
-            //Clear the messages
-            messages.clear();            
+            tx.commit();
+            
+            if (trace) { log.trace("Committed JTA transaction"); }
+            
+            tx = startTx();  
+            
+            enlistResources(tx);
          }
-         catch (Exception e)
+         
+         //Clear the messages
+         messages.clear();            
+      }
+      catch (Exception e)
+      {
+         log.warn("Failed to send + acknowledge batch, closing JMS objects", e);
+         
+         handleFailure();                                                 
+      }
+   }
+   
+   private void handleFailure()
+   {
+      failed = true;
+      
+      //Failure must be handled on a separate thread to the onMessage thread since we can't close the connection
+      //from inside the onMessage method since it will block waiting for onMessage to complete
+      Thread t = new Thread(new FailureHandler());
+      
+      t.start();         
+   }
+   
+   // Inner classes ---------------------------------------------------------------
+   
+   private class FailureHandler implements Runnable
+   {
+      public void run()
+      {
+         // Clear the messages
+         messages.clear();
+                     
+         cleanup();
+         
+         boolean ok = false;
+         
+         if (maxRetries > 0 || maxRetries == -1)
          {
-            log.warn("Failed to send + acknowledge batch, closing JMS objects", e);
+            log.warn( "Will retry after a pause of " + failureRetryInterval);
             
-            /*
-             * If an Exception occurs in attempting to send / ack the batch, this might be due
-             * to a network problem on either the source or destination connection.
-             * If it was on the source connection then the server has probably NACKed the unacked
-             * messages back to the destination anyway.
-             * If the failure occurred during 2PC commit protocol then the participants may or may not
-             * have reached the prepared state, if they do then the tx will commit at some time during
-             * recovery.
-             * 
-             * So we can safely close the dead connections, without fear of stepping outside our
-             * QoS guarantee.
-             * 
-             * 
-             */
+            pause(failureRetryInterval);
             
-            //Clear the messages
-            messages.clear();
-                        
-            cleanup();
+            //Now we try
+            ok = setupJMSObjectsWithRetry();
+         }
+         
+         if (!ok)
+         {
+            //We haven't managed to recreate connections or maxRetries = 0
+            log.warn("Unable to set up connections, bridge will be stopped");
             
-            boolean ok = false;
-            
-            if (maxRetries > 0 || maxRetries == -1)
-            {
-               log.warn("Will try and re-set up connections after a pause of " + failureRetryInterval);
-               
-               pause(this.failureRetryInterval);
-               
-               //Now we try
-               ok = setupJMSObjectsWithRetry();
+            try
+            {                  
+               stop();
             }
+            catch (Exception ignore)
+            {                  
+            }
+         }
+         else
+         {
+            log.info("Succeeded in reconnecting to servers");
             
-            if (!ok)
+            synchronized (lock)
             {
-               //We haven't managed to recreate connections or maxRetries = 0
-               log.warn("Unable to set up connections, bridge will be stopped");
-               
-               try
-               {                  
-                  stop();
-               }
-               catch (Exception ignore)
-               {                  
-               }
+               failed = false;
             }
-            
-         }                                                      
+         }    
       }
    }
    
-   // Inner classes ---------------------------------------------------------------
-   
    private class BatchTimeChecker implements Runnable
    {
       public void run()
@@ -894,13 +1269,16 @@
                {
                   if (trace) { log.trace(this + " waited enough"); }
                   
-                  if (!messages.isEmpty())
-                  {
-                     if (trace) { log.trace(this + " got some messages so sending batch"); }
-                     
-                     sendBatch();
-                     
-                     if (trace) { log.trace(this + " sent batch"); }
+                  synchronized (lock)
+                  {              
+                     if (!failed && !messages.isEmpty())
+                     {
+                        if (trace) { log.trace(this + " got some messages so sending batch"); }
+                        
+                        sendBatch();                     
+                        
+                        if (trace) { log.trace(this + " sent batch"); }
+                     }
                   }
                   
                   batchExpiryTime = System.currentTimeMillis() + maxBatchTime;
@@ -933,6 +1311,14 @@
       {
          synchronized (lock)
          {
+            if (failed)
+            {
+               //Ignore the message
+               if (trace) { log.trace("Bridge has failed so ignoring message"); }
+                              
+               return;
+            }
+            
             if (trace) { log.trace(this + " received message " + msg); }
             
             messages.add(msg);

Added: trunk/src/main/org/jboss/jms/server/bridge/BridgeMBean.java
===================================================================
--- trunk/src/main/org/jboss/jms/server/bridge/BridgeMBean.java	2007-01-16 14:25:37 UTC (rev 1969)
+++ trunk/src/main/org/jboss/jms/server/bridge/BridgeMBean.java	2007-01-16 20:58:56 UTC (rev 1970)
@@ -0,0 +1,107 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2005, JBoss Inc., and individual contributors as indicated
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jboss.jms.server.bridge;
+
+
+/**
+ * A BridgeMBean
+ *
+ * @author <a href="mailto:tim.fox at jboss.com">Tim Fox</a>
+ * @version <tt>$Revision: 1.1 $</tt>
+ *
+ * $Id$
+ *
+ */
+public interface BridgeMBean
+{
+   String getSourceDestinationLookup();
+   
+   void setSourceDestinationLookup(String lookup);
+   
+   String getTargetDestinationLookup();
+   
+   void setTargetDestinationLookup(String lookup);
+      
+   String getSourceUsername();
+   
+   void setSourceUserName(String name);
+   
+   String getSourcePassword();
+   
+   void setSourcePassword(String pwd);
+      
+   String getTargetUsername();
+   
+   void setTargetUsername(String name);
+   
+   String getTargetPassword();
+   
+   void setTargetPassword(String pwd);
+      
+   String getSelector();
+   
+   void setSelector(String selector);
+   
+   long getFailureRetryInterval();
+   
+   void setFailureRetryInterval(long interval);     
+   
+   int getMaxRetries();
+   
+   void setMaxRetries(int retries);
+      
+   int getQualityOfServiceMode();
+   
+   void setQualityOfServiceMode(int mode);   
+   
+   int getMaxBatchSize();
+   
+   void setMaxBatchSize(int size);
+   
+   long getMaxBatchTime();
+   
+   void setMaxBatchTime(long time);
+      
+   String getSubName();
+   
+   void setSubName(String subname);
+      
+   String getClientID();
+   
+   void setClientID(String id);
+      
+   boolean isPaused();
+   
+   boolean isFailed();
+      
+   void setSourceJNDIProperties(String props);
+   
+   void setTargetJNDIProperties(String props);
+   
+   String getSourceJNDIProperties();
+   
+   String getTargetJNDIProperties();
+   
+   void pause() throws Exception;
+   
+   void resume() throws Exception;  
+}

Added: trunk/src/main/org/jboss/jms/server/bridge/BridgeService.java
===================================================================
--- trunk/src/main/org/jboss/jms/server/bridge/BridgeService.java	2007-01-16 14:25:37 UTC (rev 1969)
+++ trunk/src/main/org/jboss/jms/server/bridge/BridgeService.java	2007-01-16 20:58:56 UTC (rev 1970)
@@ -0,0 +1,395 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2005, JBoss Inc., and individual contributors as indicated
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jboss.jms.server.bridge;
+
+import java.io.ByteArrayInputStream;
+import java.util.Properties;
+
+import javax.jms.Destination;
+import javax.naming.InitialContext;
+
+import org.jboss.messaging.core.plugin.contract.MessagingComponent;
+import org.jboss.messaging.core.plugin.contract.ServerPlugin;
+import org.jboss.system.ServiceMBeanSupport;
+
+/**
+ * A BridgeService
+ *
+ * @author <a href="mailto:tim.fox at jboss.com">Tim Fox</a>
+ * @version <tt>$Revision: 1.1 $</tt>
+ *
+ * $Id$
+ *
+ */
+public class BridgeService extends ServiceMBeanSupport
+   implements ServerPlugin, BridgeMBean
+{
+   private Bridge bridge;
+   
+   private String sourceJNDIProperties;
+   
+   private String targetJNDIProperties;
+   
+   private String sourceConnectionFactoryLookup;
+   
+   private String targetConnectionFactoryLookup;
+   
+   private String sourceDestinationLookup;
+   
+   private String targetDestinationLookup;
+      
+   
+   public BridgeService()
+   {
+      bridge = new Bridge();
+   }
+   
+   // JMX attributes ----------------------------------------------------------------
+   
+   public synchronized String getSourceConnectionFactoryLookup()
+   {
+      return this.sourceConnectionFactoryLookup;
+   }
+   
+   public synchronized String getTargetConnectionFactoryLookup()
+   {
+      return this.targetConnectionFactoryLookup;
+   }
+   
+   public synchronized void setSourceConnectionFactoryLookup(String lookup)
+   {
+      if (getState() != STOPPED)
+      {
+         log.warn("Cannot set SourceConnectionFactoryLookup when bridge is started");
+         return;
+      }
+      this.sourceConnectionFactoryLookup = lookup;
+   }
+   
+   public synchronized void setTargetConnectionFactoryLookup(String lookup)
+   {
+      if (getState() != STOPPED)
+      {
+         log.warn("Cannot set DestConnectionFactoryLookup when bridge is started");
+         return;
+      }
+      this.targetConnectionFactoryLookup = lookup;
+   }
+   
+   public String getSourceDestinationLookup()
+   {
+      return sourceDestinationLookup;
+   }
+
+   public String getTargetDestinationLookup()
+   {
+      return targetDestinationLookup;
+   }
+
+   public void setSourceDestinationLookup(String lookup)
+   {
+      if (getState() != STOPPED)
+      {
+         log.warn("Cannot set SourceDestinationLookup when bridge is started");
+         return;
+      }
+      this.sourceDestinationLookup = lookup;
+   }
+
+   public void setTargetDestinationLookup(String lookup)
+   {
+      if (getState() != STOPPED)
+      {
+         log.warn("Cannot set TargetDestinationLookup when bridge is started");
+         return;
+      }
+      this.targetDestinationLookup = lookup;
+   }
+    
+   public String getSourceUsername()
+   {
+      return bridge.getSourceUsername();
+   }
+   
+   public String getSourcePassword()
+   {
+      return bridge.getSourcePassword();
+   }
+   
+   public void setSourceUserName(String name)
+   {
+      bridge.setSourceUserName(name);
+   }
+   
+   public void setSourcePassword(String pwd)
+   {
+      bridge.setSourcePassword(pwd);
+   }
+
+   public String getTargetUsername()
+   {
+      return bridge.getDestUsername();
+   }
+
+   public String getTargetPassword()
+   {
+      return bridge.getDestPassword();
+   }
+   
+   public void setTargetUsername(String name)
+   {
+      bridge.setDestUserName(name);
+   }
+   
+   public void setTargetPassword(String pwd)
+   {
+      bridge.setDestPassword(pwd);
+   }
+   
+   public int getQualityOfServiceMode()
+   {
+      return bridge.getQualityOfServiceMode();
+   }
+   
+   public void setQualityOfServiceMode(int mode)
+   {
+      bridge.setQualityOfServiceMode(mode);
+   }
+   
+   public String getSelector()
+   {
+      return bridge.getSelector();
+   }
+
+   public void setSelector(String selector)
+   {
+      bridge.setSelector(selector);
+   }
+
+   public int getMaxBatchSize()
+   {
+      return bridge.getMaxBatchSize();
+   }
+   
+   public void setMaxBatchSize(int size)
+   {
+      bridge.setMaxBatchSize(size);
+   }
+
+   public long getMaxBatchTime()
+   {
+      return bridge.getMaxBatchTime();
+   }
+   
+   public void setMaxBatchTime(long time)
+   {
+      bridge.setMaxBatchTime(time);
+   }
+
+   public String getSubName()
+   {
+      return bridge.getSubName();
+   }
+   
+   public void setSubName(String subname)
+   {
+      bridge.setSubName(subname);
+   }
+
+   public String getClientID()
+   {
+      return bridge.getClientID();
+   }
+     
+   public void setClientID(String clientID)
+   {
+      bridge.setClientID(clientID);
+   }
+   
+   public long getFailureRetryInterval()
+   {
+      return bridge.getFailureRetryInterval();
+   }
+   
+   public void setFailureRetryInterval(long interval)
+   {
+      bridge.setFailureRetryInterval(interval);
+   }
+   
+   public int getMaxRetries()
+   {
+      return bridge.getMaxRetries();
+   }
+   
+   public void setMaxRetries(int retries)
+   {
+      bridge.setMaxRetries(retries);
+   }
+   
+   public boolean isFailed()
+   {
+      return bridge.isFailed();
+   }
+
+   public boolean isPaused()
+   {
+      return bridge.isPaused();
+   }
+
+   public synchronized String getSourceJNDIProperties()
+   {
+      return sourceJNDIProperties;
+   }
+   
+   public synchronized void setSourceJNDIProperties(String props)
+   {
+      if (props != null)
+      {
+         props = props.trim();
+         if ("".equals(props))
+         {
+            props = null;
+         }
+      }
+      this.sourceJNDIProperties = props;
+   }
+   
+   public synchronized String getTargetJNDIProperties()
+   {
+      return targetJNDIProperties;
+   }
+   
+   public synchronized void setTargetJNDIProperties(String props)
+   {
+      if (props != null)
+      {
+         props = props.trim();
+         if ("".equals(props))
+         {
+            props = null;
+         }
+      }
+      this.targetJNDIProperties = props;
+   }
+
+   public MessagingComponent getInstance()
+   {
+      return bridge;
+   }
+   
+   // JMX operations ----------------------------------------------------------------
+   
+   public void pause() throws Exception
+   {
+      bridge.pause();
+   }
+   
+   public void resume() throws Exception
+   {
+      bridge.resume();
+   }
+   
+   // ServiceMBeanSupport overrides --------------------------------------------------
+
+   protected void startService() throws Exception
+   {
+      super.startService();
+      
+      Properties sourceProps = null;
+      
+      if (sourceJNDIProperties != null)
+      {
+         sourceProps = createProps(sourceJNDIProperties);
+      }
+      
+      Properties targetProps = null;
+      
+      if (targetJNDIProperties != null)
+      {
+         targetProps = createProps(targetJNDIProperties);
+      }
+      
+      InitialContext icSource = null;
+      
+      if (sourceProps == null)
+      {
+         icSource = new InitialContext();
+      }
+      else
+      {
+         icSource = new InitialContext(sourceProps);
+      }
+      
+      Destination sourceDest = (Destination)icSource.lookup(sourceDestinationLookup);
+      
+      InitialContext icDest = null;
+      
+      if (targetProps == null)
+      {
+         icDest = new InitialContext();
+      }
+      else
+      {
+         icDest = new InitialContext(sourceProps);
+      }
+      
+      Destination targetDest = (Destination)icDest.lookup(targetDestinationLookup);
+                     
+      ConnectionFactoryFactory sourceCff =
+         new JNDIConnectionFactoryFactory(sourceProps, sourceConnectionFactoryLookup);
+      
+      ConnectionFactoryFactory destCff =
+         new JNDIConnectionFactoryFactory(targetProps, targetConnectionFactoryLookup);
+      
+      bridge.setSourceDestination(sourceDest);
+      
+      bridge.setTargetDestination(targetDest);
+      
+      bridge.setSourceConnectionFactoryFactory(sourceCff);
+      
+      bridge.setDestConnectionFactoryFactory(destCff);
+      
+      bridge.start();      
+   }
+   
+
+   protected void stopService() throws Exception
+   {
+      bridge.stop();
+   }
+   
+   // Private ---------------------------------------------------------------------------------
+   
+   private Properties createProps(String propsString) throws Exception
+   {
+      ByteArrayInputStream is = new ByteArrayInputStream(propsString.getBytes());
+      
+      Properties props = new Properties();
+      
+      props.load(is);   
+      
+      return props;
+   }
+
+
+
+}

Modified: trunk/src/main/org/jboss/jms/server/bridge/JNDIConnectionFactoryFactory.java
===================================================================
--- trunk/src/main/org/jboss/jms/server/bridge/JNDIConnectionFactoryFactory.java	2007-01-16 14:25:37 UTC (rev 1969)
+++ trunk/src/main/org/jboss/jms/server/bridge/JNDIConnectionFactoryFactory.java	2007-01-16 20:58:56 UTC (rev 1970)
@@ -56,7 +56,14 @@
       
       try
       {
-         ic = new InitialContext(jndiProperties);
+         if (jndiProperties == null)
+         {
+            ic = new InitialContext();
+         }
+         else
+         {
+            ic = new InitialContext(jndiProperties);
+         }
          
          cf = (ConnectionFactory)ic.lookup(lookup);         
       }

Modified: trunk/src/main/org/jboss/jms/server/endpoint/ServerConnectionEndpoint.java
===================================================================
--- trunk/src/main/org/jboss/jms/server/endpoint/ServerConnectionEndpoint.java	2007-01-16 14:25:37 UTC (rev 1969)
+++ trunk/src/main/org/jboss/jms/server/endpoint/ServerConnectionEndpoint.java	2007-01-16 20:58:56 UTC (rev 1970)
@@ -500,8 +500,11 @@
       this.usingVersion = version;
    }
    
-   
-           
+   public ServerPeer getServerPeer()
+   {
+      return serverPeer;
+   }
+        
    public String toString()
    {
       return "ConnectionEndpoint[" + id + "]";
@@ -584,11 +587,6 @@
       }
    }
    
-   ServerPeer getServerPeer()
-   {
-      return serverPeer;
-   }
-   
    String getRemotingClientSessionId()
    {
       return remotingClientSessionId;

Modified: trunk/src/main/org/jboss/messaging/core/plugin/postoffice/DefaultPostOffice.java
===================================================================
--- trunk/src/main/org/jboss/messaging/core/plugin/postoffice/DefaultPostOffice.java	2007-01-16 14:25:37 UTC (rev 1969)
+++ trunk/src/main/org/jboss/messaging/core/plugin/postoffice/DefaultPostOffice.java	2007-01-16 20:58:56 UTC (rev 1970)
@@ -48,6 +48,7 @@
 import org.jboss.messaging.core.Queue;
 import org.jboss.messaging.core.local.PagingFilteredQueue;
 import org.jboss.messaging.core.plugin.JDBCSupport;
+import org.jboss.messaging.core.plugin.contract.ClusteredPostOffice;
 import org.jboss.messaging.core.plugin.contract.Condition;
 import org.jboss.messaging.core.plugin.contract.ConditionFactory;
 import org.jboss.messaging.core.plugin.contract.MessageStore;
@@ -519,13 +520,22 @@
 
             Condition condition = conditionFactory.createCondition(conditionText);
 
-            Binding binding = createBinding(nodeID, condition, queueName, channelID,
-                                            selector, true, failed, failedNodeID);
-
-            log.debug(this + " loaded from database " + binding);
-            
-            binding.getQueue().deactivate();
-            addBinding(binding);
+            //Temp hack
+            //For non clustered po don't want to load other nodes bindings!
+            if (!(this instanceof ClusteredPostOffice) && (nodeID != this.currentNodeId))
+            {
+               //Don't load other nodes binding
+            }
+            else
+            {               
+               Binding binding = createBinding(nodeID, condition, queueName, channelID,
+                                               selector, true, failed, failedNodeID);
+      
+               log.debug(this + " loaded from database " + binding);
+               
+               binding.getQueue().deactivate();
+               addBinding(binding);
+            }
          }
       }
       finally

Modified: trunk/tests/bin/runtest
===================================================================
--- trunk/tests/bin/runtest	2007-01-16 14:25:37 UTC (rev 1969)
+++ trunk/tests/bin/runtest	2007-01-16 20:58:56 UTC (rev 1970)
@@ -158,27 +158,9 @@
    fi
 fi
 
-if [ "$isRemote" = "true" ]; then
 
-  export TEST_DATABASE TEST_SERIALIZATION TEST_CLUSTERED TEST_REMOTING
 
-  $reldir/start-rmi-server $REMOTE_DEBUG_FLAG_0 -use-existent-test-classpath-file -index 0
 
-  if [ "$TEST_CLUSTERED" = "true" ]; then
-
-     # start the second remote server
-     $reldir/start-rmi-server $REMOTE_DEBUG_FLAG_1 -use-existent-test-classpath-file -index 1
-
-     # start the third remote server
-     $reldir/start-rmi-server $REMOTE_DEBUG_FLAG_2 -use-existent-test-classpath-file -index 2
-
-     # start the fourth remote server
-     $reldir/start-rmi-server $REMOTE_DEBUG_FLAG_3 -use-existent-test-classpath-file -index 3
-
-  fi
-fi
-
-
 $JAVA_HOME/bin/java $JAVA_OPTS -cp "$CLASSPATH" \
 org.jboss.test.messaging.tools.junit.SelectiveTestRunner $TARGET_CLASS $TARGET_TEST
 

Modified: trunk/tests/bin/start-rmi-server
===================================================================
--- trunk/tests/bin/start-rmi-server	2007-01-16 14:25:37 UTC (rev 1969)
+++ trunk/tests/bin/start-rmi-server	2007-01-16 20:58:56 UTC (rev 1970)
@@ -58,8 +58,9 @@
    JAVA_OPTS="$JAVA_OPTS -Dtest.serialization=$TEST_SERIALIZATION"
 fi
 
+# We need to append the index even if non clustered since we may have many non clustered servers
 if [ "$TEST_REMOTING" != "" ]; then
-   JAVA_OPTS="$JAVA_OPTS -Dtest.remoting=$TEST_REMOTING -Dtest.logfile.suffix=remote-server"
+   JAVA_OPTS="$JAVA_OPTS -Dtest.remoting=$TEST_REMOTING -Dtest.logfile.suffix=remote-server$index"
 fi
 
 if [ "$TEST_CLUSTERED" != "" ]; then

Added: trunk/tests/etc/bridge-recovery.properties
===================================================================
--- trunk/tests/etc/bridge-recovery.properties	2007-01-16 14:25:37 UTC (rev 1969)
+++ trunk/tests/etc/bridge-recovery.properties	2007-01-16 20:58:56 UTC (rev 1970)
@@ -0,0 +1,9 @@
+#Only valid for testing the bridge recovery from within the test suite 
+
+server0.jndi.java.naming.factory.initial=org.jboss.test.messaging.tools.jndi.RemoteInitialContextFactory
+server0.jndi.jboss.messaging.test.server.index=0
+server0.xaconnectionfactorylookup=/XAConnectionFactory
+
+server1.jndi.java.naming.factory.initial=org.jboss.test.messaging.tools.jndi.RemoteInitialContextFactory
+server1.jndi.jboss.messaging.test.server.index=1
+server1.xaconnectionfactorylookup=/XAConnectionFactory

Added: trunk/tests/etc/jbossjta-properties.xml
===================================================================
--- trunk/tests/etc/jbossjta-properties.xml	2007-01-16 14:25:37 UTC (rev 1969)
+++ trunk/tests/etc/jbossjta-properties.xml	2007-01-16 20:58:56 UTC (rev 1970)
@@ -0,0 +1,257 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!-- Arjuna JTA config for JBoss Messaging test suite
+This config has some quicker settings (lik recovery period) than you would
+probably have in a real production config, this is so the tests don't take aeons to run -->
+
+<transaction-service>
+
+    <properties depends="common" name="arjuna">
+        <!--
+        Transaction Reaper Timeout (default is 120000 microseconds).
+      -->
+        <property
+            name="com.arjuna.ats.arjuna.coordinator.txReaperTimeout" value="120000"/>
+        <!--
+        Transaction Reaper Mode, can be: NORMAL or DYNAMIC (default is NORMAL).
+      -->
+        <property name="com.arjuna.ats.arjuna.coordinator.txReaperMode" value="NORMAL"/>
+        <!--
+        (default is NO)
+      -->
+        <property name="com.arjuna.ats.arjuna.coordinator.asyncCommit" value="NO"/>
+        <!--
+        (default is NO)
+      -->
+        <property name="com.arjuna.ats.arjuna.coordinator.asyncPrepare" value="NO"/>
+        <!--
+        (default is YES)
+      -->
+        <property
+            name="com.arjuna.ats.arjuna.coordinator.commitOnePhase" value="YES"/>
+        <!--
+        (default is defaultStore)
+      -->
+        <property name="com.arjuna.ats.arjuna.objectstore.localOSRoot" value="defaultStore"/>
+        <!--
+        default is under user.home - must be writeable!)
+      -->
+        <property
+            name="com.arjuna.ats.arjuna.objectstore.objectStoreDir" value="ObjectStore"/>
+        <!--
+        (default is ON)
+      -->
+        <property
+            name="com.arjuna.ats.arjuna.objectstore.objectStoreSync" value="ON"/>
+        <!--
+        (default is ShadowNoFileLockStore)
+      -->
+        <property
+            name="com.arjuna.ats.arjuna.objectstore.objectStoreType" value="ShadowNoFileLockStore"/>
+        <!--
+        (default is 255)
+      -->
+        <property
+            name="com.arjuna.ats.arjuna.objectstore.hashedDirectories" value="255"/>
+        <!--
+        (default is ON)
+      -->
+        <property
+            name="com.arjuna.ats.arjuna.objectstore.transactionSync" value="ON"/>
+        <!--
+        (Must be unique across all Arjuna instances.)
+      -->
+        <property name="com.arjuna.ats.arjuna.xa.nodeIdentifier" value="node0"/>
+        <!-- property
+        name="com.arjuna.ats.arjuna.coordinator.actionStore"
+      value="HashedActionStore"
+      value="JDBCActionStore"
+      -->
+        <!-- property
+        name="com.arjuna.ats.arjuna.objectstore.jdbcTxDbAccess"
+      value="JDBCAccess"
+      -->
+        <!-- property
+        name="com.arjuna.ats.arjuna.objectstore.objectStoreType"
+      value="ShadowNoFileLockStore"
+      value="JDBCStore"
+      -->
+        <!-- property
+        name="com.arjuna.ats.arjuna.objectstore.jdbcUserDbAccess"
+      value="JDBCAccess"
+      -->
+        <!-- property
+        name="com.arjuna.ats.arjuna.objectstore.jdbcPoolSizeInitial"
+      value="1"
+      -->
+        <!-- property
+        name="com.arjuna.ats.arjuna.objectstore.jdbcPoolSizeMaximum"
+      value="1"
+      -->
+        <!-- property
+        name="com.arjuna.ats.arjuna.objectstore.jdbcPoolPutConnections"
+      value="false"
+      -->
+        <!-- property
+        name="com.arjuna.ats.arjuna.internal.arjuna.objectstore.cacheStore.size"
+      value=""
+      -->
+        <!-- property
+        name="com.arjuna.ats.arjuna.internal.arjuna.objectstore.cacheStore.period"
+      value=""
+      -->
+        <!--
+        The location for creating temporary files, e.g., Uids.
+        Default is under user.home.
+        IMPORTANT: make sure the directory is lockable, e.g., /tmp on Unix
+        may not be!
+      -->
+        <!--
+        <property
+          name="com.arjuna.ats.arjuna.common.varDir"
+          value="var"/>
+      -->
+    </properties>
+    <properties depends="arjuna" name="recoverymanager">
+        <!--
+        Properties used only by the RecoveryManager.
+      -->
+        <!--
+        Periodic recovery settings.
+        Time values in this section are in seconds.
+      -->
+        <!--
+        Interval in seconds between initiating the periodic recovery modules.
+        Default is 120 seconds.
+      -->
+        <property
+            name="com.arjuna.ats.arjuna.recovery.periodicRecoveryPeriod" value="10"/>
+        <!--
+        Interval in seconds between first and second pass of periodic recovery.
+        Default is 10 seconds.
+      -->
+        <property
+            name="com.arjuna.ats.arjuna.recovery.recoveryBackoffPeriod" value="2"/>
+
+        <!--
+        Expired entry removal
+      -->
+        <!--
+        Expiry scanners to use (order of invocation is random).
+        Names must begin with "com.arjuna.ats.arjuna.recovery.expiryScanner"
+      -->
+        <property
+            name="com.arjuna.ats.arjuna.recovery.expiryScannerTransactionStatusManager" value="com.arjuna.ats.internal.arjuna.recovery.ExpiredTransactionStatusManagerScanner"/>
+        <!--
+        Interval, in hours, between running the expiry scanners.
+        This can be quite long. The absolute value determines the interval -
+        if the value is negative, the scan will NOT be run until after one
+        interval has elapsed. If positive the first scan will be immediately
+        after startup. Zero will prevent any scanning.
+        Default  = 12 = run immediately, then every 12 hours.
+      -->
+        <property
+            name="com.arjuna.ats.arjuna.recovery.expiryScanInterval" value="12"/>
+        <!--
+        Age, in hours, for removal of transaction status manager item.
+        This should be longer than any ts-using process will remain running.
+        Zero = Never removed.  Default is 12.
+      -->
+        <property
+            name="com.arjuna.ats.arjuna.recovery.transactionStatusManagerExpiryTime" value="12"/>
+        <!--
+        Use this to fix the port on which the TransactionStatusManager listens,
+        The default behaviour is to use any free port.
+      -->
+        <property
+            name="com.arjuna.ats.arjuna.recovery.transactionStatusManagerPort" value="0"/>
+        <!--
+        Properties used only by the RecoveryManager.
+      -->
+        <!--
+        Periodic recovery modules to use.  Invoked in sort-order of names.
+      -->
+        <property
+            name="com.arjuna.ats.arjuna.recovery.recoveryExtension1" value="com.arjuna.ats.internal.jta.recovery.arjunacore.XARecoveryModule"/>
+    </properties>
+    <properties name="common">
+        <!-- CLF 2.0 properties -->
+        <property name="com.arjuna.common.util.logging.DebugLevel"
+            type="System" value="0x00000000"/>
+        <property name="com.arjuna.common.util.logging.FacilityLevel"
+            type="System" value="0xffffffff"/>
+        <property name="com.arjuna.common.util.logging.VisibilityLevel"
+            type="System" value="0xffffffff"/>
+        <property name="com.arjuna.common.util.logger" type="System" value="log4j"/>
+    </properties>
+    <properties depends="arjuna" name="txoj">
+        <!--
+        (default is LockStore of installation - must be writeable!)
+      -->
+        <!--
+        <property
+          name="com.arjuna.ats.txoj.lockstore.lockStoreDir"
+          value="LockStore"/>
+      -->
+        <!--
+        (default is BasicLockStore)
+      -->
+        <property name="com.arjuna.ats.txoj.lockstore.lockStoreType" value="BasicLockStore"/>
+        <!--
+        (default is NO)
+      -->
+        <property name="com.arjuna.ats.txoj.lockstore.multipleLockStore" value="NO"/>
+        <!--
+        (default is YES)
+      -->
+        <property name="com.arjuna.ats.txoj.lockstore.singleLockStore" value="YES"/>
+        <!--
+        (default is YES)
+      -->
+        <property
+            name="com.arjuna.ats.txoj.lockstore.allowNestedLocking" value="YES"/>
+    </properties>
+    <properties depends="arjuna" name="jta">
+
+
+        <!-- This used when deployed in the app server and we want to do a recovery of a JMS provider, the string after the semi colon
+        must match the JMS provider name from the JMSProviderAdapter -->
+
+        <!--
+        <property name="com.arjuna.ats.jta.recovery.XAResourceRecovery.JBMESSAGING" value="org.jboss.jms.recovery.JMSProviderXAResourceRecovery;DefaultJMSProvider"/>
+-->
+
+        <!-- This is used for recovery using the message bridge, in which case JMSProviderAdapters aren't deployed so the string after the semi-colon
+        is first the provider name, then a comma, then the name of a properties file available on the classpath which has the server connection information, e.g:
+        provider1.jndi.prop1=xxxx
+        provider1.jndi.prop2=yyyy
+        provider1.jndi.prop3=zzzz
+        provider1.xaconnectionfactorylookup=xyz
+        provider2.jndi.prop1=xxxx
+        provider2.jndi.prop2=yyyy
+        provider2.jndi.prop3=zzzz
+        provider2.xaconnectionfactorylookup=xyz
+        -->
+        <property name="com.arjuna.ats.jta.recovery.XAResourceRecovery.JBMESSAGINGBRIDGE_SERVER0" value="org.jboss.jms.recovery.BridgeXAResourceRecovery;server0,bridge-recovery.properties"/>
+        <property name="com.arjuna.ats.jta.recovery.XAResourceRecovery.JBMESSAGINGBRIDGE_SERVER1" value="org.jboss.jms.recovery.BridgeXAResourceRecovery;server1,bridge-recovery.properties"/>
+
+        <!--
+        Support subtransactions in the JTA layer?
+        Default is NO.
+      -->
+        <property name="com.arjuna.ats.jta.supportSubtransactions" value="NO"/>
+        <property name="com.arjuna.ats.jta.jtaTMImplementation" value="com.arjuna.ats.internal.jta.transaction.arjunacore.TransactionManagerImple"/>
+        <!--
+         com.arjuna.ats.internal.jta.transaction.jts.TransactionManagerImple
+         -->
+        <property name="com.arjuna.ats.jta.jtaUTImplementation" value="com.arjuna.ats.internal.jta.transaction.arjunacore.UserTransactionImple"/>
+        <!--
+         com.arjuna.ats.internal.jta.transaction.jts.UserTransactionImple
+         -->
+    </properties>
+    <properties depends="jta" name="jdbc">
+        <!--
+           property name="com.arjuna.ats.jdbc.isolationLevel" value="TRANSACTION_SERIALIZABLE"/>
+        -->
+    </properties>
+</transaction-service>

Modified: trunk/tests/etc/log4j.xml
===================================================================
--- trunk/tests/etc/log4j.xml	2007-01-16 14:25:37 UTC (rev 1969)
+++ trunk/tests/etc/log4j.xml	2007-01-16 20:58:56 UTC (rev 1970)
@@ -38,6 +38,10 @@
       </layout>
    </appender>
 
+   <category name="com.arjuna">
+      <priority value="TRACE" class="org.jboss.logging.XLevel"/>
+   </category>
+
    <category name="org.apache">
       <priority value="INFO"/>
    </category>

Modified: trunk/tests/etc/poison.xml
===================================================================
--- trunk/tests/etc/poison.xml	2007-01-16 14:25:37 UTC (rev 1969)
+++ trunk/tests/etc/poison.xml	2007-01-16 20:58:56 UTC (rev 1970)
@@ -6,7 +6,7 @@
 
    <interceptor class="org.jboss.test.messaging.tools.aop.PoisonInterceptor" scope="PER_VM"/>
 
-   <bind pointcut="execution(* org.jboss.jms.server.endpoint.advised.ConnectionAdvised->createSessionDelegate(..))">
+   <bind pointcut="execution(* org.jboss.jms.server.endpoint.advised.ConnectionAdvised->*(..))">
       <interceptor-ref name="org.jboss.test.messaging.tools.aop.PoisonInterceptor"/>
    </bind>
 

Modified: trunk/tests/src/org/jboss/test/messaging/MessagingTestCase.java
===================================================================
--- trunk/tests/src/org/jboss/test/messaging/MessagingTestCase.java	2007-01-16 14:25:37 UTC (rev 1969)
+++ trunk/tests/src/org/jboss/test/messaging/MessagingTestCase.java	2007-01-16 20:58:56 UTC (rev 1970)
@@ -37,6 +37,7 @@
 
 import junit.framework.TestCase;
 
+import org.jboss.jms.message.MessageIdGeneratorFactory;
 import org.jboss.logging.Logger;
 import org.jboss.test.messaging.tools.ServerManagement;
 import org.jboss.tm.TransactionManagerService;
@@ -93,6 +94,8 @@
          // log the test start in the remote log, this will make hunting through logs so much easier
          ServerManagement.log(ServerManagement.INFO, banner);
       }
+      
+      MessageIdGeneratorFactory.instance.clear();
    }
 
    protected void tearDown() throws Exception

Modified: trunk/tests/src/org/jboss/test/messaging/jms/XATest.java
===================================================================
--- trunk/tests/src/org/jboss/test/messaging/jms/XATest.java	2007-01-16 14:25:37 UTC (rev 1969)
+++ trunk/tests/src/org/jboss/test/messaging/jms/XATest.java	2007-01-16 20:58:56 UTC (rev 1970)
@@ -41,8 +41,8 @@
 import org.jboss.jms.client.JBossConnectionFactory;
 import org.jboss.jms.tx.MessagingXAResource;
 import org.jboss.test.messaging.MessagingTestCase;
-import org.jboss.test.messaging.util.TransactionManagerLocator;
 import org.jboss.test.messaging.tools.ServerManagement;
+import org.jboss.test.messaging.tools.jmx.ServiceContainer;
 import org.jboss.tm.TxUtils;
 
 /**
@@ -84,15 +84,15 @@
    public void setUp() throws Exception
    {
       super.setUp();
-      ServerManagement.start("all");
+      ServerManagement.start("all,-transaction,jbossjta");
       initialContext = new InitialContext();
       
       initialContext = new InitialContext(ServerManagement.getJNDIEnvironment());
       cf = (JBossConnectionFactory)initialContext.lookup("/ConnectionFactory");
             
       if (!ServerManagement.isRemote())
-      {
-         tm = TransactionManagerLocator.getInstance().locate();
+      {        
+         tm = (TransactionManager)initialContext.lookup(ServiceContainer.TRANSACTION_MANAGER_JNDI_NAME);
       }
 
       ServerManagement.undeployQueue("Queue");

Added: trunk/tests/src/org/jboss/test/messaging/jms/bridge/BridgeMBeanTest.java
===================================================================
--- trunk/tests/src/org/jboss/test/messaging/jms/bridge/BridgeMBeanTest.java	2007-01-16 14:25:37 UTC (rev 1969)
+++ trunk/tests/src/org/jboss/test/messaging/jms/bridge/BridgeMBeanTest.java	2007-01-16 20:58:56 UTC (rev 1970)
@@ -0,0 +1,152 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2005, JBoss Inc., and individual contributors as indicated
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jboss.test.messaging.jms.bridge;
+
+import javax.management.ObjectName;
+
+import org.jboss.test.messaging.MessagingTestCase;
+import org.jboss.test.messaging.tools.ServerManagement;
+
+/**
+ * A BridgeMBeanTest
+ *
+ * @author <a href="mailto:tim.fox at jboss.com">Tim Fox</a>
+ * @version <tt>$Revision: 1.1 $</tt>
+ *
+ * $Id$
+ *
+ */
+public class BridgeMBeanTest extends MessagingTestCase
+{
+
+   public BridgeMBeanTest(String name)
+   {
+      super(name);
+   }
+
+   protected void setUp() throws Exception
+   {
+      super.setUp();
+   }
+
+   protected void tearDown() throws Exception
+   {
+      super.tearDown();
+   }
+   
+   /*
+    
+    Example config
+    
+      String config = 
+         "<mbean code=org.jboss.jms.server.bridge.BridgeService " +
+                 "name=jboss.messaging:service=Bridge,name=exampleBridge" +
+                 "xmbean-dd=\"xmdesc/Bridge-xmbean.xml\">" +      
+            "<attribute name=\"SourceConnectionFactoryLookup\">/ConnectionFactory</attribute>"+      
+            "<attribute name=\"TargetConnectionFactoryLookup\">/ConnectionFactory</attribute>"+     
+            "<attribute name=\"SourceDestinationLookup\">/topic/sourceTopic</attribute>"+     
+            "<attribute name=\"TargetDestinationLookup\">/queue/targetQueue</attribute>"+     
+            "<attribute name=\"SourceUsername\">bob</attribute>"+      
+            "<attribute name=\"SourcePassword\">pwd1</attribute>"+      
+            "<attribute name=\"TargetUsername\">jane</attribute>"+      
+            "<attribute name=\"TargetPassword\">pwd2</attribute>"+      
+            "<attribute name=\"QualityOfServiceMode\">2</attribute>"+      
+            "<attribute name=\"Selector\">vegetable='marrow'</attribute>"+      
+            "<attribute name=\"MaxBatchSize\">100</attribute>"+           
+            "<attribute name=\"MaxBatchTime\">5000</attribute>"+      
+            "<attribute name=\"SubName\">mySubscription</attribute>"+      
+            "<attribute name=\"ClientID\">clientid-123</attribute>"+      
+            "<attribute name=\"FailureRetryInterval\">5000</attribute>"+      
+            "<attribute name=\"MaxRetries\">-1</attribute>"+      
+            "<attribute name=\"SourceJNDIProperties\"><![CDATA["+
+"java.naming.factory.initial=org.jnp.interfaces.NamingContextFactory\n"+
+"java.naming.provider.url=jnp://server1:1099\n"+
+"java.naming.factory.url.pkgs=org.jboss.naming:org.jnp.interfaces\n"+
+"]]>"+
+            "</attribute>";
+            "<attribute name=\"TargetJNDIProperties\"><![CDATA["+
+"java.naming.factory.initial=org.jnp.interfaces.NamingContextFactory\n"+
+"java.naming.provider.url=jnp://server1:1099\n"+
+"java.naming.factory.url.pkgs=org.jboss.naming:org.jnp.interfaces\n"+
+"]]>"+
+            "</attribute>"+
+         "</mbean>";    
+
+    
+    */
+   
+   
+   private ObjectName deployBridge(String bridgeName, String sourceCFLookup, String targetCFLookup,
+                             String sourceDestLookup, String targetDestLookup,
+                             String sourceUsername, String sourcePassword,
+                             String targetUsername, String targetPassword,
+                             int qos, String selector, int maxBatchSize,
+                             long maxBatchTime, String subName, String clientID,
+                             long failureRetryInterval, int maxRetries,
+                             String sourceJNDIProperties,
+                             String targetJNDIProperties) throws Exception
+   {
+      String config = 
+      "<mbean code=org.jboss.jms.server.bridge.BridgeService " +
+      "name=jboss.messaging:service=Bridge,name=" + bridgeName +
+      "xmbean-dd=\"xmdesc/Bridge-xmbean.xml\">" +      
+          "<attribute name=\"SourceConnectionFactoryLookup\">" + sourceCFLookup + "/attribute>"+      
+          "<attribute name=\"TargetConnectionFactoryLookup\">" + targetCFLookup + "</attribute>"+     
+          "<attribute name=\"SourceDestinationLookup\">" + sourceDestLookup + "</attribute>"+     
+          "<attribute name=\"TargetDestinationLookup\">" + targetDestLookup + "</attribute>"+     
+          sourceUsername == null ? "" :
+          "<attribute name=\"SourceUsername\">" + sourceUsername + "</attribute>"+      
+          sourcePassword == null ? "" :
+          "<attribute name=\"SourcePassword\">" + sourcePassword +"</attribute>"+     
+          targetUsername == null ? "" :
+          "<attribute name=\"TargetUsername\">" + targetUsername +"</attribute>"+    
+          targetPassword == null ? "" :
+          "<attribute name=\"TargetPassword\">" + targetPassword + "</attribute>"+      
+          "<attribute name=\"QualityOfServiceMode\">" + qos +"</attribute>"+      
+          selector == null ? "" :
+          "<attribute name=\"Selector\">" + selector + "</attribute>"+      
+          "<attribute name=\"MaxBatchSize\">" + maxBatchSize + "</attribute>"+           
+          "<attribute name=\"MaxBatchTime\">" + maxBatchTime +"</attribute>"+    
+          subName == null ? "" :
+          "<attribute name=\"SubName\">" + subName + "</attribute>"+      
+          clientID == null ? "" :
+          "<attribute name=\"ClientID\">" + clientID + "</attribute>"+      
+          "<attribute name=\"FailureRetryInterval\">" + failureRetryInterval + "</attribute>"+      
+          "<attribute name=\"MaxRetries\">" + maxRetries +"</attribute>"+      
+          sourceJNDIProperties == null ? "" :
+          "<attribute name=\"SourceJNDIProperties\"><![CDATA["+
+         sourceJNDIProperties +
+         "]]>"+
+          "</attribute>"+
+          targetJNDIProperties == null ? "" :
+          "<attribute name=\"TargetJNDIProperties\"><![CDATA["+
+         targetJNDIProperties +
+         "]]>"+
+          "</attribute>"+
+      "</mbean>";
+      
+      log.info(config);
+      
+      return ServerManagement.deploy(config);            
+   }
+
+}

Modified: trunk/tests/src/org/jboss/test/messaging/jms/bridge/BridgeTest.java
===================================================================
--- trunk/tests/src/org/jboss/test/messaging/jms/bridge/BridgeTest.java	2007-01-16 14:25:37 UTC (rev 1969)
+++ trunk/tests/src/org/jboss/test/messaging/jms/bridge/BridgeTest.java	2007-01-16 20:58:56 UTC (rev 1970)
@@ -38,7 +38,6 @@
 import org.jboss.jms.server.bridge.ConnectionFactoryFactory;
 import org.jboss.jms.server.bridge.JNDIConnectionFactoryFactory;
 import org.jboss.logging.Logger;
-import org.jboss.test.messaging.MessagingTestCase;
 import org.jboss.test.messaging.tools.ServerManagement;
 
 /**
@@ -50,10 +49,12 @@
  * $Id$
  *
  */
-public class BridgeTest extends MessagingTestCase
+public class BridgeTest extends BridgeTestBase
 {
    private static final Logger log = Logger.getLogger(BridgeTest.class);
    
+   private static final int NODE_COUNT = 2;
+   
    public BridgeTest(String name)
    {
       super(name);
@@ -61,12 +62,12 @@
 
    protected void setUp() throws Exception
    {
-      super.setUp();
+      super.setUp();     
    }
 
    protected void tearDown() throws Exception
-   {
-      super.tearDown();
+   {            
+      super.tearDown();      
    }
    
    // MaxBatchSize but no MaxBatchTime
@@ -125,7 +126,65 @@
       testNoMaxBatchTime(Bridge.QOS_ONCE_AND_ONLY_ONCE, false);
    }
    
+   //Same server
    
+   // MaxBatchSize but no MaxBatchTime
+   
+   public void testNoMaxBatchTimeSameServer_AtMostOnce_P() throws Exception
+   {
+      if (!ServerManagement.isRemote())
+      {
+         return;
+      }
+      testNoMaxBatchTimeSameServer(Bridge.QOS_AT_MOST_ONCE, true);
+   }
+   
+   public void testNoMaxBatchTimeSameServer_DuplicatesOk_P() throws Exception
+   {
+      if (!ServerManagement.isRemote())
+      {
+         return;
+      }
+      testNoMaxBatchTimeSameServer(Bridge.QOS_DUPLICATES_OK, true);
+   }
+   
+   public void testNoMaxBatchTimeSameServer_OnceAndOnlyOnce_P() throws Exception
+   {
+      if (!ServerManagement.isRemote())
+      {
+         return;
+      }
+      testNoMaxBatchTimeSameServer(Bridge.QOS_ONCE_AND_ONLY_ONCE, true);
+   }
+   
+   public void testNoMaxBatchTimeSameServer_AtMostOnce_NP() throws Exception
+   {
+      if (!ServerManagement.isRemote())
+      {
+         return;
+      }
+      testNoMaxBatchTimeSameServer(Bridge.QOS_AT_MOST_ONCE, false);
+   }
+   
+   public void testNoMaxBatchTimeSameServer_DuplicatesOk_NP() throws Exception
+   {
+      if (!ServerManagement.isRemote())
+      {
+         return;
+      }
+      testNoMaxBatchTimeSameServer(Bridge.QOS_DUPLICATES_OK, false);
+   }
+   
+   public void testNoMaxBatchTimeSameServer_OnceAndOnlyOnce_NP() throws Exception
+   {
+      if (!ServerManagement.isRemote())
+      {
+         return;
+      }
+      testNoMaxBatchTimeSameServer(Bridge.QOS_ONCE_AND_ONLY_ONCE, false);
+   }
+   
+   
    // MaxBatchTime but no MaxBatchSize
    
    public void testMaxBatchTime_AtMostOnce_P() throws Exception
@@ -182,98 +241,901 @@
       testMaxBatchTime(Bridge.QOS_ONCE_AND_ONLY_ONCE, false);
    }
     
+   // Same server
    
-   // Stress 
+   // MaxBatchTime but no MaxBatchSize
    
-   public void testStress_AtMostOnce_P() throws Exception
+   public void testMaxBatchTimeSameServer_AtMostOnce_P() throws Exception
    {
       if (!ServerManagement.isRemote())
       {
          return;
       }
-      testStress(Bridge.QOS_AT_MOST_ONCE, true);
+      this.testMaxBatchTimeSameServer(Bridge.QOS_AT_MOST_ONCE, true);
    }
    
-   public void testStress_DuplicatesOk_P() throws Exception
+   public void testMaxBatchTimeSameServer_DuplicatesOk_P() throws Exception
    {
       if (!ServerManagement.isRemote())
       {
          return;
       }
-      testStress(Bridge.QOS_DUPLICATES_OK, true);
+      this.testMaxBatchTimeSameServer(Bridge.QOS_DUPLICATES_OK, true);
    }
    
-   public void testStress_OnceAndOnlyOnce_P() throws Exception
+   public void testMaxBatchTimeSameServer_OnceAndOnlyOnce_P() throws Exception
    {
       if (!ServerManagement.isRemote())
       {
          return;
       }
-      testStress(Bridge.QOS_ONCE_AND_ONLY_ONCE, true);
+      testMaxBatchTimeSameServer(Bridge.QOS_ONCE_AND_ONLY_ONCE, true);
    }
    
-   public void testStress_AtMostOnce_NP() throws Exception
+   public void testMaxBatchTimeSameServer_AtMostOnce_NP() throws Exception
    {
       if (!ServerManagement.isRemote())
       {
          return;
       }
-      testStress(Bridge.QOS_AT_MOST_ONCE, false);
+      this.testMaxBatchTimeSameServer(Bridge.QOS_AT_MOST_ONCE, false);
    }
    
-   public void testStress_DuplicatesOk_NP() throws Exception
+   public void testMaxBatchTimeSameServer_DuplicatesOk_NP() throws Exception
    {
       if (!ServerManagement.isRemote())
       {
          return;
       }
-      testStress(Bridge.QOS_DUPLICATES_OK, false);
+      this.testMaxBatchTimeSameServer(Bridge.QOS_DUPLICATES_OK, false);
    }
    
-   public void testStress_OnceAndOnlyOnce_NP() throws Exception
+   public void testMaxBatchTimeSameServer_OnceAndOnlyOnce_NP() throws Exception
    {
       if (!ServerManagement.isRemote())
       {
          return;
       }
-      testStress(Bridge.QOS_ONCE_AND_ONLY_ONCE, false);
+      testMaxBatchTimeSameServer(Bridge.QOS_ONCE_AND_ONLY_ONCE, false);
    }
    
+   // Stress with batch size of 50
    
+   public void testStress_AtMostOnce_P_50() throws Exception
+   {
+      if (!ServerManagement.isRemote())
+      {
+         return;
+      }
+      testStress(Bridge.QOS_AT_MOST_ONCE, true, 50);
+   }
    
-   private static class Sender implements Runnable
+   public void testStress_DuplicatesOk_P_50() throws Exception
    {
-      int numMessages;
+      if (!ServerManagement.isRemote())
+      {
+         return;
+      }
+      testStress(Bridge.QOS_DUPLICATES_OK, true, 50);
+   }
+   
+   public void testStress_OnceAndOnlyOnce_P_50() throws Exception
+   {
+      if (!ServerManagement.isRemote())
+      {
+         return;
+      }
+      testStress(Bridge.QOS_ONCE_AND_ONLY_ONCE, true, 50);
+   }
+   
+   public void testStress_AtMostOnce_NP_50() throws Exception
+   {
+      if (!ServerManagement.isRemote())
+      {
+         return;
+      }
+      testStress(Bridge.QOS_AT_MOST_ONCE, false, 50);
+   }
+   
+   public void testStress_DuplicatesOk_NP_50() throws Exception
+   {
+      if (!ServerManagement.isRemote())
+      {
+         return;
+      }
+      testStress(Bridge.QOS_DUPLICATES_OK, false, 50);
+   }
+   
+   public void testStress_OnceAndOnlyOnce_NP_50() throws Exception
+   {
+      if (!ServerManagement.isRemote())
+      {
+         return;
+      }
+      testStress(Bridge.QOS_ONCE_AND_ONLY_ONCE, false, 50);
+   }
+   
+   // Stress with batch size of 1
+   
+   public void testStress_AtMostOnce_P_1() throws Exception
+   {
+      if (!ServerManagement.isRemote())
+      {
+         return;
+      }
+      testStress(Bridge.QOS_AT_MOST_ONCE, true, 1);
+   }
+   
+   public void testStress_DuplicatesOk_P_1() throws Exception
+   {
+      if (!ServerManagement.isRemote())
+      {
+         return;
+      }
+      testStress(Bridge.QOS_DUPLICATES_OK, true, 1);
+   }
+   
+   public void testStress_OnceAndOnlyOnce_P_1() throws Exception
+   {
+      if (!ServerManagement.isRemote())
+      {
+         return;
+      }
+      testStress(Bridge.QOS_ONCE_AND_ONLY_ONCE, true, 1);
+   }
+   
+   public void testStress_AtMostOnce_NP_1() throws Exception
+   {
+      if (!ServerManagement.isRemote())
+      {
+         return;
+      }
+      testStress(Bridge.QOS_AT_MOST_ONCE, false, 1);
+   }
+   
+   public void testStress_DuplicatesOk_NP_1() throws Exception
+   {
+      if (!ServerManagement.isRemote())
+      {
+         return;
+      }
+      testStress(Bridge.QOS_DUPLICATES_OK, false, 1);
+   }
+   
+   public void testStress_OnceAndOnlyOnce_NP_1() throws Exception
+   {
+      if (!ServerManagement.isRemote())
+      {
+         return;
+      }
+      testStress(Bridge.QOS_ONCE_AND_ONLY_ONCE, false, 1);
+   }
+   
+   // Stress on same server
+   
+   // Stress with batch size of 50
+   
+   public void testStressSameServer_AtMostOnce_P_50() throws Exception
+   {
+      if (!ServerManagement.isRemote())
+      {
+         return;
+      }
+      testStressSameServer(Bridge.QOS_AT_MOST_ONCE, true, 50);
+   }
+   
+   public void testStressSameServer_DuplicatesOk_P_50() throws Exception
+   {
+      if (!ServerManagement.isRemote())
+      {
+         return;
+      }
+      testStressSameServer(Bridge.QOS_DUPLICATES_OK, true, 50);
+   }
+   
+   public void testStressSameServer_OnceAndOnlyOnce_P_50() throws Exception
+   {
+      if (!ServerManagement.isRemote())
+      {
+         return;
+      }
+      testStress(Bridge.QOS_ONCE_AND_ONLY_ONCE, true, 50);
+   }
+   
+   public void testStressSameServer_AtMostOnce_NP_50() throws Exception
+   {
+      if (!ServerManagement.isRemote())
+      {
+         return;
+      }
+      testStressSameServer(Bridge.QOS_AT_MOST_ONCE, false, 50);
+   }
+   
+   public void testStressSameServer_DuplicatesOk_NP_50() throws Exception
+   {
+      if (!ServerManagement.isRemote())
+      {
+         return;
+      }
+      testStressSameServer(Bridge.QOS_DUPLICATES_OK, false, 50);
+   }
+   
+   public void testStressSameServer_OnceAndOnlyOnce_NP_50() throws Exception
+   {
+      if (!ServerManagement.isRemote())
+      {
+         return;
+      }
+      testStressSameServer(Bridge.QOS_ONCE_AND_ONLY_ONCE, false, 50);
+   }
+   
+   // Stress with batch size of 1
+   
+   public void testStressSameServer_AtMostOnce_P_1() throws Exception
+   {
+      if (!ServerManagement.isRemote())
+      {
+         return;
+      }
+      testStressSameServer(Bridge.QOS_AT_MOST_ONCE, true, 1);
+   }
+   
+   public void testStressSameServer_DuplicatesOk_P_1() throws Exception
+   {
+      if (!ServerManagement.isRemote())
+      {
+         return;
+      }
+      testStressSameServer(Bridge.QOS_DUPLICATES_OK, true, 1);
+   }
+   
+   public void testStressSameServer_OnceAndOnlyOnce_P_1() throws Exception
+   {
+      if (!ServerManagement.isRemote())
+      {
+         return;
+      }
+      testStressSameServer(Bridge.QOS_ONCE_AND_ONLY_ONCE, true, 1);
+   }
+   
+   public void testStressSameServer_AtMostOnce_NP_1() throws Exception
+   {
+      if (!ServerManagement.isRemote())
+      {
+         return;
+      }
+      testStressSameServer(Bridge.QOS_AT_MOST_ONCE, false, 1);
+   }
+   
+   public void testStressSameServer_DuplicatesOk_NP_1() throws Exception
+   {
+      if (!ServerManagement.isRemote())
+      {
+         return;
+      }
+      testStressSameServer(Bridge.QOS_DUPLICATES_OK, false, 1);
+   }
+   
+   public void testStressSameServer_OnceAndOnlyOnce_NP_1() throws Exception
+   {
+      if (!ServerManagement.isRemote())
+      {
+         return;
+      }
+      testStressSameServer(Bridge.QOS_ONCE_AND_ONLY_ONCE, false, 1);
+   }
+   
+   public void testParams() throws Exception
+   {
+      try
+      {               
+         ServerManagement.deployQueue("sourceQueue", 0);
+         
+         ServerManagement.deployQueue("destQueue", 1);
+         
+         Hashtable props0 = ServerManagement.getJNDIEnvironment(0);
+         
+         Hashtable props1 = ServerManagement.getJNDIEnvironment(1);
+         
+         ConnectionFactoryFactory cff0 = new JNDIConnectionFactoryFactory(props0, "/ConnectionFactory");
+         
+         ConnectionFactoryFactory cff1 = new JNDIConnectionFactoryFactory(props1, "/ConnectionFactory");
+                      
+         InitialContext ic0 = new InitialContext(props0);
+         
+         InitialContext ic1 = new InitialContext(props1);
+         
+         Queue sourceQueue = (Queue)ic0.lookup("/queue/sourceQueue");
+         
+         Queue destQueue = (Queue)ic1.lookup("/queue/destQueue");
+           
+         Bridge bridge;
+         
+         int qosMode = Bridge.QOS_AT_MOST_ONCE;
+         
+         int batchSize = 10;
+         
+         int maxBatchTime = -1;
+         
+         String sourceUsername = null;
+         
+         String sourcePassword = null;
+         
+         String destUsername = null;
+         
+         String destPassword = null;
+         
+         String selector = null;
+         
+         long failureRetryInterval = 5000;
+         
+         int maxRetries = 10;
+         
+         String subName = null;
+         
+         String clientID = null;
+         
+         try
+         {
+            bridge= new Bridge(null, cff1, sourceQueue, destQueue,
+                               sourceUsername, sourcePassword, destUsername, destPassword,
+                               selector, failureRetryInterval, maxRetries, qosMode,
+                               batchSize, maxBatchTime,
+                               subName, clientID);
+         }
+         catch (IllegalArgumentException e)
+         {
+            //Ok
+         }
+         
+         try
+         {
+            bridge= new Bridge(cff0, null, sourceQueue, destQueue,
+                               sourceUsername, sourcePassword, destUsername, destPassword,
+                               selector, failureRetryInterval, maxRetries, qosMode,
+                               batchSize, maxBatchTime,
+                               subName, clientID);
+         }
+         catch (IllegalArgumentException e)
+         {
+            //Ok
+         }
+         
+         try
+         {
+            bridge= new Bridge(cff0, cff1, null, destQueue,
+                               sourceUsername, sourcePassword, destUsername, destPassword,
+                               selector, failureRetryInterval, maxRetries, qosMode,
+                               batchSize, maxBatchTime,
+                               subName, clientID);
+         }
+         catch (IllegalArgumentException e)
+         {
+            //Ok
+         }
+         
+         try
+         {
+            bridge= new Bridge(cff0, cff1, sourceQueue, null,
+                               sourceUsername, sourcePassword, destUsername, destPassword,
+                               selector, failureRetryInterval, maxRetries, qosMode,
+                               batchSize, maxBatchTime,
+                               subName, clientID);
+         }
+         catch (IllegalArgumentException e)
+         {
+            //Ok
+         }
+         
+         try
+         {
+            bridge= new Bridge(cff0, cff1, sourceQueue, destQueue,
+                               sourceUsername, sourcePassword, destUsername, destPassword,
+                               selector, -2, maxRetries, qosMode,
+                               batchSize, maxBatchTime,
+                               subName, clientID);
+         }
+         catch (IllegalArgumentException e)
+         {
+            //Ok
+         }
+         
+         try
+         {
+            bridge= new Bridge(cff0, cff1, sourceQueue, destQueue,
+                               sourceUsername, sourcePassword, destUsername, destPassword,
+                               selector, -1, 10, qosMode,
+                               batchSize, maxBatchTime,
+                               subName, clientID);
+         }
+         catch (IllegalArgumentException e)
+         {
+            //Ok
+         }
+         
+         try
+         {
+            bridge= new Bridge(cff0, cff1, sourceQueue, null,
+                               sourceUsername, sourcePassword, destUsername, destPassword,
+                               selector, failureRetryInterval, maxRetries, -2,
+                               batchSize, maxBatchTime,
+                               subName, clientID);
+         }
+         catch (IllegalArgumentException e)
+         {
+            //Ok
+         }
+         
+         try
+         {
+            bridge= new Bridge(cff0, cff1, sourceQueue, null,
+                               sourceUsername, sourcePassword, destUsername, destPassword,
+                               selector, failureRetryInterval, maxRetries, 3,
+                               batchSize, maxBatchTime,
+                               subName, clientID);
+         }
+         catch (IllegalArgumentException e)
+         {
+            //Ok
+         }
+         
+         try
+         {
+            bridge= new Bridge(cff0, cff1, sourceQueue, null,
+                               sourceUsername, sourcePassword, destUsername, destPassword,
+                               selector, failureRetryInterval, maxRetries, 3,
+                               0, maxBatchTime,
+                               subName, clientID);
+         }
+         catch (IllegalArgumentException e)
+         {
+            //Ok
+         }
+         
+         try
+         {
+            bridge= new Bridge(cff0, cff1, sourceQueue, null,
+                               sourceUsername, sourcePassword, destUsername, destPassword,
+                               selector, failureRetryInterval, maxRetries, 3,
+                               batchSize, -2,
+                               subName, clientID);
+         }
+         catch (IllegalArgumentException e)
+         {
+            //Ok
+         }
+      }
+      finally
+      {                      
+         try
+         {
+            ServerManagement.undeployQueue("sourceQueue", 0);
+         }
+         catch (Exception e)
+         {
+            log.error("Failed to undeploy", e);
+         }
+         
+         try
+         {
+            ServerManagement.undeployQueue("destQueue", 1);
+         }
+         catch (Exception e)
+         {
+            log.error("Failed to undeploy", e);
+         }
+      }         
+   }
+   
+   public void testSelector() throws Exception
+   {
+      Connection connSource = null;
       
-      Session sess;
+      Connection connDest = null;
       
-      MessageProducer prod;
+      Bridge bridge = null;
+            
+      try
+      {
+         ServerManagement.deployQueue("sourceQueue", 0);
+         
+         ServerManagement.deployQueue("destQueue", 1);
+         
+         Hashtable props0 = ServerManagement.getJNDIEnvironment(0);
+         
+         Hashtable props1 = ServerManagement.getJNDIEnvironment(1);
+         
+         ConnectionFactoryFactory cff0 = new JNDIConnectionFactoryFactory(props0, "/ConnectionFactory");
+         
+         ConnectionFactoryFactory cff1 = new JNDIConnectionFactoryFactory(props1, "/ConnectionFactory");
+                      
+         InitialContext ic0 = new InitialContext(props0);
+         
+         InitialContext ic1 = new InitialContext(props1);
+         
+         ConnectionFactory cf0 = (ConnectionFactory)ic0.lookup("/ConnectionFactory");
+         
+         ConnectionFactory cf1 = (ConnectionFactory)ic1.lookup("/ConnectionFactory");
+         
+         Queue sourceQueue = (Queue)ic0.lookup("/queue/sourceQueue");
+         
+         Queue destQueue = (Queue)ic1.lookup("/queue/destQueue");
+         
+         final int BATCH_SIZE = 10;
+         
+         String selector = "vegetable='radish'";
+         
+         bridge = new Bridge(cff0, cff1, sourceQueue, destQueue,
+                  null, null, null, null,
+                  selector, 5000, 10, Bridge.QOS_AT_MOST_ONCE,
+                  1, -1,
+                  null, null);
+         
+         bridge.start();
+            
+         connSource = cf0.createConnection();
+         
+         connDest = cf1.createConnection();
+         
+         Session sessSend = connSource.createSession(false, Session.AUTO_ACKNOWLEDGE);
+         
+         MessageProducer prod = sessSend.createProducer(sourceQueue);
+         
+         //Send half the messges
+
+         for (int i = 0; i < BATCH_SIZE; i++)
+         {
+            TextMessage tm = sessSend.createTextMessage("message" + i);
+            
+            if (i >= BATCH_SIZE / 2)
+            {
+               tm.setStringProperty("vegetable", "radish");
+            }
+            else
+            {
+               tm.setStringProperty("vegetable", "cauliflower");
+            }
+            
+            prod.send(tm);
+         }
+         
+         Session sessRec = connDest.createSession(false, Session.AUTO_ACKNOWLEDGE);
+         
+         MessageConsumer cons = sessRec.createConsumer(destQueue);
+         
+         connDest.start();
+                                 
+         for (int i = BATCH_SIZE / 2 ; i < BATCH_SIZE; i++)
+         {
+            TextMessage tm = (TextMessage)cons.receive(1000);
+            
+            assertNotNull(tm);
+            
+            assertEquals("message" + i, tm.getText());
+         }
+         
+         Message m = cons.receive(1000);
+         
+         assertNull(m);
+                       
+      }
+      finally
+      {      
+         if (connSource != null)
+         {
+            try
+            {
+               connSource.close();
+            }
+            catch (Exception e)
+            {
+               log.error("Failed to close connection", e);
+            }
+         }
+         
+         if (connDest != null)
+         {
+            try
+            {
+               connDest.close();
+            }
+            catch (Exception e)
+            {
+              log.error("Failed to close connection", e);
+            }
+         }
+         
+         if (bridge != null)
+         {
+            bridge.stop();
+         }
+         
+         try
+         {
+            ServerManagement.undeployQueue("sourceQueue", 0);
+         }
+         catch (Exception e)
+         {
+            log.error("Failed to undeploy", e);
+         }
+         
+         try
+         {
+            ServerManagement.undeployQueue("destQueue", 1);
+         }
+         catch (Exception e)
+         {
+            log.error("Failed to undeploy", e);
+         }
+      }                  
+   }
+   
+   public void testNonDurableSubscriber() throws Exception
+   {
+      Connection connSource = null;
       
-      Exception ex;
+      Connection connDest = null;
       
-      public void run()
+      Bridge bridge = null;
+            
+      try
       {
+         ServerManagement.deployTopic("sourceTopic", 0);
+         
+         ServerManagement.deployQueue("destQueue", 1);
+         
+         Hashtable props0 = ServerManagement.getJNDIEnvironment(0);
+         
+         Hashtable props1 = ServerManagement.getJNDIEnvironment(1);
+         
+         ConnectionFactoryFactory cff0 = new JNDIConnectionFactoryFactory(props0, "/ConnectionFactory");
+         
+         ConnectionFactoryFactory cff1 = new JNDIConnectionFactoryFactory(props1, "/ConnectionFactory");
+                      
+         InitialContext ic0 = new InitialContext(props0);
+         
+         InitialContext ic1 = new InitialContext(props1);
+         
+         ConnectionFactory cf0 = (ConnectionFactory)ic0.lookup("/ConnectionFactory");
+         
+         ConnectionFactory cf1 = (ConnectionFactory)ic1.lookup("/ConnectionFactory");
+         
+         Queue sourceQueue = (Queue)ic0.lookup("/queue/sourceQueue");
+         
+         Queue destQueue = (Queue)ic1.lookup("/queue/destQueue");
+         
+         final int BATCH_SIZE = 10;
+         
+         bridge = new Bridge(cff0, cff1, sourceQueue, destQueue,
+                  null, null, null, null,
+                  null, 5000, 10, Bridge.QOS_AT_MOST_ONCE,
+                  1, -1,
+                  null, null);
+         
+         bridge.start();
+            
+         connSource = cf0.createConnection();
+         
+         connDest = cf1.createConnection();
+         
+         Session sessSend = connSource.createSession(false, Session.AUTO_ACKNOWLEDGE);
+         
+         MessageProducer prod = sessSend.createProducer(sourceQueue);         
+
+         for (int i = 0; i < BATCH_SIZE; i++)
+         {
+            TextMessage tm = sessSend.createTextMessage("message" + i);
+                        
+            prod.send(tm);
+         }
+         
+         Session sessRec = connDest.createSession(false, Session.AUTO_ACKNOWLEDGE);
+         
+         MessageConsumer cons = sessRec.createConsumer(destQueue);
+         
+         connDest.start();
+                                 
+         for (int i = 0 ; i < BATCH_SIZE; i++)
+         {
+            TextMessage tm = (TextMessage)cons.receive(1000);
+            
+            assertNotNull(tm);
+            
+            assertEquals("message" + i, tm.getText());
+         }
+         
+         Message m = cons.receive(1000);
+         
+         assertNull(m);
+                       
+      }
+      finally
+      {      
+         if (connSource != null)
+         {
+            try
+            {
+               connSource.close();
+            }
+            catch (Exception e)
+            {
+               log.error("Failed to close connection", e);
+            }
+         }
+         
+         if (connDest != null)
+         {
+            try
+            {
+               connDest.close();
+            }
+            catch (Exception e)
+            {
+              log.error("Failed to close connection", e);
+            }
+         }
+         
+         if (bridge != null)
+         {
+            bridge.stop();
+         }
+         
          try
          {
-            for (int i = 0; i < numMessages; i++)
+            ServerManagement.undeployTopic("sourceTopic", 0);
+         }
+         catch (Exception e)
+         {
+            log.error("Failed to undeploy", e);
+         }
+         
+         try
+         {
+            ServerManagement.undeployQueue("destQueue", 1);
+         }
+         catch (Exception e)
+         {
+            log.error("Failed to undeploy", e);
+         }
+      }                  
+   }
+   
+   public void testDurableSubscriber() throws Exception
+   {
+      Connection connSource = null;
+      
+      Connection connDest = null;
+      
+      Bridge bridge = null;
+            
+      try
+      {
+         ServerManagement.deployTopic("sourceTopic", 0);
+         
+         ServerManagement.deployQueue("destQueue", 1);
+         
+         Hashtable props0 = ServerManagement.getJNDIEnvironment(0);
+         
+         Hashtable props1 = ServerManagement.getJNDIEnvironment(1);
+         
+         ConnectionFactoryFactory cff0 = new JNDIConnectionFactoryFactory(props0, "/ConnectionFactory");
+         
+         ConnectionFactoryFactory cff1 = new JNDIConnectionFactoryFactory(props1, "/ConnectionFactory");
+                      
+         InitialContext ic0 = new InitialContext(props0);
+         
+         InitialContext ic1 = new InitialContext(props1);
+         
+         ConnectionFactory cf0 = (ConnectionFactory)ic0.lookup("/ConnectionFactory");
+         
+         ConnectionFactory cf1 = (ConnectionFactory)ic1.lookup("/ConnectionFactory");
+         
+         Queue sourceQueue = (Queue)ic0.lookup("/queue/sourceQueue");
+         
+         Queue destQueue = (Queue)ic1.lookup("/queue/destQueue");
+         
+         final int BATCH_SIZE = 10;
+         
+         bridge = new Bridge(cff0, cff1, sourceQueue, destQueue,
+                  null, null, null, null,
+                  null, 5000, 10, Bridge.QOS_AT_MOST_ONCE,
+                  1, -1,
+                  "subTest", "clientid123");
+         
+         bridge.start();
+            
+         connSource = cf0.createConnection();
+         
+         connDest = cf1.createConnection();
+         
+         Session sessSend = connSource.createSession(false, Session.AUTO_ACKNOWLEDGE);
+         
+         MessageProducer prod = sessSend.createProducer(sourceQueue);         
+
+         for (int i = 0; i < BATCH_SIZE; i++)
+         {
+            TextMessage tm = sessSend.createTextMessage("message" + i);
+                        
+            prod.send(tm);
+         }
+         
+         Session sessRec = connDest.createSession(false, Session.AUTO_ACKNOWLEDGE);
+         
+         MessageConsumer cons = sessRec.createConsumer(destQueue);
+         
+         connDest.start();
+                                 
+         for (int i = 0 ; i < BATCH_SIZE; i++)
+         {
+            TextMessage tm = (TextMessage)cons.receive(1000);
+            
+            assertNotNull(tm);
+            
+            assertEquals("message" + i, tm.getText());
+         }
+         
+         Message m = cons.receive(1000);
+         
+         assertNull(m);
+                       
+      }
+      finally
+      {      
+         if (connSource != null)
+         {
+            try
             {
-               TextMessage tm = sess.createTextMessage("message" + i);
-                                            
-               prod.send(tm);
-               
-               log.trace("Sent message " + i);
+               connSource.close();
             }
+            catch (Exception e)
+            {
+               log.error("Failed to close connection", e);
+            }
          }
+         
+         if (connDest != null)
+         {
+            try
+            {
+               connDest.close();
+            }
+            catch (Exception e)
+            {
+              log.error("Failed to close connection", e);
+            }
+         }
+         
+         if (bridge != null)
+         {
+            bridge.stop();
+         }
+         
+         try
+         {
+            ServerManagement.undeployTopic("sourceTopic", 0);
+         }
          catch (Exception e)
          {
-            log.error("Failed to send", e);
-            ex = e;
-         }         
-      }
-      
-   }   
+            log.error("Failed to undeploy", e);
+         }
+         
+         try
+         {
+            ServerManagement.undeployQueue("destQueue", 1);
+         }
+         catch (Exception e)
+         {
+            log.error("Failed to undeploy", e);
+         }
+      }                  
+   }
    
-   private void testStress(int qosMode, boolean persistent) throws Exception
+   
+   // Private -------------------------------------------------------------------------------
+       
+   
+   
+   private void testStress(int qosMode, boolean persistent, int batchSize) throws Exception
    {
       Connection connSource = null;
       
@@ -285,10 +1147,6 @@
             
       try
       {
-         ServerManagement.start(0, "all", null, true);
-         
-         ServerManagement.start(1, "all", null, false);
-         
          ServerManagement.deployQueue("sourceQueue", 0);
          
          ServerManagement.deployQueue("destQueue", 1);
@@ -312,13 +1170,11 @@
          Queue sourceQueue = (Queue)ic0.lookup("/queue/sourceQueue");
          
          Queue destQueue = (Queue)ic1.lookup("/queue/destQueue");
-         
-         final int BATCH_SIZE = 50;
-         
+           
          bridge = new Bridge(cff0, cff1, sourceQueue, destQueue,
                   null, null, null, null,
                   null, 5000, 10, qosMode,
-                  BATCH_SIZE, -1,
+                  batchSize, -1,
                   null, null);
          
          bridge.start();
@@ -333,7 +1189,7 @@
          
          final int NUM_MESSAGES = 2000;
          
-         Sender sender = new Sender();
+         StressSender sender = new StressSender();
          sender.sess = sessSend;
          sender.prod = prod;
          sender.numMessages = NUM_MESSAGES;
@@ -424,10 +1280,131 @@
          {
             log.error("Failed to undeploy", e);
          }
+      }      
+   }
+   
+   //Both source and destination on same rm
+   private void testStressSameServer(int qosMode, boolean persistent, int batchSize) throws Exception
+   {
+      Connection connSource = null;
+      
+      Bridge bridge = null;
+      
+      Thread t = null;
+            
+      try
+      {
+         ServerManagement.deployQueue("sourceQueue", 0);
          
-         ServerManagement.stop(0);
+         ServerManagement.deployQueue("destQueue", 0);
          
-         ServerManagement.stop(1);
+         Hashtable props0 = ServerManagement.getJNDIEnvironment(0);
+         
+         ConnectionFactoryFactory cff0 = new JNDIConnectionFactoryFactory(props0, "/ConnectionFactory");
+                      
+         InitialContext ic0 = new InitialContext(props0);
+         
+         ConnectionFactory cf0 = (ConnectionFactory)ic0.lookup("/ConnectionFactory");
+         
+         Queue sourceQueue = (Queue)ic0.lookup("/queue/sourceQueue");
+         
+         Queue destQueue = (Queue)ic0.lookup("/queue/destQueue");
+           
+         bridge = new Bridge(cff0, cff0, sourceQueue, destQueue,
+                  null, null, null, null,
+                  null, 5000, 10, qosMode,
+                  batchSize, -1,
+                  null, null);
+         
+         bridge.start();
+            
+         connSource = cf0.createConnection();
+         
+         Session sessSend = connSource.createSession(false, Session.AUTO_ACKNOWLEDGE);
+         
+         MessageProducer prod = sessSend.createProducer(sourceQueue);
+         
+         final int NUM_MESSAGES = 2000;
+         
+         StressSender sender = new StressSender();
+         sender.sess = sessSend;
+         sender.prod = prod;
+         sender.numMessages = NUM_MESSAGES;
+         prod.setDeliveryMode(persistent ? DeliveryMode.PERSISTENT : DeliveryMode.NON_PERSISTENT);
+                          
+         Session sessRec = connSource.createSession(false, Session.AUTO_ACKNOWLEDGE);
+         
+         MessageConsumer cons = sessRec.createConsumer(destQueue);
+         
+         connSource.start();
+         
+         t = new Thread(sender);
+         
+         t.start();
+                 
+         for (int i = 0; i < NUM_MESSAGES; i++)
+         {
+            TextMessage tm = (TextMessage)cons.receive(5000);
+            
+            assertNotNull(tm);
+            
+            assertEquals("message" + i, tm.getText());
+         }
+         
+         Message m = cons.receive(1000);
+         
+         assertNull(m);
+         
+         t.join();
+         
+         if (sender.ex != null)
+         {
+            //An error occurred during the send
+            throw sender.ex;
+         }
+           
+      }
+      finally
+      {    
+         if (t != null)
+         {
+            t.join(10000);
+         }
+         
+         if (connSource != null)
+         {
+            try
+            {
+               connSource.close();
+            }
+            catch (Exception e)
+            {
+               log.error("Failed to close connection", e);
+            }
+         }
+                          
+         if (bridge != null)
+         {
+            bridge.stop();
+         }
+         
+         try
+         {
+            ServerManagement.undeployQueue("sourceQueue", 0);
+         }
+         catch (Exception e)
+         {
+            log.error("Failed to undeploy", e);
+         }
+         
+         try
+         {
+            ServerManagement.undeployQueue("destQueue", 0);
+         }
+         catch (Exception e)
+         {
+            log.error("Failed to undeploy", e);
+         }
       }      
    }
    
@@ -442,10 +1419,6 @@
             
       try
       {
-         ServerManagement.start(0, "all", null, true);
-         
-         ServerManagement.start(1, "all", null, false);
-         
          ServerManagement.deployQueue("sourceQueue", 0);
          
          ServerManagement.deployQueue("destQueue", 1);
@@ -646,10 +1619,195 @@
          {
             log.error("Failed to undeploy", e);
          }
+      }                  
+   }
+   
+   private void testNoMaxBatchTimeSameServer(int qosMode, boolean persistent) throws Exception
+   {
+      Connection connSource = null;
+   
+      Bridge bridge = null;
+            
+      try
+      {
+         ServerManagement.deployQueue("sourceQueue", 0);
          
-         ServerManagement.stop(0);
+         ServerManagement.deployQueue("destQueue", 0);
          
-         ServerManagement.stop(1);
+         Hashtable props0 = ServerManagement.getJNDIEnvironment(0);
+         
+         ConnectionFactoryFactory cff0 = new JNDIConnectionFactoryFactory(props0, "/ConnectionFactory");
+                 
+         InitialContext ic0 = new InitialContext(props0);
+         
+         ConnectionFactory cf0 = (ConnectionFactory)ic0.lookup("/ConnectionFactory");
+           
+         Queue sourceQueue = (Queue)ic0.lookup("/queue/sourceQueue");
+         
+         Queue destQueue = (Queue)ic0.lookup("/queue/destQueue");
+         
+         final int BATCH_SIZE = 10;
+         
+         bridge = new Bridge(cff0, cff0, sourceQueue, destQueue,
+                  null, null, null, null,
+                  null, 5000, 10, qosMode,
+                  BATCH_SIZE, -1,
+                  null, null);
+         
+         bridge.start();
+            
+         connSource = cf0.createConnection();
+         
+         Session sessSend = connSource.createSession(false, Session.AUTO_ACKNOWLEDGE);
+         
+         MessageProducer prod = sessSend.createProducer(sourceQueue);
+         
+         prod.setDeliveryMode(persistent ? DeliveryMode.PERSISTENT : DeliveryMode.NON_PERSISTENT);        
+         
+         //Send half the messges
+
+         for (int i = 0; i < BATCH_SIZE / 2; i++)
+         {
+            TextMessage tm = sessSend.createTextMessage("message" + i);
+            
+            prod.send(tm);
+         }
+         
+         Session sessRec = connSource.createSession(false, Session.AUTO_ACKNOWLEDGE);
+         
+         MessageConsumer cons = sessRec.createConsumer(destQueue);
+         
+         connSource.start();
+         
+         //Verify none are received
+         
+         Message m = cons.receive(2000);
+         
+         assertNull(m);
+         
+         //Send the other half
+         
+         for (int i = BATCH_SIZE / 2; i < BATCH_SIZE; i++)
+         {
+            TextMessage tm = sessSend.createTextMessage("message" + i);
+            
+            prod.send(tm);
+         }
+         
+         //This should now be receivable
+         
+         for (int i = 0; i < BATCH_SIZE; i++)
+         {
+            TextMessage tm = (TextMessage)cons.receive(1000);
+            
+            assertNotNull(tm);
+            
+            assertEquals("message" + i, tm.getText());
+         }
+         
+         m = cons.receive(1000);
+         
+         assertNull(m);
+         
+         //Send another batch with one more than batch size
+         
+         for (int i = 0; i < BATCH_SIZE + 1; i++)
+         {
+            TextMessage tm = sessSend.createTextMessage("message" + i);
+            
+            prod.send(tm);
+         }
+         
+         //Make sure only batch size are received
+         
+         for (int i = 0; i < BATCH_SIZE; i++)
+         {
+            TextMessage tm = (TextMessage)cons.receive(1000);
+            
+            assertNotNull(tm);
+            
+            assertEquals("message" + i, tm.getText());
+         }
+         
+         m = cons.receive(2000);
+         
+         assertNull(m);
+         
+         //Final batch
+         
+         for (int i = 0; i < BATCH_SIZE - 1; i++)
+         {
+            TextMessage tm = sessSend.createTextMessage("message" + i);
+            
+            prod.send(tm);
+         }
+         
+         TextMessage tm = (TextMessage)cons.receive(1000);
+         
+         assertNotNull(tm);
+         
+         assertEquals("message" + BATCH_SIZE, tm.getText());
+         
+         for (int i = 0; i < BATCH_SIZE - 1; i++)
+         {
+            tm = (TextMessage)cons.receive(1000);
+            
+            assertNotNull(tm);
+            
+            assertEquals("message" + i, tm.getText());
+         }
+         
+         m = cons.receive(1000);
+         
+         assertNull(m);
+         
+         
+         //Make sure no messages are left in the source dest
+         
+         MessageConsumer cons2 = sessSend.createConsumer(sourceQueue);
+         
+         connSource.start();
+         
+         m = cons2.receive(1000);
+         
+         assertNull(m);          
+      }
+      finally
+      {      
+         if (connSource != null)
+         {
+            try
+            {
+               connSource.close();
+            }
+            catch (Exception e)
+            {
+               log.error("Failed to close connection", e);
+            }
+         }
+         
+         if (bridge != null)
+         {
+            bridge.stop();
+         }
+         
+         try
+         {
+            ServerManagement.undeployQueue("sourceQueue", 0);
+         }
+         catch (Exception e)
+         {
+            log.error("Failed to undeploy", e);
+         }
+         
+         try
+         {
+            ServerManagement.undeployQueue("destQueue", 1);
+         }
+         catch (Exception e)
+         {
+            log.error("Failed to undeploy", e);
+         }
       }                  
    }
    
@@ -663,10 +1821,6 @@
             
       try
       {
-         ServerManagement.start(0, "all", null, true);
-         
-         ServerManagement.start(1, "all", null, false);
-         
          ServerManagement.deployQueue("sourceQueue", 0);
          
          ServerManagement.deployQueue("destQueue", 1);
@@ -808,16 +1962,185 @@
          
          try
          {
-            ServerManagement.undeployQueue("destQueue", 1);
+            ServerManagement.undeployQueue("destQueue", 0);
          }
          catch (Exception e)
          {
             log.error("Failed to undeploy", e);
          }
+      }                  
+   }
+   
+   private void testMaxBatchTimeSameServer(int qosMode, boolean persistent) throws Exception
+   {
+      Connection connSource = null;
+      
+      Bridge bridge = null;
+            
+      try
+      {
+         ServerManagement.deployQueue("sourceQueue", 0);
          
-         ServerManagement.stop(0);
+         ServerManagement.deployQueue("destQueue", 0);
          
-         ServerManagement.stop(1);
+         Hashtable props0 = ServerManagement.getJNDIEnvironment(0);
+         
+         ConnectionFactoryFactory cff0 = new JNDIConnectionFactoryFactory(props0, "/ConnectionFactory");
+           
+         InitialContext ic0 = new InitialContext(props0);
+           
+         ConnectionFactory cf0 = (ConnectionFactory)ic0.lookup("/ConnectionFactory");
+         
+         ConnectionFactory cf1 = (ConnectionFactory)ic0.lookup("/ConnectionFactory");
+         
+         Queue sourceQueue = (Queue)ic0.lookup("/queue/sourceQueue");
+         
+         Queue destQueue = (Queue)ic0.lookup("/queue/destQueue");
+         
+         final long MAX_BATCH_TIME = 3000;
+         
+         final int MAX_BATCH_SIZE = 100000; // something big so it won't reach it
+         
+         bridge = new Bridge(cff0, cff0, sourceQueue, destQueue,
+                  null, null, null, null,
+                  null, 5000, 10, qosMode,
+                  MAX_BATCH_SIZE, MAX_BATCH_TIME,
+                  null, null);
+         
+         bridge.start();
+            
+         connSource = cf0.createConnection();
+
+         Session sessSend = connSource.createSession(false, Session.AUTO_ACKNOWLEDGE);
+         
+         MessageProducer prod = sessSend.createProducer(sourceQueue);
+         
+         prod.setDeliveryMode(persistent ? DeliveryMode.PERSISTENT : DeliveryMode.NON_PERSISTENT);                          
+         
+         final int NUM_MESSAGES = 10;
+         
+         //Send some message
+
+         for (int i = 0; i < NUM_MESSAGES; i++)
+         {
+            TextMessage tm = sessSend.createTextMessage("message" + i);
+            
+            prod.send(tm);
+         }
+         
+         Session sessRec = connSource.createSession(false, Session.AUTO_ACKNOWLEDGE);
+         
+         MessageConsumer cons = sessRec.createConsumer(destQueue);
+         
+         connSource.start();
+         
+         //Verify none are received
+         
+         Message m = cons.receive(2000);
+         
+         assertNull(m);
+         
+         //Wait a bit longer
+         
+         Thread.sleep(1500);
+         
+         //Messages should now be receivable
+         
+         for (int i = 0; i < NUM_MESSAGES; i++)
+         {
+            TextMessage tm = (TextMessage)cons.receive(1000);
+            
+            assertNotNull(tm);
+            
+            assertEquals("message" + i, tm.getText());
+         }
+         
+         m = cons.receive(1000);
+         
+         assertNull(m);
+         
+         //Make sure no messages are left in the source dest
+         
+         MessageConsumer cons2 = sessSend.createConsumer(sourceQueue);
+         
+         connSource.start();
+         
+         m = cons2.receive(1000);
+         
+         assertNull(m);
+         
+      }
+      finally
+      {      
+         if (connSource != null)
+         {
+            try
+            {
+               connSource.close();
+            }
+            catch (Exception e)
+            {
+               log.error("Failed to close connection", e);
+            }
+         }
+          
+         if (bridge != null)
+         {
+            bridge.stop();
+         }
+         
+         try
+         {
+            ServerManagement.undeployQueue("sourceQueue", 0);
+         }
+         catch (Exception e)
+         {
+            log.error("Failed to undeploy", e);
+         }
+         
+         try
+         {
+            ServerManagement.undeployQueue("destQueue", 1);
+         }
+         catch (Exception e)
+         {
+            log.error("Failed to undeploy", e);
+         }
       }                  
    }
+   
+   
+   // Inner classes -------------------------------------------------------------------
+   
+   private static class StressSender implements Runnable
+   {
+      int numMessages;
+      
+      Session sess;
+      
+      MessageProducer prod;
+      
+      Exception ex;
+      
+      public void run()
+      {
+         try
+         {
+            for (int i = 0; i < numMessages; i++)
+            {
+               TextMessage tm = sess.createTextMessage("message" + i);
+                                            
+               prod.send(tm);
+               
+               log.trace("Sent message " + i);
+            }
+         }
+         catch (Exception e)
+         {
+            log.error("Failed to send", e);
+            ex = e;
+         }         
+      }
+      
+   } 
 }

Added: trunk/tests/src/org/jboss/test/messaging/jms/bridge/BridgeTestBase.java
===================================================================
--- trunk/tests/src/org/jboss/test/messaging/jms/bridge/BridgeTestBase.java	2007-01-16 14:25:37 UTC (rev 1969)
+++ trunk/tests/src/org/jboss/test/messaging/jms/bridge/BridgeTestBase.java	2007-01-16 20:58:56 UTC (rev 1970)
@@ -0,0 +1,108 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2005, JBoss Inc., and individual contributors as indicated
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jboss.test.messaging.jms.bridge;
+
+import org.jboss.logging.Logger;
+import org.jboss.test.messaging.MessagingTestCase;
+import org.jboss.test.messaging.tools.ServerManagement;
+
+/**
+ * 
+ * A BridgeTestBase
+ *
+ * @author <a href="mailto:tim.fox at jboss.com">Tim Fox</a>
+ * @version <tt>$Revision: 1.1 $</tt>
+ *
+ * $Id$
+ *
+ */
+public class BridgeTestBase extends MessagingTestCase
+{
+   private static final Logger log = Logger.getLogger(BridgeTest.class);
+   
+   private static final int NODE_COUNT = 2;
+   
+   public BridgeTestBase(String name)
+   {
+      super(name);
+   }
+
+   protected void setUp() throws Exception
+   {
+      super.setUp();
+      
+      if (ServerManagement.isRemote())
+      {                 
+         for (int i = 0; i < NODE_COUNT; i++)
+         {
+            // make sure all servers are created and started; make sure that database is zapped
+            // ONLY for the first server, the others rely on values they expect to find in shared
+            // tables; don't clear the database for those.
+            ServerManagement.start(i, "all,-transaction,jbossjta", i == 0);
+         }
+      }
+
+   }
+
+   protected void tearDown() throws Exception
+   { 
+      if (ServerManagement.isRemote())
+      {         
+         for (int i = 0; i < NODE_COUNT; i++)
+         {
+            try
+            {
+               if (ServerManagement.isStarted(i))
+               {
+                  ServerManagement.log(ServerManagement.INFO, "Undeploying Server " + i, i);
+                  
+                  ServerManagement.stop(i);
+               }
+            }
+            catch (Exception e)
+            {
+               log.error("Failed to stop server", e);
+            }
+         }
+         
+         for (int i = 1; i < NODE_COUNT; i++)
+         {
+            try
+            {
+               ServerManagement.kill(i);
+            }
+            catch (Exception e)
+            {
+               log.error("Failed to kill server", e);
+            }
+         }
+      }
+      
+      super.tearDown();
+      
+   }
+   
+   
+   // Inner classes -------------------------------------------------------------------
+   
+}
+

Added: trunk/tests/src/org/jboss/test/messaging/jms/bridge/ReconnectTest.java
===================================================================
--- trunk/tests/src/org/jboss/test/messaging/jms/bridge/ReconnectTest.java	2007-01-16 14:25:37 UTC (rev 1969)
+++ trunk/tests/src/org/jboss/test/messaging/jms/bridge/ReconnectTest.java	2007-01-16 20:58:56 UTC (rev 1970)
@@ -0,0 +1,798 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2005, JBoss Inc., and individual contributors as indicated
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jboss.test.messaging.jms.bridge;
+
+import java.util.Hashtable;
+
+import javax.jms.Connection;
+import javax.jms.ConnectionFactory;
+import javax.jms.DeliveryMode;
+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.jboss.jms.server.bridge.Bridge;
+import org.jboss.jms.server.bridge.ConnectionFactoryFactory;
+import org.jboss.jms.server.bridge.JNDIConnectionFactoryFactory;
+import org.jboss.logging.Logger;
+import org.jboss.test.messaging.MessagingTestCase;
+import org.jboss.test.messaging.tools.ServerManagement;
+
+/**
+ * 
+ * A ReconnectTest
+ *
+ * @author <a href="mailto:tim.fox at jboss.com">Tim Fox</a>
+ * @version <tt>$Revision: 1.1 $</tt>
+ *
+ * $Id$
+ *
+ */
+public class ReconnectTest extends BridgeTestBase
+{
+   private static final Logger log = Logger.getLogger(ReconnectTest.class);
+   
+   private static final int NODE_COUNT = 2;
+   
+   public ReconnectTest(String name)
+   {
+      super(name);
+   }
+
+   protected void setUp() throws Exception
+   {
+      super.setUp();      
+   }
+
+   protected void tearDown() throws Exception
+   {      
+      super.tearDown();      
+   }
+      
+   // Crash and reconnect
+   
+   public void testCrashAndReconnectDestBasic_OnceAndOnlyOnce_P() throws Exception
+   {
+      if (!ServerManagement.isRemote())
+      {
+         return;
+      }
+      testCrashAndReconnectDestBasic(Bridge.QOS_ONCE_AND_ONLY_ONCE, true);
+   }
+   
+   public void testCrashAndReconnectDestBasic_OnceAndOnlyOnce_NP() throws Exception
+   {
+      if (!ServerManagement.isRemote())
+      {
+         return;
+      }
+      testCrashAndReconnectDestBasic(Bridge.QOS_ONCE_AND_ONLY_ONCE, false);
+   }
+   
+   
+   public void testCrashAndReconnectDestCrashBeforePrepare_OnceAndOnlyOnce_P() throws Exception
+   {
+      if (!ServerManagement.isRemote())
+      {
+         return;
+      }
+      testCrashAndReconnectDestCrashBeforePrepare(Bridge.QOS_ONCE_AND_ONLY_ONCE, true);
+   }
+   
+   public void testCrashAndReconnectDestCrashBeforePrepare_OnceAndOnlyOnce_NP() throws Exception
+   {
+      if (!ServerManagement.isRemote())
+      {
+         return;
+      }
+      testCrashAndReconnectDestCrashBeforePrepare(Bridge.QOS_ONCE_AND_ONLY_ONCE, false);
+   }
+   
+   
+   
+   public void testCrashAndReconnectDestCrashOnCommit_OnceAndOnlyOnce_P() throws Exception
+   {
+      if (!ServerManagement.isRemote())
+      {
+         return;
+      }
+      testCrashAndReconnectDestCrashOnCommit(Bridge.QOS_ONCE_AND_ONLY_ONCE, true);
+   }
+   
+   public void testCrashAndReconnectDestCrashOnCommit_OnceAndOnlyOnce_NP() throws Exception
+   {
+      if (!ServerManagement.isRemote())
+      {
+         return;
+      }
+      testCrashAndReconnectDestCrashOnCommit(Bridge.QOS_ONCE_AND_ONLY_ONCE, false);
+   }
+
+
+   /*
+    * Send some messages
+    * Crash the destination server
+    * Bring the destination server back up
+    * Send some more messages
+    * Verify all messages are received
+    */
+   private void testCrashAndReconnectDestBasic(int qosMode, boolean persistent) throws Exception
+   {
+      Connection connSource = null;
+      
+      Connection connDest = null;
+      
+      Bridge bridge = null;
+            
+      try
+      {
+         ServerManagement.deployQueue("sourceQueue", 0);
+         
+         ServerManagement.deployQueue("destQueue", 1);
+         
+         Hashtable props0 = ServerManagement.getJNDIEnvironment(0);
+         
+         Hashtable props1 = ServerManagement.getJNDIEnvironment(1);
+         
+         ConnectionFactoryFactory cff0 = new JNDIConnectionFactoryFactory(props0, "/ConnectionFactory");
+         
+         ConnectionFactoryFactory cff1 = new JNDIConnectionFactoryFactory(props1, "/ConnectionFactory");
+               
+         InitialContext ic0 = new InitialContext(props0);
+         
+         InitialContext ic1 = new InitialContext(props1);
+         
+         ConnectionFactory cf0 = (ConnectionFactory)ic0.lookup("/ConnectionFactory");
+         
+         ConnectionFactory cf1 = (ConnectionFactory)ic1.lookup("/ConnectionFactory");
+         
+         Queue sourceQueue = (Queue)ic0.lookup("/queue/sourceQueue");
+         
+         Queue destQueue = (Queue)ic1.lookup("/queue/destQueue");
+         
+         bridge = new Bridge(cff0, cff1, sourceQueue, destQueue,
+                  null, null, null, null,
+                  null, 1000, -1, qosMode,
+                  10, -1,
+                  null, null);
+         
+         bridge.start();
+            
+         connSource = cf0.createConnection();
+         
+         connDest = cf1.createConnection();
+         
+         Session sessSend = connSource.createSession(false, Session.AUTO_ACKNOWLEDGE);
+         
+         MessageProducer prod = sessSend.createProducer(sourceQueue);
+         
+         prod.setDeliveryMode(persistent ? DeliveryMode.PERSISTENT : DeliveryMode.NON_PERSISTENT);                          
+         
+         final int NUM_MESSAGES = 10;
+         
+         for (int i = 0; i < NUM_MESSAGES / 2; i++)
+         {
+            TextMessage tm = sessSend.createTextMessage("message" + i);
+            
+            prod.send(tm);
+         }
+         
+         Session sessRec = connDest.createSession(false, Session.AUTO_ACKNOWLEDGE);
+         
+         MessageConsumer cons = sessRec.createConsumer(destQueue);
+         
+         connDest.start();
+         
+         //Verify none are received
+         
+         Message m = cons.receive(1000);
+         
+         assertNull(m);
+         
+         connDest.close();
+         
+         ic1.close();
+         
+         //Now crash the dest server
+         
+         log.info("About to crash server");
+         
+         ServerManagement.kill(1);
+         
+         //Wait a while before starting up to simulate the dest being down for a while
+         log.info("Waiting 15 secs before bringing server back up");
+         Thread.sleep(15000);
+         log.info("Done wait");
+         
+         //Restart the server
+         
+         ServerManagement.start(1, "all", false);
+         
+         ServerManagement.deployQueue("destQueue", 1);
+                           
+         cff1 = new JNDIConnectionFactoryFactory(props1, "/ConnectionFactory");
+               
+         ic1 = new InitialContext(props1);
+         
+         cf1 = (ConnectionFactory)ic1.lookup("/ConnectionFactory");
+                  
+         destQueue = (Queue)ic1.lookup("/queue/destQueue");
+         
+         connDest = cf1.createConnection();
+         
+         sessRec = connDest.createSession(false, Session.AUTO_ACKNOWLEDGE);
+         
+         cons = sessRec.createConsumer(destQueue);
+         
+         connDest.start();
+           
+         //Send some more messages
+         
+         for (int i = NUM_MESSAGES / 2; i < NUM_MESSAGES; i++)
+         {
+            TextMessage tm = sessSend.createTextMessage("message" + i);
+            
+            prod.send(tm);
+         }
+                  
+         //Messages should now be receivable
+         
+         for (int i = 0; i < NUM_MESSAGES; i++)
+         {
+            TextMessage tm = (TextMessage)cons.receive(10000);
+            
+            assertNotNull(tm);
+            
+            assertEquals("message" + i, tm.getText());
+         }
+         
+         m = cons.receive(1000);
+         
+         assertNull(m);
+         
+         //Make sure no messages are left in the source dest
+         
+         MessageConsumer cons2 = sessSend.createConsumer(sourceQueue);
+         
+         connSource.start();
+         
+         m = cons2.receive(1000);
+         
+         assertNull(m);
+         
+         log.info("Got here");
+         
+      }
+      finally
+      {      
+         if (connSource != null)
+         {
+            try
+            {
+               connSource.close();
+            }
+            catch (Exception e)
+            {
+               log.error("Failed to close connection", e);
+            }
+         }
+         
+         if (connDest != null)
+         {
+            try
+            {
+               connDest.close();
+            }
+            catch (Exception e)
+            {
+              log.error("Failed to close connection", e);
+            }
+         }
+         
+         
+         if (bridge != null)
+         {
+            try
+            {
+               bridge.stop();
+            }
+            catch (Exception e)
+            {
+               log.error("Failed to stop bridge", e);
+            }
+         }
+         
+         try
+         {
+            ServerManagement.undeployQueue("sourceQueue", 0);
+         }
+         catch (Exception e)
+         {
+            log.error("Failed to undeploy", e);
+         }
+         
+         try
+         {
+            ServerManagement.undeployQueue("destQueue", 1);
+         }
+         catch (Exception e)
+         {
+            log.error("Failed to undeploy", e);
+         }
+      }                  
+   }
+   
+   
+   /*
+    * Send some messages
+    * Crash the destination server
+    * Set the max batch time such that it will attempt to send the batch while the dest server is down
+    * Bring up the destination server
+    * Send some more messages
+    * Verify all messages are received
+    */
+   private void testCrashAndReconnectDestCrashBeforePrepare(int qosMode, boolean persistent) throws Exception
+   {
+      Connection connSource = null;
+      
+      Connection connDest = null;
+      
+      Bridge bridge = null;
+            
+      try
+      {
+         ServerManagement.deployQueue("sourceQueue", 0);
+         
+         ServerManagement.deployQueue("destQueue", 1);
+         
+         Hashtable props0 = ServerManagement.getJNDIEnvironment(0);
+         
+         Hashtable props1 = ServerManagement.getJNDIEnvironment(1);
+         
+         ConnectionFactoryFactory cff0 = new JNDIConnectionFactoryFactory(props0, "/ConnectionFactory");
+         
+         ConnectionFactoryFactory cff1 = new JNDIConnectionFactoryFactory(props1, "/ConnectionFactory");
+               
+         InitialContext ic0 = new InitialContext(props0);
+         
+         InitialContext ic1 = new InitialContext(props1);
+         
+         ConnectionFactory cf0 = (ConnectionFactory)ic0.lookup("/ConnectionFactory");
+         
+         ConnectionFactory cf1 = (ConnectionFactory)ic1.lookup("/ConnectionFactory");
+         
+         Queue sourceQueue = (Queue)ic0.lookup("/queue/sourceQueue");
+         
+         Queue destQueue = (Queue)ic1.lookup("/queue/destQueue");
+         
+         bridge = new Bridge(cff0, cff1, sourceQueue, destQueue,
+                  null, null, null, null,
+                  null, 1000, -1, qosMode,
+                  10, 5000,
+                  null, null);
+         
+         bridge.start();
+            
+         connSource = cf0.createConnection();
+         
+         connDest = cf1.createConnection();
+         
+         Session sessSend = connSource.createSession(false, Session.AUTO_ACKNOWLEDGE);
+         
+         MessageProducer prod = sessSend.createProducer(sourceQueue);
+         
+         prod.setDeliveryMode(persistent ? DeliveryMode.PERSISTENT : DeliveryMode.NON_PERSISTENT);                          
+         
+         final int NUM_MESSAGES = 10;
+         
+         for (int i = 0; i < NUM_MESSAGES / 2; i++)
+         {
+            TextMessage tm = sessSend.createTextMessage("message" + i);
+            
+            prod.send(tm);
+         }
+         
+         Session sessRec = connDest.createSession(false, Session.AUTO_ACKNOWLEDGE);
+         
+         MessageConsumer cons = sessRec.createConsumer(destQueue);
+         
+         connDest.start();
+         
+         //Verify none are received
+         
+         Message m = cons.receive(1000);
+         
+         assertNull(m);
+         
+         connDest.close();
+         
+         ic1.close();
+         
+         //Now crash the dest server
+         
+         log.info("About to crash server");
+         
+         ServerManagement.kill(1);
+         
+         //Wait a while before starting up to simulate the dest being down for a while
+         log.info("Waiting 15 secs before bringing server back up");
+         Thread.sleep(15000);
+         log.info("Done wait");
+         
+         //Restart the server
+         
+         ServerManagement.start(1, "all", false);
+         
+         ServerManagement.deployQueue("destQueue", 1);
+                           
+         cff1 = new JNDIConnectionFactoryFactory(props1, "/ConnectionFactory");
+               
+         ic1 = new InitialContext(props1);
+         
+         cf1 = (ConnectionFactory)ic1.lookup("/ConnectionFactory");
+                  
+         destQueue = (Queue)ic1.lookup("/queue/destQueue");
+         
+         connDest = cf1.createConnection();
+         
+         sessRec = connDest.createSession(false, Session.AUTO_ACKNOWLEDGE);
+         
+         cons = sessRec.createConsumer(destQueue);
+         
+         connDest.start();
+           
+         //Send some more messages
+         
+         for (int i = NUM_MESSAGES / 2; i < NUM_MESSAGES; i++)
+         {
+            TextMessage tm = sessSend.createTextMessage("message" + i);
+            
+            prod.send(tm);
+         }
+                  
+         //Messages should now be receivable
+         
+         for (int i = 0; i < NUM_MESSAGES; i++)
+         {
+            TextMessage tm = (TextMessage)cons.receive(10000);
+            
+            assertNotNull(tm);
+            
+            assertEquals("message" + i, tm.getText());
+         }
+         
+         m = cons.receive(1000);
+         
+         assertNull(m);
+         
+         //Make sure no messages are left in the source dest
+         
+         MessageConsumer cons2 = sessSend.createConsumer(sourceQueue);
+         
+         connSource.start();
+         
+         m = cons2.receive(1000);
+         
+         assertNull(m);
+         
+         log.info("Got here");
+         
+      }
+      finally
+      {      
+         if (connSource != null)
+         {
+            try
+            {
+               connSource.close();
+            }
+            catch (Exception e)
+            {
+               log.error("Failed to close connection", e);
+            }
+         }
+         
+         if (connDest != null)
+         {
+            try
+            {
+               connDest.close();
+            }
+            catch (Exception e)
+            {
+              log.error("Failed to close connection", e);
+            }
+         }
+         
+         
+         if (bridge != null)
+         {
+            try
+            {
+               bridge.stop();
+            }
+            catch (Exception e)
+            {
+               log.error("Failed to stop bridge", e);
+            }
+         }
+         
+         try
+         {
+            ServerManagement.undeployQueue("sourceQueue", 0);
+         }
+         catch (Exception e)
+         {
+            log.error("Failed to undeploy", e);
+         }
+         
+         try
+         {
+            ServerManagement.undeployQueue("destQueue", 1);
+         }
+         catch (Exception e)
+         {
+            log.error("Failed to undeploy", e);
+         }
+      }                  
+   }
+   
+   /*
+    * Send some messages   
+    * Crash the server after prepare but on commit
+    * Bring up the destination server
+    * Send some more messages
+    * Verify all messages are received
+    */
+   private void testCrashAndReconnectDestCrashOnCommit(int qosMode, boolean persistent) throws Exception
+   {
+      Connection connSource = null;
+      
+      Connection connDest = null;
+      
+      Bridge bridge = null;
+            
+      try
+      {
+         ServerManagement.deployQueue("sourceQueue", 0);
+         
+         ServerManagement.deployQueue("destQueue", 1);
+         
+         Hashtable props0 = ServerManagement.getJNDIEnvironment(0);
+         
+         Hashtable props1 = ServerManagement.getJNDIEnvironment(1);
+         
+         ConnectionFactoryFactory cff0 = new JNDIConnectionFactoryFactory(props0, "/ConnectionFactory");
+         
+         ConnectionFactoryFactory cff1 = new JNDIConnectionFactoryFactory(props1, "/ConnectionFactory");
+               
+         InitialContext ic0 = new InitialContext(props0);
+         
+         InitialContext ic1 = new InitialContext(props1);
+         
+         ConnectionFactory cf0 = (ConnectionFactory)ic0.lookup("/ConnectionFactory");
+         
+         ConnectionFactory cf1 = (ConnectionFactory)ic1.lookup("/ConnectionFactory");
+         
+         Queue sourceQueue = (Queue)ic0.lookup("/queue/sourceQueue");
+         
+         Queue destQueue = (Queue)ic1.lookup("/queue/destQueue");
+         
+         final int NUM_MESSAGES = 10;         
+         
+         bridge = new Bridge(cff0, cff1, sourceQueue, destQueue,
+                  null, null, null, null,
+                  null, 1000, -1, qosMode,
+                  NUM_MESSAGES, 5000,
+                  null, null);
+         
+         bridge.start();
+         
+         connSource = cf0.createConnection();
+         
+         connDest = cf1.createConnection();
+         
+         Session sessSend = connSource.createSession(false, Session.AUTO_ACKNOWLEDGE);
+         
+         MessageProducer prod = sessSend.createProducer(sourceQueue);
+         
+         prod.setDeliveryMode(persistent ? DeliveryMode.PERSISTENT : DeliveryMode.NON_PERSISTENT);                          
+         
+         for (int i = 0; i < NUM_MESSAGES / 2; i++)
+         {
+            TextMessage tm = sessSend.createTextMessage("message" + i);
+            
+            prod.send(tm);
+         }
+         
+         Session sessRec = connDest.createSession(false, Session.AUTO_ACKNOWLEDGE);
+         
+         MessageConsumer cons = sessRec.createConsumer(destQueue);
+         
+         connDest.start();
+         
+         //Verify none are received
+         
+         Message m = cons.receive(1000);
+          
+         assertNull(m);
+         
+         connDest.close();
+         
+         ic1.close();
+         
+         //Poison server 1 so it crashes on commit of dest but after prepare
+         
+         //This means the transaction branch on source will get commmitted
+         //but the branch on dest won't be - it will remain prepared
+         //This corresponds to a HeuristicMixedException
+         
+         ServerManagement.poisonTheServer(1);
+         
+         ServerManagement.nullServer(1);
+         
+                     
+         //Wait for maxBatchTime to kick in so a batch is sent
+         //This should cause the server to crash after prepare but before commit
+         
+         Thread.sleep(20000);
+               
+         //Restart the server
+         
+         log.info("Restarting server");
+                  
+         ServerManagement.start(1, "all", false);
+         
+         log.info("Restarted server");
+         
+         ServerManagement.deployQueue("destQueue", 1);
+         
+         log.info("Deployed queue");
+         
+         
+         log.info("Now sleeping");
+         
+         Thread.sleep(120000);
+         
+         log.info("Slept");
+                           
+         cff1 = new JNDIConnectionFactoryFactory(props1, "/ConnectionFactory");
+               
+         ic1 = new InitialContext(props1);
+         
+         cf1 = (ConnectionFactory)ic1.lookup("/ConnectionFactory");
+                  
+         destQueue = (Queue)ic1.lookup("/queue/destQueue");
+         
+         connDest = cf1.createConnection();
+         
+         sessRec = connDest.createSession(false, Session.AUTO_ACKNOWLEDGE);
+         
+         cons = sessRec.createConsumer(destQueue);
+         
+         connDest.start();
+           
+         //Send some more messages
+         
+         for (int i = NUM_MESSAGES / 2; i < NUM_MESSAGES; i++)
+         {
+            TextMessage tm = sessSend.createTextMessage("message" + i);
+            
+            prod.send(tm);
+         }
+                  
+         //Messages should now be receivable
+         
+         for (int i = 0; i < NUM_MESSAGES; i++)
+         {
+            TextMessage tm = (TextMessage)cons.receive(10000);
+            
+            assertNotNull(tm);
+            
+            assertEquals("message" + i, tm.getText());
+         }
+         
+         m = cons.receive(1000);
+         
+         assertNull(m);
+         
+         //Make sure no messages are left in the source dest
+         
+         MessageConsumer cons2 = sessSend.createConsumer(sourceQueue);
+         
+         connSource.start();
+         
+         m = cons2.receive(1000);
+         
+         assertNull(m);
+         
+         log.info("Got here");
+         
+      }
+      finally
+      {      
+         log.info("In finally");
+         
+         if (connSource != null)
+         {
+            try
+            {
+               connSource.close();
+            }
+            catch (Exception e)
+            {
+               log.error("Failed to close connection", e);
+            }
+         }
+         
+         if (connDest != null)
+         {
+            try
+            {
+               connDest.close();
+            }
+            catch (Exception e)
+            {
+              log.error("Failed to close connection", e);
+            }
+         }
+         
+         
+         if (bridge != null)
+         {
+            try
+            {
+               bridge.stop();
+            }
+            catch (Exception e)
+            {
+               log.error("Failed to stop bridge", e);
+            }
+         }
+         
+         try
+         {
+            ServerManagement.undeployQueue("sourceQueue", 0);
+         }
+         catch (Exception e)
+         {
+            log.error("Failed to undeploy", e);
+         }
+         
+         try
+         {
+            ServerManagement.undeployQueue("destQueue", 1);
+         }
+         catch (Exception e)
+         {
+            log.error("Failed to undeploy", e);
+         }
+      }                  
+   }
+   
+   // Inner classes -------------------------------------------------------------------
+   
+}

Modified: trunk/tests/src/org/jboss/test/messaging/jms/clustering/base/ClusteringTestBase.java
===================================================================
--- trunk/tests/src/org/jboss/test/messaging/jms/clustering/base/ClusteringTestBase.java	2007-01-16 14:25:37 UTC (rev 1969)
+++ trunk/tests/src/org/jboss/test/messaging/jms/clustering/base/ClusteringTestBase.java	2007-01-16 20:58:56 UTC (rev 1970)
@@ -89,7 +89,7 @@
       queue = new Queue[nodeCount];
       topic = new Topic[nodeCount];
 
-      for(int i = 0; i < nodeCount; i++)
+      for (int i = 0; i < nodeCount; i++)
       {
          // make sure all servers are created and started; make sure that database is zapped
          // ONLY for the first server, the others rely on values they expect to find in shared

Modified: trunk/tests/src/org/jboss/test/messaging/tools/ServerManagement.java
===================================================================
--- trunk/tests/src/org/jboss/test/messaging/tools/ServerManagement.java	2007-01-16 14:25:37 UTC (rev 1969)
+++ trunk/tests/src/org/jboss/test/messaging/tools/ServerManagement.java	2007-01-16 20:58:56 UTC (rev 1970)
@@ -192,8 +192,6 @@
    {
       Server s = create(i);
 
-      MessageIdGeneratorFactory.instance.clear();
-
       log.info("starting server " + i);
 
       s.start(config, attrOverrides, clearDatabase);
@@ -265,6 +263,12 @@
          servers[i] = null;
       }
    }
+   
+   //Need to do this after a poison otherwise this will think the server is still alive
+   public static synchronized void nullServer(int i)
+   {
+      servers[i] = null;
+   }
 
    /** 
     * Kills the server and waits keep trying any dumb communication until the server is effectively
@@ -334,11 +338,11 @@
     */
    private static synchronized Server spawn(final int i) throws Exception
    {
-      if(isLocal())
+      if (isLocal())
       {
          return null;
       }
-
+      
       StringBuffer sb = new StringBuffer();
 
       sb.append("java").append(' ');
@@ -399,12 +403,12 @@
             testLogfileSuffix = testLogfileSuffix.substring(0, pos) + "server";
          }
 
-         if (clustered != null)
-         {
-            testLogfileSuffix += i;
-         }
+         //We need to add the i even in the non clustered case since we can have multiple
+         //non clustered servers
+         testLogfileSuffix += i;
+         
       }
-
+      
       sb.append("-Dtest.logfile.suffix=").append(testLogfileSuffix).append(' ');
 
       String classPath = System.getProperty("java.class.path");
@@ -1027,11 +1031,11 @@
       String name =
          "//localhost:" + RMITestServer.DEFAULT_REGISTRY_PORT + "/" +
          RMITestServer.RMI_SERVER_PREFIX + index;
-
+      
       Server s = null;
       int retries = initialRetries;
 
-      while(s == null && retries > 0)
+      while (s == null && retries > 0)
       {
          int attempt = initialRetries - retries + 1;
          try

Modified: trunk/tests/src/org/jboss/test/messaging/tools/aop/PoisonInterceptor.java
===================================================================
--- trunk/tests/src/org/jboss/test/messaging/tools/aop/PoisonInterceptor.java	2007-01-16 14:25:37 UTC (rev 1969)
+++ trunk/tests/src/org/jboss/test/messaging/tools/aop/PoisonInterceptor.java	2007-01-16 20:58:56 UTC (rev 1970)
@@ -6,10 +6,17 @@
  */
 package org.jboss.test.messaging.tools.aop;
 
-import org.jboss.logging.Logger;
+import java.rmi.registry.LocateRegistry;
+import java.rmi.registry.Registry;
+
 import org.jboss.aop.advice.Interceptor;
 import org.jboss.aop.joinpoint.Invocation;
 import org.jboss.aop.joinpoint.MethodInvocation;
+import org.jboss.jms.server.endpoint.ServerConnectionEndpoint;
+import org.jboss.jms.server.endpoint.advised.ConnectionAdvised;
+import org.jboss.jms.tx.TransactionRequest;
+import org.jboss.logging.Logger;
+import org.jboss.test.messaging.tools.jmx.rmi.RMITestServer;
 
 /**
  * Used to force a "poisoned" server to do all sorts of bad things. Used for testing.
@@ -46,18 +53,25 @@
       {
          // Used by the failover tests to kill server in the middle of an invocation.
 
-         log.info("#####"); 
-         log.info("#####");
-         log.info("##### Halting the server!");
-         log.info("#####");
-         log.info("#####");
-
-         Runtime.getRuntime().halt(1);
-
+         crash(invocation.getTargetObject());
       }
+      else if ("sendTransaction".equals(methodName))
+      {
+         TransactionRequest request = (TransactionRequest)mi.getArguments()[0];
+         
+         if (request.getRequestType() == TransactionRequest.TWO_PHASE_COMMIT_REQUEST)
+         {
+            //Crash on 2pc commit - used in message bridge tests
+            
+            log.info("##### Crashing on 2PC commit!!");
+            
+            crash(invocation.getTargetObject());            
+         }
+      }
 
       return invocation.invokeNext();
    }
+  
 
    // Public ---------------------------------------------------------------------------------------
 
@@ -66,7 +80,35 @@
    // Protected ------------------------------------------------------------------------------------
 
    // Private --------------------------------------------------------------------------------------
+   
+   private void crash(Object target) throws Exception
+   {
+      ConnectionAdvised advised = (ConnectionAdvised)target;
+      
+      ServerConnectionEndpoint endpoint = (ServerConnectionEndpoint)advised.getEndpoint();
+      
+      int serverId = endpoint.getServerPeer().getServerPeerID();
+            
+      //First unregister from the RMI registry
+      Registry registry = LocateRegistry.getRegistry(RMITestServer.DEFAULT_REGISTRY_PORT);
 
+      String name = RMITestServer.RMI_SERVER_PREFIX + serverId;
+      registry.unbind(name);
+      log.info("unregistered " + name + " from registry");
+
+      name = RMITestServer.NAMING_SERVER_PREFIX + serverId;
+      registry.unbind(name);
+      log.info("unregistered " + name + " from registry");
+      
+      log.info("#####"); 
+      log.info("#####");
+      log.info("##### Halting the server!");
+      log.info("#####");
+      log.info("#####");
+
+      Runtime.getRuntime().halt(1);
+   }
+
    // Inner classes --------------------------------------------------------------------------------
 
 }

Modified: trunk/tests/src/org/jboss/test/messaging/tools/jmx/ServiceContainer.java
===================================================================
--- trunk/tests/src/org/jboss/test/messaging/tools/jmx/ServiceContainer.java	2007-01-16 14:25:37 UTC (rev 1969)
+++ trunk/tests/src/org/jboss/test/messaging/tools/jmx/ServiceContainer.java	2007-01-16 20:58:56 UTC (rev 1970)
@@ -38,14 +38,15 @@
 import java.util.Properties;
 import java.util.Set;
 import java.util.StringTokenizer;
+
 import javax.management.Attribute;
 import javax.management.MBeanAttributeInfo;
 import javax.management.MBeanException;
 import javax.management.MBeanInfo;
 import javax.management.MBeanServer;
 import javax.management.MBeanServerFactory;
+import javax.management.NotificationListener;
 import javax.management.ObjectName;
-import javax.management.NotificationListener;
 import javax.naming.Context;
 import javax.naming.InitialContext;
 import javax.naming.NameNotFoundException;
@@ -53,6 +54,7 @@
 import javax.sql.DataSource;
 import javax.transaction.TransactionManager;
 import javax.transaction.UserTransaction;
+
 import org.hsqldb.Server;
 import org.hsqldb.persist.HsqlProperties;
 import org.jboss.jms.jndi.JNDIProviderAdapter;
@@ -81,8 +83,8 @@
 import org.jboss.test.messaging.tools.jndi.Constants;
 import org.jboss.test.messaging.tools.jndi.InVMInitialContextFactory;
 import org.jboss.test.messaging.tools.jndi.InVMInitialContextFactoryBuilder;
-import org.jboss.tm.TransactionManagerLocator;
 import org.jboss.tm.TransactionManagerService;
+import org.jboss.tm.TxManager;
 import org.jboss.tm.usertx.client.ServerVMClientUserTransaction;
 
 
@@ -182,6 +184,7 @@
    private Server hsqldbServer;
 
    private boolean transaction;
+   private boolean jbossjta; //To use the ex-Arjuna tx mgr
    private boolean database;
    private boolean jca;
    private boolean remoting;
@@ -361,8 +364,8 @@
          startServiceController();
 
          registerClassLoader();
-
-         if (transaction)
+         
+         if (transaction || jbossjta)
          {
             startTransactionManager();
          }
@@ -385,6 +388,12 @@
                                    DEFAULTDS_MANAGED_CONNECTION_POOL_OBJECT_NAME);
             startWrapperDataSourceService();
          }
+         if (database && (transaction || jbossjta) && jca && cleanDatabase)
+         {
+            // We make sure the database is clean (only if we have all dependencies the database,
+            // othewise we'll get an access error)
+            deleteAllData();
+         }
 
          if (remoting)
          {
@@ -396,13 +405,6 @@
             startSecurityManager();
          }
 
-         if (database && transaction && jca && cleanDatabase)
-         {
-            // We make sure the database is clean (only if we have all dependencies the database,
-            // othewise we'll get an access error)
-            deleteAllData();
-         }
-
          loadJNDIContexts();
 
          // aways install multiplexer as this is a cheap operation. The actual JChannels are started
@@ -988,7 +990,16 @@
    {
       if (tm == null)
       {
-         tm = TransactionManagerLocator.getInstance().locate();
+         if (jbossjta)
+         {
+            log.info("Starting arjuna tx mgr");
+            tm = com.arjuna.ats.jta.TransactionManager.transactionManager();
+         }
+         else
+         {
+            log.info("Starting non arjuna tx mgr");
+            tm = TxManager.getInstance();
+         }
       }
 
       TransactionManagerJMXWrapper mbean = new TransactionManagerJMXWrapper(tm);
@@ -1179,7 +1190,8 @@
                       "clientLeasePeriod=" + clientLeasePeriod + "&" +
                       "callbackStore=org.jboss.remoting.callback.BlockingCallbackStore&" +
                       "clientSocketClass=org.jboss.jms.client.remoting.ClientSocketWrapper&" +
-                      "serverSocketClass=org.jboss.jms.server.remoting.ServerSocketWrapper";
+                      "serverSocketClass=org.jboss.jms.server.remoting.ServerSocketWrapper&" +
+                      "NumberOfRetries=1&NumberOfCallRetries=1";
 
       // specific parameters per transport
 
@@ -1391,6 +1403,20 @@
                transaction = false;
             }
          }
+         else if ("jbossjta".equals(tok))
+         {
+            if (transaction)
+            {
+               throw new IllegalArgumentException("Cannot have the old JBoss transaction manager AND the JBoss Transactions transaction manager");
+            }
+            
+            //Use the JBoss Transactions (ex Arjuna) JTA
+            jbossjta = true;
+            if (minus)
+            {
+               jbossjta = false;
+            }
+         }
          else if ("database".equals(tok))
          {
             database = true;

Modified: trunk/tests/src/org/jboss/test/messaging/tools/jmx/rmi/LocalTestServer.java
===================================================================
--- trunk/tests/src/org/jboss/test/messaging/tools/jmx/rmi/LocalTestServer.java	2007-01-16 14:25:37 UTC (rev 1969)
+++ trunk/tests/src/org/jboss/test/messaging/tools/jmx/rmi/LocalTestServer.java	2007-01-16 20:58:56 UTC (rev 1970)
@@ -295,8 +295,6 @@
    {
       try
       {
-         log.info(" Server peer ID ........... " + serverPeerID);
-
          log.debug("creating ServerPeer instance");
 
          // we are using the "default" service deployment descriptors available in

Deleted: trunk/tests/src/org/jboss/test/messaging/util/TransactionManagerLocator.java
===================================================================
--- trunk/tests/src/org/jboss/test/messaging/util/TransactionManagerLocator.java	2007-01-16 14:25:37 UTC (rev 1969)
+++ trunk/tests/src/org/jboss/test/messaging/util/TransactionManagerLocator.java	2007-01-16 20:58:56 UTC (rev 1970)
@@ -1,61 +0,0 @@
-/*
-  * JBoss, Home of Professional Open Source
-  * Copyright 2005, JBoss Inc., and individual contributors as indicated
-  * by the @authors tag. See the copyright.txt in the distribution for a
-  * full listing of individual contributors.
-  *
-  * This is free software; you can redistribute it and/or modify it
-  * under the terms of the GNU Lesser General Public License as
-  * published by the Free Software Foundation; either version 2.1 of
-  * the License, or (at your option) any later version.
-  *
-  * This software is distributed in the hope that it will be useful,
-  * but WITHOUT ANY WARRANTY; without even the implied warranty of
-  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-  * Lesser General Public License for more details.
-  *
-  * You should have received a copy of the GNU Lesser General Public
-  * License along with this software; if not, write to the Free
-  * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
-  * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
-  */
-package org.jboss.test.messaging.util;
-
-import javax.transaction.TransactionManager;
-
-
-/**
- * Mimics the JBossTM locator API with creation of JBossTS implementation.
- *
- * @author <a href="mailto:juha at jboss.org">Juha Lindfors</a>
- *
- * @version $Revision: $
- */
-public class TransactionManagerLocator
-{
-   private static TransactionManagerLocator instance = new TransactionManagerLocator();
-
-   private TransactionManager tm;
-
-
-   private TransactionManagerLocator()
-   {}
-
-
-   public static TransactionManagerLocator getInstance()
-   {
-      return instance;
-   }
-
-   public synchronized TransactionManager locate()
-   {
-      if (tm != null)
-         return tm;
-
-      tm = com.arjuna.ats.jta.TransactionManager.transactionManager();
-      
-      return tm;
-   }
-
-
-}




More information about the jboss-cvs-commits mailing list