@Override
  public synchronized void shutdown() throws IllegalStateException {
    if (!_state.isRunning())
      throw new IllegalStateException(
          "Registration ("
              + _id
              + ") is not in running state to be shutdown. Current state :"
              + _state);

    _sourcesConnection.unregisterMbeans();
    _sourcesConnection.stop();
    _status.shutdown();
    _state = RegistrationState.SHUTDOWN;

    // remove this registration stats from client stats Collector list.
    _client.getBootstrapEventsStats().removeStatsCollector(_id.getId());
    _client.getInBoundStatsCollectors().removeStatsCollector(_id.getId());
    _client.getRelayConsumerStatsCollectors().removeStatsCollector(_id.getId());
    _client.getBootstrapConsumerStatsCollectors().removeStatsCollector(_id.getId());
    _client.getUnifiedClientStatsCollectors().removeStatsCollector(_id.getId());
  }
  @Override
  public synchronized void resume() throws IllegalStateException {
    if (_state == RegistrationState.RESUMED) return;

    if ((_state != RegistrationState.PAUSED) && (_state != RegistrationState.SUSPENDED_ON_ERROR))
      throw new IllegalStateException(
          "Registration ("
              + _id
              + ") is not in correct state to be resumed. Current state :"
              + _state);

    _sourcesConnection.getConnectionStatus().resume();
    _status.resume();
    _state = RegistrationState.RESUMED;
  }
  @Override
  public synchronized void suspendOnError(Throwable ex) throws IllegalStateException {
    if (_state == RegistrationState.SUSPENDED_ON_ERROR) return;

    if (!_state.isRunning())
      throw new IllegalStateException(
          "Registration ("
              + _id
              + ") is not in correct state to be suspended. Current state :"
              + _state);

    _sourcesConnection.getConnectionStatus().suspendOnError(ex);
    _status.suspendOnError(ex);
    _state = RegistrationState.SUSPENDED_ON_ERROR;
  }
  @Override
  public synchronized void pause() throws IllegalStateException {
    if (_state == RegistrationState.PAUSED) return;

    if ((_state != RegistrationState.STARTED) && (_state != RegistrationState.RESUMED))
      throw new IllegalStateException(
          "Registration ("
              + _id
              + ") is not in correct state to be paused. Current state :"
              + _state);

    _sourcesConnection.getConnectionStatus().pause();
    _status.pause();
    _state = RegistrationState.PAUSED;
  }
  @Override
  public synchronized boolean start() throws IllegalStateException, DatabusClientException {
    _log.info("Starting registration (" + toString() + ") !!");

    if (_state.isRunning()) {
      _log.info("Registration (" + _id + ") already started !!");
      return false;
    }

    if (_state != RegistrationState.REGISTERED)
      throw new IllegalStateException(
          "Registration (" + _id + ") not in startable state !! Current State is :" + _state);

    if ((null == _sources) || (_sources.isEmpty()))
      throw new DatabusClientException(
          "Registration (" + _id + ") does not have any sources to start !!");

    if ((null == _consumers) || (_consumers.isEmpty()))
      throw new DatabusClientException(
          "Registration (" + _id + ") does not have any consumers to start !!");

    List<ServerInfo> relays = _client.getRelays();
    List<ServerInfo> bootstrapServers = _client.getBootstrapServices();

    List<DatabusCombinedConsumer> streamConsumers = new ArrayList<DatabusCombinedConsumer>();
    List<DatabusCombinedConsumer> bootstrapConsumers = new ArrayList<DatabusCombinedConsumer>();

    if ((null == relays) || (relays.isEmpty()))
      throw new DatabusClientException("No configured relays in the client to start");

    Set<ServerInfo> candidateRelays = new HashSet<ServerInfo>();

    for (ServerInfo s : relays) {
      if (canServe(s, _sources)) candidateRelays.add(s);
    }

    if (candidateRelays.isEmpty())
      throw new DatabusClientException("No candidate relays for source : " + _sources);

    streamConsumers.addAll(_consumers);

    boolean canConsumerBootstrap = false;
    _streamConsumerRawRegistrations = new ArrayList<DatabusV2ConsumerRegistration>();
    _streamConsumerRawRegistrations.add(
        new DatabusV2ConsumerRegistration(streamConsumers, _sources, _filterConfig));

    for (DatabusCombinedConsumer c : _consumers) {
      if (c.canBootstrap()) {
        canConsumerBootstrap = true;
        bootstrapConsumers.add(c);
      }
    }

    boolean enableBootstrap =
        _client.getClientStaticConfig().getRuntime().getBootstrap().isEnabled();
    Set<ServerInfo> candidateBootstrapServers = new HashSet<ServerInfo>();

    if (enableBootstrap && canConsumerBootstrap) {
      if ((null == bootstrapServers) || (bootstrapServers.isEmpty()))
        throw new DatabusClientException("No configured bootstrap servers in the client to start");

      for (ServerInfo s : bootstrapServers) {
        if (canServe(s, _sources)) candidateBootstrapServers.add(s);
      }

      if (candidateBootstrapServers.isEmpty())
        throw new DatabusClientException("No candidate bootstrap servers for source : " + _sources);

      _bootstrapConsumerRawRegistrations = new ArrayList<DatabusV2ConsumerRegistration>();
      ;
      _bootstrapConsumerRawRegistrations.add(
          new DatabusV2ConsumerRegistration(bootstrapConsumers, _sources, _filterConfig));
    }

    // All validations done. Setup and start
    initializeStatsCollectors();

    DatabusSourcesConnection.StaticConfig connConfig =
        _client.getClientStaticConfig().getConnection(_sources);

    if (null == connConfig) connConfig = _client.getClientStaticConfig().getConnectionDefaults();

    DbusEventBuffer eventBuffer = null;
    {
      DbusEventBuffer.StaticConfig cfg = connConfig.getEventBuffer();
      eventBuffer =
          new DbusEventBuffer(
              cfg.getMaxSize(),
              cfg.getMaxIndividualBufferSize(),
              cfg.getScnIndexSize(),
              cfg.getReadBufferSize(),
              cfg.getMaxEventSize(),
              cfg.getAllocationPolicy(),
              new File(cfg.getMmapDirectory().getAbsolutePath() + "_stream_" + _id),
              cfg.getQueuePolicy(),
              cfg.getTrace(),
              null,
              cfg.getAssertLevel(),
              cfg.getBufferRemoveWaitPeriod(),
              cfg.getRestoreMMappedBuffers(),
              cfg.getRestoreMMappedBuffersValidateEvents(),
              cfg.isEnableScnIndex(),
              _client.getEventFactory());
      eventBuffer.setDropOldEvents(true);
      eventBuffer.start(0);
    }

    DbusEventBuffer bootstrapBuffer = null;
    if (enableBootstrap && canConsumerBootstrap) {
      DbusEventBuffer.StaticConfig bstCfg = connConfig.getBstEventBuffer();
      bootstrapBuffer =
          new DbusEventBuffer(
              bstCfg.getMaxSize(),
              bstCfg.getMaxIndividualBufferSize(),
              bstCfg.getScnIndexSize(),
              bstCfg.getReadBufferSize(),
              bstCfg.getMaxEventSize(),
              bstCfg.getAllocationPolicy(),
              new File(bstCfg.getMmapDirectory().getAbsolutePath() + "_bootstrap_" + _id),
              bstCfg.getQueuePolicy(),
              bstCfg.getTrace(),
              null,
              bstCfg.getAssertLevel(),
              bstCfg.getBufferRemoveWaitPeriod(),
              bstCfg.getRestoreMMappedBuffers(),
              bstCfg.getRestoreMMappedBuffersValidateEvents(),
              bstCfg.isEnableScnIndex(),
              _client.getEventFactory());
      bootstrapBuffer.setDropOldEvents(false);
      bootstrapBuffer.start(0);
    }

    List<DatabusSubscription> subs = createSubscriptions(_sources);

    if (null != _checkpointPersistenceProvider
        && _client.getClientStaticConfig().getCheckpointPersistence().isClearBeforeUse()) {
      _log.info("Clearing checkpoint for sources :" + _sources + " with regId :" + _id);
      _checkpointPersistenceProvider.removeCheckpoint(_sources);
    }

    _sourcesConnection =
        createConnection(
            connConfig,
            subs,
            candidateRelays,
            candidateBootstrapServers,
            eventBuffer,
            bootstrapBuffer);
    _sourcesConnection.start();
    _state = RegistrationState.STARTED;
    _status.start();

    _state = RegistrationState.STARTED;
    return true;
  }