@Test(timeout = 30000)
  public void testCommandsIgnoredWhenOffline() throws Exception {
    this.transport = createTransport();

    assertNotNull(failoverTransport);

    ConnectionStateTracker tracker = failoverTransport.getStateTracker();
    assertNotNull(tracker);

    ConnectionId id = new ConnectionId("1");
    ConnectionInfo connection = new ConnectionInfo(id);

    // Track a connection
    tracker.track(connection);
    try {
      this.transport.oneway(new RemoveInfo(new ConnectionId("1")));
    } catch (Exception e) {
      fail("Should not have failed to remove this known connection");
    }

    try {
      this.transport.oneway(new RemoveInfo(new ConnectionId("2")));
    } catch (Exception e) {
      fail("Should not have failed to remove this unknown connection");
    }

    this.transport.oneway(new MessageAck());
    this.transport.oneway(new ShutdownInfo());
  }
 protected void restoreTransport(FanoutTransportHandler th) throws Exception, IOException {
   th.transport.start();
   stateTracker.setRestoreConsumers(th.transport == primary);
   stateTracker.restore(th.transport);
   for (Iterator<RequestCounter> iter2 = requestMap.values().iterator(); iter2.hasNext(); ) {
     RequestCounter rc = iter2.next();
     th.transport.oneway(rc.command);
   }
 }
  @Override
  public void oneway(Object o) throws IOException {
    final Command command = (Command) o;
    try {
      synchronized (reconnectMutex) {

        // Wait for transport to be connected.
        while (connectedCount < minAckCount && !disposed && connectionFailure == null) {
          LOG.debug("Waiting for at least " + minAckCount + " transports to be connected.");
          reconnectMutex.wait(1000);
        }

        // Still not fully connected.
        if (connectedCount < minAckCount) {

          Exception error;

          // Throw the right kind of error..
          if (disposed) {
            error = new IOException("Transport disposed.");
          } else if (connectionFailure != null) {
            error = connectionFailure;
          } else {
            error = new IOException("Unexpected failure.");
          }

          if (error instanceof IOException) {
            throw (IOException) error;
          }
          throw IOExceptionSupport.create(error);
        }

        // If it was a request and it was not being tracked by
        // the state tracker,
        // then hold it in the requestMap so that we can replay
        // it later.
        boolean fanout = isFanoutCommand(command);
        if (stateTracker.track(command) == null && command.isResponseRequired()) {
          int size = fanout ? minAckCount : 1;
          requestMap.put(new Integer(command.getCommandId()), new RequestCounter(command, size));
        }

        // Send the message.
        if (fanout) {
          for (Iterator<FanoutTransportHandler> iter = transports.iterator(); iter.hasNext(); ) {
            FanoutTransportHandler th = iter.next();
            if (th.transport != null) {
              try {
                th.transport.oneway(command);
              } catch (IOException e) {
                LOG.debug("Send attempt: failed.");
                th.onException(e);
              }
            }
          }
        } else {
          try {
            primary.transport.oneway(command);
          } catch (IOException e) {
            LOG.debug("Send attempt: failed.");
            primary.onException(e);
          }
        }
      }
    } catch (InterruptedException e) {
      // Some one may be trying to stop our thread.
      Thread.currentThread().interrupt();
      throw new InterruptedIOException();
    }
  }