[hornetq-commits] JBoss hornetq SVN: r9307 - in branches/2_2_0_HA_Improvements: src/config/common/schema and 18 other directories.

do-not-reply at jboss.org do-not-reply at jboss.org
Fri Jun 11 11:33:39 EDT 2010


Author: timfox
Date: 2010-06-11 11:33:36 -0400 (Fri, 11 Jun 2010)
New Revision: 9307

Added:
   branches/2_2_0_HA_Improvements/src/main/org/hornetq/core/client/impl/ClientSessionFactoryImpl_Old.java
   branches/2_2_0_HA_Improvements/src/main/org/hornetq/core/client/impl/FailoverManagerImpl_Old.java
   branches/2_2_0_HA_Improvements/src/main/org/hornetq/core/client/impl/FailoverManager_Old.java
Removed:
   branches/2_2_0_HA_Improvements/src/main/org/hornetq/core/client/impl/FailoverManager.java
   branches/2_2_0_HA_Improvements/src/main/org/hornetq/core/client/impl/FailoverManagerImpl.java
Modified:
   branches/2_2_0_HA_Improvements/build-hornetq.xml
   branches/2_2_0_HA_Improvements/build.xml
   branches/2_2_0_HA_Improvements/src/config/common/schema/hornetq-configuration.xsd
   branches/2_2_0_HA_Improvements/src/main/org/hornetq/api/core/client/ClientSessionFactory.java
   branches/2_2_0_HA_Improvements/src/main/org/hornetq/api/core/client/HornetQClient.java
   branches/2_2_0_HA_Improvements/src/main/org/hornetq/api/core/management/HornetQServerControl.java
   branches/2_2_0_HA_Improvements/src/main/org/hornetq/core/client/impl/ClientSessionFactoryImpl.java
   branches/2_2_0_HA_Improvements/src/main/org/hornetq/core/client/impl/ClientSessionFactoryInternal.java
   branches/2_2_0_HA_Improvements/src/main/org/hornetq/core/client/impl/ClientSessionImpl.java
   branches/2_2_0_HA_Improvements/src/main/org/hornetq/core/client/impl/ClientSessionInternal.java
   branches/2_2_0_HA_Improvements/src/main/org/hornetq/core/client/impl/DelegatingSession.java
   branches/2_2_0_HA_Improvements/src/main/org/hornetq/core/cluster/DiscoveryEntry.java
   branches/2_2_0_HA_Improvements/src/main/org/hornetq/core/cluster/impl/DiscoveryGroupImpl.java
   branches/2_2_0_HA_Improvements/src/main/org/hornetq/core/config/BroadcastGroupConfiguration.java
   branches/2_2_0_HA_Improvements/src/main/org/hornetq/core/config/Configuration.java
   branches/2_2_0_HA_Improvements/src/main/org/hornetq/core/config/impl/ConfigurationImpl.java
   branches/2_2_0_HA_Improvements/src/main/org/hornetq/core/config/impl/FileConfiguration.java
   branches/2_2_0_HA_Improvements/src/main/org/hornetq/core/deployers/impl/FileConfigurationParser.java
   branches/2_2_0_HA_Improvements/src/main/org/hornetq/core/management/impl/BroadcastGroupControlImpl.java
   branches/2_2_0_HA_Improvements/src/main/org/hornetq/core/management/impl/HornetQServerControlImpl.java
   branches/2_2_0_HA_Improvements/src/main/org/hornetq/core/persistence/StorageManager.java
   branches/2_2_0_HA_Improvements/src/main/org/hornetq/core/persistence/impl/journal/JournalStorageManager.java
   branches/2_2_0_HA_Improvements/src/main/org/hornetq/core/persistence/impl/nullpm/NullStorageManager.java
   branches/2_2_0_HA_Improvements/src/main/org/hornetq/core/protocol/core/impl/PacketDecoder.java
   branches/2_2_0_HA_Improvements/src/main/org/hornetq/core/protocol/core/impl/PacketImpl.java
   branches/2_2_0_HA_Improvements/src/main/org/hornetq/core/server/cluster/BroadcastGroup.java
   branches/2_2_0_HA_Improvements/src/main/org/hornetq/core/server/cluster/ClusterManager.java
   branches/2_2_0_HA_Improvements/src/main/org/hornetq/core/server/cluster/impl/BroadcastGroupImpl.java
   branches/2_2_0_HA_Improvements/src/main/org/hornetq/core/server/cluster/impl/ClusterManagerImpl.java
   branches/2_2_0_HA_Improvements/src/main/org/hornetq/core/server/impl/HornetQServerImpl.java
   branches/2_2_0_HA_Improvements/src/main/org/hornetq/utils/UUID.java
   branches/2_2_0_HA_Improvements/tests/src/org/hornetq/tests/unit/core/paging/impl/PagingStoreImplTest.java
Log:
new HA

Modified: branches/2_2_0_HA_Improvements/build-hornetq.xml
===================================================================
--- branches/2_2_0_HA_Improvements/build-hornetq.xml	2010-06-11 04:11:42 UTC (rev 9306)
+++ branches/2_2_0_HA_Improvements/build-hornetq.xml	2010-06-11 15:33:36 UTC (rev 9307)
@@ -1599,10 +1599,86 @@
    <!-- Server execution targets                                                                 -->
    <!-- ======================================================================================== -->
 
+<target name="runLive" depends="jar">
+      <mkdir dir="logs"/>
+   	  <property name="server.config" value="${src.dir}/config/ha-test/live"/>
+      <java classname="org.hornetq.integration.bootstrap.HornetQBootstrapServer" fork="false">
+         <jvmarg value="-XX:+UseParallelGC"/>
+         <jvmarg value="-Xms512M"/>
+         <jvmarg value="-Xmx2048M"/>
+         <jvmarg value="-XX:+AggressiveOpts"/>
+         <jvmarg value="-XX:+UseFastAccessorMethods"/>
+         <jvmarg value="-Dcom.sun.management.jmxremote"/>
+         <jvmarg value="-Djava.util.logging.config.file=${src.config.trunk.non-clustered.dir}/logging.properties"/>
+         <jvmarg value="-Djava.library.path=${native.bin.dir}"/>
+         <!--<jvmarg line="-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000"/>-->
+         <arg line="hornetq-beans.xml"/>
+         <classpath path="${server.config}" />
+         <classpath refid="jms.standalone.server.classpath"/>
+      </java>
+   </target>
+
+<target name="runBackup1" depends="jar">
+      <mkdir dir="logs"/>
+   	  <property name="server.config" value="${src.dir}/config/ha-test/backup-1"/>
+      <java classname="org.hornetq.integration.bootstrap.HornetQBootstrapServer" fork="false">
+         <jvmarg value="-XX:+UseParallelGC"/>
+         <jvmarg value="-Xms512M"/>
+         <jvmarg value="-Xmx2048M"/>
+         <jvmarg value="-XX:+AggressiveOpts"/>
+         <jvmarg value="-XX:+UseFastAccessorMethods"/>
+         <jvmarg value="-Dcom.sun.management.jmxremote"/>
+         <jvmarg value="-Djava.util.logging.config.file=${src.config.trunk.non-clustered.dir}/logging.properties"/>
+         <jvmarg value="-Djava.library.path=${native.bin.dir}"/>
+         <!--<jvmarg line="-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000"/>-->
+         <arg line="hornetq-beans.xml"/>
+         <classpath path="${server.config}" />
+         <classpath refid="jms.standalone.server.classpath"/>
+      </java>
+   </target>
+
+<target name="runBackup2" depends="jar">
+      <mkdir dir="logs"/>
+   	  <property name="server.config" value="${src.dir}/config/ha-test/backup-2"/>
+      <java classname="org.hornetq.integration.bootstrap.HornetQBootstrapServer" fork="false">
+         <jvmarg value="-XX:+UseParallelGC"/>
+         <jvmarg value="-Xms512M"/>
+         <jvmarg value="-Xmx2048M"/>
+         <jvmarg value="-XX:+AggressiveOpts"/>
+         <jvmarg value="-XX:+UseFastAccessorMethods"/>
+         <jvmarg value="-Dcom.sun.management.jmxremote"/>
+         <jvmarg value="-Djava.util.logging.config.file=${src.config.trunk.non-clustered.dir}/logging.properties"/>
+         <jvmarg value="-Djava.library.path=${native.bin.dir}"/>
+         <!--<jvmarg line="-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000"/>-->
+         <arg line="hornetq-beans.xml"/>
+         <classpath path="${server.config}" />
+         <classpath refid="jms.standalone.server.classpath"/>
+      </java>
+   </target>
+
+<target name="runBackup3" depends="jar">
+      <mkdir dir="logs"/>
+   	  <property name="server.config" value="${src.dir}/config/ha-test/backup-3"/>
+      <java classname="org.hornetq.integration.bootstrap.HornetQBootstrapServer" fork="false">
+         <jvmarg value="-XX:+UseParallelGC"/>
+         <jvmarg value="-Xms512M"/>
+         <jvmarg value="-Xmx2048M"/>
+         <jvmarg value="-XX:+AggressiveOpts"/>
+         <jvmarg value="-XX:+UseFastAccessorMethods"/>
+         <jvmarg value="-Dcom.sun.management.jmxremote"/>
+         <jvmarg value="-Djava.util.logging.config.file=${src.config.trunk.non-clustered.dir}/logging.properties"/>
+         <jvmarg value="-Djava.library.path=${native.bin.dir}"/>
+         <!--<jvmarg line="-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000"/>-->
+         <arg line="hornetq-beans.xml"/>
+         <classpath path="${server.config}" />
+         <classpath refid="jms.standalone.server.classpath"/>
+      </java>
+   </target>
+
    <target name="runServer" depends="jar">
       <mkdir dir="logs"/>
    	  <property name="server.config" value="${src.config.trunk.non-clustered.dir}"/>
-      <java classname="org.hornetq.integration.bootstrap.HornetQBootstrapServer" fork="true">
+      <java classname="org.hornetq.integration.bootstrap.HornetQBootstrapServer" fork="false">
          <jvmarg value="-XX:+UseParallelGC"/>
          <jvmarg value="-Xms512M"/>
          <jvmarg value="-Xmx2048M"/>

Modified: branches/2_2_0_HA_Improvements/build.xml
===================================================================
--- branches/2_2_0_HA_Improvements/build.xml	2010-06-11 04:11:42 UTC (rev 9306)
+++ branches/2_2_0_HA_Improvements/build.xml	2010-06-11 15:33:36 UTC (rev 9307)
@@ -319,6 +319,22 @@
       <ant antfile="build-hornetq.xml" target="runServer"/>
    </target>
 
+   <target name="runLive" depends="createthirdparty">
+      <ant antfile="build-hornetq.xml" target="runLive"/>
+   </target>
+
+   <target name="runBackup1" depends="createthirdparty">
+      <ant antfile="build-hornetq.xml" target="runBackup1"/>
+   </target>
+
+   <target name="runBackup2" depends="createthirdparty">
+      <ant antfile="build-hornetq.xml" target="runBackup2"/>
+   </target>
+
+   <target name="runBackup3" depends="createthirdparty">
+      <ant antfile="build-hornetq.xml" target="runBackup3"/>
+   </target>
+
    <target name="runClusteredServer" depends="createthirdparty">
       <ant antfile="build-hornetq.xml" target="runClusteredServer"/>
    </target>

Modified: branches/2_2_0_HA_Improvements/src/config/common/schema/hornetq-configuration.xsd
===================================================================
--- branches/2_2_0_HA_Improvements/src/config/common/schema/hornetq-configuration.xsd	2010-06-11 04:11:42 UTC (rev 9306)
+++ branches/2_2_0_HA_Improvements/src/config/common/schema/hornetq-configuration.xsd	2010-06-11 15:33:36 UTC (rev 9307)
@@ -71,7 +71,7 @@
 				</xsd:element>			
 				<xsd:element maxOccurs="1" minOccurs="0" name="persist-delivery-count-before-delivery" type="xsd:boolean">
 				</xsd:element>
-				<xsd:element maxOccurs="1" minOccurs="0" name="backup-connector-ref" type="backup-connectorType">
+				<xsd:element maxOccurs="1" minOccurs="0" name="live-connector-ref" type="live-connectorType">
 				</xsd:element>				
 				<xsd:element maxOccurs="1" minOccurs="0" name="connectors">
                     <xsd:complexType>
@@ -492,7 +492,7 @@
        </xsd:complexType>
     </xsd:element>
     
-	<xsd:complexType name="backup-connectorType">
+	<xsd:complexType name="live-connectorType">
 		<xsd:attribute name="connector-name" type="xsd:IDREF" use="required">
 		</xsd:attribute>
 	</xsd:complexType>

Modified: branches/2_2_0_HA_Improvements/src/main/org/hornetq/api/core/client/ClientSessionFactory.java
===================================================================
--- branches/2_2_0_HA_Improvements/src/main/org/hornetq/api/core/client/ClientSessionFactory.java	2010-06-11 04:11:42 UTC (rev 9306)
+++ branches/2_2_0_HA_Improvements/src/main/org/hornetq/api/core/client/ClientSessionFactory.java	2010-06-11 15:33:36 UTC (rev 9307)
@@ -13,14 +13,9 @@
 
 package org.hornetq.api.core.client;
 
-import java.util.List;
-
 import org.hornetq.api.core.HornetQException;
-import org.hornetq.api.core.Interceptor;
-import org.hornetq.api.core.Pair;
-import org.hornetq.api.core.TransportConfiguration;
-import org.hornetq.api.core.client.loadbalance.ConnectionLoadBalancingPolicy;
 
+
 /**
  * A ClientSessionFactory is the entry point to create and configure HornetQ resources to produce and consume messages.
  * <br>
@@ -136,654 +131,634 @@
                                boolean preAcknowledge,
                                int ackBatchSize) throws HornetQException;
 
-   /**
-    * Returns the list of <em>live - backup</em> connectors pairs configured 
-    * that sessions created by this factory will use to connect
-    * to HornetQ servers or <code>null</code> if the factory is using discovery group.
-    * 
-    * The backup configuration (returned by {@link org.hornetq.api.core.Pair#b}) can be <code>null</code> if there is no
-    * backup for the corresponding live configuration (returned by {@link org.hornetq.api.core.Pair#a})
-    * 
-    * @return a list of pair of TransportConfiguration corresponding to the live - backup nodes
-    */
-   List<Pair<TransportConfiguration, TransportConfiguration>> getStaticConnectors();
-
-   /**
-    * Sets the static list of live - backup connectors pairs that sessions created by this factory will use to connect
-    * to HornetQ servers.
-    * 
-    * The backup configuration (returned by {@link Pair#b}) can be <code>null</code> if there is no
-    * backup for the corresponding live configuration (returned by {@link Pair#a})
-    * 
-    * @param staticConnectors a list of pair of TransportConfiguration corresponding to the live - backup nodes
-    */
-   void setStaticConnectors(List<Pair<TransportConfiguration, TransportConfiguration>> staticConnectors);
-
-   /**
-    * Returns the period used to check if a client has failed to receive pings from the server.
-    *   
-    * Period is in milliseconds, default value is {@link HornetQClient#DEFAULT_CLIENT_FAILURE_CHECK_PERIOD}.
-    * 
-    * @return the period used to check if a client has failed to receive pings from the server
-    */
-   long getClientFailureCheckPeriod();
-
-   /**
-    * Sets the period (in milliseconds) used to check if a client has failed to receive pings from the server.
-    * 
-    * Value must be -1 (to disable) or greater than 0.
-    * 
-    * @param clientFailureCheckPeriod the period to check failure
-    */
-   void setClientFailureCheckPeriod(long clientFailureCheckPeriod);
-
-   /**
-    * When <code>true</code>, consumers created through this factory will create temporary files to cache large messages.
-    * 
-    * There is 1 temporary file created for each large message.
-    * 
-    * Default value is {@link HornetQClient#DEFAULT_CACHE_LARGE_MESSAGE_CLIENT}.
-    * 
-    * @return <code>true</code> if consumers created through this factory will cache large messages in temporary files, <code>false</code> else
-    */
-   boolean isCacheLargeMessagesClient();
-
-   /**
-    * Sets whether large messages received by consumers created through this factory will be cached in temporary files or not.
-    * 
-    * @param cached <code>true</code> to cache large messages in temporary files, <code>false</code> else
-    */
-   void setCacheLargeMessagesClient(boolean cached);
-
-   /**
-    * Returns the connection <em>time-to-live</em>.
-    * This TTL determines how long the server will keep a connection alive in the absence of any data arriving from the client.
-    * 
-    * Value is in milliseconds, default value is {@link HornetQClient#DEFAULT_CONNECTION_TTL}.
-    * 
-    * @return the connection time-to-live in milliseconds
-    */
-   long getConnectionTTL();
-
-   /**
-    * Sets this factory's connections <em>time-to-live</em>.
-    * 
-    * Value must be -1 (to disable) or greater or equals to 0.
-    * 
-    * @param connectionTTL period in milliseconds
-    */
-   void setConnectionTTL(long connectionTTL);
-
-   /**
-    * Returns the blocking calls timeout.
-    * 
-    * If client's blocking calls to the server take more than this timeout, the call will throw a {@link HornetQException} with the code {@link HornetQException#CONNECTION_TIMEDOUT}.
-    * Value is in milliseconds, default value is {@link HornetQClient#DEFAULT_CALL_TIMEOUT}.
-    * 
-    * @return the blocking calls timeout
-    */
-   long getCallTimeout();
-
-   /**
-    * Sets the blocking call timeout.
-    * 
-    * Value must be greater or equals to 0
-    * 
-    * @param callTimeout blocking call timeout in milliseconds
-    */
-   void setCallTimeout(long callTimeout);
-
-   /**
-    * Returns the large message size threshold.
-    * 
-    * Messages whose size is if greater than this value will be handled as <em>large messages</em>.
-    * 
-    * Value is in bytes, default value is {@link HornetQClient#DEFAULT_MIN_LARGE_MESSAGE_SIZE}.
-    * 
-    * @return the message size threshold to treat messages as large messages.
-    */
-   int getMinLargeMessageSize();
-
-   /**
-    * Sets the large message size threshold.
-    * 
-    * Value must be greater than 0.
-    * 
-    * @param minLargeMessageSize large message size threshold in bytes
-    */
-   void setMinLargeMessageSize(int minLargeMessageSize);
-
-   /**
-    * Returns the window size for flow control of the consumers created through this factory.
-    * 
-    * Value is in bytes, default value is {@link HornetQClient#DEFAULT_CONSUMER_WINDOW_SIZE}.
-    * 
-    * @return the window size used for consumer flow control
-    */
-   int getConsumerWindowSize();
-
-   /**
-    * Sets the window size for flow control of the consumers created through this factory.
-    * 
-    * Value must be -1 (to disable flow control), 0 (to not buffer any messages) or greater than 0 (to set the maximum size of the buffer)
-    *
-    * @param consumerWindowSize window size (in bytes) used for consumer flow control
-    */
-   void setConsumerWindowSize(int consumerWindowSize);
-
-   /**
-    * Returns the maximum rate of message consumption for consumers created through this factory.
-    * 
-    * This value controls the rate at which a consumer can consume messages. A consumer will never consume messages at a rate faster than the rate specified.
-    * 
-    * Value is -1 (to disable) or a positive integer corresponding to the maximum desired message consumption rate specified in units of messages per second.
-    * Default value is {@link HornetQClient#DEFAULT_CONSUMER_MAX_RATE}.
-    * 
-    * @return the consumer max rate
-    */
-   int getConsumerMaxRate();
-
-   /**
-    * Sets the maximum rate of message consumption for consumers created through this factory.
-    * 
-    * Value must -1 (to disable) or a positive integer corresponding to the maximum desired message consumption rate specified in units of messages per second.
-    * 
-    * @param consumerMaxRate maximum rate of message consumption (in messages per seconds)
-    */
-   void setConsumerMaxRate(int consumerMaxRate);
-
-   /**
-    * Returns the size for the confirmation window of clients using this factory.
-    * 
-    * Value is in bytes or -1 (to disable the window). Default value is {@link HornetQClient#DEFAULT_CONFIRMATION_WINDOW_SIZE}.
-    * 
-    * @return the size for the confirmation window of clients using this factory
-    */
-   int getConfirmationWindowSize();
-
-   /**
-    * Sets the size for the confirmation window buffer of clients using this factory.
-    * 
-    * Value must be -1 (to disable the window) or greater than 0.
-
-    * @param confirmationWindowSize size of the confirmation window (in bytes)
-    */
-   void setConfirmationWindowSize(int confirmationWindowSize);
-
-   /**
-    * Returns the window size for flow control of the producers created through this factory.
-    * 
-    * Value must be -1 (to disable flow control) or greater than 0 to determine the maximum amount of bytes at any give time (to prevent overloading the connection).
-    * Default value is {@link HornetQClient#DEFAULT_PRODUCER_WINDOW_SIZE}.
-    * 
-    * @return the window size for flow control of the producers created through this factory.
-    */
-   int getProducerWindowSize();
-
-   /**
-    * Returns the window size for flow control of the producers created through this factory.
-    * 
-    * Value must be -1 (to disable flow control) or greater than 0.
-    * 
-    * @param producerWindowSize window size (in bytest) for flow control of the producers created through this factory.
-    */
-   void setProducerWindowSize(int producerWindowSize);
-
-   /**
-    * Returns the maximum rate of message production for producers created through this factory.
-    * 
-    * This value controls the rate at which a producer can produce messages. A producer will never produce messages at a rate faster than the rate specified.
-    * 
-    * Value is -1 (to disable) or a positive integer corresponding to the maximum desired message production rate specified in units of messages per second.
-    * Default value is {@link HornetQClient#DEFAULT_PRODUCER_MAX_RATE}.
-    * 
-    * @return  maximum rate of message production (in messages per seconds)
-    */
-   int getProducerMaxRate();
-
-   /**
-    * Sets the maximum rate of message production for producers created through this factory.
-    * 
-    * Value must -1 (to disable) or a positive integer corresponding to the maximum desired message production rate specified in units of messages per second.
-    * 
-    * @param producerMaxRate maximum rate of message production (in messages per seconds)
-    */
-   void setProducerMaxRate(int producerMaxRate);
-
-   /**
-    * Returns whether consumers created through this factory will block while sending message acknowledgements or do it asynchronously.
-    * 
-    * Default value is {@link HornetQClient#DEFAULT_BLOCK_ON_ACKNOWLEDGE}.
-    * 
-    * @return whether consumers will block while sending message acknowledgements or do it asynchronously
-    */
-   boolean isBlockOnAcknowledge();
-
-   /**
-    * Sets whether consumers created through this factory will block while sending message acknowledgements or do it asynchronously.
-    *
-    * @param blockOnAcknowledge <code>true</code> to block when sending message acknowledgements or <code>false</code> to send them asynchronously
-    */
-   void setBlockOnAcknowledge(boolean blockOnAcknowledge);
-
-   /**
-    * Returns whether producers created through this factory will block while sending <em>durable</em> messages or do it asynchronously.
-    * <br>
-    * If the session is configured to send durable message asynchronously, the client can set a SendAcknowledgementHandler on the ClientSession
-    * to be notified once the message has been handled by the server.
-    * 
-    * Default value is {@link HornetQClient#DEFAULT_BLOCK_ON_DURABLE_SEND}.
-    *
-    * @return whether producers will block while sending persistent messages or do it asynchronously
-    */
-   boolean isBlockOnDurableSend();
-
-   /**
-    * Sets whether producers created through this factory will block while sending <em>durable</em> messages or do it asynchronously.
-    * 
-    * @param blockOnDurableSend <code>true</code> to block when sending durable messages or <code>false</code> to send them asynchronously
-    */
-   void setBlockOnDurableSend(boolean blockOnDurableSend);
-
-   /**
-    * Returns whether producers created through this factory will block while sending <em>non-durable</em> messages or do it asynchronously.
-    * <br>
-    * If the session is configured to send non-durable message asynchronously, the client can set a SendAcknowledgementHandler on the ClientSession
-    * to be notified once the message has been handled by the server.
-    * 
-    * Default value is {@link HornetQClient#DEFAULT_BLOCK_ON_NON_DURABLE_SEND}.
-    *
-    * @return whether producers will block while sending non-durable messages or do it asynchronously
-    */
-   boolean isBlockOnNonDurableSend();
-
-   /**
-    * Sets whether producers created through this factory will block while sending <em>non-durable</em> messages or do it asynchronously.
-    * 
-    * @param blockOnNonDurableSend <code>true</code> to block when sending non-durable messages or <code>false</code> to send them asynchronously
-    */
-   void setBlockOnNonDurableSend(boolean blockOnNonDurableSend);
-
-   /**
-    * Returns whether producers created through this factory will automatically
-    * assign a group ID to the messages they sent.
-    * 
-    * if <code>true</code>, a random unique group ID is created and set on each message for the property
-    * {@link org.hornetq.api.core.Message#HDR_GROUP_ID}.
-    * Default value is {@link HornetQClient#DEFAULT_AUTO_GROUP}.
-    * 
-    * @return whether producers will automatically assign a group ID to their messages
-    */
-   boolean isAutoGroup();
-
-   /**
-    * Sets whether producers created through this factory will automatically
-    * assign a group ID to the messages they sent.
-    * 
-    * @param autoGroup <code>true</code> to automatically assign a group ID to each messages sent through this factory, <code>false</code> else
-    */
-   void setAutoGroup(boolean autoGroup);
-
-   /**
-    * Returns the group ID that will be eventually set on each message for the property {@link org.hornetq.api.core.Message#HDR_GROUP_ID}.
-    * 
-    * Default value is is <code>null</code> and no group ID will be set on the messages.
-    * 
-    * @return the group ID that will be eventually set on each message
-    */
-   String getGroupID();
    
-   /**
-    * Sets the group ID that will be  set on each message sent through this factory.
-    * 
-    * @param groupID the group ID to use
-    */
-   void setGroupID(String groupID);
+//   /**
+//    * Returns the period used to check if a client has failed to receive pings from the server.
+//    *   
+//    * Period is in milliseconds, default value is {@link HornetQClient#DEFAULT_CLIENT_FAILURE_CHECK_PERIOD}.
+//    * 
+//    * @return the period used to check if a client has failed to receive pings from the server
+//    */
+//   long getClientFailureCheckPeriod();
+//
+//   /**
+//    * Sets the period (in milliseconds) used to check if a client has failed to receive pings from the server.
+//    * 
+//    * Value must be -1 (to disable) or greater than 0.
+//    * 
+//    * @param clientFailureCheckPeriod the period to check failure
+//    */
+//   void setClientFailureCheckPeriod(long clientFailureCheckPeriod);
+//
+//   /**
+//    * When <code>true</code>, consumers created through this factory will create temporary files to cache large messages.
+//    * 
+//    * There is 1 temporary file created for each large message.
+//    * 
+//    * Default value is {@link HornetQClient#DEFAULT_CACHE_LARGE_MESSAGE_CLIENT}.
+//    * 
+//    * @return <code>true</code> if consumers created through this factory will cache large messages in temporary files, <code>false</code> else
+//    */
+//   boolean isCacheLargeMessagesClient();
+//
+//   /**
+//    * Sets whether large messages received by consumers created through this factory will be cached in temporary files or not.
+//    * 
+//    * @param cached <code>true</code> to cache large messages in temporary files, <code>false</code> else
+//    */
+//   void setCacheLargeMessagesClient(boolean cached);
+//
+//   /**
+//    * Returns the connection <em>time-to-live</em>.
+//    * This TTL determines how long the server will keep a connection alive in the absence of any data arriving from the client.
+//    * 
+//    * Value is in milliseconds, default value is {@link HornetQClient#DEFAULT_CONNECTION_TTL}.
+//    * 
+//    * @return the connection time-to-live in milliseconds
+//    */
+//   long getConnectionTTL();
+//
+//   /**
+//    * Sets this factory's connections <em>time-to-live</em>.
+//    * 
+//    * Value must be -1 (to disable) or greater or equals to 0.
+//    * 
+//    * @param connectionTTL period in milliseconds
+//    */
+//   void setConnectionTTL(long connectionTTL);
+//
+//   /**
+//    * Returns the blocking calls timeout.
+//    * 
+//    * If client's blocking calls to the server take more than this timeout, the call will throw a {@link HornetQException} with the code {@link HornetQException#CONNECTION_TIMEDOUT}.
+//    * Value is in milliseconds, default value is {@link HornetQClient#DEFAULT_CALL_TIMEOUT}.
+//    * 
+//    * @return the blocking calls timeout
+//    */
+//   long getCallTimeout();
+//
+//   /**
+//    * Sets the blocking call timeout.
+//    * 
+//    * Value must be greater or equals to 0
+//    * 
+//    * @param callTimeout blocking call timeout in milliseconds
+//    */
+//   void setCallTimeout(long callTimeout);
+//
+//   /**
+//    * Returns the large message size threshold.
+//    * 
+//    * Messages whose size is if greater than this value will be handled as <em>large messages</em>.
+//    * 
+//    * Value is in bytes, default value is {@link HornetQClient#DEFAULT_MIN_LARGE_MESSAGE_SIZE}.
+//    * 
+//    * @return the message size threshold to treat messages as large messages.
+//    */
+//   int getMinLargeMessageSize();
+//
+//   /**
+//    * Sets the large message size threshold.
+//    * 
+//    * Value must be greater than 0.
+//    * 
+//    * @param minLargeMessageSize large message size threshold in bytes
+//    */
+//   void setMinLargeMessageSize(int minLargeMessageSize);
+//
+//   /**
+//    * Returns the window size for flow control of the consumers created through this factory.
+//    * 
+//    * Value is in bytes, default value is {@link HornetQClient#DEFAULT_CONSUMER_WINDOW_SIZE}.
+//    * 
+//    * @return the window size used for consumer flow control
+//    */
+//   int getConsumerWindowSize();
+//
+//   /**
+//    * Sets the window size for flow control of the consumers created through this factory.
+//    * 
+//    * Value must be -1 (to disable flow control), 0 (to not buffer any messages) or greater than 0 (to set the maximum size of the buffer)
+//    *
+//    * @param consumerWindowSize window size (in bytes) used for consumer flow control
+//    */
+//   void setConsumerWindowSize(int consumerWindowSize);
+//
+//   /**
+//    * Returns the maximum rate of message consumption for consumers created through this factory.
+//    * 
+//    * This value controls the rate at which a consumer can consume messages. A consumer will never consume messages at a rate faster than the rate specified.
+//    * 
+//    * Value is -1 (to disable) or a positive integer corresponding to the maximum desired message consumption rate specified in units of messages per second.
+//    * Default value is {@link HornetQClient#DEFAULT_CONSUMER_MAX_RATE}.
+//    * 
+//    * @return the consumer max rate
+//    */
+//   int getConsumerMaxRate();
+//
+//   /**
+//    * Sets the maximum rate of message consumption for consumers created through this factory.
+//    * 
+//    * Value must -1 (to disable) or a positive integer corresponding to the maximum desired message consumption rate specified in units of messages per second.
+//    * 
+//    * @param consumerMaxRate maximum rate of message consumption (in messages per seconds)
+//    */
+//   void setConsumerMaxRate(int consumerMaxRate);
+//
+//   /**
+//    * Returns the size for the confirmation window of clients using this factory.
+//    * 
+//    * Value is in bytes or -1 (to disable the window). Default value is {@link HornetQClient#DEFAULT_CONFIRMATION_WINDOW_SIZE}.
+//    * 
+//    * @return the size for the confirmation window of clients using this factory
+//    */
+//   int getConfirmationWindowSize();
+//
+//   /**
+//    * Sets the size for the confirmation window buffer of clients using this factory.
+//    * 
+//    * Value must be -1 (to disable the window) or greater than 0.
+//
+//    * @param confirmationWindowSize size of the confirmation window (in bytes)
+//    */
+//   void setConfirmationWindowSize(int confirmationWindowSize);
+//
+//   /**
+//    * Returns the window size for flow control of the producers created through this factory.
+//    * 
+//    * Value must be -1 (to disable flow control) or greater than 0 to determine the maximum amount of bytes at any give time (to prevent overloading the connection).
+//    * Default value is {@link HornetQClient#DEFAULT_PRODUCER_WINDOW_SIZE}.
+//    * 
+//    * @return the window size for flow control of the producers created through this factory.
+//    */
+//   int getProducerWindowSize();
+//
+//   /**
+//    * Returns the window size for flow control of the producers created through this factory.
+//    * 
+//    * Value must be -1 (to disable flow control) or greater than 0.
+//    * 
+//    * @param producerWindowSize window size (in bytest) for flow control of the producers created through this factory.
+//    */
+//   void setProducerWindowSize(int producerWindowSize);
+//
+//   /**
+//    * Returns the maximum rate of message production for producers created through this factory.
+//    * 
+//    * This value controls the rate at which a producer can produce messages. A producer will never produce messages at a rate faster than the rate specified.
+//    * 
+//    * Value is -1 (to disable) or a positive integer corresponding to the maximum desired message production rate specified in units of messages per second.
+//    * Default value is {@link HornetQClient#DEFAULT_PRODUCER_MAX_RATE}.
+//    * 
+//    * @return  maximum rate of message production (in messages per seconds)
+//    */
+//   int getProducerMaxRate();
+//
+//   /**
+//    * Sets the maximum rate of message production for producers created through this factory.
+//    * 
+//    * Value must -1 (to disable) or a positive integer corresponding to the maximum desired message production rate specified in units of messages per second.
+//    * 
+//    * @param producerMaxRate maximum rate of message production (in messages per seconds)
+//    */
+//   void setProducerMaxRate(int producerMaxRate);
+//
+//   /**
+//    * Returns whether consumers created through this factory will block while sending message acknowledgements or do it asynchronously.
+//    * 
+//    * Default value is {@link HornetQClient#DEFAULT_BLOCK_ON_ACKNOWLEDGE}.
+//    * 
+//    * @return whether consumers will block while sending message acknowledgements or do it asynchronously
+//    */
+//   boolean isBlockOnAcknowledge();
+//
+//   /**
+//    * Sets whether consumers created through this factory will block while sending message acknowledgements or do it asynchronously.
+//    *
+//    * @param blockOnAcknowledge <code>true</code> to block when sending message acknowledgements or <code>false</code> to send them asynchronously
+//    */
+//   void setBlockOnAcknowledge(boolean blockOnAcknowledge);
+//
+//   /**
+//    * Returns whether producers created through this factory will block while sending <em>durable</em> messages or do it asynchronously.
+//    * <br>
+//    * If the session is configured to send durable message asynchronously, the client can set a SendAcknowledgementHandler on the ClientSession
+//    * to be notified once the message has been handled by the server.
+//    * 
+//    * Default value is {@link HornetQClient#DEFAULT_BLOCK_ON_DURABLE_SEND}.
+//    *
+//    * @return whether producers will block while sending persistent messages or do it asynchronously
+//    */
+//   boolean isBlockOnDurableSend();
+//
+//   /**
+//    * Sets whether producers created through this factory will block while sending <em>durable</em> messages or do it asynchronously.
+//    * 
+//    * @param blockOnDurableSend <code>true</code> to block when sending durable messages or <code>false</code> to send them asynchronously
+//    */
+//   void setBlockOnDurableSend(boolean blockOnDurableSend);
+//
+//   /**
+//    * Returns whether producers created through this factory will block while sending <em>non-durable</em> messages or do it asynchronously.
+//    * <br>
+//    * If the session is configured to send non-durable message asynchronously, the client can set a SendAcknowledgementHandler on the ClientSession
+//    * to be notified once the message has been handled by the server.
+//    * 
+//    * Default value is {@link HornetQClient#DEFAULT_BLOCK_ON_NON_DURABLE_SEND}.
+//    *
+//    * @return whether producers will block while sending non-durable messages or do it asynchronously
+//    */
+//   boolean isBlockOnNonDurableSend();
+//
+//   /**
+//    * Sets whether producers created through this factory will block while sending <em>non-durable</em> messages or do it asynchronously.
+//    * 
+//    * @param blockOnNonDurableSend <code>true</code> to block when sending non-durable messages or <code>false</code> to send them asynchronously
+//    */
+//   void setBlockOnNonDurableSend(boolean blockOnNonDurableSend);
+//
+//   /**
+//    * Returns whether producers created through this factory will automatically
+//    * assign a group ID to the messages they sent.
+//    * 
+//    * if <code>true</code>, a random unique group ID is created and set on each message for the property
+//    * {@link org.hornetq.api.core.Message#HDR_GROUP_ID}.
+//    * Default value is {@link HornetQClient#DEFAULT_AUTO_GROUP}.
+//    * 
+//    * @return whether producers will automatically assign a group ID to their messages
+//    */
+//   boolean isAutoGroup();
+//
+//   /**
+//    * Sets whether producers created through this factory will automatically
+//    * assign a group ID to the messages they sent.
+//    * 
+//    * @param autoGroup <code>true</code> to automatically assign a group ID to each messages sent through this factory, <code>false</code> else
+//    */
+//   void setAutoGroup(boolean autoGroup);
+//
+//   /**
+//    * Returns the group ID that will be eventually set on each message for the property {@link org.hornetq.api.core.Message#HDR_GROUP_ID}.
+//    * 
+//    * Default value is is <code>null</code> and no group ID will be set on the messages.
+//    * 
+//    * @return the group ID that will be eventually set on each message
+//    */
+//   String getGroupID();
+//   
+//   /**
+//    * Sets the group ID that will be  set on each message sent through this factory.
+//    * 
+//    * @param groupID the group ID to use
+//    */
+//   void setGroupID(String groupID);
+//
+//   /**
+//    * Returns whether messages will pre-acknowledged on the server before they are sent to the consumers or not.
+//    *
+//    * Default value is {@link HornetQClient#DEFAULT_PRE_ACKNOWLEDGE}
+//    */
+//   boolean isPreAcknowledge();
+//
+//   /**
+//    * Sets to <code>true</code> to pre-acknowledge consumed messages on the server before they are sent to consumers, else set to <code>false</code> to let
+//    * clients acknowledge the message they consume.
+//    * 
+//    * @param preAcknowledge <code>true</code> to enable pre-acknowledgement, <code>false</code> else
+//    */
+//   void setPreAcknowledge(boolean preAcknowledge);
+//
+//   /**
+//    * Returns the acknowledgements batch size.
+//    * 
+//    * Default value is  {@link HornetQClient#DEFAULT_ACK_BATCH_SIZE}.
+//    * 
+//    * @return the acknowledgements batch size
+//    */
+//   int getAckBatchSize();
+//
+//   /**
+//    * Sets the acknowledgements batch size.
+//    * 
+//    * Value must be equal or greater than 0.
+//    * 
+//    * @param ackBatchSize acknowledgements batch size
+//    */
+//   void setAckBatchSize(int ackBatchSize);
+//
+//   /**
+//    * Returns the local bind address to which the multicast socket is bound for discovery.
+//    * 
+//    * This is null if the multicast socket is not bound, or no discovery is being used
+//    * 
+//    * @return the local bind address to which the multicast socket is bound for discovery
+//    */
+//   String getLocalBindAddress();
+//
+//   /**
+//    * Sets the local bind address to which the multicast socket is bound for discovery.
+//    * 
+//    * @param the local bind address
+//    */
+//   void setLocalBindAddress(String localBindAddress);
+//   
+//   /**
+//    * Returns the address to listen to discover which connectors this factory can use.
+//    * The discovery address must be set to enable this factory to discover HornetQ servers.
+//    * 
+//    * @return the address to listen to discover which connectors this factory can use
+//    */
+//   String getDiscoveryAddress();
+//
+//   /**
+//    * Sets the address to listen to discover which connectors this factory can use.
+//    * 
+//    * @param discoveryAddress address to listen to discover which connectors this factory can use
+//    */
+//   void setDiscoveryAddress(String discoveryAddress);
+//
+//   /**
+//    * Returns the port to listen to discover which connectors this factory can use.
+//    * The discovery port must be set to enable this factory to discover HornetQ servers.
+//    * 
+//    * @return the port to listen to discover which connectors this factory can use
+//    */   
+//   int getDiscoveryPort();
+//
+//
+//   /**
+//    * Sets the port to listen to discover which connectors this factory can use.
+//    * 
+//    * @param discoveryPort port to listen to discover which connectors this factory can use
+//    */
+//   void setDiscoveryPort(int discoveryPort);
+//
+//   /**
+//    * Returns the refresh timeout for discovered HornetQ servers.
+//    * 
+//    * If this factory uses discovery to find HornetQ servers, the list of discovered servers
+//    * will be refreshed according to this timeout.
+//    * 
+//    * Value is in milliseconds, default value is {@link HornetQClient#DEFAULT_DISCOVERY_REFRESH_TIMEOUT}.
+//    * 
+//    * @return the refresh timeout for discovered HornetQ servers
+//    */
+//   long getDiscoveryRefreshTimeout();
+//
+//   /**
+//    * Sets the refresh timeout for discovered HornetQ servers.
+//    * 
+//    * Value must be greater than 0.
+//    * 
+//    * @param discoveryRefreshTimeout refresh timeout (in milliseconds) for discovered HornetQ servers
+//    */
+//   void setDiscoveryRefreshTimeout(long discoveryRefreshTimeout);
+//
+//   /**
+//    * Returns the initial wait timeout if this factory is configured to use discovery.
+//    * 
+//    * Value is in milliseconds, default value is  {@link HornetQClient#DEFAULT_DISCOVERY_INITIAL_WAIT_TIMEOUT}.
+//    * 
+//    * @return the initial wait timeout if this factory is configured to use discovery 
+//    */
+//   long getDiscoveryInitialWaitTimeout();
+//
+//   /**
+//    * Sets the initial wait timeout if this factory is configured to use discovery.
+//    * 
+//    * Value is in milliseconds and must be greater than 0.
+//    * 
+//    * @param initialWaitTimeout initial wait timeout when using discovery 
+//    */
+//   void setDiscoveryInitialWaitTimeout(long initialWaitTimeout);
+//
+//   /**
+//    * Returns whether this factory will use global thread pools (shared among all the factories in the same JVM)
+//    * or its own pools.
+//    * 
+//    * Default value is {@link HornetQClient#DEFAULT_USE_GLOBAL_POOLS}.
+//    * 
+//    * @return <code>true</code> if this factory uses global thread pools, <code>false</code> else
+//    */
+//   boolean isUseGlobalPools();
+//
+//   /**
+//    * Sets whether this factory will use global thread pools (shared among all the factories in the same JVM)
+//    * or its own pools.
+//    * 
+//    * @param useGlobalPools <code>true</code> to let this factory uses global thread pools, <code>false</code> else
+//    */
+//   void setUseGlobalPools(boolean useGlobalPools);
+//
+//   /**
+//    * Returns the maximum size of the scheduled thread pool.
+//    * 
+//    * Default value is {@link HornetQClient#DEFAULT_SCHEDULED_THREAD_POOL_MAX_SIZE}.
+//    * 
+//    * @return the maximum size of the scheduled thread pool.
+//    */
+//   int getScheduledThreadPoolMaxSize();
+//
+//   /**
+//    * Sets the maximum size of the scheduled thread pool.
+//    * 
+//    * This setting is relevant only if this factory does not use global pools.
+//    * Value must be greater than 0.
+//    * 
+//    * @param scheduledThreadPoolMaxSize  maximum size of the scheduled thread pool.
+//    */
+//   void setScheduledThreadPoolMaxSize(int scheduledThreadPoolMaxSize);
+//
+//   /**
+//    * Returns the maximum size of the thread pool.
+//    * 
+//    * Default value is {@link HornetQClient#DEFAULT_THREAD_POOL_MAX_SIZE}.
+//    * 
+//    * @return the maximum size of the thread pool.
+//    */
+//   int getThreadPoolMaxSize();
+//
+//   /**
+//    * Sets the maximum size of the thread pool.
+//    * 
+//    * This setting is relevant only if this factory does not use global pools.
+//    * Value must be -1 (for unlimited thread pool) or greater than 0.
+//    * 
+//    * @param threadPoolMaxSize  maximum size of the thread pool.
+//    */
+//   void setThreadPoolMaxSize(int threadPoolMaxSize);
+//
+//   /**
+//    * Returns the time to retry connections created by this factory after failure. 
+//    * 
+//    * Value is in milliseconds, default is {@link HornetQClient#DEFAULT_RETRY_INTERVAL}.
+//    * 
+//    * @return the time to retry connections created by this factory after failure
+//    */
+//   long getRetryInterval();
+//
+//   /**
+//    * Sets the time to retry connections created by this factory after failure.
+//    * 
+//    * Value must be greater than 0.
+//    * 
+//    * @param retryInterval time (in milliseconds) to retry connections created by this factory after failure 
+//    */
+//   void setRetryInterval(long retryInterval);
+//
+//   /**
+//    * Returns the multiplier to apply to successive retry intervals.
+//    * 
+//    * Default value is  {@link HornetQClient#DEFAULT_RETRY_INTERVAL_MULTIPLIER}.
+//    * 
+//    * @return the multiplier to apply to successive retry intervals
+//    */
+//   double getRetryIntervalMultiplier();
+//
+//   /**
+//    * Sets the multiplier to apply to successive retry intervals.
+//    * 
+//    * Value must be positive.
+//    * 
+//    * @param retryIntervalMultiplier multiplier to apply to successive retry intervals
+//    */
+//   void setRetryIntervalMultiplier(double retryIntervalMultiplier);
+//
+//   /**
+//    * Returns the maximum retry interval (in the case a retry interval multiplier has been specified).
+//    * 
+//    * Value is in milliseconds, default value is  {@link HornetQClient#DEFAULT_MAX_RETRY_INTERVAL}.
+//    * 
+//    * @return the maximum retry interval
+//    */
+//   long getMaxRetryInterval();
+//
+//   /**
+//    * Sets the maximum retry interval.
+//    * 
+//    * Value must be greater than 0.
+//    * 
+//    * @param maxRetryInterval maximum retry interval to apply in the case a retry interval multiplier has been specified
+//    */
+//   void setMaxRetryInterval(long maxRetryInterval);
+//
+//   /**
+//    * Returns the maximum number of attempts to retry connection in case of failure.
+//    * 
+//    * Default value is {@link HornetQClient#DEFAULT_RECONNECT_ATTEMPTS}.
+//    * 
+//    * @return the maximum number of attempts to retry connection in case of failure.
+//    */
+//   int getReconnectAttempts();
+//
+//   /**
+//    * Sets the maximum number of attempts to retry connection in case of failure.
+//    * 
+//    * Value must be -1 (to retry infinitely), 0 (to never retry connection) or greater than 0.
+//    * 
+//    * @param reconnectAttempts maximum number of attempts to retry connection in case of failure
+//    */
+//   void setReconnectAttempts(int reconnectAttempts);
+//   
+//   /**
+//    * Returns true if the client will automatically attempt to connect to the backup server if the initial
+//    * connection to the live server fails
+//    * 
+//    * Default value is {@link HornetQClient.DEFAULT_FAILOVER_ON_INITIAL_CONNECTION}.
+//    * 
+//    * @return
+//    */
+//   boolean isFailoverOnInitialConnection();
+//   
+//   /**
+//    * Sets the value for FailoverOnInitialReconnection
+//    * 
+//    * @param failover
+//    */
+//   void setFailoverOnInitialConnection(boolean failover);
+//
+//   /**
+//    * Returns whether connections created by this factory must failover in case the server they are
+//    * connected to <em>has normally shut down</em>.
+//    * 
+//    * Default value is {@link HornetQClient#DEFAULT_FAILOVER_ON_SERVER_SHUTDOWN}.
+//    * 
+//    * @return <code>true</code> if connections must failover if the server has normally shut down, else <code>false</code>
+//    */
+//   boolean isFailoverOnServerShutdown();
+//
+//   /**
+//    * Sets whether connections created by this factory must failover in case the server they are
+//    * connected to <em>has normally shut down</em>
+//    * 
+//    * @param failoverOnServerShutdown <code>true</code> if connections must failover if the server has normally shut down, <code>false</code> else
+//    */
+//   void setFailoverOnServerShutdown(boolean failoverOnServerShutdown);
+//
+//   /**
+//    * Returns the class name of the connection load balancing policy.
+//    * 
+//    * Default value is "org.hornetq.api.core.client.loadbalance.RoundRobinConnectionLoadBalancingPolicy".
+//    * 
+//    * @return the class name of the connection load balancing policy
+//    */
+//   String getConnectionLoadBalancingPolicyClassName();
+//
+//   /**
+//    * Sets the class name of the connection load balancing policy.
+//    * 
+//    * Value must be the name of a class implementing {@link ConnectionLoadBalancingPolicy}.
+//    * 
+//    * @param loadBalancingPolicyClassName class name of the connection load balancing policy
+//    */
+//   void setConnectionLoadBalancingPolicyClassName(String loadBalancingPolicyClassName);
+//
+//   /**
+//    * Returns the initial size of messages created through this factory.
+//    * 
+//    * Value is in bytes, default value is  {@link HornetQClient#DEFAULT_INITIAL_MESSAGE_PACKET_SIZE}.
+//    * 
+//    * @return the initial size of messages created through this factory
+//    */
+//   int getInitialMessagePacketSize();
+//
+//   /**
+//    * Sets the initial size of messages created through this factory.
+//    * 
+//    * Value must be greater than 0.
+//    * 
+//    * @param size initial size of messages created through this factory.
+//    */
+//   void setInitialMessagePacketSize(int size);
+//   
+//   /**
+//    * Adds an interceptor which will be executed <em>after packets are received from the server</em>.
+//    * 
+//    * @param interceptor an Interceptor
+//    */
+//   void addInterceptor(Interceptor interceptor);
+//
+//   /**
+//    * Removes an interceptor.
+//    * 
+//    * @param interceptor interceptor to remove
+//    * 
+//    * @return <code>true</code> if the interceptor is removed from this factory, <code>false</code> else
+//    */
+//   boolean removeInterceptor(Interceptor interceptor);
+//
+//   /**
+//    * Closes this factory and release all its resources
+//    */
+//   void close();
 
-   /**
-    * Returns whether messages will pre-acknowledged on the server before they are sent to the consumers or not.
-    *
-    * Default value is {@link HornetQClient#DEFAULT_PRE_ACKNOWLEDGE}
-    */
-   boolean isPreAcknowledge();
-
-   /**
-    * Sets to <code>true</code> to pre-acknowledge consumed messages on the server before they are sent to consumers, else set to <code>false</code> to let
-    * clients acknowledge the message they consume.
-    * 
-    * @param preAcknowledge <code>true</code> to enable pre-acknowledgement, <code>false</code> else
-    */
-   void setPreAcknowledge(boolean preAcknowledge);
-
-   /**
-    * Returns the acknowledgements batch size.
-    * 
-    * Default value is  {@link HornetQClient#DEFAULT_ACK_BATCH_SIZE}.
-    * 
-    * @return the acknowledgements batch size
-    */
-   int getAckBatchSize();
-
-   /**
-    * Sets the acknowledgements batch size.
-    * 
-    * Value must be equal or greater than 0.
-    * 
-    * @param ackBatchSize acknowledgements batch size
-    */
-   void setAckBatchSize(int ackBatchSize);
-
-   /**
-    * Returns the local bind address to which the multicast socket is bound for discovery.
-    * 
-    * This is null if the multicast socket is not bound, or no discovery is being used
-    * 
-    * @return the local bind address to which the multicast socket is bound for discovery
-    */
-   String getLocalBindAddress();
-
-   /**
-    * Sets the local bind address to which the multicast socket is bound for discovery.
-    * 
-    * @param the local bind address
-    */
-   void setLocalBindAddress(String localBindAddress);
    
-   /**
-    * Returns the address to listen to discover which connectors this factory can use.
-    * The discovery address must be set to enable this factory to discover HornetQ servers.
-    * 
-    * @return the address to listen to discover which connectors this factory can use
-    */
-   String getDiscoveryAddress();
-
-   /**
-    * Sets the address to listen to discover which connectors this factory can use.
-    * 
-    * @param discoveryAddress address to listen to discover which connectors this factory can use
-    */
-   void setDiscoveryAddress(String discoveryAddress);
-
-   /**
-    * Returns the port to listen to discover which connectors this factory can use.
-    * The discovery port must be set to enable this factory to discover HornetQ servers.
-    * 
-    * @return the port to listen to discover which connectors this factory can use
-    */   
-   int getDiscoveryPort();
-
-
-   /**
-    * Sets the port to listen to discover which connectors this factory can use.
-    * 
-    * @param discoveryPort port to listen to discover which connectors this factory can use
-    */
-   void setDiscoveryPort(int discoveryPort);
-
-   /**
-    * Returns the refresh timeout for discovered HornetQ servers.
-    * 
-    * If this factory uses discovery to find HornetQ servers, the list of discovered servers
-    * will be refreshed according to this timeout.
-    * 
-    * Value is in milliseconds, default value is {@link HornetQClient#DEFAULT_DISCOVERY_REFRESH_TIMEOUT}.
-    * 
-    * @return the refresh timeout for discovered HornetQ servers
-    */
-   long getDiscoveryRefreshTimeout();
-
-   /**
-    * Sets the refresh timeout for discovered HornetQ servers.
-    * 
-    * Value must be greater than 0.
-    * 
-    * @param discoveryRefreshTimeout refresh timeout (in milliseconds) for discovered HornetQ servers
-    */
-   void setDiscoveryRefreshTimeout(long discoveryRefreshTimeout);
-
-   /**
-    * Returns the initial wait timeout if this factory is configured to use discovery.
-    * 
-    * Value is in milliseconds, default value is  {@link HornetQClient#DEFAULT_DISCOVERY_INITIAL_WAIT_TIMEOUT}.
-    * 
-    * @return the initial wait timeout if this factory is configured to use discovery 
-    */
-   long getDiscoveryInitialWaitTimeout();
-
-   /**
-    * Sets the initial wait timeout if this factory is configured to use discovery.
-    * 
-    * Value is in milliseconds and must be greater than 0.
-    * 
-    * @param initialWaitTimeout initial wait timeout when using discovery 
-    */
-   void setDiscoveryInitialWaitTimeout(long initialWaitTimeout);
-
-   /**
-    * Returns whether this factory will use global thread pools (shared among all the factories in the same JVM)
-    * or its own pools.
-    * 
-    * Default value is {@link HornetQClient#DEFAULT_USE_GLOBAL_POOLS}.
-    * 
-    * @return <code>true</code> if this factory uses global thread pools, <code>false</code> else
-    */
-   boolean isUseGlobalPools();
-
-   /**
-    * Sets whether this factory will use global thread pools (shared among all the factories in the same JVM)
-    * or its own pools.
-    * 
-    * @param useGlobalPools <code>true</code> to let this factory uses global thread pools, <code>false</code> else
-    */
-   void setUseGlobalPools(boolean useGlobalPools);
-
-   /**
-    * Returns the maximum size of the scheduled thread pool.
-    * 
-    * Default value is {@link HornetQClient#DEFAULT_SCHEDULED_THREAD_POOL_MAX_SIZE}.
-    * 
-    * @return the maximum size of the scheduled thread pool.
-    */
-   int getScheduledThreadPoolMaxSize();
-
-   /**
-    * Sets the maximum size of the scheduled thread pool.
-    * 
-    * This setting is relevant only if this factory does not use global pools.
-    * Value must be greater than 0.
-    * 
-    * @param scheduledThreadPoolMaxSize  maximum size of the scheduled thread pool.
-    */
-   void setScheduledThreadPoolMaxSize(int scheduledThreadPoolMaxSize);
-
-   /**
-    * Returns the maximum size of the thread pool.
-    * 
-    * Default value is {@link HornetQClient#DEFAULT_THREAD_POOL_MAX_SIZE}.
-    * 
-    * @return the maximum size of the thread pool.
-    */
-   int getThreadPoolMaxSize();
-
-   /**
-    * Sets the maximum size of the thread pool.
-    * 
-    * This setting is relevant only if this factory does not use global pools.
-    * Value must be -1 (for unlimited thread pool) or greater than 0.
-    * 
-    * @param threadPoolMaxSize  maximum size of the thread pool.
-    */
-   void setThreadPoolMaxSize(int threadPoolMaxSize);
-
-   /**
-    * Returns the time to retry connections created by this factory after failure. 
-    * 
-    * Value is in milliseconds, default is {@link HornetQClient#DEFAULT_RETRY_INTERVAL}.
-    * 
-    * @return the time to retry connections created by this factory after failure
-    */
-   long getRetryInterval();
-
-   /**
-    * Sets the time to retry connections created by this factory after failure.
-    * 
-    * Value must be greater than 0.
-    * 
-    * @param retryInterval time (in milliseconds) to retry connections created by this factory after failure 
-    */
-   void setRetryInterval(long retryInterval);
-
-   /**
-    * Returns the multiplier to apply to successive retry intervals.
-    * 
-    * Default value is  {@link HornetQClient#DEFAULT_RETRY_INTERVAL_MULTIPLIER}.
-    * 
-    * @return the multiplier to apply to successive retry intervals
-    */
-   double getRetryIntervalMultiplier();
-
-   /**
-    * Sets the multiplier to apply to successive retry intervals.
-    * 
-    * Value must be positive.
-    * 
-    * @param retryIntervalMultiplier multiplier to apply to successive retry intervals
-    */
-   void setRetryIntervalMultiplier(double retryIntervalMultiplier);
-
-   /**
-    * Returns the maximum retry interval (in the case a retry interval multiplier has been specified).
-    * 
-    * Value is in milliseconds, default value is  {@link HornetQClient#DEFAULT_MAX_RETRY_INTERVAL}.
-    * 
-    * @return the maximum retry interval
-    */
-   long getMaxRetryInterval();
-
-   /**
-    * Sets the maximum retry interval.
-    * 
-    * Value must be greater than 0.
-    * 
-    * @param maxRetryInterval maximum retry interval to apply in the case a retry interval multiplier has been specified
-    */
-   void setMaxRetryInterval(long maxRetryInterval);
-
-   /**
-    * Returns the maximum number of attempts to retry connection in case of failure.
-    * 
-    * Default value is {@link HornetQClient#DEFAULT_RECONNECT_ATTEMPTS}.
-    * 
-    * @return the maximum number of attempts to retry connection in case of failure.
-    */
-   int getReconnectAttempts();
-
-   /**
-    * Sets the maximum number of attempts to retry connection in case of failure.
-    * 
-    * Value must be -1 (to retry infinitely), 0 (to never retry connection) or greater than 0.
-    * 
-    * @param reconnectAttempts maximum number of attempts to retry connection in case of failure
-    */
-   void setReconnectAttempts(int reconnectAttempts);
+//   List<Pair<TransportConfiguration, TransportConfiguration>> getClusterTopology();
+//   
+//   void registerTopologyListener(ClusterTopologyListener listener);
+//   
+//   void unregisterTopologyListener(ClusterTopologyListener listener);
    
-   /**
-    * Returns true if the client will automatically attempt to connect to the backup server if the initial
-    * connection to the live server fails
-    * 
-    * Default value is {@link HornetQClient.DEFAULT_FAILOVER_ON_INITIAL_CONNECTION}.
-    * 
-    * @return
-    */
-   boolean isFailoverOnInitialConnection();
-   
-   /**
-    * Sets the value for FailoverOnInitialReconnection
-    * 
-    * @param failover
-    */
-   void setFailoverOnInitialConnection(boolean failover);
-
-   /**
-    * Returns whether connections created by this factory must failover in case the server they are
-    * connected to <em>has normally shut down</em>.
-    * 
-    * Default value is {@link HornetQClient#DEFAULT_FAILOVER_ON_SERVER_SHUTDOWN}.
-    * 
-    * @return <code>true</code> if connections must failover if the server has normally shut down, else <code>false</code>
-    */
-   boolean isFailoverOnServerShutdown();
-
-   /**
-    * Sets whether connections created by this factory must failover in case the server they are
-    * connected to <em>has normally shut down</em>
-    * 
-    * @param failoverOnServerShutdown <code>true</code> if connections must failover if the server has normally shut down, <code>false</code> else
-    */
-   void setFailoverOnServerShutdown(boolean failoverOnServerShutdown);
-
-   /**
-    * Returns the class name of the connection load balancing policy.
-    * 
-    * Default value is "org.hornetq.api.core.client.loadbalance.RoundRobinConnectionLoadBalancingPolicy".
-    * 
-    * @return the class name of the connection load balancing policy
-    */
-   String getConnectionLoadBalancingPolicyClassName();
-
-   /**
-    * Sets the class name of the connection load balancing policy.
-    * 
-    * Value must be the name of a class implementing {@link ConnectionLoadBalancingPolicy}.
-    * 
-    * @param loadBalancingPolicyClassName class name of the connection load balancing policy
-    */
-   void setConnectionLoadBalancingPolicyClassName(String loadBalancingPolicyClassName);
-
-   /**
-    * Returns the initial size of messages created through this factory.
-    * 
-    * Value is in bytes, default value is  {@link HornetQClient#DEFAULT_INITIAL_MESSAGE_PACKET_SIZE}.
-    * 
-    * @return the initial size of messages created through this factory
-    */
-   int getInitialMessagePacketSize();
-
-   /**
-    * Sets the initial size of messages created through this factory.
-    * 
-    * Value must be greater than 0.
-    * 
-    * @param size initial size of messages created through this factory.
-    */
-   void setInitialMessagePacketSize(int size);
-   
-   /**
-    * Adds an interceptor which will be executed <em>after packets are received from the server</em>.
-    * 
-    * @param interceptor an Interceptor
-    */
-   void addInterceptor(Interceptor interceptor);
-
-   /**
-    * Removes an interceptor.
-    * 
-    * @param interceptor interceptor to remove
-    * 
-    * @return <code>true</code> if the interceptor is removed from this factory, <code>false</code> else
-    */
-   boolean removeInterceptor(Interceptor interceptor);
-
-   /**
-    * Closes this factory and release all its resources
-    */
    void close();
 
-   /**
-    * Creates a copy of this factory.
-    * 
-    * @return a copy of this factory with the same parameters values
-    */
-   ClientSessionFactory copy();
-
 }

Modified: branches/2_2_0_HA_Improvements/src/main/org/hornetq/api/core/client/HornetQClient.java
===================================================================
--- branches/2_2_0_HA_Improvements/src/main/org/hornetq/api/core/client/HornetQClient.java	2010-06-11 04:11:42 UTC (rev 9306)
+++ branches/2_2_0_HA_Improvements/src/main/org/hornetq/api/core/client/HornetQClient.java	2010-06-11 15:33:36 UTC (rev 9307)
@@ -16,6 +16,7 @@
 import org.hornetq.api.core.TransportConfiguration;
 import org.hornetq.api.core.client.loadbalance.RoundRobinConnectionLoadBalancingPolicy;
 import org.hornetq.core.client.impl.ClientSessionFactoryImpl;
+import org.hornetq.core.client.impl.ServerLocatorImpl;
 
 import java.util.List;
 
@@ -93,73 +94,61 @@
    public static final int DEFAULT_INITIAL_MESSAGE_PACKET_SIZE = 1500;
    
    /**
-    * Creates a ClientSessionFactory using all the defaults.
-    *
-    * @return the ClientSessionFactory.
+    * Create a ServerLocator which creates session factories using a static list of transportConfigurations, the ServerLocator is not updated automatically
+    * as the cluster topology changes, and no HA backup information is propagated to the client
+    * 
+    * @param transportConfigurations
+    * @return the ServerLocator
     */
-   public static ClientSessionFactory createClientSessionFactory()
+   public static ServerLocator createServerLocatorWithoutHA(TransportConfiguration... transportConfigurations)
    {
-      return new ClientSessionFactoryImpl();
+      return new ServerLocatorImpl(false, transportConfigurations);
    }
-
+   
    /**
-    * Creates a new ClientSessionFactory using the same configuration as the one passed in.
-    *
-    * @param other The ClientSessionFactory to copy
-    * @return The new ClientSessionFactory
+    * Create a ServerLocator which creates session factories from a set of live servers, no HA backup information is propagated to the client
+    * 
+    * The UDP address and port are used to listen for live servers in the cluster
+    * 
+    * @param discoveryAddress The UDP group address to listen for updates
+    * @param discoveryPort the UDP port to listen for updates
+    * @return the ServerLocator
     */
-   public static ClientSessionFactory createClientSessionFactory(final ClientSessionFactory other)
+   public static ServerLocator createServerLocatorWithoutHA(String discoveryAddress, final int discoveryPort)
    {
-      return new ClientSessionFactoryImpl(other);
+      return new ServerLocatorImpl(false, discoveryAddress, discoveryPort);
    }
-
+   
    /**
-    * Creates a ClientSessionFactory that uses discovery to connect to the servers.
-    *
-    * @param discoveryAddress The address to use for discovery
-    * @param discoveryPort The port to use for discovery.
-    * @return The ClientSessionFactory.
+    * Create a ServerLocator which will receive cluster topology updates from the cluster as servers leave or join and new backups are appointed or removed.
+    * The initial list of servers supplied in this method is simply to make an initial connection to the cluster, once that connection is made, up to date
+    * cluster topology information is downloaded and automatically updated whenever the cluster topology changes. If the topology includes backup servers
+    * that information is also propagated to the client so that it can know which server to failover onto in case of live server failure.
+    * @param initialServers The initial set of servers used to make a connection to the cluster. Each one is tried in turn until a successful connection is made. Once
+    * a connection is made, the cluster topology is downloaded and the rest of the list is ignored.
+    * @return the ServerLocator
     */
-   public static ClientSessionFactory createClientSessionFactory(final String discoveryAddress, final int discoveryPort)
+   public static ServerLocator createServerLocatorWithHA(TransportConfiguration... initialServers)
    {
-      return new ClientSessionFactoryImpl(discoveryAddress, discoveryPort);
+      return new ServerLocatorImpl(true, initialServers);
    }
-
+   
    /**
-    * Creates a ClientSessionFactory using a List of TransportConfigurations and backups.
-    *
-    * @param staticConnectors The list of TransportConfiguration's to use.
-    * @return The ClientSessionFactory.
+    * Create a ServerLocator which will receive cluster topology updates from the cluster as servers leave or join and new backups are appointed or removed.
+    * The discoveryAddress and discoveryPort parameters in this method are used to listen for UDP broadcasts which contain connection information for members of the cluster.
+    * The broadcasted connection information is simply used to make an initial connection to the cluster, once that connection is made, up to date
+    * cluster topology information is downloaded and automatically updated whenever the cluster topology changes. If the topology includes backup servers
+    * that information is also propagated to the client so that it can know which server to failover onto in case of live server failure.
+    * @param discoveryAddress The UDP group address to listen for updates
+    * @param discoveryPort the UDP port to listen for updates
+    * @return the ServerLocator
     */
-   public static ClientSessionFactory createClientSessionFactory(final List<Pair<TransportConfiguration, TransportConfiguration>> staticConnectors)
+   public static ServerLocator createServerLocatorWithHA(String discoveryAddress, final int discoveryPort)
    {
-      return new ClientSessionFactoryImpl(staticConnectors);
+      return new ServerLocatorImpl(true, discoveryAddress, discoveryPort);
    }
+   
 
-   /**
-    * Creates a ClientConnectionFactory using a TransportConfiguration of the server and a backup if needed.
-    *
-    * @param connectorConfig The TransportConfiguration of the server to connect to.
-    * @param backupConnectorConfig The TransportConfiguration of the backup server to connect to (or {@code null} if there is no backup)
-    * @return The ClientSessionFactory.
-    */
-   public static ClientSessionFactory createClientSessionFactory(final TransportConfiguration connectorConfig,
-                                   final TransportConfiguration backupConnectorConfig)
-   {
-      return new ClientSessionFactoryImpl(connectorConfig, backupConnectorConfig);
-   }
-
-   /**
-    * Creates a ClientSessionFactory using the TransportConfiguration of the server to connect to.
-    *
-    * @param connectorConfig The TransportConfiguration of the server.
-    * @return The ClientSessionFactory.
-    */
-   public static ClientSessionFactory createClientSessionFactory(final TransportConfiguration connectorConfig)
-   {
-      return new ClientSessionFactoryImpl(connectorConfig);
-   }
-
    private HornetQClient()
    {
    }

Modified: branches/2_2_0_HA_Improvements/src/main/org/hornetq/api/core/management/HornetQServerControl.java
===================================================================
--- branches/2_2_0_HA_Improvements/src/main/org/hornetq/api/core/management/HornetQServerControl.java	2010-06-11 04:11:42 UTC (rev 9306)
+++ branches/2_2_0_HA_Improvements/src/main/org/hornetq/api/core/management/HornetQServerControl.java	2010-06-11 15:33:36 UTC (rev 9307)
@@ -29,11 +29,11 @@
    // Attributes ----------------------------------------------------
 
    /**
-    * Returns the name of the connector used to connect to the backup.
+    * Returns the name of the connector used to connect to the live.
     * <br>
-    * If this server has no backup or is itself a backup, the value is {@code null}.
+    * If this server is not a backup that uses shared nothing HA, it's value is null
     */
-   String getBackupConnectorName();
+   String getLiveConnectorName();
 
    /**
     * Returns this server's version.

Modified: branches/2_2_0_HA_Improvements/src/main/org/hornetq/core/client/impl/ClientSessionFactoryImpl.java
===================================================================
--- branches/2_2_0_HA_Improvements/src/main/org/hornetq/core/client/impl/ClientSessionFactoryImpl.java	2010-06-11 04:11:42 UTC (rev 9306)
+++ branches/2_2_0_HA_Improvements/src/main/org/hornetq/core/client/impl/ClientSessionFactoryImpl.java	2010-06-11 15:33:36 UTC (rev 9307)
@@ -1,5 +1,5 @@
 /*
- * Copyright 2009 Red Hat, Inc.
+ * Copyright 2010 Red Hat, Inc.
  * Red Hat licenses this file to you under the Apache License, version
  * 2.0 (the "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
@@ -10,52 +10,66 @@
  * implied.  See the License for the specific language governing
  * permissions and limitations under the License.
  */
+
 package org.hornetq.core.client.impl;
 
-import java.io.Serializable;
-import java.net.InetAddress;
-import java.security.AccessController;
-import java.security.PrivilegedAction;
+import java.lang.ref.WeakReference;
 import java.util.ArrayList;
 import java.util.HashSet;
-import java.util.Iterator;
-import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
-import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.concurrent.Executor;
 import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
 import java.util.concurrent.ScheduledExecutorService;
-import java.util.concurrent.ThreadFactory;
 import java.util.concurrent.TimeUnit;
+import java.util.concurrent.locks.Lock;
 
+import org.hornetq.api.core.HornetQBuffer;
 import org.hornetq.api.core.HornetQException;
 import org.hornetq.api.core.Interceptor;
-import org.hornetq.api.core.Pair;
 import org.hornetq.api.core.TransportConfiguration;
 import org.hornetq.api.core.client.ClientSession;
-import org.hornetq.api.core.client.ClientSessionFactory;
-import org.hornetq.api.core.client.HornetQClient;
-import org.hornetq.api.core.client.loadbalance.ConnectionLoadBalancingPolicy;
-import org.hornetq.core.cluster.DiscoveryEntry;
-import org.hornetq.core.cluster.DiscoveryGroup;
-import org.hornetq.core.cluster.DiscoveryListener;
-import org.hornetq.core.cluster.impl.DiscoveryGroupImpl;
+import org.hornetq.api.core.client.SessionFailureListener;
 import org.hornetq.core.logging.Logger;
-import org.hornetq.utils.HornetQThreadFactory;
+import org.hornetq.core.protocol.core.Channel;
+import org.hornetq.core.protocol.core.ChannelHandler;
+import org.hornetq.core.protocol.core.CoreRemotingConnection;
+import org.hornetq.core.protocol.core.Packet;
+import org.hornetq.core.protocol.core.impl.PacketImpl;
+import org.hornetq.core.protocol.core.impl.RemotingConnectionImpl;
+import org.hornetq.core.protocol.core.impl.wireformat.ClusterTopologyMessage;
+import org.hornetq.core.protocol.core.impl.wireformat.CreateSessionMessage;
+import org.hornetq.core.protocol.core.impl.wireformat.CreateSessionResponseMessage;
+import org.hornetq.core.protocol.core.impl.wireformat.Ping;
+import org.hornetq.core.remoting.FailureListener;
+import org.hornetq.core.version.Version;
+import org.hornetq.spi.core.protocol.ProtocolType;
+import org.hornetq.spi.core.remoting.BufferHandler;
+import org.hornetq.spi.core.remoting.Connection;
+import org.hornetq.spi.core.remoting.ConnectionLifeCycleListener;
+import org.hornetq.spi.core.remoting.Connector;
+import org.hornetq.spi.core.remoting.ConnectorFactory;
+import org.hornetq.utils.ConcurrentHashSet;
+import org.hornetq.utils.ConfigurationHelper;
+import org.hornetq.utils.ExecutorFactory;
+import org.hornetq.utils.OrderedExecutorFactory;
 import org.hornetq.utils.UUIDGenerator;
+import org.hornetq.utils.VersionLoader;
 
 /**
- * @author <a href="mailto:tim.fox at jboss.com">Tim Fox</a>
- * @author <a href="mailto:clebert.suconic at jboss.org">Clebert Suconic</a>
- * @author <a href="mailto:jmesnil at redhat.com">Jeff Mesnil</a>
- * @author <a href="mailto:ataylor at redhat.com">Andy Taylor</a>
- * @version <tt>$Revision: 3602 $</tt>
+ * A ClientSessionFactoryImpl
  * 
+ * Encapsulates a connection to a server
+ *
+ * @author Tim Fox
+ *
+ *
  */
-public class ClientSessionFactoryImpl implements ClientSessionFactoryInternal, DiscoveryListener, Serializable
+public class ClientSessionFactoryImpl implements ClientSessionFactoryInternal, ConnectionLifeCycleListener
 {
+
    // Constants
    // ------------------------------------------------------------------------------------
 
@@ -66,1130 +80,1160 @@
    // Attributes
    // -----------------------------------------------------------------------------------
 
-   private final Map<Pair<TransportConfiguration, TransportConfiguration>, FailoverManager> failoverManagerMap = new LinkedHashMap<Pair<TransportConfiguration, TransportConfiguration>, FailoverManager>();
+   private final ServerLocatorInternal serverLocator;
 
-   private volatile boolean receivedBroadcast = false;
+   private TransportConfiguration connectorConfig;
 
-   private ExecutorService threadPool;
+   private ConnectorFactory connectorFactory;
 
-   private ScheduledExecutorService scheduledThreadPool;
+   private Map<String, Object> transportParams;
 
-   private DiscoveryGroup discoveryGroup;
+   private final long callTimeout;
 
-   private ConnectionLoadBalancingPolicy loadBalancingPolicy;
+   private final long clientFailureCheckPeriod;
 
-   private FailoverManager[] failoverManagerArray;
+   private final long connectionTTL;
 
-   private boolean readOnly;
+   private final Set<ClientSessionInternal> sessions = new HashSet<ClientSessionInternal>();
 
-   // Settable attributes:
+   private final Object exitLock = new Object();
 
-   private boolean cacheLargeMessagesClient = HornetQClient.DEFAULT_CACHE_LARGE_MESSAGE_CLIENT;
+   private final Object createSessionLock = new Object();
 
-   private List<Pair<TransportConfiguration, TransportConfiguration>> staticConnectors;
+   private boolean inCreateSession;
 
-   private String localBindAddress;
+   private final Object failoverLock = new Object();
 
-   private String discoveryAddress;
+   private final ExecutorFactory orderedExecutorFactory;
 
-   private int discoveryPort;
+   private final ExecutorService threadPool;
 
-   private long discoveryRefreshTimeout;
+   private final ScheduledExecutorService scheduledThreadPool;
 
-   private long discoveryInitialWaitTimeout;
+   private final Executor closeExecutor;
 
-   private long clientFailureCheckPeriod;
+   private CoreRemotingConnection connection;
 
-   private long connectionTTL;
+   private final long retryInterval;
 
-   private long callTimeout;
+   private final double retryIntervalMultiplier; // For exponential backoff
 
-   private int minLargeMessageSize;
+   private final long maxRetryInterval;
 
-   private int consumerWindowSize;
+   private final int reconnectAttempts;
 
-   private int consumerMaxRate;
+   private final boolean failoverOnServerShutdown;
 
-   private int confirmationWindowSize;
+   private final Set<SessionFailureListener> listeners = new ConcurrentHashSet<SessionFailureListener>();
 
-   private int producerWindowSize;
+   private Connector connector;
 
-   private int producerMaxRate;
+   private Future<?> pingerFuture;
 
-   private boolean blockOnAcknowledge;
+   private PingRunnable pingRunnable;
 
-   private boolean blockOnDurableSend;
+   private volatile boolean exitLoop;
 
-   private boolean blockOnNonDurableSend;
+   private final List<Interceptor> interceptors;
 
-   private boolean autoGroup;
+   private volatile boolean stopPingingAfterOne;
 
-   private boolean preAcknowledge;
+   private volatile boolean closed;
 
-   private String connectionLoadBalancingPolicyClassName;
+   // Static
+   // ---------------------------------------------------------------------------------------
 
-   private int ackBatchSize;
+   // Constructors
+   // ---------------------------------------------------------------------------------
 
-   private boolean useGlobalPools;
+   public ClientSessionFactoryImpl(final ServerLocatorInternal serverLocator,
+                                   final TransportConfiguration connectorConfig,
+                                   final boolean failoverOnServerShutdown,
+                                   final long callTimeout,
+                                   final long clientFailureCheckPeriod,
+                                   final long connectionTTL,
+                                   final long retryInterval,
+                                   final double retryIntervalMultiplier,
+                                   final long maxRetryInterval,
+                                   final int reconnectAttempts,
+                                   final boolean failoverOnInitialConnection,
+                                   final ExecutorService threadPool,
+                                   final ScheduledExecutorService scheduledThreadPool,
+                                   final List<Interceptor> interceptors) throws HornetQException
+   {
+      this.serverLocator = serverLocator;
 
-   private int scheduledThreadPoolMaxSize;
+      this.connectorConfig = connectorConfig;
 
-   private int threadPoolMaxSize;
+      this.failoverOnServerShutdown = failoverOnServerShutdown;
 
-   private long retryInterval;
+      connectorFactory = instantiateConnectorFactory(connectorConfig.getFactoryClassName());
 
-   private double retryIntervalMultiplier;
+      transportParams = connectorConfig.getParams();
 
-   private long maxRetryInterval;
+      checkTransportKeys(connectorFactory, transportParams);
 
-   private int reconnectAttempts;
+      this.callTimeout = callTimeout;
 
-   private boolean failoverOnInitialConnection;
+      this.clientFailureCheckPeriod = clientFailureCheckPeriod;
 
-   private int initialMessagePacketSize;
+      this.connectionTTL = connectionTTL;
 
-   private volatile boolean closed;
+      this.retryInterval = retryInterval;
 
-   private boolean failoverOnServerShutdown;
+      this.retryIntervalMultiplier = retryIntervalMultiplier;
 
-   private final List<Interceptor> interceptors = new CopyOnWriteArrayList<Interceptor>();
+      this.maxRetryInterval = maxRetryInterval;
 
-   private static ExecutorService globalThreadPool;
+      this.reconnectAttempts = reconnectAttempts;
 
-   private static ScheduledExecutorService globalScheduledThreadPool;
+      this.scheduledThreadPool = scheduledThreadPool;
 
-   private String groupID;
+      this.threadPool = threadPool;
 
-   private static synchronized ExecutorService getGlobalThreadPool()
-   {
-      if (ClientSessionFactoryImpl.globalThreadPool == null)
-      {
-         ThreadFactory factory = new HornetQThreadFactory("HornetQ-client-global-threads", true, getThisClassLoader());
+      orderedExecutorFactory = new OrderedExecutorFactory(threadPool);
 
-         ClientSessionFactoryImpl.globalThreadPool = Executors.newCachedThreadPool(factory);
-      }
+      closeExecutor = orderedExecutorFactory.getExecutor();
 
-      return ClientSessionFactoryImpl.globalThreadPool;
-   }
+      this.interceptors = interceptors;
 
-   private static synchronized ScheduledExecutorService getGlobalScheduledThreadPool()
-   {
-      if (ClientSessionFactoryImpl.globalScheduledThreadPool == null)
+      // Get the connection
+
+      getConnectionWithRetry(reconnectAttempts);
+
+      if (connection == null && failoverOnInitialConnection)
       {
-         ThreadFactory factory = new HornetQThreadFactory("HornetQ-client-global-scheduled-threads", true, getThisClassLoader());
+         TransportConfiguration backupConfig = serverLocator.getBackup(connectorConfig);
 
-         ClientSessionFactoryImpl.globalScheduledThreadPool = Executors.newScheduledThreadPool(HornetQClient.DEFAULT_SCHEDULED_THREAD_POOL_MAX_SIZE,
+         if (backupConfig != null)
+         {
+            // Try and connect to the backup
 
-                                                                                               factory);
+            log.warn("Server is not available to make initial connection to. Will try backup server instead.");
+            
+            this.connectorConfig = backupConfig;
+            
+            connectorFactory = instantiateConnectorFactory(connectorConfig.getFactoryClassName());
+
+            transportParams = connectorConfig.getParams();
+
+            getConnectionWithRetry(reconnectAttempts);
+         }
       }
 
-      return ClientSessionFactoryImpl.globalScheduledThreadPool;
+      if (connection == null)
+      {
+         throw new HornetQException(HornetQException.NOT_CONNECTED,
+                                    "Unable to connect to server using configuration " + connectorConfig);
+      }
+
    }
 
-   private void setThreadPools()
+   public ClientSession createSession(final String username,
+                                      final String password,
+                                      final boolean xa,
+                                      final boolean autoCommitSends,
+                                      final boolean autoCommitAcks,
+                                      final boolean preAcknowledge,
+                                      final int ackBatchSize) throws HornetQException
    {
-      if (useGlobalPools)
-      {
-         threadPool = ClientSessionFactoryImpl.getGlobalThreadPool();
+      return createSessionInternal(username,
+                                   password,
+                                   xa,
+                                   autoCommitSends,
+                                   autoCommitAcks,
+                                   preAcknowledge,
+                                   ackBatchSize);
+   }
 
-         scheduledThreadPool = ClientSessionFactoryImpl.getGlobalScheduledThreadPool();
-      }
-      else
-      {
-         ThreadFactory factory = new HornetQThreadFactory("HornetQ-client-factory-threads-" + System.identityHashCode(this),
-                                                          true, getThisClassLoader());
+   public ClientSession createSession(final boolean autoCommitSends,
+                                      final boolean autoCommitAcks,
+                                      final int ackBatchSize) throws HornetQException
+   {
+      return createSessionInternal(null,
+                                   null,
+                                   false,
+                                   autoCommitSends,
+                                   autoCommitAcks,
+                                   serverLocator.isPreAcknowledge(),
+                                   ackBatchSize);
+   }
 
-         if (threadPoolMaxSize == -1)
-         {
-            threadPool = Executors.newCachedThreadPool(factory);
-         }
-         else
-         {
-            threadPool = Executors.newFixedThreadPool(threadPoolMaxSize, factory);
-         }
+   public ClientSession createXASession() throws HornetQException
+   {
+      return createSessionInternal(null,
+                                   null,
+                                   true,
+                                   false,
+                                   false,
+                                   serverLocator.isPreAcknowledge(),
+                                   serverLocator.getAckBatchSize());
+   }
 
-         factory = new HornetQThreadFactory("HornetQ-client-factory-pinger-threads-" + System.identityHashCode(this),
-                                            true, getThisClassLoader());
+   public ClientSession createTransactedSession() throws HornetQException
+   {
+      return createSessionInternal(null,
+                                   null,
+                                   false,
+                                   false,
+                                   false,
+                                   serverLocator.isPreAcknowledge(),
+                                   serverLocator.getAckBatchSize());
+   }
 
-         scheduledThreadPool = Executors.newScheduledThreadPool(scheduledThreadPoolMaxSize, factory);
-      }
+   public ClientSession createSession() throws HornetQException
+   {
+      return createSessionInternal(null,
+                                   null,
+                                   false,
+                                   true,
+                                   true,
+                                   serverLocator.isPreAcknowledge(),
+                                   serverLocator.getAckBatchSize());
    }
 
-   private synchronized void initialise() throws Exception
+   public ClientSession createSession(final boolean autoCommitSends, final boolean autoCommitAcks) throws HornetQException
    {
-      if (!readOnly)
-      {
-         setThreadPools();
+      return createSessionInternal(null,
+                                   null,
+                                   false,
+                                   autoCommitSends,
+                                   autoCommitAcks,
+                                   serverLocator.isPreAcknowledge(),
+                                   serverLocator.getAckBatchSize());
+   }
 
-         instantiateLoadBalancingPolicy();
+   public ClientSession createSession(final boolean xa, final boolean autoCommitSends, final boolean autoCommitAcks) throws HornetQException
+   {
+      return createSessionInternal(null,
+                                   null,
+                                   xa,
+                                   autoCommitSends,
+                                   autoCommitAcks,
+                                   serverLocator.isPreAcknowledge(),
+                                   serverLocator.getAckBatchSize());
+   }
 
-         if (discoveryAddress != null)
-         {
-            InetAddress groupAddress = InetAddress.getByName(discoveryAddress);
+   public ClientSession createSession(final boolean xa,
+                                      final boolean autoCommitSends,
+                                      final boolean autoCommitAcks,
+                                      final boolean preAcknowledge) throws HornetQException
+   {
+      return createSessionInternal(null,
+                                   null,
+                                   xa,
+                                   autoCommitSends,
+                                   autoCommitAcks,
+                                   preAcknowledge,
+                                   serverLocator.getAckBatchSize());
+   }
 
-            InetAddress lbAddress;
+   // ConnectionLifeCycleListener implementation --------------------------------------------------
 
-            if (localBindAddress != null)
-            {
-               lbAddress = InetAddress.getByName(localBindAddress);
-            }
-            else
-            {
-               lbAddress = null;
-            }
+   public void connectionCreated(final Connection connection, final ProtocolType protocol)
+   {
+   }
 
-            discoveryGroup = new DiscoveryGroupImpl(UUIDGenerator.getInstance().generateStringUUID(),
-                                                    discoveryAddress,
-                                                    lbAddress,
-                                                    groupAddress,
-                                                    discoveryPort,
-                                                    discoveryRefreshTimeout);
+   public void connectionDestroyed(final Object connectionID)
+   {
+      handleConnectionFailure(connectionID,
+                              new HornetQException(HornetQException.NOT_CONNECTED, "Channel disconnected"));
+   }
 
-            discoveryGroup.registerListener(this);
+   public void connectionException(final Object connectionID, final HornetQException me)
+   {
+      handleConnectionFailure(connectionID, me);
+   }
 
-            discoveryGroup.start();
-         }
-         else if (staticConnectors != null)
+   // Must be synchronized to prevent it happening concurrently with failover which can lead to
+   // inconsistencies
+   public void removeSession(final ClientSessionInternal session)
+   {
+      synchronized (createSessionLock)
+      {
+         synchronized (failoverLock)
          {
-            for (Pair<TransportConfiguration, TransportConfiguration> pair : staticConnectors)
-            {
-               FailoverManager cm = new FailoverManagerImpl(this,
-                                                            pair.a,
-                                                            pair.b,
-                                                            failoverOnServerShutdown,
-                                                            callTimeout,
-                                                            clientFailureCheckPeriod,
-                                                            connectionTTL,
-                                                            retryInterval,
-                                                            retryIntervalMultiplier,
-                                                            maxRetryInterval,
-                                                            reconnectAttempts,
-                                                            failoverOnInitialConnection,
-                                                            threadPool,
-                                                            scheduledThreadPool,
-                                                            interceptors);
+            sessions.remove(session);
 
-               failoverManagerMap.put(pair, cm);
-            }
-
-            updatefailoverManagerArray();
+            checkCloseConnection();
          }
-         else
-         {
-            throw new IllegalStateException("Before using a session factory you must either set discovery address and port or " + "provide some static transport configuration");
-         }
-         readOnly = true;
       }
    }
 
-   // Static
-   // ---------------------------------------------------------------------------------------
+   public synchronized int numConnections()
+   {
+      return connection != null ? 1 : 0;
+   }
 
-   // Constructors
-   // ---------------------------------------------------------------------------------
+   public int numSessions()
+   {
+      return sessions.size();
+   }
 
-   public ClientSessionFactoryImpl(final ClientSessionFactory other)
+   public void addFailureListener(final SessionFailureListener listener)
    {
-      localBindAddress = other.getLocalBindAddress();
+      listeners.add(listener);
+   }
 
-      discoveryAddress = other.getDiscoveryAddress();
+   public boolean removeFailureListener(final SessionFailureListener listener)
+   {
+      return listeners.remove(listener);
+   }
 
-      discoveryPort = other.getDiscoveryPort();
+   public void causeExit()
+   {
+      exitLoop = true;
+   }
 
-      staticConnectors = other.getStaticConnectors();
+   public void close()
+   {
+      if (closed)
+      {
+         return;
+      }
 
-      discoveryRefreshTimeout = other.getDiscoveryRefreshTimeout();
+      causeExit();
 
-      clientFailureCheckPeriod = other.getClientFailureCheckPeriod();
+      closed = true;
+   }
 
-      connectionTTL = other.getConnectionTTL();
+   // Public
+   // ---------------------------------------------------------------------------------------
 
-      callTimeout = other.getCallTimeout();
+   public void stopPingingAfterOne()
+   {
+      stopPingingAfterOne = true;
+   }
 
-      minLargeMessageSize = other.getMinLargeMessageSize();
+   // Protected
+   // ------------------------------------------------------------------------------------
 
-      consumerWindowSize = other.getConsumerWindowSize();
+   // Package Private
+   // ------------------------------------------------------------------------------
 
-      consumerMaxRate = other.getConsumerMaxRate();
+   // Private
+   // --------------------------------------------------------------------------------------
 
-      confirmationWindowSize = other.getConfirmationWindowSize();
+   private void handleConnectionFailure(final Object connectionID, final HornetQException me)
+   {
+      failoverOrReconnect(connectionID, me);
+   }
 
-      producerWindowSize = other.getProducerWindowSize();
+   private void failoverOrReconnect(final Object connectionID, final HornetQException me)
+   {
+      Set<ClientSessionInternal> sessionsToClose = null;
 
-      producerMaxRate = other.getProducerMaxRate();
+      synchronized (failoverLock)
+      {
+         if (connection == null || connection.getID() != connectionID)
+         {
+            // We already failed over/reconnected - probably the first failure came in, all the connections were failed
+            // over then a async connection exception or disconnect
+            // came in for one of the already exitLoop connections, so we return true - we don't want to call the
+            // listeners again
 
-      blockOnAcknowledge = other.isBlockOnAcknowledge();
+            return;
+         }
 
-      blockOnDurableSend = other.isBlockOnDurableSend();
+         // We call before reconnection occurs to give the user a chance to do cleanup, like cancel messages
+         callFailureListeners(me, false);
 
-      blockOnNonDurableSend = other.isBlockOnNonDurableSend();
+         // Now get locks on all channel 1s, whilst holding the failoverLock - this makes sure
+         // There are either no threads executing in createSession, or one is blocking on a createSession
+         // result.
 
-      autoGroup = other.isAutoGroup();
+         // Then interrupt the channel 1 that is blocking (could just interrupt them all)
 
-      preAcknowledge = other.isPreAcknowledge();
+         // Then release all channel 1 locks - this allows the createSession to exit the monitor
 
-      ackBatchSize = other.getAckBatchSize();
+         // Then get all channel 1 locks again - this ensures the any createSession thread has executed the section and
+         // returned all its connections to the connection manager (the code to return connections to connection manager
+         // must be inside the lock
 
-      connectionLoadBalancingPolicyClassName = other.getConnectionLoadBalancingPolicyClassName();
+         // Then perform failover
 
-      discoveryInitialWaitTimeout = other.getDiscoveryInitialWaitTimeout();
+         // Then release failoverLock
 
-      useGlobalPools = other.isUseGlobalPools();
+         // The other side of the bargain - during createSession:
+         // The calling thread must get the failoverLock and get its' connections when this is locked.
+         // While this is still locked it must then get the channel1 lock
+         // It can then release the failoverLock
+         // It should catch HornetQException.INTERRUPTED in the call to channel.sendBlocking
+         // It should then return its connections, with channel 1 lock still held
+         // It can then release the channel 1 lock, and retry (which will cause locking on failoverLock
+         // until failover is complete
 
-      scheduledThreadPoolMaxSize = other.getScheduledThreadPoolMaxSize();
+         boolean serverShutdown = me.getCode() == HornetQException.DISCONNECTED;
 
-      threadPoolMaxSize = other.getThreadPoolMaxSize();
+         // We will try to failover if there is a backup connector factory, but we don't do this if the server
+         // has been shutdown cleanly unless failoverOnServerShutdown is true
+         TransportConfiguration backupConfig = serverLocator.getBackup(connectorConfig);
+         
+         boolean attemptFailover = backupConfig != null && (failoverOnServerShutdown || !serverShutdown);
 
-      retryInterval = other.getRetryInterval();
+         boolean attemptReconnect;
 
-      retryIntervalMultiplier = other.getRetryIntervalMultiplier();
+         if (attemptFailover)
+         {
+            attemptReconnect = false;
+         }
+         else
+         {
+            attemptReconnect = reconnectAttempts != 0;
+         }
 
-      maxRetryInterval = other.getMaxRetryInterval();
+         if (attemptFailover || attemptReconnect)
+         {
+            lockChannel1();
 
-      reconnectAttempts = other.getReconnectAttempts();
+            final boolean needToInterrupt;
 
-      failoverOnInitialConnection = other.isFailoverOnInitialConnection();
+            synchronized (exitLock)
+            {
+               needToInterrupt = inCreateSession;
+            }
 
-      failoverOnServerShutdown = other.isFailoverOnServerShutdown();
+            unlockChannel1();
 
-      cacheLargeMessagesClient = other.isCacheLargeMessagesClient();
+            if (needToInterrupt)
+            {
+               // Forcing return all channels won't guarantee that any blocked thread will return immediately
+               // So we need to wait for it
+               forceReturnChannel1();
 
-      initialMessagePacketSize = other.getInitialMessagePacketSize();
+               // Now we need to make sure that the thread has actually exited and returned it's connections
+               // before failover occurs
 
-      groupID = other.getGroupID();
-   }
+               synchronized (exitLock)
+               {
+                  while (inCreateSession)
+                  {
+                     try
+                     {
+                        exitLock.wait(5000);
+                     }
+                     catch (InterruptedException e)
+                     {
+                     }
+                  }
+               }
+            }
 
-   public ClientSessionFactoryImpl()
-   {
-      discoveryRefreshTimeout = HornetQClient.DEFAULT_DISCOVERY_REFRESH_TIMEOUT;
+            // Now we absolutely know that no threads are executing in or blocked in createSession, and no
+            // more will execute it until failover is complete
 
-      clientFailureCheckPeriod = HornetQClient.DEFAULT_CLIENT_FAILURE_CHECK_PERIOD;
+            // So.. do failover / reconnection
 
-      connectionTTL = HornetQClient.DEFAULT_CONNECTION_TTL;
+            CoreRemotingConnection oldConnection = connection;
 
-      callTimeout = HornetQClient.DEFAULT_CALL_TIMEOUT;
+            connection = null;
 
-      minLargeMessageSize = HornetQClient.DEFAULT_MIN_LARGE_MESSAGE_SIZE;
+            try
+            {
+               connector.close();
+            }
+            catch (Exception ignore)
+            {
+            }
 
-      consumerWindowSize = HornetQClient.DEFAULT_CONSUMER_WINDOW_SIZE;
+            cancelScheduledTasks();
 
-      consumerMaxRate = HornetQClient.DEFAULT_CONSUMER_MAX_RATE;
+            connector = null;
 
-      confirmationWindowSize = HornetQClient.DEFAULT_CONFIRMATION_WINDOW_SIZE;
+            if (attemptFailover)
+            {
+               // Now try failing over to backup
 
-      producerWindowSize = HornetQClient.DEFAULT_PRODUCER_WINDOW_SIZE;
+               this.connectorConfig = backupConfig;
+               
+               connectorFactory = instantiateConnectorFactory(connectorConfig.getFactoryClassName());
 
-      producerMaxRate = HornetQClient.DEFAULT_PRODUCER_MAX_RATE;
+               transportParams = connectorConfig.getParams();
 
-      blockOnAcknowledge = HornetQClient.DEFAULT_BLOCK_ON_ACKNOWLEDGE;
+               reconnectSessions(oldConnection, reconnectAttempts == -1 ? -1 : reconnectAttempts + 1);
+            }
+            else
+            {
+               reconnectSessions(oldConnection, reconnectAttempts);
+            }
 
-      blockOnDurableSend = HornetQClient.DEFAULT_BLOCK_ON_DURABLE_SEND;
+            oldConnection.destroy();
+         }
+         else
+         {
+            connection.destroy();
 
-      blockOnNonDurableSend = HornetQClient.DEFAULT_BLOCK_ON_NON_DURABLE_SEND;
+            connection = null;
+         }
 
-      autoGroup = HornetQClient.DEFAULT_AUTO_GROUP;
+         callFailureListeners(me, true);
 
-      preAcknowledge = HornetQClient.DEFAULT_PRE_ACKNOWLEDGE;
+         if (connection == null)
+         {
+            sessionsToClose = new HashSet<ClientSessionInternal>(sessions);
+         }
+      }
 
-      ackBatchSize = HornetQClient.DEFAULT_ACK_BATCH_SIZE;
+      // This needs to be outside the failover lock to prevent deadlock
+      if (sessionsToClose != null)
+      {
+         // If connection is null it means we didn't succeed in failing over or reconnecting
+         // so we close all the sessions, so they will throw exceptions when attempted to be used
 
-      connectionLoadBalancingPolicyClassName = HornetQClient.DEFAULT_CONNECTION_LOAD_BALANCING_POLICY_CLASS_NAME;
-
-      discoveryInitialWaitTimeout = HornetQClient.DEFAULT_DISCOVERY_INITIAL_WAIT_TIMEOUT;
-
-      useGlobalPools = HornetQClient.DEFAULT_USE_GLOBAL_POOLS;
-
-      scheduledThreadPoolMaxSize = HornetQClient.DEFAULT_SCHEDULED_THREAD_POOL_MAX_SIZE;
-
-      threadPoolMaxSize = HornetQClient.DEFAULT_THREAD_POOL_MAX_SIZE;
-
-      retryInterval = HornetQClient.DEFAULT_RETRY_INTERVAL;
-
-      retryIntervalMultiplier = HornetQClient.DEFAULT_RETRY_INTERVAL_MULTIPLIER;
-
-      maxRetryInterval = HornetQClient.DEFAULT_MAX_RETRY_INTERVAL;
-
-      reconnectAttempts = HornetQClient.DEFAULT_RECONNECT_ATTEMPTS;
-
-      failoverOnInitialConnection = HornetQClient.DEFAULT_FAILOVER_ON_INITIAL_CONNECTION;
-
-      failoverOnServerShutdown = HornetQClient.DEFAULT_FAILOVER_ON_SERVER_SHUTDOWN;
-
-      cacheLargeMessagesClient = HornetQClient.DEFAULT_CACHE_LARGE_MESSAGE_CLIENT;
-
-      initialMessagePacketSize = HornetQClient.DEFAULT_INITIAL_MESSAGE_PACKET_SIZE;
+         for (ClientSessionInternal session : sessionsToClose)
+         {
+            try
+            {
+               session.cleanUp();
+            }
+            catch (Exception e)
+            {
+               log.error("Failed to cleanup session");
+            }
+         }
+      }
    }
 
-   public ClientSessionFactoryImpl(final String discoveryAddress, final int discoveryPort)
+   private ClientSession createSessionInternal(final String username,
+                                               final String password,
+                                               final boolean xa,
+                                               final boolean autoCommitSends,
+                                               final boolean autoCommitAcks,
+                                               final boolean preAcknowledge,
+                                               final int ackBatchSize) throws HornetQException
    {
-      this();
+      synchronized (createSessionLock)
+      {
+         String name = UUIDGenerator.getInstance().generateStringUUID();
 
-      this.discoveryAddress = discoveryAddress;
+         boolean retry = false;
+         do
+         {
+            Version clientVersion = VersionLoader.getVersion();
 
-      this.discoveryPort = discoveryPort;
-   }
+            Lock lock = null;
 
-   public ClientSessionFactoryImpl(final String localBindAddress, final String discoveryAddress, final int discoveryPort)
-   {
-      this();
+            try
+            {
+               Channel channel1;
 
-      this.localBindAddress = localBindAddress;
+               synchronized (failoverLock)
+               {
+                  if (connection == null)
+                  {
+                     throw new IllegalStateException("Connection is null");
+                  }
 
-      this.discoveryAddress = discoveryAddress;
+                  channel1 = connection.getChannel(1, -1);
 
-      this.discoveryPort = discoveryPort;
-   }
+                  // Lock it - this must be done while the failoverLock is held
+                  channel1.getLock().lock();
 
-   public ClientSessionFactoryImpl(final List<Pair<TransportConfiguration, TransportConfiguration>> staticConnectors)
-   {
-      this();
+                  lock = channel1.getLock();
+               } // We can now release the failoverLock
 
-      this.staticConnectors = staticConnectors;
-   }
+               // We now set a flag saying createSession is executing
+               synchronized (exitLock)
+               {
+                  inCreateSession = true;
+               }
 
-   public ClientSessionFactoryImpl(final TransportConfiguration connectorConfig,
-                                   final TransportConfiguration backupConnectorConfig)
-   {
-      this();
+               long sessionChannelID = connection.generateChannelID();
 
-      staticConnectors = new ArrayList<Pair<TransportConfiguration, TransportConfiguration>>();
+               Packet request = new CreateSessionMessage(name,
+                                                         sessionChannelID,
+                                                         clientVersion.getIncrementingVersion(),
+                                                         username,
+                                                         password,
+                                                         serverLocator.getMinLargeMessageSize(),
+                                                         xa,
+                                                         autoCommitSends,
+                                                         autoCommitAcks,
+                                                         preAcknowledge,
+                                                         serverLocator.getConfirmationWindowSize(),
+                                                         null);
 
-      staticConnectors.add(new Pair<TransportConfiguration, TransportConfiguration>(connectorConfig,
-                                                                                    backupConnectorConfig));
-   }
+               Packet pResponse;
+               try
+               {
+                  pResponse = channel1.sendBlocking(request);
+               }
+               catch (HornetQException e)
+               {
+                  if (e.getCode() == HornetQException.INCOMPATIBLE_CLIENT_SERVER_VERSIONS)
+                  {
+                     connection.destroy();
+                  }
 
-   public ClientSessionFactoryImpl(final TransportConfiguration connectorConfig)
-   {
-      this(connectorConfig, null);
-   }
+                  if (e.getCode() == HornetQException.UNBLOCKED)
+                  {
+                     // This means the thread was blocked on create session and failover unblocked it
+                     // so failover could occur
 
-   // ClientSessionFactory implementation------------------------------------------------------------
+                     retry = true;
 
-   public synchronized boolean isCacheLargeMessagesClient()
-   {
-      return cacheLargeMessagesClient;
-   }
+                     continue;
+                  }
+                  else
+                  {
+                     throw e;
+                  }
+               }
 
-   public synchronized void setCacheLargeMessagesClient(final boolean cached)
-   {
-      cacheLargeMessagesClient = cached;
-   }
+               CreateSessionResponseMessage response = (CreateSessionResponseMessage)pResponse;
 
-   public synchronized List<Pair<TransportConfiguration, TransportConfiguration>> getStaticConnectors()
-   {
-      return staticConnectors;
-   }
+               Channel sessionChannel = connection.getChannel(sessionChannelID,
+                                                              serverLocator.getConfirmationWindowSize());
 
-   public synchronized void setStaticConnectors(final List<Pair<TransportConfiguration, TransportConfiguration>> staticConnectors)
-   {
-      checkWrite();
+               ClientSessionInternal session = new ClientSessionImpl(this,
+                                                                     name,
+                                                                     username,
+                                                                     password,
+                                                                     xa,
+                                                                     autoCommitSends,
+                                                                     autoCommitAcks,
+                                                                     preAcknowledge,
+                                                                     serverLocator.isBlockOnAcknowledge(),
+                                                                     serverLocator.isAutoGroup(),
+                                                                     ackBatchSize,
+                                                                     serverLocator.getConsumerWindowSize(),
+                                                                     serverLocator.getConsumerMaxRate(),
+                                                                     serverLocator.getConfirmationWindowSize(),
+                                                                     serverLocator.getProducerWindowSize(),
+                                                                     serverLocator.getProducerMaxRate(),
+                                                                     serverLocator.isBlockOnNonDurableSend(),
+                                                                     serverLocator.isBlockOnDurableSend(),
+                                                                     serverLocator.isCacheLargeMessagesClient(),
+                                                                     serverLocator.getMinLargeMessageSize(),
+                                                                     serverLocator.getInitialMessagePacketSize(),
+                                                                     serverLocator.getGroupID(),
+                                                                     connection,
+                                                                     response.getServerVersion(),
+                                                                     sessionChannel,
+                                                                     orderedExecutorFactory.getExecutor());
 
-      this.staticConnectors = staticConnectors;
-   }
+               sessions.add(session);
 
-   public synchronized long getClientFailureCheckPeriod()
-   {
-      return clientFailureCheckPeriod;
-   }
+               ChannelHandler handler = new ClientSessionPacketHandler(session, sessionChannel);
 
-   public synchronized void setClientFailureCheckPeriod(final long clientFailureCheckPeriod)
-   {
-      checkWrite();
-      this.clientFailureCheckPeriod = clientFailureCheckPeriod;
-   }
+               sessionChannel.setHandler(handler);
 
-   public synchronized long getConnectionTTL()
-   {
-      return connectionTTL;
-   }
+               return new DelegatingSession(session);
+            }
+            catch (Throwable t)
+            {
+               if (lock != null)
+               {
+                  lock.unlock();
 
-   public synchronized void setConnectionTTL(final long connectionTTL)
-   {
-      checkWrite();
-      this.connectionTTL = connectionTTL;
-   }
+                  lock = null;
+               }
 
-   public synchronized long getCallTimeout()
-   {
-      return callTimeout;
-   }
+               if (t instanceof HornetQException)
+               {
+                  throw (HornetQException)t;
+               }
+               else
+               {
+                  HornetQException me = new HornetQException(HornetQException.INTERNAL_ERROR,
+                                                             "Failed to create session",
+                                                             t);
 
-   public synchronized void setCallTimeout(final long callTimeout)
-   {
-      checkWrite();
-      this.callTimeout = callTimeout;
-   }
+                  throw me;
+               }
+            }
+            finally
+            {
+               if (lock != null)
+               {
+                  lock.unlock();
+               }
 
-   public synchronized int getMinLargeMessageSize()
-   {
-      return minLargeMessageSize;
-   }
+               // Execution has finished so notify any failover thread that may be waiting for us to be done
+               synchronized (exitLock)
+               {
+                  inCreateSession = false;
 
-   public synchronized void setMinLargeMessageSize(final int minLargeMessageSize)
-   {
-      checkWrite();
-      this.minLargeMessageSize = minLargeMessageSize;
-   }
+                  exitLock.notify();
+               }
+            }
+         }
+         while (retry);
+      }
 
-   public synchronized int getConsumerWindowSize()
-   {
-      return consumerWindowSize;
+      // Should never get here
+      throw new IllegalStateException("Oh my God it's full of stars!");
    }
 
-   public synchronized void setConsumerWindowSize(final int consumerWindowSize)
+   private void callFailureListeners(final HornetQException me, final boolean afterReconnect)
    {
-      checkWrite();
-      this.consumerWindowSize = consumerWindowSize;
-   }
+      final List<SessionFailureListener> listenersClone = new ArrayList<SessionFailureListener>(listeners);
 
-   public synchronized int getConsumerMaxRate()
-   {
-      return consumerMaxRate;
+      for (final SessionFailureListener listener : listenersClone)
+      {
+         try
+         {
+            if (afterReconnect)
+            {
+               listener.connectionFailed(me);
+            }
+            else
+            {
+               listener.beforeReconnect(me);
+            }
+         }
+         catch (final Throwable t)
+         {
+            // Failure of one listener to execute shouldn't prevent others
+            // from
+            // executing
+            log.error("Failed to execute failure listener", t);
+         }
+      }
    }
 
-   public synchronized void setConsumerMaxRate(final int consumerMaxRate)
+   /*
+    * Re-attach sessions all pre-existing sessions to the new remoting connection
+    */
+   private void reconnectSessions(final CoreRemotingConnection oldConnection, final int reconnectAttempts)
    {
-      checkWrite();
-      this.consumerMaxRate = consumerMaxRate;
-   }
+      getConnectionWithRetry(reconnectAttempts);
 
-   public synchronized int getConfirmationWindowSize()
-   {
-      return confirmationWindowSize;
-   }
+      if (connection == null)
+      {
+         log.warn("Failed to connect to server.");
 
-   public synchronized void setConfirmationWindowSize(final int confirmationWindowSize)
-   {
-      checkWrite();
-      this.confirmationWindowSize = confirmationWindowSize;
-   }
+         return;
+      }
 
-   public synchronized int getProducerWindowSize()
-   {
-      return producerWindowSize;
-   }
+      List<FailureListener> oldListeners = oldConnection.getFailureListeners();
 
-   public synchronized void setProducerWindowSize(final int producerWindowSize)
-   {
-      checkWrite();
-      this.producerWindowSize = producerWindowSize;
-   }
+      List<FailureListener> newListeners = new ArrayList<FailureListener>(connection.getFailureListeners());
 
-   public synchronized int getProducerMaxRate()
-   {
-      return producerMaxRate;
-   }
+      for (FailureListener listener : oldListeners)
+      {
+         // Add all apart from the first one which is the old DelegatingFailureListener
 
-   public synchronized void setProducerMaxRate(final int producerMaxRate)
-   {
-      checkWrite();
-      this.producerMaxRate = producerMaxRate;
-   }
+         if (listener instanceof DelegatingFailureListener == false)
+         {
+            newListeners.add(listener);
+         }
+      }
 
-   public synchronized boolean isBlockOnAcknowledge()
-   {
-      return blockOnAcknowledge;
-   }
+      connection.setFailureListeners(newListeners);
 
-   public synchronized void setBlockOnAcknowledge(final boolean blockOnAcknowledge)
-   {
-      checkWrite();
-      this.blockOnAcknowledge = blockOnAcknowledge;
+      for (ClientSessionInternal session : sessions)
+      {
+         session.handleFailover(connection);
+      }
    }
 
-   public synchronized boolean isBlockOnDurableSend()
+   private void getConnectionWithRetry(final int reconnectAttempts)
    {
-      return blockOnDurableSend;
-   }
+      long interval = retryInterval;
 
-   public synchronized void setBlockOnDurableSend(final boolean blockOnDurableSend)
-   {
-      checkWrite();
-      this.blockOnDurableSend = blockOnDurableSend;
-   }
+      int count = 0;
 
-   public synchronized boolean isBlockOnNonDurableSend()
-   {
-      return blockOnNonDurableSend;
-   }
+      while (true)
+      {
+         if (exitLoop)
+         {
+            return;
+         }
 
-   public synchronized void setBlockOnNonDurableSend(final boolean blockOnNonDurableSend)
-   {
-      checkWrite();
-      this.blockOnNonDurableSend = blockOnNonDurableSend;
-   }
+         getConnection();
 
-   public synchronized boolean isAutoGroup()
-   {
-      return autoGroup;
-   }
+         if (connection == null)
+         {
+            // Failed to get connection
 
-   public synchronized void setAutoGroup(final boolean autoGroup)
-   {
-      checkWrite();
-      this.autoGroup = autoGroup;
-   }
+            if (reconnectAttempts != 0)
+            {
+               count++;
 
-   public synchronized boolean isPreAcknowledge()
-   {
-      return preAcknowledge;
-   }
+               if (reconnectAttempts != -1 && count == reconnectAttempts)
+               {
+                  log.warn("Tried " + reconnectAttempts + " times to connect. Now giving up.");
 
-   public synchronized void setPreAcknowledge(final boolean preAcknowledge)
-   {
-      checkWrite();
-      this.preAcknowledge = preAcknowledge;
-   }
+                  return;
+               }
 
-   public synchronized int getAckBatchSize()
-   {
-      return ackBatchSize;
-   }
+               try
+               {
+                  Thread.sleep(interval);
+               }
+               catch (InterruptedException ignore)
+               {
+               }
 
-   public synchronized void setAckBatchSize(final int ackBatchSize)
-   {
-      checkWrite();
-      this.ackBatchSize = ackBatchSize;
-   }
+               // Exponential back-off
+               long newInterval = (long)(interval * retryIntervalMultiplier);
 
-   public synchronized long getDiscoveryInitialWaitTimeout()
-   {
-      return discoveryInitialWaitTimeout;
-   }
+               if (newInterval > maxRetryInterval)
+               {
+                  newInterval = maxRetryInterval;
+               }
 
-   public synchronized void setDiscoveryInitialWaitTimeout(final long initialWaitTimeout)
-   {
-      checkWrite();
-      discoveryInitialWaitTimeout = initialWaitTimeout;
+               interval = newInterval;
+            }
+            else
+            {
+               return;
+            }
+         }
+         else
+         {
+            return;
+         }
+      }
    }
 
-   public synchronized boolean isUseGlobalPools()
+   private void cancelScheduledTasks()
    {
-      return useGlobalPools;
-   }
+      if (pingerFuture != null)
+      {
+         pingRunnable.cancel();
 
-   public synchronized void setUseGlobalPools(final boolean useGlobalPools)
-   {
-      checkWrite();
-      this.useGlobalPools = useGlobalPools;
-   }
+         pingerFuture.cancel(false);
 
-   public synchronized int getScheduledThreadPoolMaxSize()
-   {
-      return scheduledThreadPoolMaxSize;
-   }
+         pingRunnable = null;
 
-   public synchronized void setScheduledThreadPoolMaxSize(final int scheduledThreadPoolMaxSize)
-   {
-      checkWrite();
-      this.scheduledThreadPoolMaxSize = scheduledThreadPoolMaxSize;
+         pingerFuture = null;
+      }
    }
 
-   public synchronized int getThreadPoolMaxSize()
+   private void checkCloseConnection()
    {
-      return threadPoolMaxSize;
-   }
+      if (connection != null && sessions.size() == 0)
+      {
+         cancelScheduledTasks();
 
-   public synchronized void setThreadPoolMaxSize(final int threadPoolMaxSize)
-   {
-      checkWrite();
-      this.threadPoolMaxSize = threadPoolMaxSize;
-   }
+         try
+         {
+            connection.destroy();
+         }
+         catch (Throwable ignore)
+         {
+         }
 
-   public synchronized long getRetryInterval()
-   {
-      return retryInterval;
-   }
+         connection = null;
 
-   public synchronized void setRetryInterval(final long retryInterval)
-   {
-      checkWrite();
-      this.retryInterval = retryInterval;
-   }
+         try
+         {
+            if (connector != null)
+            {
+               connector.close();
+            }
+         }
+         catch (Throwable ignore)
+         {
+         }
 
-   public synchronized long getMaxRetryInterval()
-   {
-      return maxRetryInterval;
+         connector = null;
+      }
    }
 
-   public synchronized void setMaxRetryInterval(final long retryInterval)
+   public CoreRemotingConnection getConnection()
    {
-      checkWrite();
-      maxRetryInterval = retryInterval;
-   }
+      if (connection == null)
+      {
+         Connection tc = null;
 
-   public synchronized double getRetryIntervalMultiplier()
-   {
-      return retryIntervalMultiplier;
-   }
+         try
+         {
+            DelegatingBufferHandler handler = new DelegatingBufferHandler();
 
-   public synchronized void setRetryIntervalMultiplier(final double retryIntervalMultiplier)
-   {
-      checkWrite();
-      this.retryIntervalMultiplier = retryIntervalMultiplier;
-   }
+            connector = connectorFactory.createConnector(transportParams,
+                                                         handler,
+                                                         this,
+                                                         closeExecutor,
+                                                         threadPool,
+                                                         scheduledThreadPool);
 
-   public synchronized int getReconnectAttempts()
-   {
-      return reconnectAttempts;
-   }
+            if (connector != null)
+            {
+               connector.start();
 
-   public synchronized void setReconnectAttempts(final int reconnectAttempts)
-   {
-      checkWrite();
-      this.reconnectAttempts = reconnectAttempts;
-   }
+               tc = connector.createConnection();
 
-   public synchronized boolean isFailoverOnInitialConnection()
-   {
-      return this.failoverOnInitialConnection;
-   }
+               if (tc == null)
+               {
+                  try
+                  {
+                     connector.close();
+                  }
+                  catch (Throwable t)
+                  {
+                  }
 
-   public synchronized void setFailoverOnInitialConnection(final boolean failover)
-   {
-      checkWrite();
-      this.failoverOnInitialConnection = failover;
-   }
+                  connector = null;
+               }
+            }
+         }
+         catch (Exception e)
+         {
+            // Sanity catch for badly behaved remoting plugins
 
-   public synchronized boolean isFailoverOnServerShutdown()
-   {
-      return failoverOnServerShutdown;
-   }
+            log.warn("connector.create or connectorFactory.createConnector should never throw an exception, implementation is badly behaved, but we'll deal with it anyway.",
+                     e);
 
-   public synchronized void setFailoverOnServerShutdown(final boolean failoverOnServerShutdown)
-   {
-      checkWrite();
-      this.failoverOnServerShutdown = failoverOnServerShutdown;
-   }
+            if (tc != null)
+            {
+               try
+               {
+                  tc.close();
+               }
+               catch (Throwable t)
+               {
+               }
+            }
 
-   public synchronized String getConnectionLoadBalancingPolicyClassName()
-   {
-      return connectionLoadBalancingPolicyClassName;
-   }
+            if (connector != null)
+            {
+               try
+               {
+                  connector.close();
+               }
+               catch (Throwable t)
+               {
+               }
+            }
 
-   public synchronized void setConnectionLoadBalancingPolicyClassName(final String loadBalancingPolicyClassName)
-   {
-      checkWrite();
-      connectionLoadBalancingPolicyClassName = loadBalancingPolicyClassName;
-   }
+            tc = null;
 
-   public synchronized String getLocalBindAddress()
-   {
-      return localBindAddress;
-   }
+            connector = null;
+         }
 
-   public synchronized void setLocalBindAddress(final String localBindAddress)
-   {
-      checkWrite();
-      this.localBindAddress = localBindAddress;
-   }
+         if (tc == null)
+         {
+            return connection;
+         }
 
-   public synchronized String getDiscoveryAddress()
-   {
-      return discoveryAddress;
-   }
+         connection = new RemotingConnectionImpl(tc, callTimeout, interceptors);
 
-   public synchronized void setDiscoveryAddress(final String discoveryAddress)
-   {
-      checkWrite();
-      this.discoveryAddress = discoveryAddress;
-   }
+         connection.addFailureListener(new DelegatingFailureListener(connection.getID()));
 
-   public synchronized int getDiscoveryPort()
-   {
-      return discoveryPort;
-   }
+         connection.getChannel(0, -1).setHandler(new Channel0Handler(connection));
 
-   public synchronized void setDiscoveryPort(final int discoveryPort)
-   {
-      checkWrite();
-      this.discoveryPort = discoveryPort;
-   }
+         if (clientFailureCheckPeriod != -1)
+         {
+            if (pingerFuture == null)
+            {
+               pingRunnable = new PingRunnable();
 
-   public synchronized long getDiscoveryRefreshTimeout()
-   {
-      return discoveryRefreshTimeout;
-   }
+               pingerFuture = scheduledThreadPool.scheduleWithFixedDelay(new ActualScheduledPinger(pingRunnable),
+                                                                         0,
+                                                                         clientFailureCheckPeriod,
+                                                                         TimeUnit.MILLISECONDS);
+            }
+            // send a ping every time we create a new remoting connection
+            // to set up its TTL on the server side
+            else
+            {
+               pingRunnable.run();
+            }
+         }
+      }
 
-   public void addInterceptor(final Interceptor interceptor)
-   {
-      interceptors.add(interceptor);
+      return connection;
    }
 
-   public boolean removeInterceptor(final Interceptor interceptor)
+   private ConnectorFactory instantiateConnectorFactory(final String connectorFactoryClassName)
    {
-      return interceptors.remove(interceptor);
+      ClassLoader loader = Thread.currentThread().getContextClassLoader();
+      try
+      {
+         Class<?> clazz = loader.loadClass(connectorFactoryClassName);
+         return (ConnectorFactory)clazz.newInstance();
+      }
+      catch (Exception e)
+      {
+         throw new IllegalArgumentException("Error instantiating connector factory \"" + connectorFactoryClassName +
+                                            "\"", e);
+      }
    }
 
-   public synchronized void setDiscoveryRefreshTimeout(final long discoveryRefreshTimeout)
+   private void lockChannel1()
    {
-      checkWrite();
-      this.discoveryRefreshTimeout = discoveryRefreshTimeout;
-   }
+      Channel channel1 = connection.getChannel(1, -1);
 
-   public synchronized int getInitialMessagePacketSize()
-   {
-      return initialMessagePacketSize;
+      channel1.getLock().lock();
    }
 
-   public synchronized void setInitialMessagePacketSize(final int size)
+   private void unlockChannel1()
    {
-      checkWrite();
-      initialMessagePacketSize = size;
-   }
+      Channel channel1 = connection.getChannel(1, -1);
 
-   public ClientSession createSession(final String username,
-                                      final String password,
-                                      final boolean xa,
-                                      final boolean autoCommitSends,
-                                      final boolean autoCommitAcks,
-                                      final boolean preAcknowledge,
-                                      final int ackBatchSize) throws HornetQException
-   {
-      return createSessionInternal(username,
-                                   password,
-                                   xa,
-                                   autoCommitSends,
-                                   autoCommitAcks,
-                                   preAcknowledge,
-                                   ackBatchSize);
+      channel1.getLock().unlock();
    }
 
-   public ClientSession createSession(final boolean autoCommitSends,
-                                      final boolean autoCommitAcks,
-                                      final int ackBatchSize) throws HornetQException
+   private void forceReturnChannel1()
    {
-      return createSessionInternal(null, null, false, autoCommitSends, autoCommitAcks, preAcknowledge, ackBatchSize);
-   }
+      Channel channel1 = connection.getChannel(1, -1);
 
-   public ClientSession createXASession() throws HornetQException
-   {
-      return createSessionInternal(null, null, true, false, false, preAcknowledge, ackBatchSize);
+      channel1.returnBlocking();
    }
 
-   public ClientSession createTransactedSession() throws HornetQException
+   private void checkTransportKeys(final ConnectorFactory factory, final Map<String, Object> params)
    {
-      return createSessionInternal(null, null, false, false, false, preAcknowledge, ackBatchSize);
-   }
-
-   public ClientSession createSession() throws HornetQException
-   {
-      return createSessionInternal(null, null, false, true, true, preAcknowledge, ackBatchSize);
-   }
-
-   public ClientSession createSession(final boolean autoCommitSends, final boolean autoCommitAcks) throws HornetQException
-   {
-      return createSessionInternal(null, null, false, autoCommitSends, autoCommitAcks, preAcknowledge, ackBatchSize);
-   }
-
-   public ClientSession createSession(final boolean xa, final boolean autoCommitSends, final boolean autoCommitAcks) throws HornetQException
-   {
-      return createSessionInternal(null, null, xa, autoCommitSends, autoCommitAcks, preAcknowledge, ackBatchSize);
-   }
-
-   public ClientSession createSession(final boolean xa,
-                                      final boolean autoCommitSends,
-                                      final boolean autoCommitAcks,
-                                      final boolean preAcknowledge) throws HornetQException
-   {
-      return createSessionInternal(null, null, xa, autoCommitSends, autoCommitAcks, preAcknowledge, ackBatchSize);
-   }
-
-   public int numSessions()
-   {
-      int num = 0;
-
-      for (FailoverManager failoverManager : failoverManagerMap.values())
+      if (params != null)
       {
-         num += failoverManager.numSessions();
-      }
+         Set<String> invalid = ConfigurationHelper.checkKeys(factory.getAllowableProperties(), params.keySet());
 
-      return num;
-   }
+         if (!invalid.isEmpty())
+         {
+            String msg = ConfigurationHelper.stringSetToCommaListString("The following keys are invalid for configuring a connector: ",
+                                                                        invalid);
 
-   public int numConnections()
-   {
-      int num = 0;
+            throw new IllegalStateException(msg);
 
-      for (FailoverManager failoverManager : failoverManagerMap.values())
-      {
-         num += failoverManager.numConnections();
+         }
       }
-
-      return num;
    }
 
-   public void close()
+   private class Channel0Handler implements ChannelHandler
    {
-      if (closed)
-      {
-         return;
-      }
+      private final CoreRemotingConnection conn;
 
-      if (discoveryGroup != null)
+      private Channel0Handler(final CoreRemotingConnection conn)
       {
-         try
-         {
-            discoveryGroup.stop();
-         }
-         catch (Exception e)
-         {
-            ClientSessionFactoryImpl.log.error("Failed to stop discovery group", e);
-         }
+         this.conn = conn;
       }
 
-      for (FailoverManager failoverManager : failoverManagerMap.values())
+      public void handlePacket(final Packet packet)
       {
-         failoverManager.causeExit();
-      }
+         final byte type = packet.getType();
 
-      failoverManagerMap.clear();
-
-      if (!useGlobalPools)
-      {
-         if (threadPool != null)
+         if (type == PacketImpl.DISCONNECT)
          {
-            threadPool.shutdown();
-
-            try
+            closeExecutor.execute(new Runnable()
             {
-               if (!threadPool.awaitTermination(10000, TimeUnit.MILLISECONDS))
+               // Must be executed on new thread since cannot block the netty thread for a long time and fail can
+               // cause reconnect loop
+               public void run()
                {
-                  ClientSessionFactoryImpl.log.warn("Timed out waiting for pool to terminate");
+                  conn.fail(new HornetQException(HornetQException.DISCONNECTED,
+                                                 "The connection was disconnected because of server shutdown"));
                }
-            }
-            catch (InterruptedException ignore)
-            {
-            }
+            });
          }
-
-         if (scheduledThreadPool != null)
+         else if (type == PacketImpl.CLUSTER_TOPOLOGY)
          {
-            scheduledThreadPool.shutdown();
-
-            try
-            {
-               if (!scheduledThreadPool.awaitTermination(10000, TimeUnit.MILLISECONDS))
-               {
-                  ClientSessionFactoryImpl.log.warn("Timed out waiting for scheduled pool to terminate");
-               }
-            }
-            catch (InterruptedException ignore)
-            {
-            }
+            ClusterTopologyMessage topMessage = (ClusterTopologyMessage)packet;
+            
+            serverLocator.onTopologyChanged(topMessage.getTopology());
          }
       }
-
-      closed = true;
    }
 
-   public ClientSessionFactory copy()
+   private class DelegatingBufferHandler implements BufferHandler
    {
-      return new ClientSessionFactoryImpl(this);
-   }
+      public void bufferReceived(final Object connectionID, final HornetQBuffer buffer)
+      {
+         CoreRemotingConnection theConn = connection;
 
-   public void setGroupID(final String groupID)
-   {
-      this.groupID = groupID;
+         if (theConn != null && connectionID == theConn.getID())
+         {
+            theConn.bufferReceived(connectionID, buffer);
+         }
+      }
    }
 
-   public String getGroupID()
+   private class DelegatingFailureListener implements FailureListener
    {
-      return groupID;
-   }
+      private final Object connectionID;
 
-   // DiscoveryListener implementation --------------------------------------------------------
-
-   public synchronized void connectorsChanged()
-   {
-      receivedBroadcast = true;
-
-      Map<String, DiscoveryEntry> newConnectors = discoveryGroup.getDiscoveryEntryMap();
-
-      Set<Pair<TransportConfiguration, TransportConfiguration>> connectorSet = new HashSet<Pair<TransportConfiguration, TransportConfiguration>>();
-
-      for (DiscoveryEntry entry : newConnectors.values())
+      DelegatingFailureListener(final Object connectionID)
       {
-         connectorSet.add(entry.getConnectorPair());
+         this.connectionID = connectionID;
       }
 
-      Iterator<Map.Entry<Pair<TransportConfiguration, TransportConfiguration>, FailoverManager>> iter = failoverManagerMap.entrySet()
-                                                                                                                          .iterator();
-      while (iter.hasNext())
+      public void connectionFailed(final HornetQException me)
       {
-         Map.Entry<Pair<TransportConfiguration, TransportConfiguration>, FailoverManager> entry = iter.next();
+         handleConnectionFailure(connectionID, me);
+      }
+   }
 
-         if (!connectorSet.contains(entry.getKey()))
-         {
-            // failoverManager no longer there - we should remove it
+   private static final class ActualScheduledPinger implements Runnable
+   {
+      private final WeakReference<PingRunnable> pingRunnable;
 
-            iter.remove();
-         }
+      ActualScheduledPinger(final PingRunnable runnable)
+      {
+         pingRunnable = new WeakReference<PingRunnable>(runnable);
       }
 
-      for (Pair<TransportConfiguration, TransportConfiguration> connectorPair : connectorSet)
+      public void run()
       {
-         if (!failoverManagerMap.containsKey(connectorPair))
+         PingRunnable runnable = pingRunnable.get();
+
+         if (runnable != null)
          {
-            // Create a new failoverManager
-
-            FailoverManager failoverManager = new FailoverManagerImpl(this,
-                                                                      connectorPair.a,
-                                                                      connectorPair.b,
-                                                                      failoverOnServerShutdown,
-                                                                      callTimeout,
-                                                                      clientFailureCheckPeriod,
-                                                                      connectionTTL,
-                                                                      retryInterval,
-                                                                      retryIntervalMultiplier,
-                                                                      maxRetryInterval,
-                                                                      reconnectAttempts,
-                                                                      failoverOnInitialConnection,
-                                                                      threadPool,
-                                                                      scheduledThreadPool,
-                                                                      interceptors);
-
-            failoverManagerMap.put(connectorPair, failoverManager);
+            runnable.run();
          }
       }
 
-      updatefailoverManagerArray();
    }
 
-   public FailoverManager[] getFailoverManagers()
+   private final class PingRunnable implements Runnable
    {
-      return failoverManagerArray;
-   }
+      private boolean cancelled;
 
-   // Protected ------------------------------------------------------------------------------
+      private boolean first;
 
-   @Override
-   protected void finalize() throws Throwable
-   {
-      close();
+      private long lastCheck = System.currentTimeMillis();
 
-      super.finalize();
-   }
-
-   // Private --------------------------------------------------------------------------------
-
-   private void checkWrite()
-   {
-      if (readOnly)
+      public synchronized void run()
       {
-         throw new IllegalStateException("Cannot set attribute on SessionFactory after it has been used");
-      }
-   }
-
-   private ClientSession createSessionInternal(final String username,
-                                               final String password,
-                                               final boolean xa,
-                                               final boolean autoCommitSends,
-                                               final boolean autoCommitAcks,
-                                               final boolean preAcknowledge,
-                                               final int ackBatchSize) throws HornetQException
-   {
-      if (closed)
-      {
-         throw new IllegalStateException("Cannot create session, factory is closed (maybe it has been garbage collected)");
-      }
-
-      try
-      {
-         initialise();
-      }
-      catch (Exception e)
-      {
-         throw new HornetQException(HornetQException.INTERNAL_ERROR, "Failed to initialise session factory", e);
-      }
-
-      if (discoveryGroup != null && !receivedBroadcast)
-      {
-         boolean ok = discoveryGroup.waitForBroadcast(discoveryInitialWaitTimeout);
-
-         if (!ok)
+         if (cancelled || stopPingingAfterOne && !first)
          {
-            throw new HornetQException(HornetQException.CONNECTION_TIMEDOUT,
-                                       "Timed out waiting to receive initial broadcast from discovery group");
+            return;
          }
-      }
 
-      synchronized (this)
-      {
-         int pos = loadBalancingPolicy.select(failoverManagerArray.length);
+         first = false;
 
-         FailoverManager failoverManager = failoverManagerArray[pos];
+         long now = System.currentTimeMillis();
 
-         ClientSession session = failoverManager.createSession(username,
-                                                               password,
-                                                               xa,
-                                                               autoCommitSends,
-                                                               autoCommitAcks,
-                                                               preAcknowledge,
-                                                               ackBatchSize,
-                                                               cacheLargeMessagesClient,
-                                                               minLargeMessageSize,
-                                                               blockOnAcknowledge,
-                                                               autoGroup,
-                                                               confirmationWindowSize,
-                                                               producerWindowSize,
-                                                               consumerWindowSize,
-                                                               producerMaxRate,
-                                                               consumerMaxRate,
-                                                               blockOnNonDurableSend,
-                                                               blockOnDurableSend,
-                                                               initialMessagePacketSize,
-                                                               groupID);
+         if (clientFailureCheckPeriod != -1 && now >= lastCheck + clientFailureCheckPeriod)
+         {
+            if (!connection.checkDataReceived())
+            {
+               final HornetQException me = new HornetQException(HornetQException.CONNECTION_TIMEDOUT,
+                                                                "Did not receive data from server for " + connection.getTransportConnection());
 
-         return session;
-      }
-   }
+               cancelled = true;
 
-   private void instantiateLoadBalancingPolicy()
-   {
-      if (connectionLoadBalancingPolicyClassName == null)
-      {
-         throw new IllegalStateException("Please specify a load balancing policy class name on the session factory");
-      }
+               threadPool.execute(new Runnable()
+               {
+                  // Must be executed on different thread
+                  public void run()
+                  {
+                     connection.fail(me);
+                  }
+               });
 
-      AccessController.doPrivileged(new PrivilegedAction<Object>()
-      {
-         public Object run()
-         {
-            ClassLoader loader = Thread.currentThread().getContextClassLoader();
-            try
-            {
-               Class<?> clazz = loader.loadClass(connectionLoadBalancingPolicyClassName);
-               loadBalancingPolicy = (ConnectionLoadBalancingPolicy)clazz.newInstance();
-               return null;
+               return;
             }
-            catch (Exception e)
+            else
             {
-               throw new IllegalArgumentException("Unable to instantiate load balancing policy \"" + connectionLoadBalancingPolicyClassName +
-                                                           "\"",
-                                                  e);
+               lastCheck = now;
             }
          }
-      });
-   }
 
-   private static ClassLoader getThisClassLoader()
-   {
-      return AccessController.doPrivileged(new PrivilegedAction<ClassLoader>()
-                                    {
-                                       public ClassLoader run()
-                                       {
-                                          return ClientSessionFactoryImpl.class.getClassLoader();
-                                       }
-                                    });
-      
-   }
+         // Send a ping
 
-   private synchronized void updatefailoverManagerArray()
-   {
-      failoverManagerArray = new FailoverManager[failoverManagerMap.size()];
+         Ping ping = new Ping(connectionTTL);
 
-      failoverManagerMap.values().toArray(failoverManagerArray);
+         Channel channel0 = connection.getChannel(0, -1);
+
+         channel0.send(ping);
+
+         connection.flush();
+      }
+
+      public synchronized void cancel()
+      {
+         cancelled = true;
+      }
    }
-
 }

Copied: branches/2_2_0_HA_Improvements/src/main/org/hornetq/core/client/impl/ClientSessionFactoryImpl_Old.java (from rev 9287, branches/2_2_0_HA_Improvements/src/main/org/hornetq/core/client/impl/ClientSessionFactoryImpl.java)
===================================================================
--- branches/2_2_0_HA_Improvements/src/main/org/hornetq/core/client/impl/ClientSessionFactoryImpl_Old.java	                        (rev 0)
+++ branches/2_2_0_HA_Improvements/src/main/org/hornetq/core/client/impl/ClientSessionFactoryImpl_Old.java	2010-06-11 15:33:36 UTC (rev 9307)
@@ -0,0 +1,1195 @@
+/*
+ * Copyright 2009 Red Hat, Inc.
+ * Red Hat licenses this file to you under the Apache License, version
+ * 2.0 (the "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ * implied.  See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+package org.hornetq.core.client.impl;
+
+import java.io.Serializable;
+import java.net.InetAddress;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.ThreadFactory;
+import java.util.concurrent.TimeUnit;
+
+import org.hornetq.api.core.HornetQException;
+import org.hornetq.api.core.Interceptor;
+import org.hornetq.api.core.Pair;
+import org.hornetq.api.core.TransportConfiguration;
+import org.hornetq.api.core.client.ClientSession;
+import org.hornetq.api.core.client.ClientSessionFactory;
+import org.hornetq.api.core.client.HornetQClient;
+import org.hornetq.api.core.client.loadbalance.ConnectionLoadBalancingPolicy;
+import org.hornetq.core.cluster.DiscoveryEntry;
+import org.hornetq.core.cluster.DiscoveryGroup;
+import org.hornetq.core.cluster.DiscoveryListener;
+import org.hornetq.core.cluster.impl.DiscoveryGroupImpl;
+import org.hornetq.core.logging.Logger;
+import org.hornetq.utils.HornetQThreadFactory;
+import org.hornetq.utils.UUIDGenerator;
+
+/**
+ * @author <a href="mailto:tim.fox at jboss.com">Tim Fox</a>
+ * @author <a href="mailto:clebert.suconic at jboss.org">Clebert Suconic</a>
+ * @author <a href="mailto:jmesnil at redhat.com">Jeff Mesnil</a>
+ * @author <a href="mailto:ataylor at redhat.com">Andy Taylor</a>
+ * @version <tt>$Revision: 3602 $</tt>
+ * 
+ */
+public class ClientSessionFactoryImpl_Old implements ClientSessionFactoryInternal, DiscoveryListener, Serializable
+{
+   // Constants
+   // ------------------------------------------------------------------------------------
+
+   private static final long serialVersionUID = 2512460695662741413L;
+
+   private static final Logger log = Logger.getLogger(ClientSessionFactoryImpl.class);
+
+   // Attributes
+   // -----------------------------------------------------------------------------------
+
+   private final Map<Pair<TransportConfiguration, TransportConfiguration>, FailoverManager> failoverManagerMap = new LinkedHashMap<Pair<TransportConfiguration, TransportConfiguration>, FailoverManager>();
+
+   private volatile boolean receivedBroadcast = false;
+
+   private ExecutorService threadPool;
+
+   private ScheduledExecutorService scheduledThreadPool;
+
+   private DiscoveryGroup discoveryGroup;
+
+   private ConnectionLoadBalancingPolicy loadBalancingPolicy;
+
+   private FailoverManager[] failoverManagerArray;
+
+   private boolean readOnly;
+
+   // Settable attributes:
+
+   private boolean cacheLargeMessagesClient = HornetQClient.DEFAULT_CACHE_LARGE_MESSAGE_CLIENT;
+
+   private List<Pair<TransportConfiguration, TransportConfiguration>> staticConnectors;
+
+   private String localBindAddress;
+
+   private String discoveryAddress;
+
+   private int discoveryPort;
+
+   private long discoveryRefreshTimeout;
+
+   private long discoveryInitialWaitTimeout;
+
+   private long clientFailureCheckPeriod;
+
+   private long connectionTTL;
+
+   private long callTimeout;
+
+   private int minLargeMessageSize;
+
+   private int consumerWindowSize;
+
+   private int consumerMaxRate;
+
+   private int confirmationWindowSize;
+
+   private int producerWindowSize;
+
+   private int producerMaxRate;
+
+   private boolean blockOnAcknowledge;
+
+   private boolean blockOnDurableSend;
+
+   private boolean blockOnNonDurableSend;
+
+   private boolean autoGroup;
+
+   private boolean preAcknowledge;
+
+   private String connectionLoadBalancingPolicyClassName;
+
+   private int ackBatchSize;
+
+   private boolean useGlobalPools;
+
+   private int scheduledThreadPoolMaxSize;
+
+   private int threadPoolMaxSize;
+
+   private long retryInterval;
+
+   private double retryIntervalMultiplier;
+
+   private long maxRetryInterval;
+
+   private int reconnectAttempts;
+
+   private boolean failoverOnInitialConnection;
+
+   private int initialMessagePacketSize;
+
+   private volatile boolean closed;
+
+   private boolean failoverOnServerShutdown;
+
+   private final List<Interceptor> interceptors = new CopyOnWriteArrayList<Interceptor>();
+
+   private static ExecutorService globalThreadPool;
+
+   private static ScheduledExecutorService globalScheduledThreadPool;
+
+   private String groupID;
+
+   private static synchronized ExecutorService getGlobalThreadPool()
+   {
+      if (ClientSessionFactoryImpl.globalThreadPool == null)
+      {
+         ThreadFactory factory = new HornetQThreadFactory("HornetQ-client-global-threads", true, getThisClassLoader());
+
+         ClientSessionFactoryImpl.globalThreadPool = Executors.newCachedThreadPool(factory);
+      }
+
+      return ClientSessionFactoryImpl.globalThreadPool;
+   }
+
+   private static synchronized ScheduledExecutorService getGlobalScheduledThreadPool()
+   {
+      if (ClientSessionFactoryImpl.globalScheduledThreadPool == null)
+      {
+         ThreadFactory factory = new HornetQThreadFactory("HornetQ-client-global-scheduled-threads", true, getThisClassLoader());
+
+         ClientSessionFactoryImpl.globalScheduledThreadPool = Executors.newScheduledThreadPool(HornetQClient.DEFAULT_SCHEDULED_THREAD_POOL_MAX_SIZE,
+
+                                                                                               factory);
+      }
+
+      return ClientSessionFactoryImpl.globalScheduledThreadPool;
+   }
+
+   private void setThreadPools()
+   {
+      if (useGlobalPools)
+      {
+         threadPool = ClientSessionFactoryImpl.getGlobalThreadPool();
+
+         scheduledThreadPool = ClientSessionFactoryImpl.getGlobalScheduledThreadPool();
+      }
+      else
+      {
+         ThreadFactory factory = new HornetQThreadFactory("HornetQ-client-factory-threads-" + System.identityHashCode(this),
+                                                          true, getThisClassLoader());
+
+         if (threadPoolMaxSize == -1)
+         {
+            threadPool = Executors.newCachedThreadPool(factory);
+         }
+         else
+         {
+            threadPool = Executors.newFixedThreadPool(threadPoolMaxSize, factory);
+         }
+
+         factory = new HornetQThreadFactory("HornetQ-client-factory-pinger-threads-" + System.identityHashCode(this),
+                                            true, getThisClassLoader());
+
+         scheduledThreadPool = Executors.newScheduledThreadPool(scheduledThreadPoolMaxSize, factory);
+      }
+   }
+
+   private synchronized void initialise() throws Exception
+   {
+      if (!readOnly)
+      {
+         setThreadPools();
+
+         instantiateLoadBalancingPolicy();
+
+         if (discoveryAddress != null)
+         {
+            InetAddress groupAddress = InetAddress.getByName(discoveryAddress);
+
+            InetAddress lbAddress;
+
+            if (localBindAddress != null)
+            {
+               lbAddress = InetAddress.getByName(localBindAddress);
+            }
+            else
+            {
+               lbAddress = null;
+            }
+
+            discoveryGroup = new DiscoveryGroupImpl(UUIDGenerator.getInstance().generateStringUUID(),
+                                                    discoveryAddress,
+                                                    lbAddress,
+                                                    groupAddress,
+                                                    discoveryPort,
+                                                    discoveryRefreshTimeout);
+
+            discoveryGroup.registerListener(this);
+
+            discoveryGroup.start();
+         }
+         else if (staticConnectors != null)
+         {
+            for (Pair<TransportConfiguration, TransportConfiguration> pair : staticConnectors)
+            {
+               FailoverManager cm = new FailoverManagerImpl(this,
+                                                            pair.a,
+                                                            pair.b,
+                                                            failoverOnServerShutdown,
+                                                            callTimeout,
+                                                            clientFailureCheckPeriod,
+                                                            connectionTTL,
+                                                            retryInterval,
+                                                            retryIntervalMultiplier,
+                                                            maxRetryInterval,
+                                                            reconnectAttempts,
+                                                            failoverOnInitialConnection,
+                                                            threadPool,
+                                                            scheduledThreadPool,
+                                                            interceptors);
+
+               failoverManagerMap.put(pair, cm);
+            }
+
+            updatefailoverManagerArray();
+         }
+         else
+         {
+            throw new IllegalStateException("Before using a session factory you must either set discovery address and port or " + "provide some static transport configuration");
+         }
+         readOnly = true;
+      }
+   }
+
+   // Static
+   // ---------------------------------------------------------------------------------------
+
+   // Constructors
+   // ---------------------------------------------------------------------------------
+
+   public ClientSessionFactoryImpl_Old(final ClientSessionFactory other)
+   {
+      localBindAddress = other.getLocalBindAddress();
+
+      discoveryAddress = other.getDiscoveryAddress();
+
+      discoveryPort = other.getDiscoveryPort();
+
+      staticConnectors = other.getStaticConnectors();
+
+      discoveryRefreshTimeout = other.getDiscoveryRefreshTimeout();
+
+      clientFailureCheckPeriod = other.getClientFailureCheckPeriod();
+
+      connectionTTL = other.getConnectionTTL();
+
+      callTimeout = other.getCallTimeout();
+
+      minLargeMessageSize = other.getMinLargeMessageSize();
+
+      consumerWindowSize = other.getConsumerWindowSize();
+
+      consumerMaxRate = other.getConsumerMaxRate();
+
+      confirmationWindowSize = other.getConfirmationWindowSize();
+
+      producerWindowSize = other.getProducerWindowSize();
+
+      producerMaxRate = other.getProducerMaxRate();
+
+      blockOnAcknowledge = other.isBlockOnAcknowledge();
+
+      blockOnDurableSend = other.isBlockOnDurableSend();
+
+      blockOnNonDurableSend = other.isBlockOnNonDurableSend();
+
+      autoGroup = other.isAutoGroup();
+
+      preAcknowledge = other.isPreAcknowledge();
+
+      ackBatchSize = other.getAckBatchSize();
+
+      connectionLoadBalancingPolicyClassName = other.getConnectionLoadBalancingPolicyClassName();
+
+      discoveryInitialWaitTimeout = other.getDiscoveryInitialWaitTimeout();
+
+      useGlobalPools = other.isUseGlobalPools();
+
+      scheduledThreadPoolMaxSize = other.getScheduledThreadPoolMaxSize();
+
+      threadPoolMaxSize = other.getThreadPoolMaxSize();
+
+      retryInterval = other.getRetryInterval();
+
+      retryIntervalMultiplier = other.getRetryIntervalMultiplier();
+
+      maxRetryInterval = other.getMaxRetryInterval();
+
+      reconnectAttempts = other.getReconnectAttempts();
+
+      failoverOnInitialConnection = other.isFailoverOnInitialConnection();
+
+      failoverOnServerShutdown = other.isFailoverOnServerShutdown();
+
+      cacheLargeMessagesClient = other.isCacheLargeMessagesClient();
+
+      initialMessagePacketSize = other.getInitialMessagePacketSize();
+
+      groupID = other.getGroupID();
+   }
+
+   public ClientSessionFactoryImpl_Old()
+   {
+      discoveryRefreshTimeout = HornetQClient.DEFAULT_DISCOVERY_REFRESH_TIMEOUT;
+
+      clientFailureCheckPeriod = HornetQClient.DEFAULT_CLIENT_FAILURE_CHECK_PERIOD;
+
+      connectionTTL = HornetQClient.DEFAULT_CONNECTION_TTL;
+
+      callTimeout = HornetQClient.DEFAULT_CALL_TIMEOUT;
+
+      minLargeMessageSize = HornetQClient.DEFAULT_MIN_LARGE_MESSAGE_SIZE;
+
+      consumerWindowSize = HornetQClient.DEFAULT_CONSUMER_WINDOW_SIZE;
+
+      consumerMaxRate = HornetQClient.DEFAULT_CONSUMER_MAX_RATE;
+
+      confirmationWindowSize = HornetQClient.DEFAULT_CONFIRMATION_WINDOW_SIZE;
+
+      producerWindowSize = HornetQClient.DEFAULT_PRODUCER_WINDOW_SIZE;
+
+      producerMaxRate = HornetQClient.DEFAULT_PRODUCER_MAX_RATE;
+
+      blockOnAcknowledge = HornetQClient.DEFAULT_BLOCK_ON_ACKNOWLEDGE;
+
+      blockOnDurableSend = HornetQClient.DEFAULT_BLOCK_ON_DURABLE_SEND;
+
+      blockOnNonDurableSend = HornetQClient.DEFAULT_BLOCK_ON_NON_DURABLE_SEND;
+
+      autoGroup = HornetQClient.DEFAULT_AUTO_GROUP;
+
+      preAcknowledge = HornetQClient.DEFAULT_PRE_ACKNOWLEDGE;
+
+      ackBatchSize = HornetQClient.DEFAULT_ACK_BATCH_SIZE;
+
+      connectionLoadBalancingPolicyClassName = HornetQClient.DEFAULT_CONNECTION_LOAD_BALANCING_POLICY_CLASS_NAME;
+
+      discoveryInitialWaitTimeout = HornetQClient.DEFAULT_DISCOVERY_INITIAL_WAIT_TIMEOUT;
+
+      useGlobalPools = HornetQClient.DEFAULT_USE_GLOBAL_POOLS;
+
+      scheduledThreadPoolMaxSize = HornetQClient.DEFAULT_SCHEDULED_THREAD_POOL_MAX_SIZE;
+
+      threadPoolMaxSize = HornetQClient.DEFAULT_THREAD_POOL_MAX_SIZE;
+
+      retryInterval = HornetQClient.DEFAULT_RETRY_INTERVAL;
+
+      retryIntervalMultiplier = HornetQClient.DEFAULT_RETRY_INTERVAL_MULTIPLIER;
+
+      maxRetryInterval = HornetQClient.DEFAULT_MAX_RETRY_INTERVAL;
+
+      reconnectAttempts = HornetQClient.DEFAULT_RECONNECT_ATTEMPTS;
+
+      failoverOnInitialConnection = HornetQClient.DEFAULT_FAILOVER_ON_INITIAL_CONNECTION;
+
+      failoverOnServerShutdown = HornetQClient.DEFAULT_FAILOVER_ON_SERVER_SHUTDOWN;
+
+      cacheLargeMessagesClient = HornetQClient.DEFAULT_CACHE_LARGE_MESSAGE_CLIENT;
+
+      initialMessagePacketSize = HornetQClient.DEFAULT_INITIAL_MESSAGE_PACKET_SIZE;
+   }
+
+   public ClientSessionFactoryImpl_Old(final String discoveryAddress, final int discoveryPort)
+   {
+      this();
+
+      this.discoveryAddress = discoveryAddress;
+
+      this.discoveryPort = discoveryPort;
+   }
+
+   public ClientSessionFactoryImpl_Old(final String localBindAddress, final String discoveryAddress, final int discoveryPort)
+   {
+      this();
+
+      this.localBindAddress = localBindAddress;
+
+      this.discoveryAddress = discoveryAddress;
+
+      this.discoveryPort = discoveryPort;
+   }
+
+   public ClientSessionFactoryImpl_Old(final List<Pair<TransportConfiguration, TransportConfiguration>> staticConnectors)
+   {
+      this();
+
+      this.staticConnectors = staticConnectors;
+   }
+
+   public ClientSessionFactoryImpl_Old(final TransportConfiguration connectorConfig,
+                                   final TransportConfiguration backupConnectorConfig)
+   {
+      this();
+
+      staticConnectors = new ArrayList<Pair<TransportConfiguration, TransportConfiguration>>();
+
+      staticConnectors.add(new Pair<TransportConfiguration, TransportConfiguration>(connectorConfig,
+                                                                                    backupConnectorConfig));
+   }
+
+   public ClientSessionFactoryImpl_Old(final TransportConfiguration connectorConfig)
+   {
+      this(connectorConfig, null);
+   }
+
+   // ClientSessionFactory implementation------------------------------------------------------------
+
+   public synchronized boolean isCacheLargeMessagesClient()
+   {
+      return cacheLargeMessagesClient;
+   }
+
+   public synchronized void setCacheLargeMessagesClient(final boolean cached)
+   {
+      cacheLargeMessagesClient = cached;
+   }
+
+   public synchronized List<Pair<TransportConfiguration, TransportConfiguration>> getStaticConnectors()
+   {
+      return staticConnectors;
+   }
+
+   public synchronized void setStaticConnectors(final List<Pair<TransportConfiguration, TransportConfiguration>> staticConnectors)
+   {
+      checkWrite();
+
+      this.staticConnectors = staticConnectors;
+   }
+
+   public synchronized long getClientFailureCheckPeriod()
+   {
+      return clientFailureCheckPeriod;
+   }
+
+   public synchronized void setClientFailureCheckPeriod(final long clientFailureCheckPeriod)
+   {
+      checkWrite();
+      this.clientFailureCheckPeriod = clientFailureCheckPeriod;
+   }
+
+   public synchronized long getConnectionTTL()
+   {
+      return connectionTTL;
+   }
+
+   public synchronized void setConnectionTTL(final long connectionTTL)
+   {
+      checkWrite();
+      this.connectionTTL = connectionTTL;
+   }
+
+   public synchronized long getCallTimeout()
+   {
+      return callTimeout;
+   }
+
+   public synchronized void setCallTimeout(final long callTimeout)
+   {
+      checkWrite();
+      this.callTimeout = callTimeout;
+   }
+
+   public synchronized int getMinLargeMessageSize()
+   {
+      return minLargeMessageSize;
+   }
+
+   public synchronized void setMinLargeMessageSize(final int minLargeMessageSize)
+   {
+      checkWrite();
+      this.minLargeMessageSize = minLargeMessageSize;
+   }
+
+   public synchronized int getConsumerWindowSize()
+   {
+      return consumerWindowSize;
+   }
+
+   public synchronized void setConsumerWindowSize(final int consumerWindowSize)
+   {
+      checkWrite();
+      this.consumerWindowSize = consumerWindowSize;
+   }
+
+   public synchronized int getConsumerMaxRate()
+   {
+      return consumerMaxRate;
+   }
+
+   public synchronized void setConsumerMaxRate(final int consumerMaxRate)
+   {
+      checkWrite();
+      this.consumerMaxRate = consumerMaxRate;
+   }
+
+   public synchronized int getConfirmationWindowSize()
+   {
+      return confirmationWindowSize;
+   }
+
+   public synchronized void setConfirmationWindowSize(final int confirmationWindowSize)
+   {
+      checkWrite();
+      this.confirmationWindowSize = confirmationWindowSize;
+   }
+
+   public synchronized int getProducerWindowSize()
+   {
+      return producerWindowSize;
+   }
+
+   public synchronized void setProducerWindowSize(final int producerWindowSize)
+   {
+      checkWrite();
+      this.producerWindowSize = producerWindowSize;
+   }
+
+   public synchronized int getProducerMaxRate()
+   {
+      return producerMaxRate;
+   }
+
+   public synchronized void setProducerMaxRate(final int producerMaxRate)
+   {
+      checkWrite();
+      this.producerMaxRate = producerMaxRate;
+   }
+
+   public synchronized boolean isBlockOnAcknowledge()
+   {
+      return blockOnAcknowledge;
+   }
+
+   public synchronized void setBlockOnAcknowledge(final boolean blockOnAcknowledge)
+   {
+      checkWrite();
+      this.blockOnAcknowledge = blockOnAcknowledge;
+   }
+
+   public synchronized boolean isBlockOnDurableSend()
+   {
+      return blockOnDurableSend;
+   }
+
+   public synchronized void setBlockOnDurableSend(final boolean blockOnDurableSend)
+   {
+      checkWrite();
+      this.blockOnDurableSend = blockOnDurableSend;
+   }
+
+   public synchronized boolean isBlockOnNonDurableSend()
+   {
+      return blockOnNonDurableSend;
+   }
+
+   public synchronized void setBlockOnNonDurableSend(final boolean blockOnNonDurableSend)
+   {
+      checkWrite();
+      this.blockOnNonDurableSend = blockOnNonDurableSend;
+   }
+
+   public synchronized boolean isAutoGroup()
+   {
+      return autoGroup;
+   }
+
+   public synchronized void setAutoGroup(final boolean autoGroup)
+   {
+      checkWrite();
+      this.autoGroup = autoGroup;
+   }
+
+   public synchronized boolean isPreAcknowledge()
+   {
+      return preAcknowledge;
+   }
+
+   public synchronized void setPreAcknowledge(final boolean preAcknowledge)
+   {
+      checkWrite();
+      this.preAcknowledge = preAcknowledge;
+   }
+
+   public synchronized int getAckBatchSize()
+   {
+      return ackBatchSize;
+   }
+
+   public synchronized void setAckBatchSize(final int ackBatchSize)
+   {
+      checkWrite();
+      this.ackBatchSize = ackBatchSize;
+   }
+
+   public synchronized long getDiscoveryInitialWaitTimeout()
+   {
+      return discoveryInitialWaitTimeout;
+   }
+
+   public synchronized void setDiscoveryInitialWaitTimeout(final long initialWaitTimeout)
+   {
+      checkWrite();
+      discoveryInitialWaitTimeout = initialWaitTimeout;
+   }
+
+   public synchronized boolean isUseGlobalPools()
+   {
+      return useGlobalPools;
+   }
+
+   public synchronized void setUseGlobalPools(final boolean useGlobalPools)
+   {
+      checkWrite();
+      this.useGlobalPools = useGlobalPools;
+   }
+
+   public synchronized int getScheduledThreadPoolMaxSize()
+   {
+      return scheduledThreadPoolMaxSize;
+   }
+
+   public synchronized void setScheduledThreadPoolMaxSize(final int scheduledThreadPoolMaxSize)
+   {
+      checkWrite();
+      this.scheduledThreadPoolMaxSize = scheduledThreadPoolMaxSize;
+   }
+
+   public synchronized int getThreadPoolMaxSize()
+   {
+      return threadPoolMaxSize;
+   }
+
+   public synchronized void setThreadPoolMaxSize(final int threadPoolMaxSize)
+   {
+      checkWrite();
+      this.threadPoolMaxSize = threadPoolMaxSize;
+   }
+
+   public synchronized long getRetryInterval()
+   {
+      return retryInterval;
+   }
+
+   public synchronized void setRetryInterval(final long retryInterval)
+   {
+      checkWrite();
+      this.retryInterval = retryInterval;
+   }
+
+   public synchronized long getMaxRetryInterval()
+   {
+      return maxRetryInterval;
+   }
+
+   public synchronized void setMaxRetryInterval(final long retryInterval)
+   {
+      checkWrite();
+      maxRetryInterval = retryInterval;
+   }
+
+   public synchronized double getRetryIntervalMultiplier()
+   {
+      return retryIntervalMultiplier;
+   }
+
+   public synchronized void setRetryIntervalMultiplier(final double retryIntervalMultiplier)
+   {
+      checkWrite();
+      this.retryIntervalMultiplier = retryIntervalMultiplier;
+   }
+
+   public synchronized int getReconnectAttempts()
+   {
+      return reconnectAttempts;
+   }
+
+   public synchronized void setReconnectAttempts(final int reconnectAttempts)
+   {
+      checkWrite();
+      this.reconnectAttempts = reconnectAttempts;
+   }
+
+   public synchronized boolean isFailoverOnInitialConnection()
+   {
+      return this.failoverOnInitialConnection;
+   }
+
+   public synchronized void setFailoverOnInitialConnection(final boolean failover)
+   {
+      checkWrite();
+      this.failoverOnInitialConnection = failover;
+   }
+
+   public synchronized boolean isFailoverOnServerShutdown()
+   {
+      return failoverOnServerShutdown;
+   }
+
+   public synchronized void setFailoverOnServerShutdown(final boolean failoverOnServerShutdown)
+   {
+      checkWrite();
+      this.failoverOnServerShutdown = failoverOnServerShutdown;
+   }
+
+   public synchronized String getConnectionLoadBalancingPolicyClassName()
+   {
+      return connectionLoadBalancingPolicyClassName;
+   }
+
+   public synchronized void setConnectionLoadBalancingPolicyClassName(final String loadBalancingPolicyClassName)
+   {
+      checkWrite();
+      connectionLoadBalancingPolicyClassName = loadBalancingPolicyClassName;
+   }
+
+   public synchronized String getLocalBindAddress()
+   {
+      return localBindAddress;
+   }
+
+   public synchronized void setLocalBindAddress(final String localBindAddress)
+   {
+      checkWrite();
+      this.localBindAddress = localBindAddress;
+   }
+
+   public synchronized String getDiscoveryAddress()
+   {
+      return discoveryAddress;
+   }
+
+   public synchronized void setDiscoveryAddress(final String discoveryAddress)
+   {
+      checkWrite();
+      this.discoveryAddress = discoveryAddress;
+   }
+
+   public synchronized int getDiscoveryPort()
+   {
+      return discoveryPort;
+   }
+
+   public synchronized void setDiscoveryPort(final int discoveryPort)
+   {
+      checkWrite();
+      this.discoveryPort = discoveryPort;
+   }
+
+   public synchronized long getDiscoveryRefreshTimeout()
+   {
+      return discoveryRefreshTimeout;
+   }
+
+   public void addInterceptor(final Interceptor interceptor)
+   {
+      interceptors.add(interceptor);
+   }
+
+   public boolean removeInterceptor(final Interceptor interceptor)
+   {
+      return interceptors.remove(interceptor);
+   }
+
+   public synchronized void setDiscoveryRefreshTimeout(final long discoveryRefreshTimeout)
+   {
+      checkWrite();
+      this.discoveryRefreshTimeout = discoveryRefreshTimeout;
+   }
+
+   public synchronized int getInitialMessagePacketSize()
+   {
+      return initialMessagePacketSize;
+   }
+
+   public synchronized void setInitialMessagePacketSize(final int size)
+   {
+      checkWrite();
+      initialMessagePacketSize = size;
+   }
+
+   public ClientSession createSession(final String username,
+                                      final String password,
+                                      final boolean xa,
+                                      final boolean autoCommitSends,
+                                      final boolean autoCommitAcks,
+                                      final boolean preAcknowledge,
+                                      final int ackBatchSize) throws HornetQException
+   {
+      return createSessionInternal(username,
+                                   password,
+                                   xa,
+                                   autoCommitSends,
+                                   autoCommitAcks,
+                                   preAcknowledge,
+                                   ackBatchSize);
+   }
+
+   public ClientSession createSession(final boolean autoCommitSends,
+                                      final boolean autoCommitAcks,
+                                      final int ackBatchSize) throws HornetQException
+   {
+      return createSessionInternal(null, null, false, autoCommitSends, autoCommitAcks, preAcknowledge, ackBatchSize);
+   }
+
+   public ClientSession createXASession() throws HornetQException
+   {
+      return createSessionInternal(null, null, true, false, false, preAcknowledge, ackBatchSize);
+   }
+
+   public ClientSession createTransactedSession() throws HornetQException
+   {
+      return createSessionInternal(null, null, false, false, false, preAcknowledge, ackBatchSize);
+   }
+
+   public ClientSession createSession() throws HornetQException
+   {
+      return createSessionInternal(null, null, false, true, true, preAcknowledge, ackBatchSize);
+   }
+
+   public ClientSession createSession(final boolean autoCommitSends, final boolean autoCommitAcks) throws HornetQException
+   {
+      return createSessionInternal(null, null, false, autoCommitSends, autoCommitAcks, preAcknowledge, ackBatchSize);
+   }
+
+   public ClientSession createSession(final boolean xa, final boolean autoCommitSends, final boolean autoCommitAcks) throws HornetQException
+   {
+      return createSessionInternal(null, null, xa, autoCommitSends, autoCommitAcks, preAcknowledge, ackBatchSize);
+   }
+
+   public ClientSession createSession(final boolean xa,
+                                      final boolean autoCommitSends,
+                                      final boolean autoCommitAcks,
+                                      final boolean preAcknowledge) throws HornetQException
+   {
+      return createSessionInternal(null, null, xa, autoCommitSends, autoCommitAcks, preAcknowledge, ackBatchSize);
+   }
+
+   public int numSessions()
+   {
+      int num = 0;
+
+      for (FailoverManager failoverManager : failoverManagerMap.values())
+      {
+         num += failoverManager.numSessions();
+      }
+
+      return num;
+   }
+
+   public int numConnections()
+   {
+      int num = 0;
+
+      for (FailoverManager failoverManager : failoverManagerMap.values())
+      {
+         num += failoverManager.numConnections();
+      }
+
+      return num;
+   }
+
+   public void close()
+   {
+      if (closed)
+      {
+         return;
+      }
+
+      if (discoveryGroup != null)
+      {
+         try
+         {
+            discoveryGroup.stop();
+         }
+         catch (Exception e)
+         {
+            ClientSessionFactoryImpl.log.error("Failed to stop discovery group", e);
+         }
+      }
+
+      for (FailoverManager failoverManager : failoverManagerMap.values())
+      {
+         failoverManager.causeExit();
+      }
+
+      failoverManagerMap.clear();
+
+      if (!useGlobalPools)
+      {
+         if (threadPool != null)
+         {
+            threadPool.shutdown();
+
+            try
+            {
+               if (!threadPool.awaitTermination(10000, TimeUnit.MILLISECONDS))
+               {
+                  ClientSessionFactoryImpl.log.warn("Timed out waiting for pool to terminate");
+               }
+            }
+            catch (InterruptedException ignore)
+            {
+            }
+         }
+
+         if (scheduledThreadPool != null)
+         {
+            scheduledThreadPool.shutdown();
+
+            try
+            {
+               if (!scheduledThreadPool.awaitTermination(10000, TimeUnit.MILLISECONDS))
+               {
+                  ClientSessionFactoryImpl.log.warn("Timed out waiting for scheduled pool to terminate");
+               }
+            }
+            catch (InterruptedException ignore)
+            {
+            }
+         }
+      }
+
+      closed = true;
+   }
+
+   public ClientSessionFactory copy()
+   {
+      return new ClientSessionFactoryImpl(this);
+   }
+
+   public void setGroupID(final String groupID)
+   {
+      this.groupID = groupID;
+   }
+
+   public String getGroupID()
+   {
+      return groupID;
+   }
+
+   // DiscoveryListener implementation --------------------------------------------------------
+
+   public synchronized void connectorsChanged()
+   {
+      receivedBroadcast = true;
+
+      Map<String, DiscoveryEntry> newConnectors = discoveryGroup.getDiscoveryEntryMap();
+
+      Set<Pair<TransportConfiguration, TransportConfiguration>> connectorSet = new HashSet<Pair<TransportConfiguration, TransportConfiguration>>();
+
+      for (DiscoveryEntry entry : newConnectors.values())
+      {
+         connectorSet.add(entry.getConnectorPair());
+      }
+
+      Iterator<Map.Entry<Pair<TransportConfiguration, TransportConfiguration>, FailoverManager>> iter = failoverManagerMap.entrySet()
+                                                                                                                          .iterator();
+      while (iter.hasNext())
+      {
+         Map.Entry<Pair<TransportConfiguration, TransportConfiguration>, FailoverManager> entry = iter.next();
+
+         if (!connectorSet.contains(entry.getKey()))
+         {
+            // failoverManager no longer there - we should remove it
+
+            iter.remove();
+         }
+      }
+
+      for (Pair<TransportConfiguration, TransportConfiguration> connectorPair : connectorSet)
+      {
+         if (!failoverManagerMap.containsKey(connectorPair))
+         {
+            // Create a new failoverManager
+
+            FailoverManager failoverManager = new FailoverManagerImpl(this,
+                                                                      connectorPair.a,
+                                                                      connectorPair.b,
+                                                                      failoverOnServerShutdown,
+                                                                      callTimeout,
+                                                                      clientFailureCheckPeriod,
+                                                                      connectionTTL,
+                                                                      retryInterval,
+                                                                      retryIntervalMultiplier,
+                                                                      maxRetryInterval,
+                                                                      reconnectAttempts,
+                                                                      failoverOnInitialConnection,
+                                                                      threadPool,
+                                                                      scheduledThreadPool,
+                                                                      interceptors);
+
+            failoverManagerMap.put(connectorPair, failoverManager);
+         }
+      }
+
+      updatefailoverManagerArray();
+   }
+
+   public FailoverManager[] getFailoverManagers()
+   {
+      return failoverManagerArray;
+   }
+
+   // Protected ------------------------------------------------------------------------------
+
+   @Override
+   protected void finalize() throws Throwable
+   {
+      close();
+
+      super.finalize();
+   }
+
+   // Private --------------------------------------------------------------------------------
+
+   private void checkWrite()
+   {
+      if (readOnly)
+      {
+         throw new IllegalStateException("Cannot set attribute on SessionFactory after it has been used");
+      }
+   }
+
+   private ClientSession createSessionInternal(final String username,
+                                               final String password,
+                                               final boolean xa,
+                                               final boolean autoCommitSends,
+                                               final boolean autoCommitAcks,
+                                               final boolean preAcknowledge,
+                                               final int ackBatchSize) throws HornetQException
+   {
+      if (closed)
+      {
+         throw new IllegalStateException("Cannot create session, factory is closed (maybe it has been garbage collected)");
+      }
+
+      try
+      {
+         initialise();
+      }
+      catch (Exception e)
+      {
+         throw new HornetQException(HornetQException.INTERNAL_ERROR, "Failed to initialise session factory", e);
+      }
+
+      if (discoveryGroup != null && !receivedBroadcast)
+      {
+         boolean ok = discoveryGroup.waitForBroadcast(discoveryInitialWaitTimeout);
+
+         if (!ok)
+         {
+            throw new HornetQException(HornetQException.CONNECTION_TIMEDOUT,
+                                       "Timed out waiting to receive initial broadcast from discovery group");
+         }
+      }
+
+      synchronized (this)
+      {
+         int pos = loadBalancingPolicy.select(failoverManagerArray.length);
+
+         FailoverManager failoverManager = failoverManagerArray[pos];
+
+         ClientSession session = failoverManager.createSession(username,
+                                                               password,
+                                                               xa,
+                                                               autoCommitSends,
+                                                               autoCommitAcks,
+                                                               preAcknowledge,
+                                                               ackBatchSize,
+                                                               cacheLargeMessagesClient,
+                                                               minLargeMessageSize,
+                                                               blockOnAcknowledge,
+                                                               autoGroup,
+                                                               confirmationWindowSize,
+                                                               producerWindowSize,
+                                                               consumerWindowSize,
+                                                               producerMaxRate,
+                                                               consumerMaxRate,
+                                                               blockOnNonDurableSend,
+                                                               blockOnDurableSend,
+                                                               initialMessagePacketSize,
+                                                               groupID);
+
+         return session;
+      }
+   }
+
+   private void instantiateLoadBalancingPolicy()
+   {
+      if (connectionLoadBalancingPolicyClassName == null)
+      {
+         throw new IllegalStateException("Please specify a load balancing policy class name on the session factory");
+      }
+
+      AccessController.doPrivileged(new PrivilegedAction<Object>()
+      {
+         public Object run()
+         {
+            ClassLoader loader = Thread.currentThread().getContextClassLoader();
+            try
+            {
+               Class<?> clazz = loader.loadClass(connectionLoadBalancingPolicyClassName);
+               loadBalancingPolicy = (ConnectionLoadBalancingPolicy)clazz.newInstance();
+               return null;
+            }
+            catch (Exception e)
+            {
+               throw new IllegalArgumentException("Unable to instantiate load balancing policy \"" + connectionLoadBalancingPolicyClassName +
+                                                           "\"",
+                                                  e);
+            }
+         }
+      });
+   }
+
+   private static ClassLoader getThisClassLoader()
+   {
+      return AccessController.doPrivileged(new PrivilegedAction<ClassLoader>()
+                                    {
+                                       public ClassLoader run()
+                                       {
+                                          return ClientSessionFactoryImpl.class.getClassLoader();
+                                       }
+                                    });
+      
+   }
+
+   private synchronized void updatefailoverManagerArray()
+   {
+      failoverManagerArray = new FailoverManager[failoverManagerMap.size()];
+
+      failoverManagerMap.values().toArray(failoverManagerArray);
+   }
+
+}

Modified: branches/2_2_0_HA_Improvements/src/main/org/hornetq/core/client/impl/ClientSessionFactoryInternal.java
===================================================================
--- branches/2_2_0_HA_Improvements/src/main/org/hornetq/core/client/impl/ClientSessionFactoryInternal.java	2010-06-11 04:11:42 UTC (rev 9306)
+++ branches/2_2_0_HA_Improvements/src/main/org/hornetq/core/client/impl/ClientSessionFactoryInternal.java	2010-06-11 15:33:36 UTC (rev 9307)
@@ -13,6 +13,7 @@
 package org.hornetq.core.client.impl;
 
 import org.hornetq.api.core.client.ClientSessionFactory;
+import org.hornetq.api.core.client.SessionFailureListener;
 
 /**
  * A ClientSessionFactoryInternal
@@ -22,9 +23,17 @@
  */
 public interface ClientSessionFactoryInternal extends ClientSessionFactory
 {
+   
+   void addFailureListener(SessionFailureListener listener);
+
+   boolean removeFailureListener(SessionFailureListener listener);
+   
    // for testing
 
    int numConnections();
 
    int numSessions();
+   
+   void removeSession(final ClientSessionInternal session);
+   
 }

Modified: branches/2_2_0_HA_Improvements/src/main/org/hornetq/core/client/impl/ClientSessionImpl.java
===================================================================
--- branches/2_2_0_HA_Improvements/src/main/org/hornetq/core/client/impl/ClientSessionImpl.java	2010-06-11 04:11:42 UTC (rev 9306)
+++ branches/2_2_0_HA_Improvements/src/main/org/hornetq/core/client/impl/ClientSessionImpl.java	2010-06-11 15:33:36 UTC (rev 9307)
@@ -108,7 +108,7 @@
 
    // Attributes ----------------------------------------------------------------------------
 
-   private final FailoverManager failoverManager;
+   private final ClientSessionFactoryInternal sessionFactory;
 
    private final String name;
 
@@ -181,10 +181,12 @@
    private final String groupID;
 
    private volatile boolean inClose;
+   
+   private volatile SimpleString defaultAddress;
 
    // Constructors ----------------------------------------------------------------------------
 
-   public ClientSessionImpl(final FailoverManager connectionManager,
+   public ClientSessionImpl(final ClientSessionFactoryInternal sessionFactory,
                             final String name,
                             final String username,
                             final String password,
@@ -211,7 +213,7 @@
                             final Channel channel,
                             final Executor executor) throws HornetQException
    {
-      failoverManager = connectionManager;
+      this.sessionFactory = sessionFactory;
 
       this.name = name;
 
@@ -641,15 +643,32 @@
    {
       stop(true);
    }
+   
+   public void stop(final boolean waitForOnMessage) throws HornetQException
+   {
+      checkClosed();
 
+      if (started)
+      {
+         for (ClientConsumerInternal clientConsumerInternal : consumers.values())
+         {
+            clientConsumerInternal.stop(waitForOnMessage);
+         }
+
+         channel.sendBlocking(new PacketImpl(PacketImpl.SESS_STOP));
+
+         started = false;
+      }
+   }
+
    public void addFailureListener(final SessionFailureListener listener)
    {
-      failoverManager.addFailureListener(listener);
+      sessionFactory.addFailureListener(listener);
    }
 
    public boolean removeFailureListener(final SessionFailureListener listener)
    {
-      return failoverManager.removeFailureListener(listener);
+      return sessionFactory.removeFailureListener(listener);
    }
 
    public int getVersion()
@@ -1028,9 +1047,12 @@
          // not having any credits to send
       }
    }
+   
+   public ClientSessionFactoryInternal getSessionFactory()
+   {
+      return sessionFactory;
+   }
 
-   private volatile SimpleString defaultAddress;
-
    public void setAddress(final Message message, final SimpleString address)
    {
       if (defaultAddress == null)
@@ -1081,11 +1103,6 @@
       channel.returnBlocking();
    }
 
-   public FailoverManager getConnectionManager()
-   {
-      return failoverManager;
-   }
-
    public void sendProducerCreditsMessage(final int credits, final SimpleString address)
    {
       channel.send(new SessionRequestProducerCreditsMessage(credits, address));
@@ -1275,7 +1292,7 @@
 
       ClientSessionInternal other = (ClientSessionInternal)xares;
 
-      return failoverManager == other.getConnectionManager();
+      return sessionFactory == other.getSessionFactory();
    }
 
    public int prepare(final Xid xid) throws XAException
@@ -1655,7 +1672,7 @@
          channel.close();
       }
 
-      failoverManager.removeSession(this);
+      sessionFactory.removeSession(this);
    }
 
    private void cleanUpChildren() throws Exception
@@ -1700,23 +1717,8 @@
       }
    }
 
-   public void stop(final boolean waitForOnMessage) throws HornetQException
-   {
-      checkClosed();
 
-      if (started)
-      {
-         for (ClientConsumerInternal clientConsumerInternal : consumers.values())
-         {
-            clientConsumerInternal.stop(waitForOnMessage);
-         }
 
-         channel.sendBlocking(new PacketImpl(PacketImpl.SESS_STOP));
-
-         started = false;
-      }
-   }
-
    private static class BindingQueryImpl implements BindingQuery
    {
 

Modified: branches/2_2_0_HA_Improvements/src/main/org/hornetq/core/client/impl/ClientSessionInternal.java
===================================================================
--- branches/2_2_0_HA_Improvements/src/main/org/hornetq/core/client/impl/ClientSessionInternal.java	2010-06-11 04:11:42 UTC (rev 9306)
+++ branches/2_2_0_HA_Improvements/src/main/org/hornetq/core/client/impl/ClientSessionInternal.java	2010-06-11 15:33:36 UTC (rev 9307)
@@ -66,7 +66,7 @@
 
    void setForceNotSameRM(boolean force);
 
-   FailoverManager getConnectionManager();
+   ClientSessionFactoryInternal getSessionFactory();
 
    void workDone();
 

Modified: branches/2_2_0_HA_Improvements/src/main/org/hornetq/core/client/impl/DelegatingSession.java
===================================================================
--- branches/2_2_0_HA_Improvements/src/main/org/hornetq/core/client/impl/DelegatingSession.java	2010-06-11 04:11:42 UTC (rev 9306)
+++ branches/2_2_0_HA_Improvements/src/main/org/hornetq/core/client/impl/DelegatingSession.java	2010-06-11 15:33:36 UTC (rev 9307)
@@ -506,9 +506,9 @@
       session.stop();
    }
 
-   public FailoverManager getConnectionManager()
+   public ClientSessionFactoryInternal getSessionFactory()
    {
-      return session.getConnectionManager();
+      return session.getSessionFactory();
    }
 
    public void setForceNotSameRM(final boolean force)

Deleted: branches/2_2_0_HA_Improvements/src/main/org/hornetq/core/client/impl/FailoverManager.java
===================================================================
--- branches/2_2_0_HA_Improvements/src/main/org/hornetq/core/client/impl/FailoverManager.java	2010-06-11 04:11:42 UTC (rev 9306)
+++ branches/2_2_0_HA_Improvements/src/main/org/hornetq/core/client/impl/FailoverManager.java	2010-06-11 15:33:36 UTC (rev 9307)
@@ -1,66 +0,0 @@
-/*
- * Copyright 2009 Red Hat, Inc.
- * Red Hat licenses this file to you under the Apache License, version
- * 2.0 (the "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *    http://www.apache.org/licenses/LICENSE-2.0
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
- * implied.  See the License for the specific language governing
- * permissions and limitations under the License.
- */
-
-package org.hornetq.core.client.impl;
-
-import org.hornetq.api.core.HornetQException;
-import org.hornetq.api.core.client.ClientSession;
-import org.hornetq.api.core.client.SessionFailureListener;
-import org.hornetq.core.protocol.core.CoreRemotingConnection;
-
-/**
- * A ConnectionManager
- *
- * @author <a href="mailto:tim.fox at jboss.com">Tim Fox</a>
- * 
- * Created 27 Nov 2008 18:45:46
- *
- *
- */
-public interface FailoverManager
-{
-   ClientSession createSession(final String username,
-                               final String password,
-                               final boolean xa,
-                               final boolean autoCommitSends,
-                               final boolean autoCommitAcks,
-                               final boolean preAcknowledge,
-                               final int ackBatchSize,
-                               final boolean cacheLargeMessageClient,
-                               final int minLargeMessageSize,
-                               final boolean blockOnAcknowledge,
-                               final boolean autoGroup,
-                               final int confirmationWindowSize,
-                               final int producerWindowSize,
-                               final int consumerWindowSize,
-                               final int producerMaxRate,
-                               final int consumerMaxRate,
-                               final boolean blockOnNonDurableSend,
-                               final boolean blockOnDurableSend,
-                               final int initialMessagePacketSize,
-                               final String groupID) throws HornetQException;
-
-   void removeSession(final ClientSessionInternal session);
-
-   public CoreRemotingConnection getConnection();
-
-   int numConnections();
-
-   int numSessions();
-
-   void addFailureListener(SessionFailureListener listener);
-
-   boolean removeFailureListener(SessionFailureListener listener);
-
-   void causeExit();
-}

Deleted: branches/2_2_0_HA_Improvements/src/main/org/hornetq/core/client/impl/FailoverManagerImpl.java
===================================================================
--- branches/2_2_0_HA_Improvements/src/main/org/hornetq/core/client/impl/FailoverManagerImpl.java	2010-06-11 04:11:42 UTC (rev 9306)
+++ branches/2_2_0_HA_Improvements/src/main/org/hornetq/core/client/impl/FailoverManagerImpl.java	2010-06-11 15:33:36 UTC (rev 9307)
@@ -1,1227 +0,0 @@
-/*
- * Copyright 2009 Red Hat, Inc.
- * Red Hat licenses this file to you under the Apache License, version
- * 2.0 (the "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *    http://www.apache.org/licenses/LICENSE-2.0
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
- * implied.  See the License for the specific language governing
- * permissions and limitations under the License.
- */
-
-package org.hornetq.core.client.impl;
-
-import java.lang.ref.WeakReference;
-import java.util.ArrayList;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.Executor;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Future;
-import java.util.concurrent.ScheduledExecutorService;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.locks.Lock;
-
-import org.hornetq.api.core.HornetQBuffer;
-import org.hornetq.api.core.HornetQException;
-import org.hornetq.api.core.Interceptor;
-import org.hornetq.api.core.TransportConfiguration;
-import org.hornetq.api.core.client.ClientSession;
-import org.hornetq.api.core.client.ClientSessionFactory;
-import org.hornetq.api.core.client.SessionFailureListener;
-import org.hornetq.core.logging.Logger;
-import org.hornetq.core.protocol.core.Channel;
-import org.hornetq.core.protocol.core.ChannelHandler;
-import org.hornetq.core.protocol.core.CoreRemotingConnection;
-import org.hornetq.core.protocol.core.Packet;
-import org.hornetq.core.protocol.core.impl.PacketImpl;
-import org.hornetq.core.protocol.core.impl.RemotingConnectionImpl;
-import org.hornetq.core.protocol.core.impl.wireformat.CreateSessionMessage;
-import org.hornetq.core.protocol.core.impl.wireformat.CreateSessionResponseMessage;
-import org.hornetq.core.protocol.core.impl.wireformat.Ping;
-import org.hornetq.core.remoting.FailureListener;
-import org.hornetq.core.version.Version;
-import org.hornetq.spi.core.protocol.ProtocolType;
-import org.hornetq.spi.core.remoting.BufferHandler;
-import org.hornetq.spi.core.remoting.Connection;
-import org.hornetq.spi.core.remoting.ConnectionLifeCycleListener;
-import org.hornetq.spi.core.remoting.Connector;
-import org.hornetq.spi.core.remoting.ConnectorFactory;
-import org.hornetq.utils.ConcurrentHashSet;
-import org.hornetq.utils.ConfigurationHelper;
-import org.hornetq.utils.ExecutorFactory;
-import org.hornetq.utils.OrderedExecutorFactory;
-import org.hornetq.utils.UUIDGenerator;
-import org.hornetq.utils.VersionLoader;
-
-/**
- * A ConnectionManagerImpl
- *
- * @author <a href="mailto:tim.fox at jboss.com">Tim Fox</a>
- * 
- * Created 27 Nov 2008 18:46:06
- *
- */
-public class FailoverManagerImpl implements FailoverManager, ConnectionLifeCycleListener
-{
-   // Constants
-   // ------------------------------------------------------------------------------------
-
-   private static final long serialVersionUID = 2512460695662741413L;
-
-   private static final Logger log = Logger.getLogger(FailoverManagerImpl.class);
-
-   // debug
-
-   private static Map<TransportConfiguration, Set<CoreRemotingConnection>> debugConns;
-
-   private static boolean debug = false;
-
-   public static void enableDebug()
-   {
-      FailoverManagerImpl.debug = true;
-
-      FailoverManagerImpl.debugConns = new ConcurrentHashMap<TransportConfiguration, Set<CoreRemotingConnection>>();
-   }
-
-   public static void disableDebug()
-   {
-      FailoverManagerImpl.debug = false;
-
-      FailoverManagerImpl.debugConns.clear();
-      FailoverManagerImpl.debugConns = null;
-   }
-
-   private void checkAddDebug(final CoreRemotingConnection conn)
-   {
-      Set<CoreRemotingConnection> conns;
-
-      synchronized (FailoverManagerImpl.debugConns)
-      {
-         conns = FailoverManagerImpl.debugConns.get(connectorConfig);
-
-         if (conns == null)
-         {
-            conns = new HashSet<CoreRemotingConnection>();
-
-            FailoverManagerImpl.debugConns.put(connectorConfig, conns);
-         }
-
-         conns.add(conn);
-      }
-   }
-
-   public static void failAllConnectionsForConnector(final TransportConfiguration config)
-   {
-      Set<CoreRemotingConnection> conns;
-
-      synchronized (FailoverManagerImpl.debugConns)
-      {
-         conns = FailoverManagerImpl.debugConns.get(config);
-
-         if (conns != null)
-         {
-            conns = new HashSet<CoreRemotingConnection>(FailoverManagerImpl.debugConns.get(config));
-         }
-      }
-
-      if (conns != null)
-      {
-         for (CoreRemotingConnection conn : conns)
-         {
-            conn.fail(new HornetQException(HornetQException.INTERNAL_ERROR, "simulated connection failure"));
-         }
-      }
-   }
-
-   // Attributes
-   // -----------------------------------------------------------------------------------
-
-   private final TransportConfiguration connectorConfig;
-
-   private ConnectorFactory connectorFactory;
-
-   private Map<String, Object> transportParams;
-
-   private ConnectorFactory backupConnectorFactory;
-
-   private Map<String, Object> backupTransportParams;
-
-   private final long callTimeout;
-
-   private final long clientFailureCheckPeriod;
-
-   private final long connectionTTL;
-
-   private final Set<ClientSessionInternal> sessions = new HashSet<ClientSessionInternal>();
-
-   private final Object exitLock = new Object();
-
-   private final Object createSessionLock = new Object();
-
-   private boolean inCreateSession;
-
-   private final Object failoverLock = new Object();
-
-   private final ExecutorFactory orderedExecutorFactory;
-
-   private final ExecutorService threadPool;
-
-   private final ScheduledExecutorService scheduledThreadPool;
-
-   private final Executor closeExecutor;
-
-   private CoreRemotingConnection connection;
-
-   private final long retryInterval;
-
-   private final double retryIntervalMultiplier; // For exponential backoff
-
-   private final long maxRetryInterval;
-
-   private final int reconnectAttempts;
-
-   private final boolean failoverOnServerShutdown;
-
-   private final Set<SessionFailureListener> listeners = new ConcurrentHashSet<SessionFailureListener>();
-
-   private Connector connector;
-
-   private Future<?> pingerFuture;
-
-   private PingRunnable pingRunnable;
-
-   private volatile boolean exitLoop;
-
-   private final List<Interceptor> interceptors;
-
-   private volatile boolean stopPingingAfterOne;
-
-   private final boolean failoverOnInitialConnection;
-
-   // Static
-   // ---------------------------------------------------------------------------------------
-
-   // Constructors
-   // ---------------------------------------------------------------------------------
-
-   public FailoverManagerImpl(final ClientSessionFactory sessionFactory,
-                              final TransportConfiguration connectorConfig,
-                              final TransportConfiguration backupConfig,
-                              final boolean failoverOnServerShutdown,
-                              final long callTimeout,
-                              final long clientFailureCheckPeriod,
-                              final long connectionTTL,
-                              final long retryInterval,
-                              final double retryIntervalMultiplier,
-                              final long maxRetryInterval,
-                              final int reconnectAttempts,
-                              final boolean failoverOnInitialConnection,
-                              final ExecutorService threadPool,
-                              final ScheduledExecutorService scheduledThreadPool,
-                              final List<Interceptor> interceptors)
-   {
-      this.connectorConfig = connectorConfig;
-
-      this.failoverOnServerShutdown = failoverOnServerShutdown;
-
-      connectorFactory = instantiateConnectorFactory(connectorConfig.getFactoryClassName());
-
-      transportParams = connectorConfig.getParams();
-
-      checkTransportKeys(connectorFactory, transportParams);
-
-      if (backupConfig != null)
-      {
-         backupConnectorFactory = instantiateConnectorFactory(backupConfig.getFactoryClassName());
-
-         backupTransportParams = backupConfig.getParams();
-
-         checkTransportKeys(backupConnectorFactory, backupTransportParams);
-      }
-      else
-      {
-         backupConnectorFactory = null;
-
-         backupTransportParams = null;
-      }
-
-      this.callTimeout = callTimeout;
-
-      this.clientFailureCheckPeriod = clientFailureCheckPeriod;
-
-      this.connectionTTL = connectionTTL;
-
-      this.retryInterval = retryInterval;
-
-      this.retryIntervalMultiplier = retryIntervalMultiplier;
-
-      this.maxRetryInterval = maxRetryInterval;
-
-      this.reconnectAttempts = reconnectAttempts;
-
-      this.failoverOnInitialConnection = failoverOnInitialConnection;
-
-      this.scheduledThreadPool = scheduledThreadPool;
-
-      this.threadPool = threadPool;
-
-      orderedExecutorFactory = new OrderedExecutorFactory(threadPool);
-
-      closeExecutor = orderedExecutorFactory.getExecutor();
-
-      this.interceptors = interceptors;
-   }
-
-   // ConnectionLifeCycleListener implementation --------------------------------------------------
-
-   public void connectionCreated(final Connection connection, final ProtocolType protocol)
-   {
-   }
-
-   public void connectionDestroyed(final Object connectionID)
-   {
-      handleConnectionFailure(connectionID,
-                              new HornetQException(HornetQException.NOT_CONNECTED, "Channel disconnected"));
-   }
-
-   public void connectionException(final Object connectionID, final HornetQException me)
-   {
-      handleConnectionFailure(connectionID, me);
-   }
-
-   // ConnectionManager implementation ------------------------------------------------------------------
-
-   public ClientSession createSession(final String username,
-                                      final String password,
-                                      final boolean xa,
-                                      final boolean autoCommitSends,
-                                      final boolean autoCommitAcks,
-                                      final boolean preAcknowledge,
-                                      final int ackBatchSize,
-                                      final boolean cacheLargeMessageClient,
-                                      final int minLargeMessageSize,
-                                      final boolean blockOnAcknowledge,
-                                      final boolean autoGroup,
-                                      final int confWindowSize,
-                                      final int producerWindowSize,
-                                      final int consumerWindowSize,
-                                      final int producerMaxRate,
-                                      final int consumerMaxRate,
-                                      final boolean blockOnNonDurableSend,
-                                      final boolean blockOnDurableSend,
-                                      final int initialMessagePacketSize,
-                                      final String groupID) throws HornetQException
-   {
-      synchronized (createSessionLock)
-      {
-         String name = UUIDGenerator.getInstance().generateSimpleStringUUID().toString();
-
-         boolean retry = false;
-         do
-         {
-            Version clientVersion = VersionLoader.getVersion();
-
-            CoreRemotingConnection theConnection = null;
-
-            Lock lock = null;
-
-            try
-            {
-               Channel channel1;
-
-               synchronized (failoverLock)
-               {
-                  theConnection = getConnectionWithRetry(reconnectAttempts);
-
-                  if (theConnection == null)
-                  {
-                     if (exitLoop)
-                     {
-                        return null;
-                     }
-
-                     if (failoverOnInitialConnection && backupConnectorFactory != null)
-                     {
-                        // Try and connect to the backup
-
-                        log.warn("Server is not available to make initial connection to. Will " + "try backup server instead.");
-
-                        connectorFactory = backupConnectorFactory;
-
-                        transportParams = backupTransportParams;
-
-                        backupConnectorFactory = null;
-
-                        backupTransportParams = null;
-
-                        theConnection = getConnectionWithRetry(reconnectAttempts);
-                     }
-
-                     if (exitLoop)
-                     {
-                        return null;
-                     }
-
-                     if (theConnection == null)
-                     {
-                        throw new HornetQException(HornetQException.NOT_CONNECTED,
-                                                   "Unable to connect to server using configuration " + connectorConfig);
-                     }
-                  }
-
-                  channel1 = theConnection.getChannel(1, -1);
-
-                  // Lock it - this must be done while the failoverLock is held
-                  channel1.getLock().lock();
-
-                  lock = channel1.getLock();
-               } // We can now release the failoverLock
-
-               // We now set a flag saying createSession is executing
-               synchronized (exitLock)
-               {
-                  inCreateSession = true;
-               }
-
-               long sessionChannelID = theConnection.generateChannelID();
-
-               Packet request = new CreateSessionMessage(name,
-                                                         sessionChannelID,
-                                                         clientVersion.getIncrementingVersion(),
-                                                         username,
-                                                         password,
-                                                         minLargeMessageSize,
-                                                         xa,
-                                                         autoCommitSends,
-                                                         autoCommitAcks,
-                                                         preAcknowledge,
-                                                         confWindowSize,
-                                                         null);
-
-               Packet pResponse;
-               try
-               {
-                  pResponse = channel1.sendBlocking(request);
-               }
-               catch (HornetQException e)
-               {
-                  if (e.getCode() == HornetQException.INCOMPATIBLE_CLIENT_SERVER_VERSIONS)
-                  {
-                     theConnection.destroy();
-                  }
-
-                  if (e.getCode() == HornetQException.UNBLOCKED)
-                  {
-                     // This means the thread was blocked on create session and failover unblocked it
-                     // so failover could occur
-
-                     retry = true;
-
-                     continue;
-                  }
-                  else
-                  {
-                     throw e;
-                  }
-               }
-
-               CreateSessionResponseMessage response = (CreateSessionResponseMessage)pResponse;
-
-               Channel sessionChannel = theConnection.getChannel(sessionChannelID, confWindowSize);
-
-               ClientSessionInternal session = new ClientSessionImpl(this,
-                                                                     name,
-                                                                     username,
-                                                                     password,
-                                                                     xa,
-                                                                     autoCommitSends,
-                                                                     autoCommitAcks,
-                                                                     preAcknowledge,
-                                                                     blockOnAcknowledge,
-                                                                     autoGroup,
-                                                                     ackBatchSize,
-                                                                     consumerWindowSize,
-                                                                     consumerMaxRate,
-                                                                     confWindowSize,
-                                                                     producerWindowSize,
-                                                                     producerMaxRate,
-                                                                     blockOnNonDurableSend,
-                                                                     blockOnDurableSend,
-                                                                     cacheLargeMessageClient,
-                                                                     minLargeMessageSize,
-                                                                     initialMessagePacketSize,
-                                                                     groupID,
-                                                                     theConnection,
-                                                                     response.getServerVersion(),
-                                                                     sessionChannel,
-                                                                     orderedExecutorFactory.getExecutor());
-
-               sessions.add(session);
-
-               ChannelHandler handler = new ClientSessionPacketHandler(session, sessionChannel);
-
-               sessionChannel.setHandler(handler);
-
-               return new DelegatingSession(session);
-            }
-            catch (Throwable t)
-            {
-               if (lock != null)
-               {
-                  lock.unlock();
-
-                  lock = null;
-               }
-
-               if (t instanceof HornetQException)
-               {
-                  throw (HornetQException)t;
-               }
-               else
-               {
-                  HornetQException me = new HornetQException(HornetQException.INTERNAL_ERROR,
-                                                             "Failed to create session", t);
-
-                  throw me;
-               }
-            }
-            finally
-            {
-               if (lock != null)
-               {
-                  lock.unlock();
-               }
-
-               // Execution has finished so notify any failover thread that may be waiting for us to be done
-               synchronized (exitLock)
-               {
-                  inCreateSession = false;
-
-                  exitLock.notify();
-               }
-            }
-         }
-         while (retry);
-      }
-
-      // Should never get here
-      throw new IllegalStateException("Oh my God it's full of stars!");
-   }
-
-   // Must be synchronized to prevent it happening concurrently with failover which can lead to
-   // inconsistencies
-   public void removeSession(final ClientSessionInternal session)
-   {
-      // TODO - can we simplify this locking?
-      synchronized (createSessionLock)
-      {
-         synchronized (failoverLock)
-         {
-            sessions.remove(session);
-
-            checkCloseConnection();
-         }
-      }
-   }
-
-   public synchronized int numConnections()
-   {
-      return connection != null ? 1 : 0;
-   }
-
-   public int numSessions()
-   {
-      return sessions.size();
-   }
-
-   public void addFailureListener(final SessionFailureListener listener)
-   {
-      listeners.add(listener);
-   }
-
-   public boolean removeFailureListener(final SessionFailureListener listener)
-   {
-      return listeners.remove(listener);
-   }
-
-   public void causeExit()
-   {
-      exitLoop = true;
-   }
-
-   // Public
-   // ---------------------------------------------------------------------------------------
-
-   public void stopPingingAfterOne()
-   {
-      stopPingingAfterOne = true;
-   }
-
-   // Protected
-   // ------------------------------------------------------------------------------------
-
-   // Package Private
-   // ------------------------------------------------------------------------------
-
-   // Private
-   // --------------------------------------------------------------------------------------
-
-   private void handleConnectionFailure(final Object connectionID, final HornetQException me)
-   {
-      failoverOrReconnect(connectionID, me);
-   }
-
-   private void failoverOrReconnect(final Object connectionID, final HornetQException me)
-   {
-      Set<ClientSessionInternal> sessionsToClose = null;
-
-      synchronized (failoverLock)
-      {
-         if (connection == null || connection.getID() != connectionID)
-         {
-            // We already failed over/reconnected - probably the first failure came in, all the connections were failed
-            // over then a async connection exception or disconnect
-            // came in for one of the already exitLoop connections, so we return true - we don't want to call the
-            // listeners again
-
-            return;
-         }
-
-         // We call before reconnection occurs to give the user a chance to do cleanup, like cancel messages
-         callFailureListeners(me, false);
-
-         // Now get locks on all channel 1s, whilst holding the failoverLock - this makes sure
-         // There are either no threads executing in createSession, or one is blocking on a createSession
-         // result.
-
-         // Then interrupt the channel 1 that is blocking (could just interrupt them all)
-
-         // Then release all channel 1 locks - this allows the createSession to exit the monitor
-
-         // Then get all channel 1 locks again - this ensures the any createSession thread has executed the section and
-         // returned all its connections to the connection manager (the code to return connections to connection manager
-         // must be inside the lock
-
-         // Then perform failover
-
-         // Then release failoverLock
-
-         // The other side of the bargain - during createSession:
-         // The calling thread must get the failoverLock and get its' connections when this is locked.
-         // While this is still locked it must then get the channel1 lock
-         // It can then release the failoverLock
-         // It should catch HornetQException.INTERRUPTED in the call to channel.sendBlocking
-         // It should then return its connections, with channel 1 lock still held
-         // It can then release the channel 1 lock, and retry (which will cause locking on failoverLock
-         // until failover is complete
-
-         boolean serverShutdown = me.getCode() == HornetQException.DISCONNECTED;
-
-         // We will try to failover if there is a backup connector factory, but we don't do this if the server
-         // has been shutdown cleanly unless failoverOnServerShutdown is true
-         boolean attemptFailover = backupConnectorFactory != null && (failoverOnServerShutdown || !serverShutdown);
-
-         boolean attemptReconnect;
-
-         if (attemptFailover)
-         {
-            attemptReconnect = false;
-         }
-         else
-         {
-            attemptReconnect = reconnectAttempts != 0;
-         }
-
-         if (attemptFailover || attemptReconnect)
-         {
-            lockChannel1();
-
-            final boolean needToInterrupt;
-
-            synchronized (exitLock)
-            {
-               needToInterrupt = inCreateSession;
-            }
-
-            unlockChannel1();
-
-            if (needToInterrupt)
-            {
-               // Forcing return all channels won't guarantee that any blocked thread will return immediately
-               // So we need to wait for it
-               forceReturnChannel1();
-
-               // Now we need to make sure that the thread has actually exited and returned it's connections
-               // before failover occurs
-
-               synchronized (exitLock)
-               {
-                  while (inCreateSession)
-                  {
-                     try
-                     {
-                        exitLock.wait(5000);
-                     }
-                     catch (InterruptedException e)
-                     {
-                     }
-                  }
-               }
-            }
-
-            // Now we absolutely know that no threads are executing in or blocked in createSession, and no
-            // more will execute it until failover is complete
-
-            // So.. do failover / reconnection
-
-            CoreRemotingConnection oldConnection = connection;
-
-            connection = null;
-
-            try
-            {
-               connector.close();
-            }
-            catch (Exception ignore)
-            {
-            }
-
-            cancelScheduledTasks();
-
-            connector = null;
-
-            if (attemptFailover)
-            {
-               // Now try failing over to backup
-
-               connectorFactory = backupConnectorFactory;
-
-               transportParams = backupTransportParams;
-
-               backupConnectorFactory = null;
-
-               backupTransportParams = null;
-
-               reconnectSessions(oldConnection, reconnectAttempts == -1 ? -1 : reconnectAttempts + 1);
-            }
-            else
-            {
-               reconnectSessions(oldConnection, reconnectAttempts);
-            }
-
-            oldConnection.destroy();
-         }
-         else
-         {
-            connection.destroy();
-
-            connection = null;
-         }
-
-         callFailureListeners(me, true);
-
-         if (connection == null)
-         {
-            sessionsToClose = new HashSet<ClientSessionInternal>(sessions);
-         }
-      }
-
-      // This needs to be outside the failover lock to prevent deadlock
-      if (sessionsToClose != null)
-      {
-         // If connection is null it means we didn't succeed in failing over or reconnecting
-         // so we close all the sessions, so they will throw exceptions when attempted to be used
-
-         for (ClientSessionInternal session : sessionsToClose)
-         {
-            try
-            {
-               session.cleanUp();
-            }
-            catch (Exception e)
-            {
-               FailoverManagerImpl.log.error("Failed to cleanup session");
-            }
-         }
-      }
-   }
-
-   private void callFailureListeners(final HornetQException me, final boolean afterReconnect)
-   {
-      final List<SessionFailureListener> listenersClone = new ArrayList<SessionFailureListener>(listeners);
-
-      for (final SessionFailureListener listener : listenersClone)
-      {
-         try
-         {
-            if (afterReconnect)
-            {
-               listener.connectionFailed(me);
-            }
-            else
-            {
-               listener.beforeReconnect(me);
-            }
-         }
-         catch (final Throwable t)
-         {
-            // Failure of one listener to execute shouldn't prevent others
-            // from
-            // executing
-            FailoverManagerImpl.log.error("Failed to execute failure listener", t);
-         }
-      }
-   }
-
-   /*
-    * Re-attach sessions all pre-existing sessions to the new remoting connection
-    */
-   private void reconnectSessions(final CoreRemotingConnection oldConnection, final int reconnectAttempts)
-   {
-      CoreRemotingConnection newConnection = getConnectionWithRetry(reconnectAttempts);
-
-      if (newConnection == null)
-      {
-         FailoverManagerImpl.log.warn("Failed to connect to server.");
-
-         return;
-      }
-
-      List<FailureListener> oldListeners = oldConnection.getFailureListeners();
-
-      List<FailureListener> newListeners = new ArrayList<FailureListener>(newConnection.getFailureListeners());
-
-      for (FailureListener listener : oldListeners)
-      {
-         // Add all apart from the first one which is the old DelegatingFailureListener
-
-         if (listener instanceof DelegatingFailureListener == false)
-         {
-            newListeners.add(listener);
-         }
-      }
-
-      newConnection.setFailureListeners(newListeners);
-
-      for (ClientSessionInternal session : sessions)
-      {
-         session.handleFailover(newConnection);
-      }
-   }
-
-   private CoreRemotingConnection getConnectionWithRetry(final int reconnectAttempts)
-   {
-      long interval = retryInterval;
-
-      int count = 0;
-
-      while (true)
-      {
-         if (exitLoop)
-         {
-            return null;
-         }
-
-         CoreRemotingConnection theConnection = getConnection();
-
-         if (theConnection == null)
-         {
-            // Failed to get connection
-
-            if (reconnectAttempts != 0)
-            {
-               count++;
-
-               if (reconnectAttempts != -1 && count == reconnectAttempts)
-               {
-                  FailoverManagerImpl.log.warn("Tried " + reconnectAttempts + " times to connect. Now giving up.");
-
-                  return null;
-               }
-
-               try
-               {
-                  Thread.sleep(interval);
-               }
-               catch (InterruptedException ignore)
-               {
-               }
-
-               // Exponential back-off
-               long newInterval = (long)(interval * retryIntervalMultiplier);
-
-               if (newInterval > maxRetryInterval)
-               {
-                  newInterval = maxRetryInterval;
-               }
-
-               interval = newInterval;
-            }
-            else
-            {
-               return null;
-            }
-         }
-         else
-         {
-
-            if (FailoverManagerImpl.debug)
-            {
-               checkAddDebug(theConnection);
-            }
-
-            return theConnection;
-         }
-      }
-   }
-
-   private void cancelScheduledTasks()
-   {
-      if (pingerFuture != null)
-      {
-         pingRunnable.cancel();
-
-         pingerFuture.cancel(false);
-
-         pingRunnable = null;
-
-         pingerFuture = null;
-      }
-   }
-
-   private void checkCloseConnection()
-   {
-      if (connection != null && sessions.size() == 0)
-      {
-         cancelScheduledTasks();
-
-         try
-         {
-            connection.destroy();
-         }
-         catch (Throwable ignore)
-         {
-         }
-
-         connection = null;
-
-         try
-         {
-            if (connector != null)
-            {
-               connector.close();
-            }
-         }
-         catch (Throwable ignore)
-         {
-         }
-
-         connector = null;
-      }
-   }
-
-   public CoreRemotingConnection getConnection()
-   {
-      if (connection == null)
-      {
-         Connection tc = null;
-
-         try
-         {
-            DelegatingBufferHandler handler = new DelegatingBufferHandler();
-
-            connector = connectorFactory.createConnector(transportParams,
-                                                         handler,
-                                                         this,
-                                                         closeExecutor,
-                                                         threadPool,
-                                                         scheduledThreadPool);
-
-            if (connector != null)
-            {
-               connector.start();
-
-               tc = connector.createConnection();
-
-               if (tc == null)
-               {
-                  try
-                  {
-                     connector.close();
-                  }
-                  catch (Throwable t)
-                  {
-                  }
-
-                  connector = null;
-               }
-            }
-         }
-         catch (Exception e)
-         {
-            // Sanity catch for badly behaved remoting plugins
-
-            FailoverManagerImpl.log.warn("connector.create or connectorFactory.createConnector should never throw an exception, implementation is badly behaved, but we'll deal with it anyway.",
-                                         e);
-
-            if (tc != null)
-            {
-               try
-               {
-                  tc.close();
-               }
-               catch (Throwable t)
-               {
-               }
-            }
-
-            if (connector != null)
-            {
-               try
-               {
-                  connector.close();
-               }
-               catch (Throwable t)
-               {
-               }
-            }
-
-            tc = null;
-
-            connector = null;
-         }
-
-         if (tc == null)
-         {
-            return connection;
-         }
-
-         connection = new RemotingConnectionImpl(tc, callTimeout, interceptors);
-
-         connection.addFailureListener(new DelegatingFailureListener(connection.getID()));
-
-         connection.getChannel(0, -1).setHandler(new Channel0Handler(connection));
-
-         if (clientFailureCheckPeriod != -1)
-         {
-            if (pingerFuture == null)
-            {
-               pingRunnable = new PingRunnable();
-
-               pingerFuture = scheduledThreadPool.scheduleWithFixedDelay(new ActualScheduledPinger(pingRunnable),
-                                                                         0,
-                                                                         clientFailureCheckPeriod,
-                                                                         TimeUnit.MILLISECONDS);
-            }
-            // send a ping every time we create a new remoting connection
-            // to set up its TTL on the server side
-            else
-            {
-               pingRunnable.run();
-            }
-         }
-      }
-
-      return connection;
-   }
-
-   private ConnectorFactory instantiateConnectorFactory(final String connectorFactoryClassName)
-   {
-      ClassLoader loader = Thread.currentThread().getContextClassLoader();
-      try
-      {
-         Class<?> clazz = loader.loadClass(connectorFactoryClassName);
-         return (ConnectorFactory)clazz.newInstance();
-      }
-      catch (Exception e)
-      {
-         throw new IllegalArgumentException("Error instantiating connector factory \"" + connectorFactoryClassName +
-                                            "\"", e);
-      }
-   }
-
-   private void lockChannel1()
-   {
-      Channel channel1 = connection.getChannel(1, -1);
-
-      channel1.getLock().lock();
-   }
-
-   private void unlockChannel1()
-   {
-      Channel channel1 = connection.getChannel(1, -1);
-
-      channel1.getLock().unlock();
-   }
-
-   private void forceReturnChannel1()
-   {
-      Channel channel1 = connection.getChannel(1, -1);
-
-      channel1.returnBlocking();
-   }
-
-   private void checkTransportKeys(final ConnectorFactory factory, final Map<String, Object> params)
-   {
-      if (params != null)
-      {
-         Set<String> invalid = ConfigurationHelper.checkKeys(factory.getAllowableProperties(), params.keySet());
-
-         if (!invalid.isEmpty())
-         {
-            String msg = ConfigurationHelper.stringSetToCommaListString("The following keys are invalid for configuring a connector: ",
-                                                                        invalid);
-
-            throw new IllegalStateException(msg);
-
-         }
-      }
-   }
-
-   private class Channel0Handler implements ChannelHandler
-   {
-      private final CoreRemotingConnection conn;
-
-      private Channel0Handler(final CoreRemotingConnection conn)
-      {
-         this.conn = conn;
-      }
-
-      public void handlePacket(final Packet packet)
-      {
-         final byte type = packet.getType();
-
-         if (type == PacketImpl.DISCONNECT)
-         {
-            closeExecutor.execute(new Runnable()
-            {
-               // Must be executed on new thread since cannot block the netty thread for a long time and fail can
-               // cause reconnect loop
-               public void run()
-               {
-                  conn.fail(new HornetQException(HornetQException.DISCONNECTED,
-                                                 "The connection was disconnected because of server shutdown"));
-               }
-            });
-         }
-      }
-   }
-
-   private class DelegatingBufferHandler implements BufferHandler
-   {
-      public void bufferReceived(final Object connectionID, final HornetQBuffer buffer)
-      {
-         CoreRemotingConnection theConn = connection;
-
-         if (theConn != null && connectionID == theConn.getID())
-         {
-            theConn.bufferReceived(connectionID, buffer);
-         }
-      }
-   }
-
-   private class DelegatingFailureListener implements FailureListener
-   {
-      private final Object connectionID;
-
-      DelegatingFailureListener(final Object connectionID)
-      {
-         this.connectionID = connectionID;
-      }
-
-      public void connectionFailed(final HornetQException me)
-      {
-         handleConnectionFailure(connectionID, me);
-      }
-   }
-
-   private static final class ActualScheduledPinger implements Runnable
-   {
-      private final WeakReference<PingRunnable> pingRunnable;
-
-      ActualScheduledPinger(final PingRunnable runnable)
-      {
-         pingRunnable = new WeakReference<PingRunnable>(runnable);
-      }
-
-      public void run()
-      {
-         PingRunnable runnable = pingRunnable.get();
-
-         if (runnable != null)
-         {
-            runnable.run();
-         }
-      }
-
-   }
-
-   private final class PingRunnable implements Runnable
-   {
-      private boolean cancelled;
-
-      private boolean first;
-
-      private long lastCheck = System.currentTimeMillis();
-
-      public synchronized void run()
-      {
-         if (cancelled || stopPingingAfterOne && !first)
-         {
-            return;
-         }
-
-         first = false;
-
-         long now = System.currentTimeMillis();
-
-         if (clientFailureCheckPeriod != -1 && now >= lastCheck + clientFailureCheckPeriod)
-         {
-            if (!connection.checkDataReceived())
-            {
-               final HornetQException me = new HornetQException(HornetQException.CONNECTION_TIMEDOUT,
-                                                                "Did not receive data from server for " + connection.getTransportConnection());
-
-               cancelled = true;
-
-               threadPool.execute(new Runnable()
-               {
-                  // Must be executed on different thread
-                  public void run()
-                  {
-                     connection.fail(me);
-                  }
-               });
-
-               return;
-            }
-            else
-            {
-               lastCheck = now;
-            }
-         }
-
-         // Send a ping
-
-         Ping ping = new Ping(connectionTTL);
-
-         Channel channel0 = connection.getChannel(0, -1);
-
-         channel0.send(ping);
-
-         connection.flush();
-      }
-
-      public synchronized void cancel()
-      {
-         cancelled = true;
-      }
-   }
-
-}

Copied: branches/2_2_0_HA_Improvements/src/main/org/hornetq/core/client/impl/FailoverManagerImpl_Old.java (from rev 9287, branches/2_2_0_HA_Improvements/src/main/org/hornetq/core/client/impl/FailoverManagerImpl.java)
===================================================================
--- branches/2_2_0_HA_Improvements/src/main/org/hornetq/core/client/impl/FailoverManagerImpl_Old.java	                        (rev 0)
+++ branches/2_2_0_HA_Improvements/src/main/org/hornetq/core/client/impl/FailoverManagerImpl_Old.java	2010-06-11 15:33:36 UTC (rev 9307)
@@ -0,0 +1,1227 @@
+/*
+ * Copyright 2009 Red Hat, Inc.
+ * Red Hat licenses this file to you under the Apache License, version
+ * 2.0 (the "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ * implied.  See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+package org.hornetq.core.client.impl;
+
+import java.lang.ref.WeakReference;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.Executor;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Future;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.locks.Lock;
+
+import org.hornetq.api.core.HornetQBuffer;
+import org.hornetq.api.core.HornetQException;
+import org.hornetq.api.core.Interceptor;
+import org.hornetq.api.core.TransportConfiguration;
+import org.hornetq.api.core.client.ClientSession;
+import org.hornetq.api.core.client.ClientSessionFactory;
+import org.hornetq.api.core.client.SessionFailureListener;
+import org.hornetq.core.logging.Logger;
+import org.hornetq.core.protocol.core.Channel;
+import org.hornetq.core.protocol.core.ChannelHandler;
+import org.hornetq.core.protocol.core.CoreRemotingConnection;
+import org.hornetq.core.protocol.core.Packet;
+import org.hornetq.core.protocol.core.impl.PacketImpl;
+import org.hornetq.core.protocol.core.impl.RemotingConnectionImpl;
+import org.hornetq.core.protocol.core.impl.wireformat.CreateSessionMessage;
+import org.hornetq.core.protocol.core.impl.wireformat.CreateSessionResponseMessage;
+import org.hornetq.core.protocol.core.impl.wireformat.Ping;
+import org.hornetq.core.remoting.FailureListener;
+import org.hornetq.core.version.Version;
+import org.hornetq.spi.core.protocol.ProtocolType;
+import org.hornetq.spi.core.remoting.BufferHandler;
+import org.hornetq.spi.core.remoting.Connection;
+import org.hornetq.spi.core.remoting.ConnectionLifeCycleListener;
+import org.hornetq.spi.core.remoting.Connector;
+import org.hornetq.spi.core.remoting.ConnectorFactory;
+import org.hornetq.utils.ConcurrentHashSet;
+import org.hornetq.utils.ConfigurationHelper;
+import org.hornetq.utils.ExecutorFactory;
+import org.hornetq.utils.OrderedExecutorFactory;
+import org.hornetq.utils.UUIDGenerator;
+import org.hornetq.utils.VersionLoader;
+
+/**
+ * A ConnectionManagerImpl
+ *
+ * @author <a href="mailto:tim.fox at jboss.com">Tim Fox</a>
+ * 
+ * Created 27 Nov 2008 18:46:06
+ *
+ */
+public class FailoverManagerImpl_Old implements FailoverManager, ConnectionLifeCycleListener
+{
+   // Constants
+   // ------------------------------------------------------------------------------------
+
+   private static final long serialVersionUID = 2512460695662741413L;
+
+   private static final Logger log = Logger.getLogger(FailoverManagerImpl.class);
+
+   // debug
+
+   private static Map<TransportConfiguration, Set<CoreRemotingConnection>> debugConns;
+
+   private static boolean debug = false;
+
+   public static void enableDebug()
+   {
+      FailoverManagerImpl.debug = true;
+
+      FailoverManagerImpl.debugConns = new ConcurrentHashMap<TransportConfiguration, Set<CoreRemotingConnection>>();
+   }
+
+   public static void disableDebug()
+   {
+      FailoverManagerImpl.debug = false;
+
+      FailoverManagerImpl.debugConns.clear();
+      FailoverManagerImpl.debugConns = null;
+   }
+
+   private void checkAddDebug(final CoreRemotingConnection conn)
+   {
+      Set<CoreRemotingConnection> conns;
+
+      synchronized (FailoverManagerImpl.debugConns)
+      {
+         conns = FailoverManagerImpl.debugConns.get(connectorConfig);
+
+         if (conns == null)
+         {
+            conns = new HashSet<CoreRemotingConnection>();
+
+            FailoverManagerImpl.debugConns.put(connectorConfig, conns);
+         }
+
+         conns.add(conn);
+      }
+   }
+
+   public static void failAllConnectionsForConnector(final TransportConfiguration config)
+   {
+      Set<CoreRemotingConnection> conns;
+
+      synchronized (FailoverManagerImpl.debugConns)
+      {
+         conns = FailoverManagerImpl.debugConns.get(config);
+
+         if (conns != null)
+         {
+            conns = new HashSet<CoreRemotingConnection>(FailoverManagerImpl.debugConns.get(config));
+         }
+      }
+
+      if (conns != null)
+      {
+         for (CoreRemotingConnection conn : conns)
+         {
+            conn.fail(new HornetQException(HornetQException.INTERNAL_ERROR, "simulated connection failure"));
+         }
+      }
+   }
+
+   // Attributes
+   // -----------------------------------------------------------------------------------
+
+   private final TransportConfiguration connectorConfig;
+
+   private ConnectorFactory connectorFactory;
+
+   private Map<String, Object> transportParams;
+
+   private ConnectorFactory backupConnectorFactory;
+
+   private Map<String, Object> backupTransportParams;
+
+   private final long callTimeout;
+
+   private final long clientFailureCheckPeriod;
+
+   private final long connectionTTL;
+
+   private final Set<ClientSessionInternal> sessions = new HashSet<ClientSessionInternal>();
+
+   private final Object exitLock = new Object();
+
+   private final Object createSessionLock = new Object();
+
+   private boolean inCreateSession;
+
+   private final Object failoverLock = new Object();
+
+   private final ExecutorFactory orderedExecutorFactory;
+
+   private final ExecutorService threadPool;
+
+   private final ScheduledExecutorService scheduledThreadPool;
+
+   private final Executor closeExecutor;
+
+   private CoreRemotingConnection connection;
+
+   private final long retryInterval;
+
+   private final double retryIntervalMultiplier; // For exponential backoff
+
+   private final long maxRetryInterval;
+
+   private final int reconnectAttempts;
+
+   private final boolean failoverOnServerShutdown;
+
+   private final Set<SessionFailureListener> listeners = new ConcurrentHashSet<SessionFailureListener>();
+
+   private Connector connector;
+
+   private Future<?> pingerFuture;
+
+   private PingRunnable pingRunnable;
+
+   private volatile boolean exitLoop;
+
+   private final List<Interceptor> interceptors;
+
+   private volatile boolean stopPingingAfterOne;
+
+   private final boolean failoverOnInitialConnection;
+
+   // Static
+   // ---------------------------------------------------------------------------------------
+
+   // Constructors
+   // ---------------------------------------------------------------------------------
+
+   public FailoverManagerImpl_Old(final ClientSessionFactory sessionFactory,
+                              final TransportConfiguration connectorConfig,
+                              final TransportConfiguration backupConfig,
+                              final boolean failoverOnServerShutdown,
+                              final long callTimeout,
+                              final long clientFailureCheckPeriod,
+                              final long connectionTTL,
+                              final long retryInterval,
+                              final double retryIntervalMultiplier,
+                              final long maxRetryInterval,
+                              final int reconnectAttempts,
+                              final boolean failoverOnInitialConnection,
+                              final ExecutorService threadPool,
+                              final ScheduledExecutorService scheduledThreadPool,
+                              final List<Interceptor> interceptors)
+   {
+      this.connectorConfig = connectorConfig;
+
+      this.failoverOnServerShutdown = failoverOnServerShutdown;
+
+      connectorFactory = instantiateConnectorFactory(connectorConfig.getFactoryClassName());
+
+      transportParams = connectorConfig.getParams();
+
+      checkTransportKeys(connectorFactory, transportParams);
+
+      if (backupConfig != null)
+      {
+         backupConnectorFactory = instantiateConnectorFactory(backupConfig.getFactoryClassName());
+
+         backupTransportParams = backupConfig.getParams();
+
+         checkTransportKeys(backupConnectorFactory, backupTransportParams);
+      }
+      else
+      {
+         backupConnectorFactory = null;
+
+         backupTransportParams = null;
+      }
+
+      this.callTimeout = callTimeout;
+
+      this.clientFailureCheckPeriod = clientFailureCheckPeriod;
+
+      this.connectionTTL = connectionTTL;
+
+      this.retryInterval = retryInterval;
+
+      this.retryIntervalMultiplier = retryIntervalMultiplier;
+
+      this.maxRetryInterval = maxRetryInterval;
+
+      this.reconnectAttempts = reconnectAttempts;
+
+      this.failoverOnInitialConnection = failoverOnInitialConnection;
+
+      this.scheduledThreadPool = scheduledThreadPool;
+
+      this.threadPool = threadPool;
+
+      orderedExecutorFactory = new OrderedExecutorFactory(threadPool);
+
+      closeExecutor = orderedExecutorFactory.getExecutor();
+
+      this.interceptors = interceptors;
+   }
+
+   // ConnectionLifeCycleListener implementation --------------------------------------------------
+
+   public void connectionCreated(final Connection connection, final ProtocolType protocol)
+   {
+   }
+
+   public void connectionDestroyed(final Object connectionID)
+   {
+      handleConnectionFailure(connectionID,
+                              new HornetQException(HornetQException.NOT_CONNECTED, "Channel disconnected"));
+   }
+
+   public void connectionException(final Object connectionID, final HornetQException me)
+   {
+      handleConnectionFailure(connectionID, me);
+   }
+
+   // ConnectionManager implementation ------------------------------------------------------------------
+
+   public ClientSession createSession(final String username,
+                                      final String password,
+                                      final boolean xa,
+                                      final boolean autoCommitSends,
+                                      final boolean autoCommitAcks,
+                                      final boolean preAcknowledge,
+                                      final int ackBatchSize,
+                                      final boolean cacheLargeMessageClient,
+                                      final int minLargeMessageSize,
+                                      final boolean blockOnAcknowledge,
+                                      final boolean autoGroup,
+                                      final int confWindowSize,
+                                      final int producerWindowSize,
+                                      final int consumerWindowSize,
+                                      final int producerMaxRate,
+                                      final int consumerMaxRate,
+                                      final boolean blockOnNonDurableSend,
+                                      final boolean blockOnDurableSend,
+                                      final int initialMessagePacketSize,
+                                      final String groupID) throws HornetQException
+   {
+      synchronized (createSessionLock)
+      {
+         String name = UUIDGenerator.getInstance().generateSimpleStringUUID().toString();
+
+         boolean retry = false;
+         do
+         {
+            Version clientVersion = VersionLoader.getVersion();
+
+            CoreRemotingConnection theConnection = null;
+
+            Lock lock = null;
+
+            try
+            {
+               Channel channel1;
+
+               synchronized (failoverLock)
+               {
+                  theConnection = getConnectionWithRetry(reconnectAttempts);
+
+                  if (theConnection == null)
+                  {
+                     if (exitLoop)
+                     {
+                        return null;
+                     }
+
+                     if (failoverOnInitialConnection && backupConnectorFactory != null)
+                     {
+                        // Try and connect to the backup
+
+                        log.warn("Server is not available to make initial connection to. Will " + "try backup server instead.");
+
+                        connectorFactory = backupConnectorFactory;
+
+                        transportParams = backupTransportParams;
+
+                        backupConnectorFactory = null;
+
+                        backupTransportParams = null;
+
+                        theConnection = getConnectionWithRetry(reconnectAttempts);
+                     }
+
+                     if (exitLoop)
+                     {
+                        return null;
+                     }
+
+                     if (theConnection == null)
+                     {
+                        throw new HornetQException(HornetQException.NOT_CONNECTED,
+                                                   "Unable to connect to server using configuration " + connectorConfig);
+                     }
+                  }
+
+                  channel1 = theConnection.getChannel(1, -1);
+
+                  // Lock it - this must be done while the failoverLock is held
+                  channel1.getLock().lock();
+
+                  lock = channel1.getLock();
+               } // We can now release the failoverLock
+
+               // We now set a flag saying createSession is executing
+               synchronized (exitLock)
+               {
+                  inCreateSession = true;
+               }
+
+               long sessionChannelID = theConnection.generateChannelID();
+
+               Packet request = new CreateSessionMessage(name,
+                                                         sessionChannelID,
+                                                         clientVersion.getIncrementingVersion(),
+                                                         username,
+                                                         password,
+                                                         minLargeMessageSize,
+                                                         xa,
+                                                         autoCommitSends,
+                                                         autoCommitAcks,
+                                                         preAcknowledge,
+                                                         confWindowSize,
+                                                         null);
+
+               Packet pResponse;
+               try
+               {
+                  pResponse = channel1.sendBlocking(request);
+               }
+               catch (HornetQException e)
+               {
+                  if (e.getCode() == HornetQException.INCOMPATIBLE_CLIENT_SERVER_VERSIONS)
+                  {
+                     theConnection.destroy();
+                  }
+
+                  if (e.getCode() == HornetQException.UNBLOCKED)
+                  {
+                     // This means the thread was blocked on create session and failover unblocked it
+                     // so failover could occur
+
+                     retry = true;
+
+                     continue;
+                  }
+                  else
+                  {
+                     throw e;
+                  }
+               }
+
+               CreateSessionResponseMessage response = (CreateSessionResponseMessage)pResponse;
+
+               Channel sessionChannel = theConnection.getChannel(sessionChannelID, confWindowSize);
+
+               ClientSessionInternal session = new ClientSessionImpl(this,
+                                                                     name,
+                                                                     username,
+                                                                     password,
+                                                                     xa,
+                                                                     autoCommitSends,
+                                                                     autoCommitAcks,
+                                                                     preAcknowledge,
+                                                                     blockOnAcknowledge,
+                                                                     autoGroup,
+                                                                     ackBatchSize,
+                                                                     consumerWindowSize,
+                                                                     consumerMaxRate,
+                                                                     confWindowSize,
+                                                                     producerWindowSize,
+                                                                     producerMaxRate,
+                                                                     blockOnNonDurableSend,
+                                                                     blockOnDurableSend,
+                                                                     cacheLargeMessageClient,
+                                                                     minLargeMessageSize,
+                                                                     initialMessagePacketSize,
+                                                                     groupID,
+                                                                     theConnection,
+                                                                     response.getServerVersion(),
+                                                                     sessionChannel,
+                                                                     orderedExecutorFactory.getExecutor());
+
+               sessions.add(session);
+
+               ChannelHandler handler = new ClientSessionPacketHandler(session, sessionChannel);
+
+               sessionChannel.setHandler(handler);
+
+               return new DelegatingSession(session);
+            }
+            catch (Throwable t)
+            {
+               if (lock != null)
+               {
+                  lock.unlock();
+
+                  lock = null;
+               }
+
+               if (t instanceof HornetQException)
+               {
+                  throw (HornetQException)t;
+               }
+               else
+               {
+                  HornetQException me = new HornetQException(HornetQException.INTERNAL_ERROR,
+                                                             "Failed to create session", t);
+
+                  throw me;
+               }
+            }
+            finally
+            {
+               if (lock != null)
+               {
+                  lock.unlock();
+               }
+
+               // Execution has finished so notify any failover thread that may be waiting for us to be done
+               synchronized (exitLock)
+               {
+                  inCreateSession = false;
+
+                  exitLock.notify();
+               }
+            }
+         }
+         while (retry);
+      }
+
+      // Should never get here
+      throw new IllegalStateException("Oh my God it's full of stars!");
+   }
+
+   // Must be synchronized to prevent it happening concurrently with failover which can lead to
+   // inconsistencies
+   public void removeSession(final ClientSessionInternal session)
+   {
+      // TODO - can we simplify this locking?
+      synchronized (createSessionLock)
+      {
+         synchronized (failoverLock)
+         {
+            sessions.remove(session);
+
+            checkCloseConnection();
+         }
+      }
+   }
+
+   public synchronized int numConnections()
+   {
+      return connection != null ? 1 : 0;
+   }
+
+   public int numSessions()
+   {
+      return sessions.size();
+   }
+
+   public void addFailureListener(final SessionFailureListener listener)
+   {
+      listeners.add(listener);
+   }
+
+   public boolean removeFailureListener(final SessionFailureListener listener)
+   {
+      return listeners.remove(listener);
+   }
+
+   public void causeExit()
+   {
+      exitLoop = true;
+   }
+
+   // Public
+   // ---------------------------------------------------------------------------------------
+
+   public void stopPingingAfterOne()
+   {
+      stopPingingAfterOne = true;
+   }
+
+   // Protected
+   // ------------------------------------------------------------------------------------
+
+   // Package Private
+   // ------------------------------------------------------------------------------
+
+   // Private
+   // --------------------------------------------------------------------------------------
+
+   private void handleConnectionFailure(final Object connectionID, final HornetQException me)
+   {
+      failoverOrReconnect(connectionID, me);
+   }
+
+   private void failoverOrReconnect(final Object connectionID, final HornetQException me)
+   {
+      Set<ClientSessionInternal> sessionsToClose = null;
+
+      synchronized (failoverLock)
+      {
+         if (connection == null || connection.getID() != connectionID)
+         {
+            // We already failed over/reconnected - probably the first failure came in, all the connections were failed
+            // over then a async connection exception or disconnect
+            // came in for one of the already exitLoop connections, so we return true - we don't want to call the
+            // listeners again
+
+            return;
+         }
+
+         // We call before reconnection occurs to give the user a chance to do cleanup, like cancel messages
+         callFailureListeners(me, false);
+
+         // Now get locks on all channel 1s, whilst holding the failoverLock - this makes sure
+         // There are either no threads executing in createSession, or one is blocking on a createSession
+         // result.
+
+         // Then interrupt the channel 1 that is blocking (could just interrupt them all)
+
+         // Then release all channel 1 locks - this allows the createSession to exit the monitor
+
+         // Then get all channel 1 locks again - this ensures the any createSession thread has executed the section and
+         // returned all its connections to the connection manager (the code to return connections to connection manager
+         // must be inside the lock
+
+         // Then perform failover
+
+         // Then release failoverLock
+
+         // The other side of the bargain - during createSession:
+         // The calling thread must get the failoverLock and get its' connections when this is locked.
+         // While this is still locked it must then get the channel1 lock
+         // It can then release the failoverLock
+         // It should catch HornetQException.INTERRUPTED in the call to channel.sendBlocking
+         // It should then return its connections, with channel 1 lock still held
+         // It can then release the channel 1 lock, and retry (which will cause locking on failoverLock
+         // until failover is complete
+
+         boolean serverShutdown = me.getCode() == HornetQException.DISCONNECTED;
+
+         // We will try to failover if there is a backup connector factory, but we don't do this if the server
+         // has been shutdown cleanly unless failoverOnServerShutdown is true
+         boolean attemptFailover = backupConnectorFactory != null && (failoverOnServerShutdown || !serverShutdown);
+
+         boolean attemptReconnect;
+
+         if (attemptFailover)
+         {
+            attemptReconnect = false;
+         }
+         else
+         {
+            attemptReconnect = reconnectAttempts != 0;
+         }
+
+         if (attemptFailover || attemptReconnect)
+         {
+            lockChannel1();
+
+            final boolean needToInterrupt;
+
+            synchronized (exitLock)
+            {
+               needToInterrupt = inCreateSession;
+            }
+
+            unlockChannel1();
+
+            if (needToInterrupt)
+            {
+               // Forcing return all channels won't guarantee that any blocked thread will return immediately
+               // So we need to wait for it
+               forceReturnChannel1();
+
+               // Now we need to make sure that the thread has actually exited and returned it's connections
+               // before failover occurs
+
+               synchronized (exitLock)
+               {
+                  while (inCreateSession)
+                  {
+                     try
+                     {
+                        exitLock.wait(5000);
+                     }
+                     catch (InterruptedException e)
+                     {
+                     }
+                  }
+               }
+            }
+
+            // Now we absolutely know that no threads are executing in or blocked in createSession, and no
+            // more will execute it until failover is complete
+
+            // So.. do failover / reconnection
+
+            CoreRemotingConnection oldConnection = connection;
+
+            connection = null;
+
+            try
+            {
+               connector.close();
+            }
+            catch (Exception ignore)
+            {
+            }
+
+            cancelScheduledTasks();
+
+            connector = null;
+
+            if (attemptFailover)
+            {
+               // Now try failing over to backup
+
+               connectorFactory = backupConnectorFactory;
+
+               transportParams = backupTransportParams;
+
+               backupConnectorFactory = null;
+
+               backupTransportParams = null;
+
+               reconnectSessions(oldConnection, reconnectAttempts == -1 ? -1 : reconnectAttempts + 1);
+            }
+            else
+            {
+               reconnectSessions(oldConnection, reconnectAttempts);
+            }
+
+            oldConnection.destroy();
+         }
+         else
+         {
+            connection.destroy();
+
+            connection = null;
+         }
+
+         callFailureListeners(me, true);
+
+         if (connection == null)
+         {
+            sessionsToClose = new HashSet<ClientSessionInternal>(sessions);
+         }
+      }
+
+      // This needs to be outside the failover lock to prevent deadlock
+      if (sessionsToClose != null)
+      {
+         // If connection is null it means we didn't succeed in failing over or reconnecting
+         // so we close all the sessions, so they will throw exceptions when attempted to be used
+
+         for (ClientSessionInternal session : sessionsToClose)
+         {
+            try
+            {
+               session.cleanUp();
+            }
+            catch (Exception e)
+            {
+               FailoverManagerImpl.log.error("Failed to cleanup session");
+            }
+         }
+      }
+   }
+
+   private void callFailureListeners(final HornetQException me, final boolean afterReconnect)
+   {
+      final List<SessionFailureListener> listenersClone = new ArrayList<SessionFailureListener>(listeners);
+
+      for (final SessionFailureListener listener : listenersClone)
+      {
+         try
+         {
+            if (afterReconnect)
+            {
+               listener.connectionFailed(me);
+            }
+            else
+            {
+               listener.beforeReconnect(me);
+            }
+         }
+         catch (final Throwable t)
+         {
+            // Failure of one listener to execute shouldn't prevent others
+            // from
+            // executing
+            FailoverManagerImpl.log.error("Failed to execute failure listener", t);
+         }
+      }
+   }
+
+   /*
+    * Re-attach sessions all pre-existing sessions to the new remoting connection
+    */
+   private void reconnectSessions(final CoreRemotingConnection oldConnection, final int reconnectAttempts)
+   {
+      CoreRemotingConnection newConnection = getConnectionWithRetry(reconnectAttempts);
+
+      if (newConnection == null)
+      {
+         FailoverManagerImpl.log.warn("Failed to connect to server.");
+
+         return;
+      }
+
+      List<FailureListener> oldListeners = oldConnection.getFailureListeners();
+
+      List<FailureListener> newListeners = new ArrayList<FailureListener>(newConnection.getFailureListeners());
+
+      for (FailureListener listener : oldListeners)
+      {
+         // Add all apart from the first one which is the old DelegatingFailureListener
+
+         if (listener instanceof DelegatingFailureListener == false)
+         {
+            newListeners.add(listener);
+         }
+      }
+
+      newConnection.setFailureListeners(newListeners);
+
+      for (ClientSessionInternal session : sessions)
+      {
+         session.handleFailover(newConnection);
+      }
+   }
+
+   private CoreRemotingConnection getConnectionWithRetry(final int reconnectAttempts)
+   {
+      long interval = retryInterval;
+
+      int count = 0;
+
+      while (true)
+      {
+         if (exitLoop)
+         {
+            return null;
+         }
+
+         CoreRemotingConnection theConnection = getConnection();
+
+         if (theConnection == null)
+         {
+            // Failed to get connection
+
+            if (reconnectAttempts != 0)
+            {
+               count++;
+
+               if (reconnectAttempts != -1 && count == reconnectAttempts)
+               {
+                  FailoverManagerImpl.log.warn("Tried " + reconnectAttempts + " times to connect. Now giving up.");
+
+                  return null;
+               }
+
+               try
+               {
+                  Thread.sleep(interval);
+               }
+               catch (InterruptedException ignore)
+               {
+               }
+
+               // Exponential back-off
+               long newInterval = (long)(interval * retryIntervalMultiplier);
+
+               if (newInterval > maxRetryInterval)
+               {
+                  newInterval = maxRetryInterval;
+               }
+
+               interval = newInterval;
+            }
+            else
+            {
+               return null;
+            }
+         }
+         else
+         {
+
+            if (FailoverManagerImpl.debug)
+            {
+               checkAddDebug(theConnection);
+            }
+
+            return theConnection;
+         }
+      }
+   }
+
+   private void cancelScheduledTasks()
+   {
+      if (pingerFuture != null)
+      {
+         pingRunnable.cancel();
+
+         pingerFuture.cancel(false);
+
+         pingRunnable = null;
+
+         pingerFuture = null;
+      }
+   }
+
+   private void checkCloseConnection()
+   {
+      if (connection != null && sessions.size() == 0)
+      {
+         cancelScheduledTasks();
+
+         try
+         {
+            connection.destroy();
+         }
+         catch (Throwable ignore)
+         {
+         }
+
+         connection = null;
+
+         try
+         {
+            if (connector != null)
+            {
+               connector.close();
+            }
+         }
+         catch (Throwable ignore)
+         {
+         }
+
+         connector = null;
+      }
+   }
+
+   public CoreRemotingConnection getConnection()
+   {
+      if (connection == null)
+      {
+         Connection tc = null;
+
+         try
+         {
+            DelegatingBufferHandler handler = new DelegatingBufferHandler();
+
+            connector = connectorFactory.createConnector(transportParams,
+                                                         handler,
+                                                         this,
+                                                         closeExecutor,
+                                                         threadPool,
+                                                         scheduledThreadPool);
+
+            if (connector != null)
+            {
+               connector.start();
+
+               tc = connector.createConnection();
+
+               if (tc == null)
+               {
+                  try
+                  {
+                     connector.close();
+                  }
+                  catch (Throwable t)
+                  {
+                  }
+
+                  connector = null;
+               }
+            }
+         }
+         catch (Exception e)
+         {
+            // Sanity catch for badly behaved remoting plugins
+
+            FailoverManagerImpl.log.warn("connector.create or connectorFactory.createConnector should never throw an exception, implementation is badly behaved, but we'll deal with it anyway.",
+                                         e);
+
+            if (tc != null)
+            {
+               try
+               {
+                  tc.close();
+               }
+               catch (Throwable t)
+               {
+               }
+            }
+
+            if (connector != null)
+            {
+               try
+               {
+                  connector.close();
+               }
+               catch (Throwable t)
+               {
+               }
+            }
+
+            tc = null;
+
+            connector = null;
+         }
+
+         if (tc == null)
+         {
+            return connection;
+         }
+
+         connection = new RemotingConnectionImpl(tc, callTimeout, interceptors);
+
+         connection.addFailureListener(new DelegatingFailureListener(connection.getID()));
+
+         connection.getChannel(0, -1).setHandler(new Channel0Handler(connection));
+
+         if (clientFailureCheckPeriod != -1)
+         {
+            if (pingerFuture == null)
+            {
+               pingRunnable = new PingRunnable();
+
+               pingerFuture = scheduledThreadPool.scheduleWithFixedDelay(new ActualScheduledPinger(pingRunnable),
+                                                                         0,
+                                                                         clientFailureCheckPeriod,
+                                                                         TimeUnit.MILLISECONDS);
+            }
+            // send a ping every time we create a new remoting connection
+            // to set up its TTL on the server side
+            else
+            {
+               pingRunnable.run();
+            }
+         }
+      }
+
+      return connection;
+   }
+
+   private ConnectorFactory instantiateConnectorFactory(final String connectorFactoryClassName)
+   {
+      ClassLoader loader = Thread.currentThread().getContextClassLoader();
+      try
+      {
+         Class<?> clazz = loader.loadClass(connectorFactoryClassName);
+         return (ConnectorFactory)clazz.newInstance();
+      }
+      catch (Exception e)
+      {
+         throw new IllegalArgumentException("Error instantiating connector factory \"" + connectorFactoryClassName +
+                                            "\"", e);
+      }
+   }
+
+   private void lockChannel1()
+   {
+      Channel channel1 = connection.getChannel(1, -1);
+
+      channel1.getLock().lock();
+   }
+
+   private void unlockChannel1()
+   {
+      Channel channel1 = connection.getChannel(1, -1);
+
+      channel1.getLock().unlock();
+   }
+
+   private void forceReturnChannel1()
+   {
+      Channel channel1 = connection.getChannel(1, -1);
+
+      channel1.returnBlocking();
+   }
+
+   private void checkTransportKeys(final ConnectorFactory factory, final Map<String, Object> params)
+   {
+      if (params != null)
+      {
+         Set<String> invalid = ConfigurationHelper.checkKeys(factory.getAllowableProperties(), params.keySet());
+
+         if (!invalid.isEmpty())
+         {
+            String msg = ConfigurationHelper.stringSetToCommaListString("The following keys are invalid for configuring a connector: ",
+                                                                        invalid);
+
+            throw new IllegalStateException(msg);
+
+         }
+      }
+   }
+
+   private class Channel0Handler implements ChannelHandler
+   {
+      private final CoreRemotingConnection conn;
+
+      private Channel0Handler(final CoreRemotingConnection conn)
+      {
+         this.conn = conn;
+      }
+
+      public void handlePacket(final Packet packet)
+      {
+         final byte type = packet.getType();
+
+         if (type == PacketImpl.DISCONNECT)
+         {
+            closeExecutor.execute(new Runnable()
+            {
+               // Must be executed on new thread since cannot block the netty thread for a long time and fail can
+               // cause reconnect loop
+               public void run()
+               {
+                  conn.fail(new HornetQException(HornetQException.DISCONNECTED,
+                                                 "The connection was disconnected because of server shutdown"));
+               }
+            });
+         }
+      }
+   }
+
+   private class DelegatingBufferHandler implements BufferHandler
+   {
+      public void bufferReceived(final Object connectionID, final HornetQBuffer buffer)
+      {
+         CoreRemotingConnection theConn = connection;
+
+         if (theConn != null && connectionID == theConn.getID())
+         {
+            theConn.bufferReceived(connectionID, buffer);
+         }
+      }
+   }
+
+   private class DelegatingFailureListener implements FailureListener
+   {
+      private final Object connectionID;
+
+      DelegatingFailureListener(final Object connectionID)
+      {
+         this.connectionID = connectionID;
+      }
+
+      public void connectionFailed(final HornetQException me)
+      {
+         handleConnectionFailure(connectionID, me);
+      }
+   }
+
+   private static final class ActualScheduledPinger implements Runnable
+   {
+      private final WeakReference<PingRunnable> pingRunnable;
+
+      ActualScheduledPinger(final PingRunnable runnable)
+      {
+         pingRunnable = new WeakReference<PingRunnable>(runnable);
+      }
+
+      public void run()
+      {
+         PingRunnable runnable = pingRunnable.get();
+
+         if (runnable != null)
+         {
+            runnable.run();
+         }
+      }
+
+   }
+
+   private final class PingRunnable implements Runnable
+   {
+      private boolean cancelled;
+
+      private boolean first;
+
+      private long lastCheck = System.currentTimeMillis();
+
+      public synchronized void run()
+      {
+         if (cancelled || stopPingingAfterOne && !first)
+         {
+            return;
+         }
+
+         first = false;
+
+         long now = System.currentTimeMillis();
+
+         if (clientFailureCheckPeriod != -1 && now >= lastCheck + clientFailureCheckPeriod)
+         {
+            if (!connection.checkDataReceived())
+            {
+               final HornetQException me = new HornetQException(HornetQException.CONNECTION_TIMEDOUT,
+                                                                "Did not receive data from server for " + connection.getTransportConnection());
+
+               cancelled = true;
+
+               threadPool.execute(new Runnable()
+               {
+                  // Must be executed on different thread
+                  public void run()
+                  {
+                     connection.fail(me);
+                  }
+               });
+
+               return;
+            }
+            else
+            {
+               lastCheck = now;
+            }
+         }
+
+         // Send a ping
+
+         Ping ping = new Ping(connectionTTL);
+
+         Channel channel0 = connection.getChannel(0, -1);
+
+         channel0.send(ping);
+
+         connection.flush();
+      }
+
+      public synchronized void cancel()
+      {
+         cancelled = true;
+      }
+   }
+
+}

Copied: branches/2_2_0_HA_Improvements/src/main/org/hornetq/core/client/impl/FailoverManager_Old.java (from rev 9287, branches/2_2_0_HA_Improvements/src/main/org/hornetq/core/client/impl/FailoverManager.java)
===================================================================
--- branches/2_2_0_HA_Improvements/src/main/org/hornetq/core/client/impl/FailoverManager_Old.java	                        (rev 0)
+++ branches/2_2_0_HA_Improvements/src/main/org/hornetq/core/client/impl/FailoverManager_Old.java	2010-06-11 15:33:36 UTC (rev 9307)
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2009 Red Hat, Inc.
+ * Red Hat licenses this file to you under the Apache License, version
+ * 2.0 (the "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ * implied.  See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+package org.hornetq.core.client.impl;
+
+import org.hornetq.api.core.HornetQException;
+import org.hornetq.api.core.client.ClientSession;
+import org.hornetq.api.core.client.SessionFailureListener;
+import org.hornetq.core.protocol.core.CoreRemotingConnection;
+
+/**
+ * A ConnectionManager
+ *
+ * @author <a href="mailto:tim.fox at jboss.com">Tim Fox</a>
+ * 
+ * Created 27 Nov 2008 18:45:46
+ *
+ *
+ */
+public interface FailoverManager_Old
+{
+   ClientSession createSession(final String username,
+                               final String password,
+                               final boolean xa,
+                               final boolean autoCommitSends,
+                               final boolean autoCommitAcks,
+                               final boolean preAcknowledge,
+                               final int ackBatchSize,
+                               final boolean cacheLargeMessageClient,
+                               final int minLargeMessageSize,
+                               final boolean blockOnAcknowledge,
+                               final boolean autoGroup,
+                               final int confirmationWindowSize,
+                               final int producerWindowSize,
+                               final int consumerWindowSize,
+                               final int producerMaxRate,
+                               final int consumerMaxRate,
+                               final boolean blockOnNonDurableSend,
+                               final boolean blockOnDurableSend,
+                               final int initialMessagePacketSize,
+                               final String groupID) throws HornetQException;
+
+   void removeSession(final ClientSessionInternal session);
+
+   public CoreRemotingConnection getConnection();
+
+   int numConnections();
+
+   int numSessions();
+
+   void addFailureListener(SessionFailureListener listener);
+
+   boolean removeFailureListener(SessionFailureListener listener);
+
+   void causeExit();
+}

Modified: branches/2_2_0_HA_Improvements/src/main/org/hornetq/core/cluster/DiscoveryEntry.java
===================================================================
--- branches/2_2_0_HA_Improvements/src/main/org/hornetq/core/cluster/DiscoveryEntry.java	2010-06-11 04:11:42 UTC (rev 9306)
+++ branches/2_2_0_HA_Improvements/src/main/org/hornetq/core/cluster/DiscoveryEntry.java	2010-06-11 15:33:36 UTC (rev 9307)
@@ -13,7 +13,6 @@
 
 package org.hornetq.core.cluster;
 
-import org.hornetq.api.core.Pair;
 import org.hornetq.api.core.TransportConfiguration;
 
 /**
@@ -25,19 +24,20 @@
  */
 public class DiscoveryEntry
 {
-   private final Pair<TransportConfiguration, TransportConfiguration> connectorPair;
+   private final TransportConfiguration connector;
 
    private final long lastUpdate;
 
-   public DiscoveryEntry(final Pair<TransportConfiguration, TransportConfiguration> connectorPair, final long lastUpdate)
+   public DiscoveryEntry(final TransportConfiguration connector, final long lastUpdate)
    {
-      this.connectorPair = connectorPair;
+      this.connector = connector;
+      
       this.lastUpdate = lastUpdate;
    }
 
-   public Pair<TransportConfiguration, TransportConfiguration> getConnectorPair()
+   public TransportConfiguration getConnector()
    {
-      return connectorPair;
+      return connector;
    }
 
    public long getLastUpdate()

Modified: branches/2_2_0_HA_Improvements/src/main/org/hornetq/core/cluster/impl/DiscoveryGroupImpl.java
===================================================================
--- branches/2_2_0_HA_Improvements/src/main/org/hornetq/core/cluster/impl/DiscoveryGroupImpl.java	2010-06-11 04:11:42 UTC (rev 9306)
+++ branches/2_2_0_HA_Improvements/src/main/org/hornetq/core/cluster/impl/DiscoveryGroupImpl.java	2010-06-11 15:33:36 UTC (rev 9307)
@@ -26,7 +26,6 @@
 
 import org.hornetq.api.core.HornetQBuffer;
 import org.hornetq.api.core.HornetQBuffers;
-import org.hornetq.api.core.Pair;
 import org.hornetq.api.core.SimpleString;
 import org.hornetq.api.core.TransportConfiguration;
 import org.hornetq.api.core.management.NotificationType;
@@ -71,7 +70,7 @@
    private volatile boolean started;
 
    private final String nodeID;
-   
+
    private final InetAddress localBindAddress;
 
    private final InetAddress groupAddress;
@@ -94,7 +93,7 @@
       this.name = name;
 
       this.timeout = timeout;
-      
+
       this.localBindAddress = localBindAddress;
 
       this.groupAddress = groupAddress;
@@ -114,7 +113,8 @@
          return;
       }
 
-      try {
+      try
+      {
          socket = new MulticastSocket(groupPort);
 
          if (localBindAddress != null)
@@ -129,10 +129,10 @@
       catch (IOException e)
       {
          log.error("Failed to create discovery group socket", e);
-         
+
          return;
       }
-      
+
       started = true;
 
       thread = new Thread(this, "hornetq-discovery-group-thread-" + name);
@@ -144,11 +144,11 @@
       if (notificationService != null)
       {
          TypedProperties props = new TypedProperties();
-         
+
          props.putSimpleStringProperty(new SimpleString("name"), new SimpleString(name));
-         
+
          Notification notification = new Notification(nodeID, NotificationType.DISCOVERY_GROUP_STARTED, props);
-         
+
          notificationService.sendNotification(notification);
       }
    }
@@ -258,12 +258,11 @@
       else
       {
          if (!currentUniqueID.equals(uniqueID))
-         {            
-            log.warn("There are more than one servers on the network broadcasting the same node id. " +
-                     "You will see this message exactly once (per node) if a node is restarted, in which case it can be safely " + 
-                     "ignored. But if it is logged continuously it means you really do have more than one node on the same network " +
-                     "active concurrently with the same node id. This could occur if you have a backup node active at the same time as " +
-                     "its live node.");
+         {
+            log.warn("There are more than one servers on the network broadcasting the same node id. " + "You will see this message exactly once (per node) if a node is restarted, in which case it can be safely "
+                     + "ignored. But if it is logged continuously it means you really do have more than one node on the same network "
+                     + "active concurrently with the same node id. This could occur if you have a backup node active at the same time as "
+                     + "its live node.");
             uniqueIDMap.put(originatingNodeID, uniqueID);
          }
       }
@@ -308,7 +307,7 @@
             String uniqueID = buffer.readString();
 
             checkUniqueID(originatingNodeID, uniqueID);
-            
+
             if (nodeID.equals(originatingNodeID))
             {
                // Ignore traffic from own node
@@ -318,7 +317,7 @@
             int size = buffer.readInt();
 
             boolean changed = false;
-            
+
             synchronized (this)
             {
                for (int i = 0; i < size; i++)
@@ -326,23 +325,9 @@
                   TransportConfiguration connector = new TransportConfiguration();
 
                   connector.decode(buffer);
+                 
+                  DiscoveryEntry entry = new DiscoveryEntry(connector, System.currentTimeMillis());
 
-                  boolean existsBackup = buffer.readBoolean();
-
-                  TransportConfiguration backupConnector = null;
-
-                  if (existsBackup)
-                  {
-                     backupConnector = new TransportConfiguration();
-
-                     backupConnector.decode(buffer);
-                  }
-
-                  Pair<TransportConfiguration, TransportConfiguration> connectorPair = new Pair<TransportConfiguration, TransportConfiguration>(connector,
-                                                                                                                                                backupConnector);
-
-                  DiscoveryEntry entry = new DiscoveryEntry(connectorPair, System.currentTimeMillis());
-
                   DiscoveryEntry oldVal = connectors.put(originatingNodeID, entry);
 
                   if (oldVal == null)

Modified: branches/2_2_0_HA_Improvements/src/main/org/hornetq/core/config/BroadcastGroupConfiguration.java
===================================================================
--- branches/2_2_0_HA_Improvements/src/main/org/hornetq/core/config/BroadcastGroupConfiguration.java	2010-06-11 04:11:42 UTC (rev 9306)
+++ branches/2_2_0_HA_Improvements/src/main/org/hornetq/core/config/BroadcastGroupConfiguration.java	2010-06-11 15:33:36 UTC (rev 9307)
@@ -16,7 +16,6 @@
 import java.io.Serializable;
 import java.util.List;
 
-import org.hornetq.api.core.Pair;
 import org.hornetq.core.logging.Logger;
 
 /**
@@ -45,7 +44,7 @@
 
    private long broadcastPeriod;
 
-   private List<Pair<String, String>> connectorInfos;
+   private List<String> connectorInfos;
 
    public BroadcastGroupConfiguration(final String name,
                                       final String localBindAddress,
@@ -53,7 +52,7 @@
                                       final String groupAddress,
                                       final int groupPort,
                                       final long broadcastPeriod,
-                                      final List<Pair<String, String>> connectorInfos)
+                                      final List<String> connectorInfos)
    {
       super();
       this.name = name;
@@ -95,7 +94,7 @@
       return broadcastPeriod;
    }
 
-   public List<Pair<String, String>> getConnectorInfos()
+   public List<String> getConnectorInfos()
    {
       return connectorInfos;
    }
@@ -151,7 +150,7 @@
    /**
     * @param connectorInfos the connectorInfos to set
     */
-   public void setConnectorInfos(final List<Pair<String, String>> connectorInfos)
+   public void setConnectorInfos(final List<String> connectorInfos)
    {
       this.connectorInfos = connectorInfos;
    }

Modified: branches/2_2_0_HA_Improvements/src/main/org/hornetq/core/config/Configuration.java
===================================================================
--- branches/2_2_0_HA_Improvements/src/main/org/hornetq/core/config/Configuration.java	2010-06-11 04:11:42 UTC (rev 9306)
+++ branches/2_2_0_HA_Improvements/src/main/org/hornetq/core/config/Configuration.java	2010-06-11 15:33:36 UTC (rev 9307)
@@ -258,16 +258,15 @@
    void setConnectorConfigurations(Map<String, TransportConfiguration> infos);
 
    /**
-    * Returns the name of the connector used to connect to the backup.
-    * <br>
-    * If this server has no backup or is itself a backup, the value is {@code null}.
+    * Returns the name of the connector used to connect to the live node - only used when using shared nothing (shared store = false).
+    * <br> 
     */
-   String getBackupConnectorName();
+   String getLiveConnectorName();
 
    /**
-    * Sets the name of the connector used to connect to the backup.
+    * Sets the name of the connector used to connect to the live node - only used when using shared nothing (shared store = false).
     */
-   void setBackupConnectorName(String name);
+   void setLiveConnectorName(String name);
 
    /**
     * Returns the broadcast groups configured for this server.

Modified: branches/2_2_0_HA_Improvements/src/main/org/hornetq/core/config/impl/ConfigurationImpl.java
===================================================================
--- branches/2_2_0_HA_Improvements/src/main/org/hornetq/core/config/impl/ConfigurationImpl.java	2010-06-11 04:11:42 UTC (rev 9306)
+++ branches/2_2_0_HA_Improvements/src/main/org/hornetq/core/config/impl/ConfigurationImpl.java	2010-06-11 15:33:36 UTC (rev 9307)
@@ -225,7 +225,7 @@
 
    protected Set<TransportConfiguration> acceptorConfigs = new HashSet<TransportConfiguration>();
 
-   protected String backupConnectorName;
+   protected String liveConnectorName;
 
    protected List<BridgeConfiguration> bridgeConfigurations = new ArrayList<BridgeConfiguration>();
 
@@ -477,14 +477,14 @@
       connectorConfigs = infos;
    }
 
-   public String getBackupConnectorName()
+   public String getLiveConnectorName()
    {
-      return backupConnectorName;
+      return liveConnectorName;
    }
 
-   public void setBackupConnectorName(final String backupConnectorName)
+   public void setLiveConnectorName(final String liveConnectorName)
    {
-      this.backupConnectorName = backupConnectorName;
+      this.liveConnectorName = liveConnectorName;
    }
    
    public GroupingHandlerConfiguration getGroupingHandlerConfiguration()
@@ -1015,14 +1015,14 @@
       {
          return false;
       }
-      if (backupConnectorName == null)
+      if (liveConnectorName == null)
       {
-         if (other.backupConnectorName != null)
+         if (other.liveConnectorName != null)
          {
             return false;
          }
       }
-      else if (!backupConnectorName.equals(other.backupConnectorName))
+      else if (!liveConnectorName.equals(other.liveConnectorName))
       {
          return false;
       }

Modified: branches/2_2_0_HA_Improvements/src/main/org/hornetq/core/config/impl/FileConfiguration.java
===================================================================
--- branches/2_2_0_HA_Improvements/src/main/org/hornetq/core/config/impl/FileConfiguration.java	2010-06-11 04:11:42 UTC (rev 9306)
+++ branches/2_2_0_HA_Improvements/src/main/org/hornetq/core/config/impl/FileConfiguration.java	2010-06-11 15:33:36 UTC (rev 9307)
@@ -47,7 +47,7 @@
 
    // Attributes ----------------------------------------------------------------------
 
-   private String configurationUrl = FileConfiguration.DEFAULT_CONFIGURATION_URL;
+   private String configurationUrl = DEFAULT_CONFIGURATION_URL;
 
    private boolean started;
 

Modified: branches/2_2_0_HA_Improvements/src/main/org/hornetq/core/deployers/impl/FileConfigurationParser.java
===================================================================
--- branches/2_2_0_HA_Improvements/src/main/org/hornetq/core/deployers/impl/FileConfigurationParser.java	2010-06-11 04:11:42 UTC (rev 9306)
+++ branches/2_2_0_HA_Improvements/src/main/org/hornetq/core/deployers/impl/FileConfigurationParser.java	2010-06-11 15:33:36 UTC (rev 9307)
@@ -31,15 +31,14 @@
 import org.hornetq.core.config.BroadcastGroupConfiguration;
 import org.hornetq.core.config.ClusterConnectionConfiguration;
 import org.hornetq.core.config.Configuration;
+import org.hornetq.core.config.CoreQueueConfiguration;
 import org.hornetq.core.config.DiscoveryGroupConfiguration;
 import org.hornetq.core.config.DivertConfiguration;
-import org.hornetq.core.config.CoreQueueConfiguration;
 import org.hornetq.core.config.impl.ConfigurationImpl;
 import org.hornetq.core.config.impl.FileConfiguration;
 import org.hornetq.core.config.impl.Validators;
 import org.hornetq.core.journal.impl.AIOSequentialFileFactory;
 import org.hornetq.core.logging.Logger;
-import org.hornetq.core.persistence.impl.journal.JournalStorageManager;
 import org.hornetq.core.security.Role;
 import org.hornetq.core.server.JournalType;
 import org.hornetq.core.server.group.impl.GroupingHandlerConfiguration;
@@ -278,15 +277,15 @@
 
       config.setInterceptorClassNames(interceptorList);
 
-      NodeList backups = e.getElementsByTagName("backup-connector-ref");
+      NodeList lives = e.getElementsByTagName("live-connector-ref");
 
-      // There should be only one - this will be enforced by the DTD
+      // There should be at most one - this will be enforced by the DTD
 
-      if (backups.getLength() > 0)
+      if (lives.getLength() > 0)
       {
-         Node backupNode = backups.item(0);
+         Node liveNode = lives.item(0);
 
-         config.setBackupConnectorName(backupNode.getAttributes().getNamedItem("connector-name").getNodeValue());
+         config.setLiveConnectorName(liveNode.getAttributes().getNamedItem("connector-name").getNodeValue());
       }
 
       NodeList connectorNodes = e.getElementsByTagName("connector");
@@ -872,7 +871,7 @@
 
       NodeList children = e.getChildNodes();
 
-      List<Pair<String, String>> connectorNames = new ArrayList<Pair<String, String>>();
+      List<String> connectorNames = new ArrayList<String>();
 
       for (int j = 0; j < children.getLength(); j++)
       {
@@ -882,18 +881,7 @@
          {
             String connectorName = child.getAttributes().getNamedItem("connector-name").getNodeValue();
 
-            Node backupConnectorNode = child.getAttributes().getNamedItem("backup-connector-name");
-
-            String backupConnectorName = null;
-
-            if (backupConnectorNode != null)
-            {
-               backupConnectorName = backupConnectorNode.getNodeValue();
-            }
-
-            Pair<String, String> connectorInfo = new Pair<String, String>(connectorName, backupConnectorName);
-
-            connectorNames.add(connectorInfo);
+            connectorNames.add(connectorName);
          }
       }
 

Modified: branches/2_2_0_HA_Improvements/src/main/org/hornetq/core/management/impl/BroadcastGroupControlImpl.java
===================================================================
--- branches/2_2_0_HA_Improvements/src/main/org/hornetq/core/management/impl/BroadcastGroupControlImpl.java	2010-06-11 04:11:42 UTC (rev 9306)
+++ branches/2_2_0_HA_Improvements/src/main/org/hornetq/core/management/impl/BroadcastGroupControlImpl.java	2010-06-11 15:33:36 UTC (rev 9307)
@@ -15,14 +15,11 @@
 
 import javax.management.MBeanOperationInfo;
 
-import org.hornetq.api.core.Pair;
-import org.hornetq.api.core.management.AddressControl;
 import org.hornetq.api.core.management.BroadcastGroupControl;
 import org.hornetq.core.config.BroadcastGroupConfiguration;
 import org.hornetq.core.persistence.StorageManager;
 import org.hornetq.core.server.cluster.BroadcastGroup;
 import org.hornetq.utils.json.JSONArray;
-import org.hornetq.utils.json.JSONObject;
 
 /**
  * A BroadcastGroupControl
@@ -91,14 +88,9 @@
          Object[] ret = new Object[configuration.getConnectorInfos().size()];
 
          int i = 0;
-         for (Pair<String, String> pair : configuration.getConnectorInfos())
+         for (String connector : configuration.getConnectorInfos())
          {
-            String[] opair = new String[2];
-
-            opair[0] = pair.a;
-            opair[1] = pair.b != null ? pair.b : null;
-
-            ret[i++] = opair;
+            ret[i++] = connector;
          }
 
          return ret;
@@ -116,12 +108,9 @@
       {
          JSONArray array = new JSONArray();
 
-         for (Pair<String, String> pair : configuration.getConnectorInfos())
+         for (String connector : configuration.getConnectorInfos())
          {
-            JSONObject p = new JSONObject();
-            p.put("a", pair.a);
-            p.put("b", pair.b);
-            array.put(p);
+            array.put(connector);
          }
          return array.toString();
       }

Modified: branches/2_2_0_HA_Improvements/src/main/org/hornetq/core/management/impl/HornetQServerControlImpl.java
===================================================================
--- branches/2_2_0_HA_Improvements/src/main/org/hornetq/core/management/impl/HornetQServerControlImpl.java	2010-06-11 04:11:42 UTC (rev 9306)
+++ branches/2_2_0_HA_Improvements/src/main/org/hornetq/core/management/impl/HornetQServerControlImpl.java	2010-06-11 15:33:36 UTC (rev 9307)
@@ -175,14 +175,14 @@
       }
    }
 
-   public String getBackupConnectorName()
+   public String getLiveConnectorName()
    {
       checkStarted();
 
       clearIO();
       try
       {
-         return configuration.getBackupConnectorName();
+         return configuration.getLiveConnectorName();
       }
       finally
       {

Modified: branches/2_2_0_HA_Improvements/src/main/org/hornetq/core/persistence/StorageManager.java
===================================================================
--- branches/2_2_0_HA_Improvements/src/main/org/hornetq/core/persistence/StorageManager.java	2010-06-11 04:11:42 UTC (rev 9306)
+++ branches/2_2_0_HA_Improvements/src/main/org/hornetq/core/persistence/StorageManager.java	2010-06-11 15:33:36 UTC (rev 9307)
@@ -13,7 +13,6 @@
 
 package org.hornetq.core.persistence;
 
-import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
 import java.util.concurrent.Executor;
@@ -82,11 +81,7 @@
    void waitOnOperations() throws Exception;
 
    void clearContext();
-
-   UUID getPersistentID();
-
-   void setPersistentID(UUID id) throws Exception;
-
+   
    long generateUniqueID();
 
    long getCurrentUniqueID();

Modified: branches/2_2_0_HA_Improvements/src/main/org/hornetq/core/persistence/impl/journal/JournalStorageManager.java
===================================================================
--- branches/2_2_0_HA_Improvements/src/main/org/hornetq/core/persistence/impl/journal/JournalStorageManager.java	2010-06-11 04:11:42 UTC (rev 9306)
+++ branches/2_2_0_HA_Improvements/src/main/org/hornetq/core/persistence/impl/journal/JournalStorageManager.java	2010-06-11 15:33:36 UTC (rev 9307)
@@ -100,8 +100,6 @@
 
    public static final byte QUEUE_BINDING_RECORD = 21;
 
-   public static final byte PERSISTENT_ID_RECORD = 23;
-
    public static final byte ID_COUNTER_RECORD = 24;
 
    public static final byte ADDRESS_SETTING_RECORD = 25;
@@ -133,8 +131,6 @@
 
    public static final byte HEURISTIC_COMPLETION = 38;
 
-   private UUID persistentID;
-
    private final BatchingIDGenerator idGenerator;
 
    private final ReplicationManager replicator;
@@ -261,14 +257,7 @@
          throw new IllegalArgumentException("Unsupported journal type " + config.getJournalType());
       }
 
-      if (config.isBackup())
-      {
-         idGenerator = null;
-      }
-      else
-      {
-         idGenerator = new BatchingIDGenerator(0, JournalStorageManager.CHECKPOINT_BATCH_SIZE, bindingsJournal);
-      }
+      idGenerator = new BatchingIDGenerator(0, JournalStorageManager.CHECKPOINT_BATCH_SIZE, bindingsJournal);      
 
       Journal localMessage = new JournalImpl(config.getJournalFileSize(),
                                              config.getJournalMinFiles(),
@@ -393,26 +382,6 @@
       getContext().executeOnCompletion(run);
    }
 
-   public UUID getPersistentID()
-   {
-      return persistentID;
-   }
-
-   public void setPersistentID(final UUID id) throws Exception
-   {
-      long recordID = generateUniqueID();
-
-      if (id != null)
-      {
-         bindingsJournal.appendAddRecord(recordID,
-                                         JournalStorageManager.PERSISTENT_ID_RECORD,
-                                         new PersistentIDEncoding(id),
-                                         true);
-      }
-
-      persistentID = id;
-   }
-
    public long generateUniqueID()
    {
       long id = idGenerator.generateID();
@@ -1079,14 +1048,6 @@
 
             queueBindingInfos.add(bindingEncoding);
          }
-         else if (rec == JournalStorageManager.PERSISTENT_ID_RECORD)
-         {
-            PersistentIDEncoding encoding = new PersistentIDEncoding();
-
-            encoding.decode(buffer);
-
-            persistentID = encoding.uuid;
-         }
          else if (rec == JournalStorageManager.ID_COUNTER_RECORD)
          {
             idGenerator.loadState(record.id, buffer);
@@ -1154,17 +1115,12 @@
       }
 
       // Must call close to make sure last id is persisted
-      if (idGenerator != null)
-      {
-         idGenerator.close();
-      }
+      idGenerator.close();      
 
       bindingsJournal.stop();
 
       messageJournal.stop();
 
-      persistentID = null;
-
       started = false;
    }
 

Modified: branches/2_2_0_HA_Improvements/src/main/org/hornetq/core/persistence/impl/nullpm/NullStorageManager.java
===================================================================
--- branches/2_2_0_HA_Improvements/src/main/org/hornetq/core/persistence/impl/nullpm/NullStorageManager.java	2010-06-11 04:11:42 UTC (rev 9306)
+++ branches/2_2_0_HA_Improvements/src/main/org/hornetq/core/persistence/impl/nullpm/NullStorageManager.java	2010-06-11 15:33:36 UTC (rev 9307)
@@ -13,7 +13,6 @@
 
 package org.hornetq.core.persistence.impl.nullpm;
 
-import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
 import java.util.Map;
@@ -46,7 +45,6 @@
 import org.hornetq.core.server.ServerMessage;
 import org.hornetq.core.server.group.impl.GroupBinding;
 import org.hornetq.core.transaction.ResourceManager;
-import org.hornetq.utils.UUID;
 
 /**
  * 
@@ -60,20 +58,8 @@
 {
    private final AtomicLong idSequence = new AtomicLong(0);
 
-   private UUID id;
-
    private volatile boolean started;
 
-   public UUID getPersistentID()
-   {
-      return id;
-   }
-
-   public void setPersistentID(final UUID id)
-   {
-      this.id = id;
-   }
-
    public void sync()
    {
       // NO OP
@@ -247,8 +233,6 @@
          throw new IllegalStateException("Not started");
       }
 
-      id = null;
-
       idSequence.set(0);
 
       started = false;

Modified: branches/2_2_0_HA_Improvements/src/main/org/hornetq/core/protocol/core/impl/PacketDecoder.java
===================================================================
--- branches/2_2_0_HA_Improvements/src/main/org/hornetq/core/protocol/core/impl/PacketDecoder.java	2010-06-11 04:11:42 UTC (rev 9306)
+++ branches/2_2_0_HA_Improvements/src/main/org/hornetq/core/protocol/core/impl/PacketDecoder.java	2010-06-11 15:33:36 UTC (rev 9307)
@@ -13,6 +13,7 @@
 
 package org.hornetq.core.protocol.core.impl;
 
+import static org.hornetq.core.protocol.core.impl.PacketImpl.CLUSTER_TOPOLOGY;
 import static org.hornetq.core.protocol.core.impl.PacketImpl.CREATESESSION;
 import static org.hornetq.core.protocol.core.impl.PacketImpl.CREATESESSION_RESP;
 import static org.hornetq.core.protocol.core.impl.PacketImpl.CREATE_QUEUE;
@@ -82,6 +83,7 @@
 import org.hornetq.api.core.HornetQBuffer;
 import org.hornetq.core.logging.Logger;
 import org.hornetq.core.protocol.core.Packet;
+import org.hornetq.core.protocol.core.impl.wireformat.ClusterTopologyMessage;
 import org.hornetq.core.protocol.core.impl.wireformat.CreateQueueMessage;
 import org.hornetq.core.protocol.core.impl.wireformat.CreateReplicationSessionMessage;
 import org.hornetq.core.protocol.core.impl.wireformat.CreateSessionMessage;
@@ -486,6 +488,11 @@
             packet = new SessionForceConsumerDelivery();
             break;
          }
+         case CLUSTER_TOPOLOGY:
+         {
+            packet = new ClusterTopologyMessage();
+            break;
+         }
          default:
          {
             throw new IllegalArgumentException("Invalid type: " + packetType);

Modified: branches/2_2_0_HA_Improvements/src/main/org/hornetq/core/protocol/core/impl/PacketImpl.java
===================================================================
--- branches/2_2_0_HA_Improvements/src/main/org/hornetq/core/protocol/core/impl/PacketImpl.java	2010-06-11 04:11:42 UTC (rev 9306)
+++ branches/2_2_0_HA_Improvements/src/main/org/hornetq/core/protocol/core/impl/PacketImpl.java	2010-06-11 15:33:36 UTC (rev 9307)
@@ -181,6 +181,10 @@
    public static final byte REPLICATION_COMPARE_DATA = 102;
 
    public static final byte REPLICATION_SYNC = 103;
+   
+   // HA
+   
+   public static final byte CLUSTER_TOPOLOGY = 110;
 
    // Static --------------------------------------------------------
 

Modified: branches/2_2_0_HA_Improvements/src/main/org/hornetq/core/server/cluster/BroadcastGroup.java
===================================================================
--- branches/2_2_0_HA_Improvements/src/main/org/hornetq/core/server/cluster/BroadcastGroup.java	2010-06-11 04:11:42 UTC (rev 9306)
+++ branches/2_2_0_HA_Improvements/src/main/org/hornetq/core/server/cluster/BroadcastGroup.java	2010-06-11 15:33:36 UTC (rev 9307)
@@ -13,7 +13,6 @@
 
 package org.hornetq.core.server.cluster;
 
-import org.hornetq.api.core.Pair;
 import org.hornetq.api.core.TransportConfiguration;
 import org.hornetq.core.server.HornetQComponent;
 import org.hornetq.core.server.management.NotificationService;
@@ -34,9 +33,9 @@
 
    String getName();
 
-   void addConnectorPair(Pair<TransportConfiguration, TransportConfiguration> connectorPair);
+   void addConnector(TransportConfiguration tcConfig);
 
-   void removeConnectorPair(Pair<TransportConfiguration, TransportConfiguration> connectorPair);
+   void removeConnector(TransportConfiguration tcConfig);
 
    int size();
 

Modified: branches/2_2_0_HA_Improvements/src/main/org/hornetq/core/server/cluster/ClusterManager.java
===================================================================
--- branches/2_2_0_HA_Improvements/src/main/org/hornetq/core/server/cluster/ClusterManager.java	2010-06-11 04:11:42 UTC (rev 9306)
+++ branches/2_2_0_HA_Improvements/src/main/org/hornetq/core/server/cluster/ClusterManager.java	2010-06-11 15:33:36 UTC (rev 9307)
@@ -13,10 +13,13 @@
 
 package org.hornetq.core.server.cluster;
 
+import java.util.List;
 import java.util.Map;
 import java.util.Set;
 
+import org.hornetq.api.core.Pair;
 import org.hornetq.api.core.SimpleString;
+import org.hornetq.api.core.TransportConfiguration;
 import org.hornetq.core.server.HornetQComponent;
 
 /**
@@ -38,4 +41,14 @@
    Set<BroadcastGroup> getBroadcastGroups();
 
    void activate();
+   
+   void startAnnouncement();
+   
+   void stopAnnouncement();
+   
+   List<Pair<TransportConfiguration, TransportConfiguration>> getClusterTopology();
+   
+   void registerTopologyListener(ClusterTopologyListener listener);
+   
+   void unregisterTopologyListener(ClusterTopologyListener listener);
 }

Modified: branches/2_2_0_HA_Improvements/src/main/org/hornetq/core/server/cluster/impl/BroadcastGroupImpl.java
===================================================================
--- branches/2_2_0_HA_Improvements/src/main/org/hornetq/core/server/cluster/impl/BroadcastGroupImpl.java	2010-06-11 04:11:42 UTC (rev 9306)
+++ branches/2_2_0_HA_Improvements/src/main/org/hornetq/core/server/cluster/impl/BroadcastGroupImpl.java	2010-06-11 15:33:36 UTC (rev 9307)
@@ -22,7 +22,6 @@
 
 import org.hornetq.api.core.HornetQBuffer;
 import org.hornetq.api.core.HornetQBuffers;
-import org.hornetq.api.core.Pair;
 import org.hornetq.api.core.SimpleString;
 import org.hornetq.api.core.TransportConfiguration;
 import org.hornetq.api.core.management.NotificationType;
@@ -59,7 +58,7 @@
 
    private DatagramSocket socket;
 
-   private final List<Pair<TransportConfiguration, TransportConfiguration>> connectorPairs = new ArrayList<Pair<TransportConfiguration, TransportConfiguration>>();
+   private final List<TransportConfiguration> connectors = new ArrayList<TransportConfiguration>();
 
    private boolean started;
 
@@ -181,19 +180,19 @@
       return name;
    }
 
-   public synchronized void addConnectorPair(final Pair<TransportConfiguration, TransportConfiguration> connectorPair)
+   public synchronized void addConnector(final TransportConfiguration tcConfig)
    {
-      connectorPairs.add(connectorPair);
+      connectors.add(tcConfig);
    }
 
-   public synchronized void removeConnectorPair(final Pair<TransportConfiguration, TransportConfiguration> connectorPair)
+   public synchronized void removeConnector(final TransportConfiguration tcConfig)
    {
-      connectorPairs.remove(connectorPair);
+      connectors.remove(tcConfig);
    }
 
    public synchronized int size()
    {
-      return connectorPairs.size();
+      return connectors.size();
    }
 
    public synchronized void activate()
@@ -214,22 +213,11 @@
 
       buff.writeString(uniqueID);
 
-      buff.writeInt(connectorPairs.size());
+      buff.writeInt(connectors.size());
 
-      for (Pair<TransportConfiguration, TransportConfiguration> connectorPair : connectorPairs)
+      for (TransportConfiguration tcConfig : connectors)
       {
-         connectorPair.a.encode(buff);
-
-         if (connectorPair.b != null)
-         {
-            buff.writeBoolean(true);
-
-            connectorPair.b.encode(buff);
-         }
-         else
-         {
-            buff.writeBoolean(false);
-         }
+         tcConfig.encode(buff);
       }
 
       byte[] data = buff.toByteBuffer().array();

Modified: branches/2_2_0_HA_Improvements/src/main/org/hornetq/core/server/cluster/impl/ClusterManagerImpl.java
===================================================================
--- branches/2_2_0_HA_Improvements/src/main/org/hornetq/core/server/cluster/impl/ClusterManagerImpl.java	2010-06-11 04:11:42 UTC (rev 9306)
+++ branches/2_2_0_HA_Improvements/src/main/org/hornetq/core/server/cluster/impl/ClusterManagerImpl.java	2010-06-11 15:33:36 UTC (rev 9307)
@@ -44,8 +44,11 @@
 import org.hornetq.core.server.cluster.BroadcastGroup;
 import org.hornetq.core.server.cluster.ClusterConnection;
 import org.hornetq.core.server.cluster.ClusterManager;
+import org.hornetq.core.server.cluster.ClusterTopologyListener;
 import org.hornetq.core.server.cluster.Transformer;
 import org.hornetq.core.server.management.ManagementService;
+import org.hornetq.utils.ConcurrentHashSet;
+import org.hornetq.utils.ExecutorFactory;
 import org.hornetq.utils.UUID;
 
 /**
@@ -67,9 +70,9 @@
 
    private final Map<String, Bridge> bridges = new HashMap<String, Bridge>();
 
-   private final Map<String, ClusterConnection> clusters = new HashMap<String, ClusterConnection>();
+   private final Map<String, ClusterConnection> clusterConnections = new HashMap<String, ClusterConnection>();
 
-   private final org.hornetq.utils.ExecutorFactory executorFactory;
+   private final ExecutorFactory executorFactory;
 
    private final HornetQServer server;
 
@@ -89,7 +92,7 @@
 
    private final boolean clustered;
 
-   public ClusterManagerImpl(final org.hornetq.utils.ExecutorFactory executorFactory,
+   public ClusterManagerImpl(final ExecutorFactory executorFactory,
                              final HornetQServer server,
                              final PostOffice postOffice,
                              final ScheduledExecutorService scheduledExecutor,
@@ -177,7 +180,7 @@
             managementService.unregisterDiscoveryGroup(group.getName());
          }
 
-         for (ClusterConnection clusterConnection : clusters.values())
+         for (ClusterConnection clusterConnection : clusterConnections.values())
          {
             clusterConnection.stop();
             managementService.unregisterCluster(clusterConnection.getName().toString());
@@ -211,7 +214,7 @@
 
    public Set<ClusterConnection> getClusterConnections()
    {
-      return new HashSet<ClusterConnection>(clusters.values());
+      return new HashSet<ClusterConnection>(clusterConnections.values());
    }
 
    public Set<BroadcastGroup> getBroadcastGroups()
@@ -221,7 +224,7 @@
 
    public ClusterConnection getClusterConnection(final SimpleString name)
    {
-      return clusters.get(name.toString());
+      return clusterConnections.get(name.toString());
    }
 
    public synchronized void activate()
@@ -236,13 +239,42 @@
          bridge.activate();
       }
 
-      for (ClusterConnection cc : clusters.values())
+      for (ClusterConnection cc : clusterConnections.values())
       {
          cc.activate();
       }
 
       backup = false;
    }
+   
+   public void startAnnouncement()
+   {
+      
+   }
+   
+   public void stopAnnouncement()
+   {
+      
+   }
+   
+   private Set<ClusterTopologyListener> listeners = new ConcurrentHashSet<ClusterTopologyListener>();
+   
+   private List<Pair<TransportConfiguration, TransportConfiguration>> topology;
+   
+   public List<Pair<TransportConfiguration, TransportConfiguration>> getClusterTopology()
+   {
+      return topology;
+   }
+   
+   public void registerTopologyListener(final ClusterTopologyListener listener)
+   {
+      listeners.add(listener);
+   }
+   
+   public void unregisterTopologyListener(final ClusterTopologyListener listener)
+   {
+      listeners.remove(listener);
+   }
 
    private synchronized void deployBroadcastGroup(final BroadcastGroupConfiguration config) throws Exception
    {
@@ -270,32 +302,18 @@
                                                         config.getGroupPort(),
                                                         !backup);
 
-      for (Pair<String, String> connectorInfo : config.getConnectorInfos())
+      for (String connectorInfo : config.getConnectorInfos())
       {
-         TransportConfiguration connector = configuration.getConnectorConfigurations().get(connectorInfo.a);
+         TransportConfiguration connector = configuration.getConnectorConfigurations().get(connectorInfo);
 
          if (connector == null)
          {
-            logWarnNoConnector(config.getName(), connectorInfo.a);
+            logWarnNoConnector(config.getName(), connectorInfo);
 
             return;
          }
 
-         TransportConfiguration backupConnector = null;
-
-         if (connectorInfo.b != null)
-         {
-            backupConnector = configuration.getConnectorConfigurations().get(connectorInfo.b);
-
-            if (connector == null)
-            {
-               logWarnNoConnector(config.getName(), connectorInfo.b);
-
-               return;
-            }
-         }
-
-         group.addConnectorPair(new Pair<TransportConfiguration, TransportConfiguration>(connector, backupConnector));
+         group.addConnector(connector);
       }
 
       ScheduledFuture<?> future = scheduledExecutor.scheduleWithFixedDelay(group,
@@ -607,7 +625,7 @@
 
       managementService.registerCluster(clusterConnection, config);
 
-      clusters.put(config.getName(), clusterConnection);
+      clusterConnections.put(config.getName(), clusterConnection);
 
       clusterConnection.start();
    }

Modified: branches/2_2_0_HA_Improvements/src/main/org/hornetq/core/server/impl/HornetQServerImpl.java
===================================================================
--- branches/2_2_0_HA_Improvements/src/main/org/hornetq/core/server/impl/HornetQServerImpl.java	2010-06-11 04:11:42 UTC (rev 9306)
+++ branches/2_2_0_HA_Improvements/src/main/org/hornetq/core/server/impl/HornetQServerImpl.java	2010-06-11 15:33:36 UTC (rev 9307)
@@ -13,6 +13,13 @@
 
 package org.hornetq.core.server.impl;
 
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.InputStream;
+import java.io.OutputStream;
 import java.lang.management.ManagementFactory;
 import java.security.AccessController;
 import java.security.PrivilegedAction;
@@ -40,8 +47,6 @@
 import org.hornetq.api.core.client.ClientSessionFactory;
 import org.hornetq.api.core.client.HornetQClient;
 import org.hornetq.core.client.impl.ClientSessionFactoryImpl;
-import org.hornetq.core.client.impl.FailoverManager;
-import org.hornetq.core.client.impl.FailoverManagerImpl;
 import org.hornetq.core.config.Configuration;
 import org.hornetq.core.config.CoreQueueConfiguration;
 import org.hornetq.core.config.DivertConfiguration;
@@ -80,8 +85,6 @@
 import org.hornetq.core.remoting.server.impl.RemotingServiceImpl;
 import org.hornetq.core.replication.ReplicationEndpoint;
 import org.hornetq.core.replication.ReplicationManager;
-import org.hornetq.core.replication.impl.ReplicationEndpointImpl;
-import org.hornetq.core.replication.impl.ReplicationManagerImpl;
 import org.hornetq.core.security.CheckType;
 import org.hornetq.core.security.Role;
 import org.hornetq.core.security.SecurityStore;
@@ -94,8 +97,10 @@
 import org.hornetq.core.server.QueueFactory;
 import org.hornetq.core.server.ServerSession;
 import org.hornetq.core.server.cluster.ClusterManager;
+import org.hornetq.core.server.cluster.LockFile;
 import org.hornetq.core.server.cluster.Transformer;
 import org.hornetq.core.server.cluster.impl.ClusterManagerImpl;
+import org.hornetq.core.server.cluster.impl.LockFileImpl;
 import org.hornetq.core.server.group.GroupingHandler;
 import org.hornetq.core.server.group.impl.GroupBinding;
 import org.hornetq.core.server.group.impl.GroupingHandlerConfiguration;
@@ -274,6 +279,329 @@
    // lifecycle methods
    // ----------------------------------------------------------------
 
+   private interface Activation extends Runnable
+   {
+      void close() throws Exception;
+   }
+
+   /*
+    * Can be overridden for tests
+    */
+   protected LockFile createLockFile(final String fileName, final String directory)
+   {
+      return new LockFileImpl(fileName, directory);
+   }
+
+   private class SharedStoreLiveActivation implements Activation
+   {
+      LockFile liveLock;
+
+      public void run()
+      {
+         try
+         {
+            log.info("Waiting to obtain live lock");
+
+            File journalDir = new File(configuration.getJournalDirectory());
+
+            if (!journalDir.exists())
+            {
+               if (configuration.isCreateJournalDir())
+               {
+                  journalDir.mkdirs();
+               }
+               else
+               {
+                  throw new IllegalArgumentException("Directory " + journalDir +
+                                                     " does not exist and will not create it");
+               }
+            }
+
+            liveLock = createLockFile("live.lock", configuration.getJournalDirectory());
+
+            liveLock.lock();
+
+            log.info("Obtained live lock");
+
+            // We now load the node id file, creating it, if it doesn't exist yet
+            File nodeIDFile = new File(configuration.getJournalDirectory(), "node.id");
+
+            if (!nodeIDFile.exists())
+            {
+               // We use another file lock to prevent a backup reading it before it is complete
+
+               LockFile nodeIDLockFile = createLockFile("nodeid.lock", configuration.getJournalDirectory());
+
+               nodeIDLockFile.lock();
+
+               OutputStream os = null;
+
+               try
+               {
+                  os = new BufferedOutputStream(new FileOutputStream(nodeIDFile));
+
+                  uuid = UUIDGenerator.getInstance().generateUUID();
+
+                  nodeID = new SimpleString(uuid.toString());
+
+                  os.write(uuid.asBytes());
+
+                  log.info("Wrote node id, it is " + nodeID);
+               }
+               finally
+               {
+                  if (os != null)
+                  {
+                     os.close();
+                  }
+               }
+
+               nodeIDLockFile.unlock();
+            }
+            else
+            {
+               // Read it
+
+               readNodeID(nodeIDFile);
+            }
+
+            initialisePart1();
+
+            initialisePart2();
+
+            log.info("Server is now live");
+         }
+         catch (Exception e)
+         {
+            log.error("Failure in initialisation", e);
+         }
+      }
+
+      public void close() throws Exception
+      {
+         if (liveLock != null)
+         {
+            // We need to delete the file too, otherwise the backup will failover when we shutdown or if the backup is
+            // started before the live
+
+            File liveFile = new File(configuration.getJournalDirectory(), "live.lock");
+
+            liveFile.delete();
+
+            liveLock.unlock();
+
+         }
+      }
+   }
+
+   private void readNodeID(final File nodeIDFile) throws Exception
+   {
+      // Read it
+      InputStream is = null;
+
+      try
+      {
+         is = new BufferedInputStream(new FileInputStream(nodeIDFile));
+
+         byte[] bytes = new byte[16];
+
+         int read = 0;
+
+         while (read < 16)
+         {
+            int r = is.read(bytes, read, 16 - read);
+
+            if (r <= 0)
+            {
+               throw new IllegalStateException("Cannot read node id file, perhaps it is corrupt?");
+            }
+
+            read += r;
+         }
+
+         uuid = new UUID(UUID.TYPE_TIME_BASED, bytes);
+
+         nodeID = new SimpleString(uuid.toString());
+
+         log.info("Read node id, it is " + nodeID);
+      }
+      finally
+      {
+         if (is != null)
+         {
+            is.close();
+         }
+      }
+   }
+
+   private class SharedStoreBackupActivation implements Activation
+   {
+      LockFile backupLock;
+
+      LockFile liveLock;
+
+      public void run()
+      {
+         try
+         {
+            backupLock = createLockFile("backup.lock", configuration.getJournalDirectory());
+
+            log.info("Waiting to become backup node");
+
+            backupLock.lock();
+
+            log.info("** got backup lock");
+
+            // We load the node id from the file in the journal dir - if the backup is started before live and live has
+            // never been started before it may not exist yet, so
+            // we wait for it
+
+            File nodeIDFile = new File(configuration.getJournalDirectory(), "node.id");
+
+            while (true)
+            {
+               // We also need to create another lock file for the node.id file since we don't want to see any partially
+               // written
+               // node id if the live node is still creating it.
+               // Also renaming is not atomic necessarily so we can't use a write and rename strategy safely
+
+               LockFile nodeIDLockFile = createLockFile("nodeid.lock", configuration.getJournalDirectory());
+
+               nodeIDLockFile.lock();
+
+               if (!nodeIDFile.exists())
+               {
+                  nodeIDLockFile.unlock();
+
+                  Thread.sleep(2000);
+
+                  continue;
+               }
+
+               nodeIDLockFile.unlock();
+
+               break;
+            }
+
+            readNodeID(nodeIDFile);
+
+            log.info("Read node id " + nodeID);
+
+            initialisePart1();
+
+            // TODO - now send announcement message to cluster
+
+            // We now look for the live.lock file - if it doesn't exist it means the live isn't started yet, so we wait
+            // for that
+            
+            clusterManager.startAnnouncement();
+
+            while (true)
+            {
+               File liveLockFile = new File(configuration.getJournalDirectory(), "live.lock");
+
+               while (!liveLockFile.exists())
+               {
+                  log.info("Waiting for server live lock file. Live server is not started");
+
+                  Thread.sleep(2000);
+               }
+
+               liveLock = createLockFile("live.lock", configuration.getJournalDirectory());
+
+               log.info("Live server is up - waiting for failover");
+
+               liveLock.lock();
+
+               // We need to test if the file exists again, since the live might have shutdown
+               if (!liveLockFile.exists())
+               {
+                  liveLock.unlock();
+
+                  continue;
+               }
+
+               log.info("Obtained live lock");
+
+               break;
+            }
+            
+            configuration.setBackup(false);
+
+            initialisePart2();
+
+            log.info("Server is now live");
+
+            backupLock.unlock();
+         }
+         catch (InterruptedException e)
+         {
+            // This can occur when closing if the thread is blocked - it's ok
+         }
+         catch (Exception e)
+         {
+            log.error("Failure in initialisation", e);
+         }
+      }
+
+      public void close() throws Exception
+      {
+         long timeout = 30000;
+
+         long start = System.currentTimeMillis();
+
+         while (backupActivationThread.isAlive() && System.currentTimeMillis() - start < timeout)
+         {
+            backupActivationThread.interrupt();
+
+            Thread.sleep(1000);
+         }
+
+         if (System.currentTimeMillis() - start >= timeout)
+         {
+            log.warn("Timed out waiting for backup activation to exit");
+         }
+
+         if (liveLock != null)
+         {
+            liveLock.unlock();
+         }
+
+         if (backupLock != null)
+         {
+            backupLock.unlock();
+         }
+
+      }
+   }
+
+   private class SharedNothingBackupActivation implements Activation
+   {
+      public void run()
+      {
+         try
+         {
+            // TODO
+
+            // Try-Connect to live server using live-connector-ref
+
+            // sit in loop and try and connect, if server is not live then it will return NOT_LIVE
+         }
+         catch (Exception e)
+         {
+            log.error("Failure in initialisation", e);
+         }
+      }
+
+      public void close() throws Exception
+      {
+      }
+   }
+
+   private Thread backupActivationThread;
+
+   private Activation activation;
+
    public synchronized void start() throws Exception
    {
       initialiseLogging();
@@ -293,30 +621,66 @@
          test.run();
       }
 
-      initialisePart1();
+      if (!configuration.isBackup())
+      {
+         if (configuration.isSharedStore())
+         {
+            activation = new SharedStoreLiveActivation();
 
+            // This should block until the lock is got
+
+            activation.run();
+         }
+      }
+
+      started = true;
+
+      HornetQServerImpl.log.info("HornetQ Server version " + getVersion().getFullVersion() + " started");
+
       if (configuration.isBackup())
       {
-         if (!configuration.isSharedStore())
+         if (configuration.isSharedStore())
          {
-            replicationEndpoint = new ReplicationEndpointImpl(this);
-            replicationEndpoint.start();
+            activation = new SharedStoreBackupActivation();
          }
-         // We defer actually initialisation until the live node has contacted the backup
-         HornetQServerImpl.log.info("Backup server initialised");
+         else
+         {
+            // Replicated
+
+            activation = new SharedNothingBackupActivation();
+         }
+
+         backupActivationThread = new Thread(activation);
+
+         backupActivationThread.start();
       }
-      else
-      {
-         initialisePart2();
-      }
 
-      // We start the remoting service here - if the server is a backup remoting service needs to be started
-      // so it can be initialised by the live node
-      remotingService.start();
+      // initialisePart1();
+      //
+      // if (configuration.isBackup())
+      // {
+      // if (!configuration.isSharedStore())
+      // {
+      // replicationEndpoint = new ReplicationEndpointImpl(this);
+      // replicationEndpoint.start();
+      // }
+      // else
+      // {
+      // backupLock = new FailoverLockFileImpl("backup.lock", configuration.getJournalDirectory());
+      // liveLock = new FailoverLockFileImpl("live.lock", configuration.getJournalDirectory());
+      // }
+      //         
+      // // We defer actually initialisation until the live node has contacted the backup
+      // //HornetQServerImpl.log.info("Backup server initialised");
+      // }
+      // else
+      // {
+      // initialisePart2();
+      // }
+      //
+      //      
+      // remotingService.start();
 
-      started = true;
-
-      HornetQServerImpl.log.info("HornetQ Server version " + getVersion().getFullVersion() + " started");
    }
 
    @Override
@@ -334,6 +698,10 @@
 
    public void stop() throws Exception
    {
+      System.out.println("*** stop called on server");
+
+      System.out.flush();
+
       synchronized (this)
       {
          if (!started)
@@ -351,12 +719,6 @@
             managementService.removeNotificationListener(groupingHandler);
             groupingHandler = null;
          }
-         // // Need to flush all sessions to make sure all confirmations get sent back to client
-         //
-         // for (ServerSession session : sessions.values())
-         // {
-         // session.getChannel().flushConfirmations();
-         // }
       }
 
       // we stop the remoting service outside a lock
@@ -459,9 +821,19 @@
 
          started = false;
          initialised = false;
-         uuid = null;
+         // uuid = null;
          nodeID = null;
 
+         if (activation != null)
+         {
+            activation.close();
+         }
+
+         if (backupActivationThread != null)
+         {
+            backupActivationThread.join();
+         }
+
          HornetQServerImpl.log.info("HornetQ Server version " + getVersion().getFullVersion() + " stopped");
 
          Logger.reset();
@@ -584,8 +956,8 @@
                                                               managementService,
                                                               this,
                                                               configuration.getManagementAddress(),
-                                                              defaultAddress == null ? null : 
-                                                                 new SimpleString(defaultAddress),
+                                                              defaultAddress == null ? null
+                                                                                    : new SimpleString(defaultAddress),
                                                               callback);
 
       sessions.put(name, session);
@@ -685,6 +1057,8 @@
                             final boolean durable,
                             final boolean temporary) throws Exception
    {
+      log.info("trying to deploy queue " + queueName);
+
       return createQueue(address, queueName, filterString, durable, temporary, true);
    }
 
@@ -760,7 +1134,7 @@
    {
       return replicationEndpoint;
    }
-   
+
    public ReplicationManager getReplicationManager()
    {
       return replicationManager;
@@ -793,7 +1167,7 @@
                                      0,
                                      1.0d,
                                      0,
-                                     1, 
+                                     1,
                                      false,
                                      threadPool,
                                      scheduledPool,
@@ -827,34 +1201,34 @@
    // Private
    // --------------------------------------------------------------------------------------
 
-   private boolean startReplication() throws Exception
-   {
-      String backupConnectorName = configuration.getBackupConnectorName();
+   // private boolean startReplication() throws Exception
+   // {
+   // String backupConnectorName = configuration.getBackupConnectorName();
+   //
+   // if (!configuration.isSharedStore() && backupConnectorName != null)
+   // {
+   // TransportConfiguration backupConnector = configuration.getConnectorConfigurations().get(backupConnectorName);
+   //
+   // if (backupConnector == null)
+   // {
+   // HornetQServerImpl.log.warn("connector with name '" + backupConnectorName +
+   // "' is not defined in the configuration.");
+   // }
+   // else
+   // {
+   //
+   // replicationFailoverManager = createBackupConnectionFailoverManager(backupConnector,
+   // threadPool,
+   // scheduledPool);
+   //
+   // replicationManager = new ReplicationManagerImpl(replicationFailoverManager, executorFactory);
+   // replicationManager.start();
+   // }
+   // }
+   //
+   // return true;
+   // }
 
-      if (!configuration.isSharedStore() && backupConnectorName != null)
-      {
-         TransportConfiguration backupConnector = configuration.getConnectorConfigurations().get(backupConnectorName);
-
-         if (backupConnector == null)
-         {
-            HornetQServerImpl.log.warn("connector with name '" + backupConnectorName +
-                                       "' is not defined in the configuration.");
-         }
-         else
-         {
-
-            replicationFailoverManager = createBackupConnectionFailoverManager(backupConnector,
-                                                                               threadPool,
-                                                                               scheduledPool);
-
-            replicationManager = new ReplicationManagerImpl(replicationFailoverManager, executorFactory);
-            replicationManager.start();
-         }
-      }
-
-      return true;
-   }
-
    private void callActivateCallbacks()
    {
       for (ActivateCallback callback : activateCallbacks)
@@ -863,7 +1237,6 @@
       }
    }
 
-
    private void callPreActiveCallbacks()
    {
       for (ActivateCallback callback : activateCallbacks)
@@ -902,11 +1275,31 @@
       return true;
    }
 
+   private class FileActivateRunner implements Runnable
+   {
+      public void run()
+      {
+
+      }
+   }
+
+   private void initialiseLogging()
+   {
+      LogDelegateFactory logDelegateFactory = (LogDelegateFactory)instantiateInstance(configuration.getLogDelegateFactoryClassName());
+
+      Logger.setDelegateFactory(logDelegateFactory);
+   }
+
+   /*
+    * Start everything apart from RemotingService and loading the data
+    */
    private void initialisePart1() throws Exception
    {
       // Create the pools - we have two pools - one for non scheduled - and another for scheduled
 
-      ThreadFactory tFactory = new HornetQThreadFactory("HornetQ-server-threads" + System.identityHashCode(this), false, getThisClassLoader());
+      ThreadFactory tFactory = new HornetQThreadFactory("HornetQ-server-threads" + System.identityHashCode(this),
+                                                        false,
+                                                        getThisClassLoader());
 
       if (configuration.getThreadPoolMaxSize() == -1)
       {
@@ -920,7 +1313,9 @@
       executorFactory = new OrderedExecutorFactory(threadPool);
 
       scheduledPool = new ScheduledThreadPoolExecutor(configuration.getScheduledThreadPoolMaxSize(),
-                                                      new HornetQThreadFactory("HornetQ-scheduled-threads", false, getThisClassLoader()));
+                                                      new HornetQThreadFactory("HornetQ-scheduled-threads",
+                                                                               false,
+                                                                               getThisClassLoader()));
 
       managementService = new ManagementServiceImpl(mbeanServer, configuration);
 
@@ -933,27 +1328,17 @@
 
          memoryManager.start();
       }
-   }
 
-   private void initialiseLogging()
-   {
-      LogDelegateFactory logDelegateFactory = (LogDelegateFactory)instantiateInstance(configuration.getLogDelegateFactoryClassName());
-
-      Logger.setDelegateFactory(logDelegateFactory);
-   }
-
-   private void initialisePart2() throws Exception
-   {
       // Create the hard-wired components
 
       if (configuration.isFileDeploymentEnabled())
       {
          deploymentManager = new FileDeploymentManager(configuration.getFileDeployerScanPeriod());
       }
-      
+
       callPreActiveCallbacks();
 
-      startReplication();
+      // startReplication();
 
       storageManager = createStorageManager();
 
@@ -1049,14 +1434,52 @@
       {
          deploySecurityFromConfiguration();
       }
-      
+
       deployGroupingHandlerConfiguration(configuration.getGroupingHandlerConfiguration());
 
+      // This can't be created until node id is set
+      clusterManager = new ClusterManagerImpl(executorFactory,
+                                              this,
+                                              postOffice,
+                                              scheduledPool,
+                                              managementService,
+                                              configuration,
+                                              uuid,
+                                              configuration.isBackup(),
+                                              configuration.isClustered());
+
+   }
+
+   /*
+    * Load the data, and start remoting service so clients can connect
+    */
+   private void initialisePart2() throws Exception
+   {
       // Load the journal and populate queues, transactions and caches in memory
+
       JournalLoadInformation[] journalInfo = loadJournals();
 
       compareJournals(journalInfo);
 
+      pagingManager.resumeDepages();
+
+      final ServerInfo dumper = new ServerInfo(this, pagingManager);
+
+      long dumpInfoInterval = configuration.getServerDumpInterval();
+
+      if (dumpInfoInterval > 0)
+      {
+         scheduledPool.scheduleWithFixedDelay(new Runnable()
+         {
+            public void run()
+            {
+               HornetQServerImpl.log.info(dumper.dump());
+            }
+         }, 0, dumpInfoInterval, TimeUnit.MILLISECONDS);
+      }
+
+      // Deploy the rest of the stuff
+
       // Deploy any predefined queues
       if (configuration.isFileDeploymentEnabled())
       {
@@ -1070,48 +1493,25 @@
       }
 
       // We need to call this here, this gives any dependent server a chance to deploy its own addresses
-      // this needs to be done before clustering is initialised
+      // this needs to be done before clustering is fully activated
       callActivateCallbacks();
 
       // Deply any pre-defined diverts
       deployDiverts();
 
-      // This can't be created until node id is set
-      clusterManager = new ClusterManagerImpl(executorFactory,
-                                              this,
-                                              postOffice,
-                                              scheduledPool,
-                                              managementService,
-                                              configuration,
-                                              uuid,
-                                              configuration.isBackup(),
-                                              configuration.isClustered());
-
-      clusterManager.start();
-
       if (deploymentManager != null)
       {
          deploymentManager.start();
       }
 
-      pagingManager.resumeDepages();
+      clusterManager.start();
 
-      final ServerInfo dumper = new ServerInfo(this, pagingManager);
+      initialised = true;
 
-      long dumpInfoInterval = configuration.getServerDumpInterval();
+      // We do this at the end - we don't want things like MDBs or other connections connecting to a backup server until
+      // it is activated
 
-      if (dumpInfoInterval > 0)
-      {
-         scheduledPool.scheduleWithFixedDelay(new Runnable()
-         {
-            public void run()
-            {
-               HornetQServerImpl.log.info(dumper.dump());
-            }
-         }, 0, dumpInfoInterval, TimeUnit.MILLISECONDS);
-      }
-
-      initialised = true;
+      remotingService.start();
    }
 
    /**
@@ -1165,9 +1565,6 @@
 
       recoverStoredConfigs();
 
-      // Set the node id - must be before we load the queues into the postoffice, but after we load the journal
-      setNodeID();
-
       Map<Long, Queue> queues = new HashMap<Long, Queue>();
 
       for (QueueBindingInfo queueBindingInfo : queueBindingInfos)
@@ -1251,42 +1648,6 @@
       }
    }
 
-   private void setNodeID() throws Exception
-   {
-      if (!configuration.isBackup())
-      {
-         if (uuid == null)
-         {
-            uuid = storageManager.getPersistentID();
-
-            if (uuid == null)
-            {
-               uuid = UUIDGenerator.getInstance().generateUUID();
-
-               storageManager.setPersistentID(uuid);
-            }
-
-            nodeID = new SimpleString(uuid.toString());
-         }
-      }
-      else
-      {
-         UUID currentUUID = storageManager.getPersistentID();
-
-         if (currentUUID != null)
-         {
-            if (!currentUUID.equals(uuid))
-            {
-               throw new IllegalStateException("Backup server already has an id but it's not the same as live");
-            }
-         }
-         else
-         {
-            storageManager.setPersistentID(uuid);
-         }
-      }
-   }
-
    private Queue createQueue(final SimpleString address,
                              final SimpleString queueName,
                              final SimpleString filterString,
@@ -1445,19 +1806,18 @@
          throw new IllegalArgumentException("Error instantiating class \"" + className + "\"", e);
       }
    }
-   
+
    private static ClassLoader getThisClassLoader()
    {
       return AccessController.doPrivileged(new PrivilegedAction<ClassLoader>()
-                                    {
-                                       public ClassLoader run()
-                                       {
-                                          return ClientSessionFactoryImpl.class.getClassLoader();
-                                       }
-                                    });
-      
+      {
+         public ClassLoader run()
+         {
+            return ClientSessionFactoryImpl.class.getClassLoader();
+         }
+      });
+
    }
-   
 
    // Inner classes
    // --------------------------------------------------------------------------------

Modified: branches/2_2_0_HA_Improvements/src/main/org/hornetq/utils/UUID.java
===================================================================
--- branches/2_2_0_HA_Improvements/src/main/org/hornetq/utils/UUID.java	2010-06-11 04:11:42 UTC (rev 9306)
+++ branches/2_2_0_HA_Improvements/src/main/org/hornetq/utils/UUID.java	2010-06-11 15:33:36 UTC (rev 9307)
@@ -211,7 +211,7 @@
       }
       return mDesc;
    }
-
+   
    /**
     * Checking equality of UUIDs is easy; just compare the 128-bit number.
     */

Modified: branches/2_2_0_HA_Improvements/tests/src/org/hornetq/tests/unit/core/paging/impl/PagingStoreImplTest.java
===================================================================
--- branches/2_2_0_HA_Improvements/tests/src/org/hornetq/tests/unit/core/paging/impl/PagingStoreImplTest.java	2010-06-11 04:11:42 UTC (rev 9306)
+++ branches/2_2_0_HA_Improvements/tests/src/org/hornetq/tests/unit/core/paging/impl/PagingStoreImplTest.java	2010-06-11 15:33:36 UTC (rev 9307)
@@ -984,13 +984,6 @@
          return 0;
       }
 
-      /* (non-Javadoc)
-       * @see org.hornetq.core.persistence.StorageManager#getPersistentID()
-       */
-      public UUID getPersistentID()
-      {
-         return null;
-      }
 
       /* (non-Javadoc)
        * @see org.hornetq.core.persistence.StorageManager#loadBindingJournal(java.util.List)
@@ -1042,13 +1035,6 @@
       }
 
       /* (non-Javadoc)
-       * @see org.hornetq.core.persistence.StorageManager#setPersistentID(org.hornetq.utils.UUID)
-       */
-      public void setPersistentID(final UUID id) throws Exception
-      {
-      }
-
-      /* (non-Javadoc)
        * @see org.hornetq.core.persistence.StorageManager#storeAcknowledge(long, long)
        */
       public void storeAcknowledge(final long queueID, final long messageID) throws Exception



More information about the hornetq-commits mailing list