@Override
  public void onPartitionBecomeBootstrapFromOffline(String partitionName) {
    try {
      if (this.blockStateTransitionLatch != null && this.blockStateTransitionLatch.getCount() > 0) {
        logger.info("Bootstrapping is waiting for blockStateTransitionLatch...");
        this.blockStateTransitionLatch.await();
      }
      participantMetrics.incStateTransitionMetric(partitionName, ReplicaState.OFFLINE, ReplicaState.BOOTSTRAP);
      // 1. take actions in storage manager (add new replica if necessary)
      onPartitionBecomePreBootstrapFromOffline(partitionName);

      // Invoke FileCopyManagerListener if it exists. This listener is responsible for copying files
      // from remote store to local disk.
      PartitionStateChangeListener fileCopyStateChangeListener =
          partitionStateChangeListeners.get(StateModelListenerType.FileCopyManagerListener);
      /**
       * If FileCopyProtocol is enabled, we will invoke the FileCopyStateChangeListener
       */
      if (clusterMapConfig.enableFileCopyProtocol && fileCopyStateChangeListener != null) {
        try{
          logger.info("Invoking FileCopy Listener for partition {}", partitionName);
          fileCopyStateChangeListener.onPartitionBecomeBootstrapFromOffline(partitionName);
          replicaSyncUpManager.waitForFileCopyCompleted(partitionName);
        } catch (Exception e){
            logger.error("FileCopy Listener failed for partition {}. Starting Normal Replication For the "
                + "Partition after clean up", partitionName);
            // If FileCopyListener fails, we can start normal replication
        }
      }

      onPartitionBecomeBootstrapFromPreBootstrap(partitionName);
      // 2. take actions in replication manager (add new replica if necessary)
      PartitionStateChangeListener replicationManagerListener =
          partitionStateChangeListeners.get(StateModelListenerType.ReplicationManagerListener);
      if (replicationManagerListener != null) {
        replicationManagerListener.onPartitionBecomeBootstrapFromOffline(partitionName);
      }
      // 3. take actions in stats manager (add new replica if necessary)
      PartitionStateChangeListener statsManagerListener =
          partitionStateChangeListeners.get(StateModelListenerType.StatsManagerListener);
      if (statsManagerListener != null) {
        statsManagerListener.onPartitionBecomeBootstrapFromOffline(partitionName);
      }
    } catch (InterruptedException e) {
      logger.error("Waiting for state transition to be unblocked was interrupted", e);
    } catch (Exception e) {
      localPartitionAndState.put(partitionName, ReplicaState.ERROR);
      throw e;
    }
    logger.info("Before setting partition {} to bootstrap", partitionName);
    localPartitionAndState.put(partitionName, ReplicaState.BOOTSTRAP);
    participantMetrics.decStateTransitionMetric(partitionName, ReplicaState.OFFLINE, ReplicaState.BOOTSTRAP);
  }
@return {@link DataNodeConfig} of current participant (The method also checks the existence of the config).
ambry-clustermap/src/main/java/com/github/ambry/clustermap/HelixParticipant.java