下面列出了怎么用com.google.common.util.concurrent.FutureCallback的API类实例代码及写法,或者点击链接到github查看源代码。
private FutureCallback<Map<Integer, Double>> momentCpuUsageCallback(final String timestamp) {
return new FutureCallback<Map<Integer, Double>>() {
@Override
public void onSuccess(Map<Integer, Double> momentCpuTime) {
Map<String, Double> transformMomentCpuTime = ProcUtil.transformHexThreadId(momentCpuTime);
int totalTime = 0;
Map<String, String> dbMomentCpuTimes = new HashMap<>();
for (Map.Entry<String, Double> entry : transformMomentCpuTime.entrySet()) {
int time = (int) (entry.getValue() * 10000);
dbMomentCpuTimes.put(KvUtils.getThreadMomentCpuTimeKey(timestamp, entry.getKey()), String.valueOf(time));
totalTime += time;
}
kvDb.putBatch(dbMomentCpuTimes);
kvDb.put(KvUtils.getThreadMomentCpuTimeKey(timestamp), String.valueOf(totalTime));
kvDb.put(KvUtils.getCollectSuccessKey(timestamp), "true");
}
@Override
public void onFailure(Throwable throwable) {
logger.error("timestamp : {},fail get moment cpu usage", timestamp, throwable);
kvDb.put(KvUtils.getCollectSuccessKey(timestamp), "true");
}
};
}
/**
* 主方法
*/
public static void main(String[] args) throws Exception {
//new JVMTest();
//getJvmInfo();
final CountDownLatch latch = new CountDownLatch(1);
HostTask hostTask = new HostTask(UUID.randomUUID().toString(), 10995, new ConsoleResponseHandler(), 5000L);
ContinueResponseJob job = hostTask.createJob();
ListenableFuture<Integer> future = hostTask.getResultFuture();
Futures.addCallback(future, new FutureCallback<Integer>() {
@Override
public void onSuccess(Integer result) {
System.out.println(result);
latch.countDown();
}
@Override
public void onFailure(Throwable t) {
t.printStackTrace();
latch.countDown();
}
});
latch.await();
}
/**
* Register a callback to cache the result of a check.
* @param target
* @param lf
*/
private void addResultCachingCallback(
Checkable<K, V> target, ListenableFuture<V> lf) {
Futures.addCallback(lf, new FutureCallback<V>() {
@Override
public void onSuccess(@Nullable V result) {
synchronized (ThrottledAsyncChecker.this) {
checksInProgress.remove(target);
completedChecks.put(target, new LastCheckResult<>(
result, timer.monotonicNow()));
}
}
@Override
public void onFailure(@Nonnull Throwable t) {
synchronized (ThrottledAsyncChecker.this) {
checksInProgress.remove(target);
completedChecks.put(target, new LastCheckResult<>(
t, timer.monotonicNow()));
}
}
}, MoreExecutors.directExecutor());
}
/**
* Adapt a {@link ListenableFuture} to java standard {@link
* CompletableFuture}, which is used by Jet.
*/
private static <T> CompletableFuture<T> toCompletableFuture(ListenableFuture<T> lf) {
CompletableFuture<T> f = new CompletableFuture<>();
// note that we don't handle CompletableFuture.cancel()
Futures.addCallback(lf, new FutureCallback<T>() {
@Override
public void onSuccess(@NullableDecl T result) {
f.complete(result);
}
@Override
public void onFailure(Throwable t) {
f.completeExceptionally(t);
}
}, directExecutor());
return f;
}
/**
* Opens a Session to Cassandra and initializes the prepared statement.
*
* @param taskNumber The number of the parallel instance.
*/
@Override
public void open(int taskNumber, int numTasks) {
this.session = cluster.connect();
MappingManager mappingManager = new MappingManager(session);
this.mapper = mappingManager.mapper(outputClass);
if (mapperOptions != null) {
Mapper.Option[] optionsArray = mapperOptions.getMapperOptions();
if (optionsArray != null) {
mapper.setDefaultSaveOptions(optionsArray);
}
}
this.callback = new FutureCallback<Void>() {
@Override
public void onSuccess(Void ignored) {
onWriteSuccess();
}
@Override
public void onFailure(Throwable t) {
onWriteFailure(t);
}
};
}
/**
* Opens a Session to Cassandra and initializes the prepared statement.
*
* @param taskNumber The number of the parallel instance.
* @throws IOException Thrown, if the output could not be opened due to an
* I/O problem.
*/
@Override
public void open(int taskNumber, int numTasks) throws IOException {
this.session = cluster.connect();
this.prepared = session.prepare(insertQuery);
this.callback = new FutureCallback<ResultSet>() {
@Override
public void onSuccess(ResultSet ignored) {
onWriteSuccess(ignored);
}
@Override
public void onFailure(Throwable t) {
onWriteFailure(t);
}
};
}
@Override
public void open(Configuration configuration) {
this.callback = new FutureCallback<V>() {
@Override
public void onSuccess(V ignored) {
semaphore.release();
}
@Override
public void onFailure(Throwable t) {
throwable.compareAndSet(null, t);
log.error("Error while sending value.", t);
semaphore.release();
}
};
this.cluster = builder.getCluster();
this.session = createSession();
throwable = new AtomicReference<>();
semaphore = new Semaphore(config.getMaxConcurrentRequests());
}
/**
* <p>Returns a future that wraps a list of all transactions that the given transaction depends on, recursively.
* Only transactions in peers memory pools are included; the recursion stops at transactions that are in the
* current best chain. So it doesn't make much sense to provide a tx that was already in the best chain and
* a precondition checks this.</p>
*
* <p>For example, if tx has 2 inputs that connect to transactions A and B, and transaction B is unconfirmed and
* has one input connecting to transaction C that is unconfirmed, and transaction C connects to transaction D
* that is in the chain, then this method will return either {B, C} or {C, B}. No ordering is guaranteed.</p>
*
* <p>This method is useful for apps that want to learn about how long an unconfirmed transaction might take
* to confirm, by checking for unexpectedly time locked transactions, unusually deep dependency trees or fee-paying
* transactions that depend on unconfirmed free transactions.</p>
*
* <p>Note that dependencies downloaded this way will not trigger the onTransaction method of event listeners.</p>
*/
public ListenableFuture<List<Transaction>> downloadDependencies(Transaction tx) {
TransactionConfidence.ConfidenceType txConfidence = tx.getConfidence().getConfidenceType();
Preconditions.checkArgument(txConfidence != TransactionConfidence.ConfidenceType.BUILDING);
log.info("{}: Downloading dependencies of {}", getAddress(), tx.getHashAsString());
final LinkedList<Transaction> results = new LinkedList<>();
// future will be invoked when the entire dependency tree has been walked and the results compiled.
final ListenableFuture<Object> future = downloadDependenciesInternal(vDownloadTxDependencyDepth, 0, tx,
new Object(), results);
final SettableFuture<List<Transaction>> resultFuture = SettableFuture.create();
Futures.addCallback(future, new FutureCallback<Object>() {
@Override
public void onSuccess(Object ignored) {
resultFuture.set(results);
}
@Override
public void onFailure(Throwable throwable) {
resultFuture.setException(throwable);
}
});
return resultFuture;
}
protected void watchCloseConfirmations() {
// When we see the close transaction get enough confirmations, we can just delete the record
// of this channel along with the refund tx from the wallet, because we're not going to need
// any of that any more.
final TransactionConfidence confidence = storedChannel.close.getConfidence();
int numConfirms = Context.get().getEventHorizon();
ListenableFuture<TransactionConfidence> future = confidence.getDepthFuture(numConfirms, Threading.SAME_THREAD);
Futures.addCallback(future, new FutureCallback<TransactionConfidence>() {
@Override
public void onSuccess(TransactionConfidence result) {
deleteChannelFromWallet();
}
@Override
public void onFailure(Throwable t) {
Throwables.propagate(t);
}
});
}
/**
* <p>Returns a future that wraps a list of all transactions that the given transaction depends on, recursively.
* Only transactions in peers memory pools are included; the recursion stops at transactions that are in the
* current best chain. So it doesn't make much sense to provide a tx that was already in the best chain and
* a precondition checks this.</p>
* <p>
* <p>For example, if tx has 2 inputs that connect to transactions A and B, and transaction B is unconfirmed and
* has one input connecting to transaction C that is unconfirmed, and transaction C connects to transaction D
* that is in the chain, then this method will return either {B, C} or {C, B}. No ordering is guaranteed.</p>
* <p>
* <p>This method is useful for apps that want to learn about how long an unconfirmed transaction might take
* to confirm, by checking for unexpectedly time locked transactions, unusually deep dependency trees or fee-paying
* transactions that depend on unconfirmed free transactions.</p>
* <p>
* <p>Note that dependencies downloaded this way will not trigger the onTransaction method of event listeners.</p>
*/
public ListenableFuture<List<Transaction>> downloadDependencies(Transaction tx) {
TransactionConfidence.ConfidenceType txConfidence = tx.getConfidence().getConfidenceType();
Preconditions.checkArgument(txConfidence != TransactionConfidence.ConfidenceType.BUILDING);
log.info("{}: Downloading dependencies of {}", getAddress(), tx.getHashAsString());
final LinkedList<Transaction> results = new LinkedList<>();
// future will be invoked when the entire dependency tree has been walked and the results compiled.
final ListenableFuture<Object> future = downloadDependenciesInternal(vDownloadTxDependencyDepth, 0, tx,
new Object(), results);
final SettableFuture<List<Transaction>> resultFuture = SettableFuture.create();
Futures.addCallback(future, new FutureCallback<Object>() {
@Override
public void onSuccess(Object ignored) {
resultFuture.set(results);
}
@Override
public void onFailure(Throwable throwable) {
resultFuture.setException(throwable);
}
});
return resultFuture;
}
public static void deleteRunItem(final Context context, final RunItem runItem) {
final ProgressDialog dialog = new ProgressDialog(context);
dialog.setTitle("Deleting run from server");
dialog.setMessage("Working...");
dialog.show();
dialog.setCancelable(false);
dialog.setCanceledOnTouchOutside(false);
mLocalRunItems.remove(runItem);
Futures.addCallback(getRunTable().delete(runItem), new FutureCallback<Void>() {
@Override
public void onSuccess(Void v) {
dialog.dismiss();
}
@Override
public void onFailure(Throwable t) {
Log.e(TAG, "Deleting key error");
}
});
}
/**
* Opens a Session to Cassandra and initializes the prepared statement.
*
* @param taskNumber The number of the parallel instance.
*/
@Override
public void open(int taskNumber, int numTasks) {
this.session = cluster.connect();
MappingManager mappingManager = new MappingManager(session);
this.mapper = mappingManager.mapper(outputClass);
if (mapperOptions != null) {
Mapper.Option[] optionsArray = mapperOptions.getMapperOptions();
if (optionsArray != null) {
mapper.setDefaultSaveOptions(optionsArray);
}
}
this.callback = new FutureCallback<Void>() {
@Override
public void onSuccess(Void ignored) {
onWriteSuccess();
}
@Override
public void onFailure(Throwable t) {
onWriteFailure(t);
}
};
}
/**
* Opens a Session to Cassandra and initializes the prepared statement.
*
* @param taskNumber The number of the parallel instance.
* @throws IOException Thrown, if the output could not be opened due to an
* I/O problem.
*/
@Override
public void open(int taskNumber, int numTasks) throws IOException {
this.session = cluster.connect();
this.prepared = session.prepare(insertQuery);
this.callback = new FutureCallback<ResultSet>() {
@Override
public void onSuccess(ResultSet ignored) {
onWriteSuccess(ignored);
}
@Override
public void onFailure(Throwable t) {
onWriteFailure(t);
}
};
}
@Override
public void open(Configuration configuration) {
this.callback = new FutureCallback<V>() {
@Override
public void onSuccess(V ignored) {
semaphore.release();
}
@Override
public void onFailure(Throwable t) {
throwable.compareAndSet(null, t);
log.error("Error while sending value.", t);
semaphore.release();
}
};
this.cluster = builder.getCluster();
this.session = createSession();
throwable = new AtomicReference<>();
semaphore = new Semaphore(config.getMaxConcurrentRequests());
}
protected void fetchServiceList(FluxSink<String> sink, GrpcRequestContainer request) {
ManagedChannel channel = createChannel(request);
var client = ServerReflectionClient.create(channel);
Futures.addCallback(client.listServices(), new FutureCallback<>() {
@Override
public void onSuccess(ImmutableList<String> result) {
result.forEach(sink::next);
channel.shutdown();
sink.complete();
}
@Override
public void onFailure(Throwable t) {
t.printStackTrace();
channel.shutdown();
sink.error(t);
}
}, executor);
}
@Nonnull
@Override
public ListenableFuture<TotalCaptureResultProxy> removeMetadataFuture(final long timestamp)
{
ListenableFuture<TotalCaptureResultProxy> future = getOrCreateFuture(timestamp);
// Remove the future from the map when it is done to free the memory.
Futures.addCallback(future, new FutureCallback<TotalCaptureResultProxy>()
{
@Override
public void onSuccess(TotalCaptureResultProxy totalCaptureResultProxy)
{
synchronized (mLock)
{
mMetadataFutures.remove(timestamp);
}
}
@Override
public void onFailure(Throwable throwable)
{
throw new UnsupportedOperationException();
}
});
return Futures2.nonCancellationPropagating(future);
}
private void sendClientDisconnect(final Channel channel, final String clientId, final boolean persistent, final Long sessionExpiryInterval) {
final boolean preventWill = channel.attr(ChannelAttributes.PREVENT_LWT).get() != null ? channel.attr(ChannelAttributes.PREVENT_LWT).get() : false;
final boolean sendWill = !preventWill && (channel.attr(ChannelAttributes.SEND_WILL).get() != null ? channel.attr(ChannelAttributes.SEND_WILL).get() : true);
final ListenableFuture<Void> persistenceFuture = clientSessionPersistence.clientDisconnected(clientId, sendWill, sessionExpiryInterval);
FutureUtils.addPersistenceCallback(persistenceFuture, new FutureCallback<Void>() {
@Override
public void onSuccess(@Nullable final Void result) {
if (!channel.attr(ChannelAttributes.TAKEN_OVER).get()) {
channelPersistence.remove(clientId);
}
final SettableFuture<Void> disconnectFuture = channel.attr(ChannelAttributes.DISCONNECT_FUTURE).get();
if (disconnectFuture != null) {
disconnectFuture.set(null);
}
}
@Override
public void onFailure(@NotNull final Throwable throwable) {
Exceptions.rethrowError("Unable to update client session data for disconnecting client " + clientId + " with clean session set to " + !persistent + ".", throwable);
}
}
);
}
private void sendSubackAndRetainedMessages(final ChannelHandlerContext ctx, @NotNull final SUBSCRIBE msg, @NotNull final Mqtt5SubAckReasonCode[] answerCodes,
@NotNull final SettableFuture<List<SubscriptionResult>> addResultsFuture, @NotNull final Set<Topic> ignoredTopics,
final @Nullable String reasonString) {
Futures.addCallback(addResultsFuture, new FutureCallback<>() {
@Override
public void onSuccess(@Nullable final List<SubscriptionResult> subscriptionResults) {
final ChannelFuture future = ctx.writeAndFlush(new SUBACK(msg.getPacketIdentifier(), ImmutableList.copyOf(answerCodes), reasonString));
// actually the ignoredTopics are unnecessary in this case, as the batching logic already applies the filtering
if (subscriptionResults != null) {
future.addListener(new SendRetainedMessagesListener(subscriptionResults, ignoredTopics, retainedMessagePersistence, retainedMessagesSender));
}
}
@Override
public void onFailure(@NotNull final Throwable throwable) {
//Already logged
ctx.channel().disconnect();
}
}, ctx.executor());
}
@NotNull
private SettableFuture<PublishStatus> queuePublish(@NotNull final String client, @NotNull final PUBLISH publish,
final int subscriptionQos, final boolean shared, final boolean retainAsPublished,
@Nullable final ImmutableIntArray subscriptionIdentifier) {
final ListenableFuture<Void> future = clientQueuePersistence.add(client, shared, createPublish(publish, subscriptionQos, retainAsPublished, subscriptionIdentifier));
final SettableFuture<PublishStatus> statusFuture = SettableFuture.create();
Futures.addCallback(future, new FutureCallback<Void>() {
@Override
public void onSuccess(final Void result) {
statusFuture.set(DELIVERED);
}
@Override
public void onFailure(final Throwable t) {
statusFuture.set(FAILED);
}
}, singleWriterService.callbackExecutor(client));
return statusFuture;
}
public ListenableFuture<HealthCheckResponse> handle() {
ShsMetrics.incHealthCheck();
SettableFuture<HealthCheckResponse> future = SettableFuture.create();
try {
Futures.addCallback(ping(), new FutureCallback<HealthCheckResponse>() {
@Override
public void onSuccess(HealthCheckResponse result) {
future.set(result);
}
@Override
public void onFailure(@NonNull Throwable t) {
logger.error("alexa health check failed: ", t);
future.set(badHealth());
}
}, MoreExecutors.directExecutor());
} catch(Exception e) {
logger.error("alexa health check failed: ", e);
future.set(badHealth());
}
return future;
}
private <T> ListenableFuture<Set<T>> getSecondClients(final List<String> serverUrls, final ConfigMeta meta, final String uri, final Function<String, Set<T>> parseFunction) {
final SettableFuture<Set<T>> secondClientsFuture = SettableFuture.create();
long delay = Numbers.toLong(config.get("queryListeningClients.delayMillis"), 1000);
executor.schedule(() -> {
ListenableFuture<Set<T>> secondFuture = doGetListeningClients(serverUrls, meta, uri, parseFunction);
Futures.addCallback(secondFuture, new FutureCallback<Set<T>>() {
@Override
public void onSuccess(Set<T> result) {
secondClientsFuture.set(result);
}
@Override
public void onFailure(Throwable t) {
secondClientsFuture.setException(t);
}
}, Constants.CURRENT_EXECUTOR);
}, delay, TimeUnit.MILLISECONDS);
return secondClientsFuture;
}
private void setupConfidenceListener() {
if (getDepositTx() != null) {
TransactionConfidence transactionConfidence = getDepositTx().getConfidence();
if (transactionConfidence.getConfidenceType() == TransactionConfidence.ConfidenceType.BUILDING) {
setConfirmedState();
} else {
ListenableFuture<TransactionConfidence> future = transactionConfidence.getDepthFuture(1);
Futures.addCallback(future, new FutureCallback<TransactionConfidence>() {
@Override
public void onSuccess(TransactionConfidence result) {
setConfirmedState();
}
@Override
public void onFailure(@NotNull Throwable t) {
t.printStackTrace();
log.error(t.getMessage());
throw new RuntimeException(t);
}
});
}
} else {
log.error("depositTx == null. That must not happen.");
}
}
public void emptyWallet(String toAddress, KeyParameter aesKey, ResultHandler resultHandler, ErrorMessageHandler errorMessageHandler)
throws InsufficientMoneyException, AddressFormatException {
SendRequest sendRequest = SendRequest.emptyWallet(Address.fromBase58(params, toAddress));
sendRequest.fee = Coin.ZERO;
sendRequest.feePerKb = getTxFeeForWithdrawalPerByte().multiply(1000);
sendRequest.aesKey = aesKey;
Wallet.SendResult sendResult = wallet.sendCoins(sendRequest);
printTx("empty wallet", sendResult.tx);
Futures.addCallback(sendResult.broadcastComplete, new FutureCallback<Transaction>() {
@Override
public void onSuccess(Transaction result) {
log.info("emptyWallet onSuccess Transaction=" + result);
resultHandler.handleResult();
}
@Override
public void onFailure(@NotNull Throwable t) {
log.error("emptyWallet onFailure " + t.toString());
errorMessageHandler.handleErrorMessage(t.getMessage());
}
});
}
public String sendFundsForMultipleAddresses(Set<String> fromAddresses,
String toAddress,
Coin receiverAmount,
Coin fee,
@Nullable String changeAddress,
@Nullable KeyParameter aesKey,
FutureCallback<Transaction> callback) throws AddressFormatException,
AddressEntryException, InsufficientMoneyException {
SendRequest request = getSendRequestForMultipleAddresses(fromAddresses, toAddress, receiverAmount, fee, changeAddress, aesKey);
Wallet.SendResult sendResult = wallet.sendCoins(request);
Futures.addCallback(sendResult.broadcastComplete, callback);
printTx("sendFunds", sendResult.tx);
return sendResult.tx.getHashAsString();
}
public SettableFuture<Tuple2<Map<String, Long>, Map<String, Long>>> getFees(FeeProvider provider) {
final SettableFuture<Tuple2<Map<String, Long>, Map<String, Long>>> resultFuture = SettableFuture.create();
ListenableFuture<Tuple2<Map<String, Long>, Map<String, Long>>> future = executorService.submit(() -> {
Thread.currentThread().setName("FeeRequest-" + provider.toString());
return provider.getFees();
});
Futures.addCallback(future, new FutureCallback<Tuple2<Map<String, Long>, Map<String, Long>>>() {
public void onSuccess(Tuple2<Map<String, Long>, Map<String, Long>> feeData) {
log.debug("Received feeData of {}\nfrom provider {}", feeData, provider);
resultFuture.set(feeData);
}
public void onFailure(@NotNull Throwable throwable) {
resultFuture.setException(throwable);
}
});
return resultFuture;
}
private void requestAllPrices(PriceProvider provider, Runnable resultHandler, FaultHandler faultHandler) {
Log.traceCall();
PriceRequest priceRequest = new PriceRequest();
SettableFuture<Tuple2<Map<String, Long>, Map<String, MarketPrice>>> future = priceRequest.requestAllPrices(provider);
Futures.addCallback(future, new FutureCallback<Tuple2<Map<String, Long>, Map<String, MarketPrice>>>() {
@Override
public void onSuccess(@Nullable Tuple2<Map<String, Long>, Map<String, MarketPrice>> result) {
UserThread.execute(() -> {
checkNotNull(result, "Result must not be null at requestAllPrices");
timeStampMap = result.first;
epochInSecondAtLastRequest = timeStampMap.get("btcAverageTs");
final Map<String, MarketPrice> priceMap = result.second;
cache.putAll(priceMap);
resultHandler.run();
});
}
@Override
public void onFailure(@NotNull Throwable throwable) {
UserThread.execute(() -> faultHandler.handleFault("Could not load marketPrices", throwable));
}
});
}
public SettableFuture<Tuple2<Map<String, Long>, Map<String, MarketPrice>>> requestAllPrices(PriceProvider provider) {
final String baseUrl = provider.getBaseUrl();
final SettableFuture<Tuple2<Map<String, Long>, Map<String, MarketPrice>>> resultFuture = SettableFuture.create();
ListenableFuture<Tuple2<Map<String, Long>, Map<String, MarketPrice>>> future = executorService.submit(() -> {
Thread.currentThread().setName("PriceRequest-" + provider.toString());
return provider.getAll();
});
Futures.addCallback(future, new FutureCallback<Tuple2<Map<String, Long>, Map<String, MarketPrice>>>() {
public void onSuccess(Tuple2<Map<String, Long>, Map<String, MarketPrice>> marketPriceTuple) {
log.debug("Received marketPriceTuple of {}\nfrom provider {}", marketPriceTuple, provider);
resultFuture.set(marketPriceTuple);
}
public void onFailure(@NotNull Throwable throwable) {
resultFuture.setException(new PriceRequestException(throwable, baseUrl));
}
});
return resultFuture;
}
protected void watchCloseConfirmations() {
// When we see the close transaction get enough confirmations, we can just delete the record
// of this channel along with the refund tx from the wallet, because we're not going to need
// any of that any more.
final TransactionConfidence confidence = storedChannel.close.getConfidence();
int numConfirms = Context.get().getEventHorizon();
ListenableFuture<TransactionConfidence> future = confidence.getDepthFuture(numConfirms, Threading.SAME_THREAD);
Futures.addCallback(future, new FutureCallback<TransactionConfidence>() {
@Override
public void onSuccess(TransactionConfidence result) {
deleteChannelFromWallet();
}
@Override
public void onFailure(Throwable t) {
Throwables.propagate(t);
}
});
}
public static void sendAsyncMessage(final JobMsg job) {
ListeningExecutorService guavaExecutor = MoreExecutors.listeningDecorator(EXECUTORS);
final ListenableFuture<Boolean> listenableFuture = guavaExecutor.submit(new Callable<Boolean>() {
@Override
public Boolean call() throws Exception {
return MessageProducer.send(job);
}
});
Futures.addCallback(listenableFuture, new FutureCallback<Boolean>() {
@Override
public void onSuccess(Boolean mqMessageStatus) {
}
@Override
public void onFailure(Throwable throwable) {
LOGGER.error(throwable.getMessage());
}
});
}
@Override
public CompletableFuture<Datagram> processRequest(ChannelHandlerContext ctx, RemotingCommand request) {
final List<RawMessageExtend> messages = deserializeRawMessagesExtend(request);
final ListenableFuture<Datagram> result = receiver.receive(messages, request);
final CompletableFuture<Datagram> future = new CompletableFuture<>();
Futures.addCallback(result, new FutureCallback<Datagram>() {
@Override
public void onSuccess(Datagram datagram) {
future.complete(datagram);
}
@Override
public void onFailure(Throwable ex) {
future.completeExceptionally(ex);
}
}, MoreExecutors.directExecutor());
return future;
}