@Override
  protected List<RegionPlan> balanceTable(TableName tableName,
    Map<ServerName, List<RegionInfo>> loadOfOneTable) {
    List<RegionPlan> regionPlans = Lists.newArrayList();
    Map<ServerName, List<RegionInfo>> correctAssignments = new HashMap<>();
    int misplacedRegions = 0;

    for (Map.Entry<ServerName, List<RegionInfo>> entry : loadOfOneTable.entrySet()) {
      ServerName current = entry.getKey();
      List<RegionInfo> regions = Lists.newArrayList();
      correctAssignments.put(current, regions);

      for (RegionInfo hri : entry.getValue()) {
        List<ServerName> favoredNodes = fnm.getFavoredNodes(hri);
        if (
          FavoredNodesPlan.getFavoredServerPosition(favoredNodes, current) != null
            || !FavoredNodesManager.isFavoredNodeApplicable(hri)
        ) {
          regions.add(hri);
        } else {
          // No favored nodes, lets unassign.
          LOG.warn("Region not on favored nodes, unassign. Region: " + hri + " current: " + current
            + " favored nodes: " + favoredNodes);
          try {
            provider.unassign(hri);
          } catch (IOException e) {
            LOG.warn("Failed unassign", e);
            continue;
          }
          RegionPlan rp = new RegionPlan(hri, null, null);
          regionPlans.add(rp);
          misplacedRegions++;
        }
      }
    }
    LOG.debug("Found misplaced regions: " + misplacedRegions + ", not on favored nodes.");
    List<RegionPlan> regionPlansFromBalance = super.balanceTable(tableName, correctAssignments);
    if (regionPlansFromBalance != null) {
      regionPlans.addAll(regionPlansFromBalance);
    }
    return regionPlans;
  }
For all regions correctly assigned to favored nodes, we just use the stochastic balancer
implementation. For the misplaced regions, we assign a bogus server to it and AM takes care.
hbase-balancer/src/main/java/org/apache/hadoop/hbase/master/balancer/FavoredStochasticBalancer.java