public static <S, R> CompletableFuture<Map<ServerName, Object>>
    coprocessorServiceOnAllRegionServers(AsyncAdmin asyncAdmin, Function<RpcChannel, S> stubMaker,
      ServiceCaller<S, R> callable) {
    CompletableFuture<Map<ServerName, Object>> future = new CompletableFuture<>();
    FutureUtils.addListener(asyncAdmin.getRegionServers(), (regionServers, error) -> {
      if (error != null) {
        future.completeExceptionally(error);
        return;
      }
      Map<ServerName, Object> resultMap = new ConcurrentHashMap<>();
      for (ServerName regionServer : regionServers) {
        FutureUtils.addListener(asyncAdmin.coprocessorService(stubMaker, callable, regionServer),
          (server, err) -> {
            if (err != null) {
              resultMap.put(regionServer, err);
            } else {
              resultMap.put(regionServer, server);
            }
            if (resultMap.size() == regionServers.size()) {
              future.complete(Collections.unmodifiableMap(resultMap));
            }
          });
      }
    });
    return future;
  }
Execute the given coprocessor call on all region servers.
<p>
The {@code stubMaker} is just a delegation to the {@code newStub} call. Usually it is only a
one line lambda expression, like:

<pre>
channel -&gt; xxxService.newStub(channel)
</pre>

@param asyncAdmin the asynchronous administrative API for HBase.
@param stubMaker  a delegation to the actual {@code newStub} call.
@param callable   a delegation to the actual protobuf rpc call. See the comment of
                  {@link ServiceCaller} for more details.
@param <S>        the type of the asynchronous stub
@param <R>        the type of the return value
@return Map of each region server to its result of the protobuf rpc call, wrapped by a
        {@link CompletableFuture}.
@see ServiceCaller
hbase-client/src/main/java/org/apache/hadoop/hbase/client/AsyncAdminClientUtils.java