private Map<Integer, BookieSocketAddress> getReplacedBookiesByIndexes(
      LedgerHandle lh,
      List<BookieSocketAddress> ensemble,
      Set<Integer> bookieIndexesToRereplicate,
      Optional<Set<BookieSocketAddress>> excludedBookies)
      throws BKException.BKNotEnoughBookiesException {
    // target bookies to replicate
    Map<Integer, BookieSocketAddress> targetBookieAddresses =
        Maps.newHashMapWithExpectedSize(bookieIndexesToRereplicate.size());
    // bookies to exclude for ensemble allocation
    Set<BookieSocketAddress> bookiesToExclude = Sets.newHashSet();
    if (excludedBookies.isPresent()) {
      bookiesToExclude.addAll(excludedBookies.get());
    }

    // excluding bookies that need to be replicated
    for (Integer bookieIndex : bookieIndexesToRereplicate) {
      BookieSocketAddress bookie = ensemble.get(bookieIndex);
      bookiesToExclude.add(bookie);
    }

    // allocate bookies
    for (Integer bookieIndex : bookieIndexesToRereplicate) {
      BookieSocketAddress oldBookie = ensemble.get(bookieIndex);
      BookieSocketAddress newBookie =
          bkc.getPlacementPolicy()
              .replaceBookie(
                  lh.getLedgerMetadata().getEnsembleSize(),
                  lh.getLedgerMetadata().getWriteQuorumSize(),
                  lh.getLedgerMetadata().getAckQuorumSize(),
                  ensemble,
                  oldBookie,
                  bookiesToExclude);
      targetBookieAddresses.put(bookieIndex, newBookie);
      bookiesToExclude.add(newBookie);
    }

    return targetBookieAddresses;
  }
 /** @return the metadata for the passed ledger handle */
 public LedgerMetadata getLedgerMetadata(LedgerHandle lh) {
   return lh.getLedgerMetadata();
 }