@Test
 public void testEnlargePool() throws Exception {
   AbstractClientConnectionFactory factory = mock(AbstractClientConnectionFactory.class);
   when(factory.isRunning()).thenReturn(true);
   TcpConnectionSupport mockConn1 = makeMockConnection("conn1");
   TcpConnectionSupport mockConn2 = makeMockConnection("conn2");
   TcpConnectionSupport mockConn3 = makeMockConnection("conn3");
   TcpConnectionSupport mockConn4 = makeMockConnection("conn4");
   when(factory.getConnection()).thenReturn(mockConn1, mockConn2, mockConn3, mockConn4);
   CachingClientConnectionFactory cachingFactory = new CachingClientConnectionFactory(factory, 2);
   cachingFactory.start();
   TcpConnection conn1 = cachingFactory.getConnection();
   TcpConnection conn2 = cachingFactory.getConnection();
   assertNotSame(conn1, conn2);
   Semaphore semaphore =
       TestUtils.getPropertyValue(
           TestUtils.getPropertyValue(cachingFactory, "pool"), "permits", Semaphore.class);
   assertEquals(0, semaphore.availablePermits());
   cachingFactory.setPoolSize(4);
   TcpConnection conn3 = cachingFactory.getConnection();
   TcpConnection conn4 = cachingFactory.getConnection();
   assertEquals(0, semaphore.availablePermits());
   conn1.close();
   conn1.close();
   conn2.close();
   conn3.close();
   conn4.close();
   assertEquals(4, semaphore.availablePermits());
 }
 @Test
 public void testGoodNetGWTimeout() throws Exception {
   final int port = SocketUtils.findAvailableServerSocket();
   AbstractClientConnectionFactory ccf = buildCF(port);
   ccf.start();
   testGoodNetGWTimeoutGuts(port, ccf);
 }
 private AbstractClientConnectionFactory buildCF(final int port) {
   AbstractClientConnectionFactory ccf = new TcpNetClientConnectionFactory("localhost", port);
   ccf.setSerializer(new DefaultSerializer());
   ccf.setDeserializer(new DefaultDeserializer());
   ccf.setSoTimeout(10000);
   ccf.setSingleUse(false);
   return ccf;
 }
 private Socket getSocket(AbstractClientConnectionFactory client) throws Exception {
   if (client instanceof TcpNetClientConnectionFactory) {
     return TestUtils.getPropertyValue(client.getConnection(), "socket", Socket.class);
   } else {
     return TestUtils.getPropertyValue(
             client.getConnection(), "socketChannel", SocketChannel.class)
         .socket();
   }
 }
 private CachingClientConnectionFactory createCCCFWith2Connections(
     TcpConnectionSupport conn1, TcpConnectionSupport conn2) throws Exception {
   AbstractClientConnectionFactory factory = mock(AbstractClientConnectionFactory.class);
   when(factory.isRunning()).thenReturn(true);
   when(factory.getConnection()).thenReturn(conn1, conn2);
   CachingClientConnectionFactory cccf = new CachingClientConnectionFactory(factory, 1);
   cccf.setConnectionWaitTimeout(1);
   cccf.start();
   return cccf;
 }
 @Test
 public void testCachedGWPropagatesSocketClose() throws Exception {
   final int port = SocketUtils.findAvailableServerSocket();
   AbstractClientConnectionFactory ccf = new TcpNetClientConnectionFactory("localhost", port);
   ccf.setSerializer(new DefaultSerializer());
   ccf.setDeserializer(new DefaultDeserializer());
   ccf.setSoTimeout(10000);
   ccf.setSingleUse(false);
   CachingClientConnectionFactory cccf = new CachingClientConnectionFactory(ccf, 1);
   cccf.start();
   testGWPropagatesSocketCloseGuts(port, cccf);
 }
 @Test
 public void testFailoverGWPropagatesSocketClose() throws Exception {
   final int port = SocketUtils.findAvailableServerSocket();
   AbstractClientConnectionFactory ccf = new TcpNetClientConnectionFactory("localhost", port);
   ccf.setSerializer(new DefaultSerializer());
   ccf.setDeserializer(new DefaultDeserializer());
   ccf.setSoTimeout(10000);
   ccf.setSingleUse(false);
   FailoverClientConnectionFactory focf =
       new FailoverClientConnectionFactory(Collections.singletonList(ccf));
   focf.start();
   testGWPropagatesSocketCloseGuts(port, focf);
 }
  @Test
  public void testRealNioSingleUse() throws Exception {

    final List<Integer> openPorts =
        SocketUtils.findAvailableServerSockets(SocketUtils.getRandomSeedPort(), 2);

    int port1 = openPorts.get(0);
    int port2 = openPorts.get(1);

    AbstractClientConnectionFactory client1 = new TcpNioClientConnectionFactory("localhost", port1);
    AbstractClientConnectionFactory client2 = new TcpNioClientConnectionFactory("localhost", port2);
    AbstractServerConnectionFactory server1 = new TcpNioServerConnectionFactory(port1);
    AbstractServerConnectionFactory server2 = new TcpNioServerConnectionFactory(port2);
    client1.setSingleUse(true);
    client2.setSingleUse(true);
    testRealGuts(client1, client2, server1, server2);
  }
 @Test
 public void testStop() throws Exception {
   AbstractClientConnectionFactory factory = mock(AbstractClientConnectionFactory.class);
   when(factory.isRunning()).thenReturn(true);
   TcpConnectionSupport mockConn1 = makeMockConnection("conn1");
   TcpConnectionSupport mockConn2 = makeMockConnection("conn2");
   int i = 3;
   when(factory.getConnection())
       .thenReturn(mockConn1)
       .thenReturn(mockConn2)
       .thenReturn(makeMockConnection("conn" + (i++)));
   CachingClientConnectionFactory cachingFactory = new CachingClientConnectionFactory(factory, 2);
   cachingFactory.start();
   TcpConnection conn1 = cachingFactory.getConnection();
   assertEquals("Cached:" + mockConn1.toString(), conn1.toString());
   conn1.close();
   conn1 = cachingFactory.getConnection();
   assertEquals("Cached:" + mockConn1.toString(), conn1.toString());
   TcpConnection conn2 = cachingFactory.getConnection();
   assertEquals("Cached:" + mockConn2.toString(), conn2.toString());
   cachingFactory.stop();
   Answer<Object> answer =
       new Answer<Object>() {
         @Override
         public Object answer(InvocationOnMock invocation) throws Throwable {
           return null;
         }
       };
   doAnswer(answer).when(mockConn1).close();
   doAnswer(answer).when(mockConn2).close();
   when(factory.isRunning()).thenReturn(false);
   conn1.close();
   conn2.close();
   verify(mockConn1).close();
   verify(mockConn2).close();
   when(mockConn1.isOpen()).thenReturn(false);
   when(mockConn2.isOpen()).thenReturn(false);
   when(factory.isRunning()).thenReturn(true);
   TcpConnection conn3 = cachingFactory.getConnection();
   assertNotSame(
       TestUtils.getPropertyValue(conn1, "theConnection"),
       TestUtils.getPropertyValue(conn3, "theConnection"));
   assertNotSame(
       TestUtils.getPropertyValue(conn2, "theConnection"),
       TestUtils.getPropertyValue(conn3, "theConnection"));
 }
 @Test
 public void testReuse() throws Exception {
   AbstractClientConnectionFactory factory = mock(AbstractClientConnectionFactory.class);
   when(factory.isRunning()).thenReturn(true);
   TcpConnectionSupport mockConn1 = makeMockConnection("conn1");
   TcpConnectionSupport mockConn2 = makeMockConnection("conn2");
   when(factory.getConnection()).thenReturn(mockConn1).thenReturn(mockConn2);
   CachingClientConnectionFactory cachingFactory = new CachingClientConnectionFactory(factory, 2);
   cachingFactory.start();
   TcpConnection conn1 = cachingFactory.getConnection();
   assertEquals("Cached:" + mockConn1.toString(), conn1.toString());
   conn1.close();
   conn1 = cachingFactory.getConnection();
   assertEquals("Cached:" + mockConn1.toString(), conn1.toString());
   TcpConnection conn2 = cachingFactory.getConnection();
   assertEquals("Cached:" + mockConn2.toString(), conn2.toString());
   conn1.close();
   conn2.close();
 }
 @Test
 public void testReducePool() throws Exception {
   AbstractClientConnectionFactory factory = mock(AbstractClientConnectionFactory.class);
   when(factory.isRunning()).thenReturn(true);
   TcpConnectionSupport mockConn1 = makeMockConnection("conn1", true);
   TcpConnectionSupport mockConn2 = makeMockConnection("conn2", true);
   TcpConnectionSupport mockConn3 = makeMockConnection("conn3", true);
   TcpConnectionSupport mockConn4 = makeMockConnection("conn4", true);
   when(factory.getConnection())
       .thenReturn(mockConn1)
       .thenReturn(mockConn2)
       .thenReturn(mockConn3)
       .thenReturn(mockConn4);
   CachingClientConnectionFactory cachingFactory = new CachingClientConnectionFactory(factory, 4);
   cachingFactory.start();
   TcpConnection conn1 = cachingFactory.getConnection();
   TcpConnection conn2 = cachingFactory.getConnection();
   TcpConnection conn3 = cachingFactory.getConnection();
   TcpConnection conn4 = cachingFactory.getConnection();
   Semaphore semaphore =
       TestUtils.getPropertyValue(
           TestUtils.getPropertyValue(cachingFactory, "pool"), "permits", Semaphore.class);
   assertEquals(0, semaphore.availablePermits());
   conn1.close();
   assertEquals(1, semaphore.availablePermits());
   cachingFactory.setPoolSize(2);
   assertEquals(0, semaphore.availablePermits());
   assertEquals(3, cachingFactory.getActiveCount());
   conn2.close();
   assertEquals(0, semaphore.availablePermits());
   assertEquals(2, cachingFactory.getActiveCount());
   conn3.close();
   assertEquals(1, cachingFactory.getActiveCount());
   assertEquals(1, cachingFactory.getIdleCount());
   conn4.close();
   assertEquals(2, semaphore.availablePermits());
   assertEquals(0, cachingFactory.getActiveCount());
   assertEquals(2, cachingFactory.getIdleCount());
   verify(mockConn1).close();
   verify(mockConn2).close();
 }
 @Test
 public void testFailoverGood() throws Exception {
   AbstractClientConnectionFactory factory1 = mock(AbstractClientConnectionFactory.class);
   AbstractClientConnectionFactory factory2 = mock(AbstractClientConnectionFactory.class);
   List<AbstractClientConnectionFactory> factories =
       new ArrayList<AbstractClientConnectionFactory>();
   factories.add(factory1);
   factories.add(factory2);
   TcpConnectionSupport conn1 = makeMockConnection();
   TcpConnectionSupport conn2 = makeMockConnection();
   when(factory1.getConnection()).thenReturn(conn1);
   when(factory2.getConnection()).thenReturn(conn2);
   when(factory1.isActive()).thenReturn(true);
   when(factory2.isActive()).thenReturn(true);
   doThrow(new IOException("fail")).when(conn1).send(Mockito.any(Message.class));
   doAnswer(
           new Answer<Object>() {
             public Object answer(InvocationOnMock invocation) throws Throwable {
               return null;
             }
           })
       .when(conn2)
       .send(Mockito.any(Message.class));
   FailoverClientConnectionFactory failoverFactory =
       new FailoverClientConnectionFactory(factories);
   failoverFactory.start();
   GenericMessage<String> message = new GenericMessage<String>("foo");
   failoverFactory.getConnection().send(message);
   Mockito.verify(conn2).send(message);
 }
 private void testCloseOnTimeoutGuts(AbstractClientConnectionFactory cf) throws Exception {
   TestingUtilities.waitListening(serverCf, null);
   cf.setSoTimeout(100);
   CachingClientConnectionFactory cccf = new CachingClientConnectionFactory(cf, 1);
   cccf.start();
   TcpConnection connection = cccf.getConnection();
   int n = 0;
   while (n++ < 100 && connection.isOpen()) {
     Thread.sleep(100);
   }
   assertFalse(connection.isOpen());
   cccf.stop();
 }
 @Test(expected = IOException.class)
 public void testFailoverConnectNone() throws Exception {
   AbstractClientConnectionFactory factory1 = mock(AbstractClientConnectionFactory.class);
   AbstractClientConnectionFactory factory2 = mock(AbstractClientConnectionFactory.class);
   List<AbstractClientConnectionFactory> factories =
       new ArrayList<AbstractClientConnectionFactory>();
   factories.add(factory1);
   factories.add(factory2);
   when(factory1.getConnection()).thenThrow(new IOException("fail"));
   when(factory2.getConnection()).thenThrow(new IOException("fail"));
   when(factory1.isActive()).thenReturn(true);
   when(factory2.isActive()).thenReturn(true);
   FailoverClientConnectionFactory failoverFactory =
       new FailoverClientConnectionFactory(factories);
   failoverFactory.start();
   GenericMessage<String> message = new GenericMessage<String>("foo");
   failoverFactory.getConnection().send(message);
 }
 @Test
 public void testOkAgainAfterCompleteFailure() throws Exception {
   AbstractClientConnectionFactory factory1 = mock(AbstractClientConnectionFactory.class);
   AbstractClientConnectionFactory factory2 = mock(AbstractClientConnectionFactory.class);
   List<AbstractClientConnectionFactory> factories =
       new ArrayList<AbstractClientConnectionFactory>();
   factories.add(factory1);
   factories.add(factory2);
   TcpConnectionSupport conn1 = makeMockConnection();
   TcpConnectionSupport conn2 = makeMockConnection();
   when(factory1.getConnection()).thenReturn(conn1);
   when(factory2.getConnection()).thenReturn(conn2);
   when(factory1.isActive()).thenReturn(true);
   when(factory2.isActive()).thenReturn(true);
   final AtomicInteger failCount = new AtomicInteger();
   doAnswer(
           new Answer<Object>() {
             @Override
             public Object answer(InvocationOnMock invocation) throws Throwable {
               if (failCount.incrementAndGet() < 3) {
                 throw new IOException("fail");
               }
               return null;
             }
           })
       .when(conn1)
       .send(Mockito.any(Message.class));
   doThrow(new IOException("fail")).when(conn2).send(Mockito.any(Message.class));
   FailoverClientConnectionFactory failoverFactory =
       new FailoverClientConnectionFactory(factories);
   failoverFactory.start();
   GenericMessage<String> message = new GenericMessage<String>("foo");
   try {
     failoverFactory.getConnection().send(message);
     fail("ExpectedFailure");
   } catch (IOException e) {
   }
   failoverFactory.getConnection().send(message);
   Mockito.verify(conn2).send(message);
   Mockito.verify(conn1, times(3)).send(message);
 }
 @Test(expected = IOException.class)
 public void testFailoverAllDead() throws Exception {
   AbstractClientConnectionFactory factory1 = mock(AbstractClientConnectionFactory.class);
   AbstractClientConnectionFactory factory2 = mock(AbstractClientConnectionFactory.class);
   List<AbstractClientConnectionFactory> factories =
       new ArrayList<AbstractClientConnectionFactory>();
   factories.add(factory1);
   factories.add(factory2);
   TcpConnectionSupport conn1 = makeMockConnection();
   TcpConnectionSupport conn2 = makeMockConnection();
   when(factory1.getConnection()).thenReturn(conn1);
   when(factory2.getConnection()).thenReturn(conn2);
   when(factory1.isActive()).thenReturn(true);
   when(factory2.isActive()).thenReturn(true);
   doThrow(new IOException("fail")).when(conn1).send(Mockito.any(Message.class));
   doThrow(new IOException("fail")).when(conn2).send(Mockito.any(Message.class));
   FailoverClientConnectionFactory failoverFactory =
       new FailoverClientConnectionFactory(factories);
   failoverFactory.start();
   GenericMessage<String> message = new GenericMessage<String>("foo");
   failoverFactory.getConnection().send(message);
   Mockito.verify(conn2).send(message);
 }
 @Test
 public void testFailoverAllDeadButOriginalOkAgain() throws Exception {
   AbstractClientConnectionFactory factory1 = mock(AbstractClientConnectionFactory.class);
   AbstractClientConnectionFactory factory2 = mock(AbstractClientConnectionFactory.class);
   List<AbstractClientConnectionFactory> factories =
       new ArrayList<AbstractClientConnectionFactory>();
   factories.add(factory1);
   factories.add(factory2);
   TcpConnectionSupport conn1 = makeMockConnection();
   TcpConnectionSupport conn2 = makeMockConnection();
   when(factory1.getConnection()).thenReturn(conn1);
   when(factory2.getConnection()).thenReturn(conn2);
   when(factory1.isActive()).thenReturn(true);
   when(factory2.isActive()).thenReturn(true);
   final AtomicBoolean failedOnce = new AtomicBoolean();
   doAnswer(
           new Answer<Object>() {
             @Override
             public Object answer(InvocationOnMock invocation) throws Throwable {
               if (!failedOnce.get()) {
                 failedOnce.set(true);
                 throw new IOException("fail");
               }
               return null;
             }
           })
       .when(conn1)
       .send(Mockito.any(Message.class));
   doThrow(new IOException("fail")).when(conn2).send(Mockito.any(Message.class));
   FailoverClientConnectionFactory failoverFactory =
       new FailoverClientConnectionFactory(factories);
   failoverFactory.start();
   GenericMessage<String> message = new GenericMessage<String>("foo");
   failoverFactory.getConnection().send(message);
   Mockito.verify(conn2).send(message);
   Mockito.verify(conn1, times(2)).send(message);
 }
 @Override
 public void start() {
   this.setActive(true);
   super.start();
 }
  @Test
  public void testFailoverCached() throws Exception {
    final int port = SocketUtils.findAvailableServerSocket();
    final CountDownLatch latch = new CountDownLatch(1);
    final AtomicBoolean done = new AtomicBoolean();
    final CountDownLatch serverLatch = new CountDownLatch(1);

    Executors.newSingleThreadExecutor()
        .execute(
            new Runnable() {

              public void run() {
                try {
                  ServerSocket server = ServerSocketFactory.getDefault().createServerSocket(port);
                  latch.countDown();
                  while (!done.get()) {
                    Socket socket = server.accept();
                    while (!socket.isClosed()) {
                      try {
                        ObjectInputStream ois = new ObjectInputStream(socket.getInputStream());
                        String request = (String) ois.readObject();
                        logger.debug("Read " + request);
                        ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());
                        oos.writeObject("bar");
                        logger.debug("Replied to " + request);
                        serverLatch.countDown();
                      } catch (IOException e) {
                        logger.debug("error on write " + e.getClass().getSimpleName());
                        socket.close();
                      }
                    }
                  }
                } catch (Exception e) {
                  if (!done.get()) {
                    e.printStackTrace();
                  }
                }
              }
            });
    assertTrue(latch.await(10000, TimeUnit.MILLISECONDS));

    // Cache
    AbstractClientConnectionFactory factory1 = mock(AbstractClientConnectionFactory.class);
    TcpConnectionSupport mockConn1 = makeMockConnection();
    when(factory1.getConnection()).thenReturn(mockConn1);
    doThrow(new IOException("fail")).when(mockConn1).send(Mockito.any(Message.class));
    CachingClientConnectionFactory cachingFactory1 =
        new CachingClientConnectionFactory(factory1, 1);

    AbstractClientConnectionFactory factory2 = new TcpNetClientConnectionFactory("localhost", port);
    factory2.setSerializer(new DefaultSerializer());
    factory2.setDeserializer(new DefaultDeserializer());
    factory2.setSoTimeout(10000);
    factory2.setSingleUse(false);
    CachingClientConnectionFactory cachingFactory2 =
        new CachingClientConnectionFactory(factory2, 1);

    // Failover
    List<AbstractClientConnectionFactory> factories =
        new ArrayList<AbstractClientConnectionFactory>();
    factories.add(cachingFactory1);
    factories.add(cachingFactory2);
    FailoverClientConnectionFactory failoverFactory =
        new FailoverClientConnectionFactory(factories);
    failoverFactory.start();

    TcpOutboundGateway gateway = new TcpOutboundGateway();
    gateway.setConnectionFactory(failoverFactory);
    PollableChannel outputChannel = new QueueChannel();
    gateway.setOutputChannel(outputChannel);
    gateway.afterPropertiesSet();
    gateway.start();

    GenericMessage<String> message = new GenericMessage<String>("foo");
    gateway.handleMessage(message);
    Message<?> reply = outputChannel.receive(0);
    assertNotNull(reply);
    assertEquals("bar", reply.getPayload());
    done.set(true);
    gateway.stop();
    verify(mockConn1).send(Mockito.any(Message.class));
  }
  private void testGWPropagatesSocketCloseGuts(final int port, AbstractClientConnectionFactory ccf)
      throws Exception {
    final CountDownLatch latch = new CountDownLatch(1);
    final AtomicBoolean done = new AtomicBoolean();
    final AtomicReference<String> lastReceived = new AtomicReference<String>();
    final CountDownLatch serverLatch = new CountDownLatch(1);

    Executors.newSingleThreadExecutor()
        .execute(
            new Runnable() {

              public void run() {
                try {
                  ServerSocket server = ServerSocketFactory.getDefault().createServerSocket(port);
                  latch.countDown();
                  int i = 0;
                  while (!done.get()) {
                    Socket socket = server.accept();
                    i++;
                    while (!socket.isClosed()) {
                      try {
                        ObjectInputStream ois = new ObjectInputStream(socket.getInputStream());
                        String request = (String) ois.readObject();
                        logger.debug("Read " + request + " closing socket");
                        socket.close();
                        lastReceived.set(request);
                        serverLatch.countDown();
                      } catch (IOException e) {
                        socket.close();
                      }
                    }
                  }
                } catch (Exception e) {
                  if (!done.get()) {
                    e.printStackTrace();
                  }
                }
              }
            });
    assertTrue(latch.await(10000, TimeUnit.MILLISECONDS));
    final TcpOutboundGateway gateway = new TcpOutboundGateway();
    gateway.setConnectionFactory(ccf);
    gateway.setRequestTimeout(Integer.MAX_VALUE);
    QueueChannel replyChannel = new QueueChannel();
    gateway.setRequiresReply(true);
    gateway.setOutputChannel(replyChannel);
    gateway.setRemoteTimeout(5000);
    gateway.afterPropertiesSet();
    gateway.start();
    try {
      gateway.handleMessage(MessageBuilder.withPayload("Test").build());
      fail("expected failure");
    } catch (Exception e) {
      assertTrue(e.getCause() instanceof EOFException);
    }
    assertEquals(0, TestUtils.getPropertyValue(gateway, "pendingReplies", Map.class).size());
    Message<?> reply = replyChannel.receive(0);
    assertNull(reply);
    done.set(true);
    ccf.getConnection();
  }
  private void testRealGuts(
      AbstractClientConnectionFactory client1,
      AbstractClientConnectionFactory client2,
      AbstractServerConnectionFactory server1,
      AbstractServerConnectionFactory server2)
      throws Exception {
    int port1;
    int port2;
    Executor exec = Executors.newCachedThreadPool();
    client1.setTaskExecutor(exec);
    client2.setTaskExecutor(exec);
    server1.setTaskExecutor(exec);
    server2.setTaskExecutor(exec);
    ApplicationEventPublisher pub =
        new ApplicationEventPublisher() {

          @Override
          public void publishEvent(ApplicationEvent event) {}
        };
    client1.setApplicationEventPublisher(pub);
    client2.setApplicationEventPublisher(pub);
    server1.setApplicationEventPublisher(pub);
    server2.setApplicationEventPublisher(pub);
    TcpInboundGateway gateway1 = new TcpInboundGateway();
    gateway1.setConnectionFactory(server1);
    SubscribableChannel channel = new DirectChannel();
    final AtomicReference<String> connectionId = new AtomicReference<String>();
    channel.subscribe(
        new MessageHandler() {
          public void handleMessage(Message<?> message) throws MessagingException {
            connectionId.set((String) message.getHeaders().get(IpHeaders.CONNECTION_ID));
            ((MessageChannel) message.getHeaders().getReplyChannel()).send(message);
          }
        });
    gateway1.setRequestChannel(channel);
    gateway1.start();
    TcpInboundGateway gateway2 = new TcpInboundGateway();
    gateway2.setConnectionFactory(server2);
    gateway2.setRequestChannel(channel);
    gateway2.start();
    TestingUtilities.waitListening(server1, null);
    TestingUtilities.waitListening(server2, null);
    List<AbstractClientConnectionFactory> factories =
        new ArrayList<AbstractClientConnectionFactory>();
    factories.add(client1);
    factories.add(client2);
    FailoverClientConnectionFactory failFactory = new FailoverClientConnectionFactory(factories);
    boolean singleUse = client1.isSingleUse();
    failFactory.setSingleUse(singleUse);
    failFactory.afterPropertiesSet();
    TcpOutboundGateway outGateway = new TcpOutboundGateway();
    outGateway.setConnectionFactory(failFactory);
    outGateway.start();
    QueueChannel replyChannel = new QueueChannel();
    outGateway.setReplyChannel(replyChannel);
    Message<String> message = new GenericMessage<String>("foo");
    outGateway.setRemoteTimeout(120000);
    outGateway.handleMessage(message);
    Socket socket = getSocket(client1);
    port1 = socket.getLocalPort();
    assertTrue(singleUse | connectionId.get().contains(Integer.toString(port1)));
    Message<?> replyMessage = replyChannel.receive(10000);
    assertNotNull(replyMessage);
    server1.stop();
    TestingUtilities.waitUntilFactoryHasThisNumberOfConnections(client1, 0);
    outGateway.handleMessage(message);
    socket = getSocket(client2);
    port2 = socket.getLocalPort();
    assertTrue(singleUse | connectionId.get().contains(Integer.toString(port2)));
    replyMessage = replyChannel.receive(10000);
    assertNotNull(replyMessage);
    gateway2.stop();
    outGateway.stop();
  }