private <S extends Stanza, E extends EventObject> AsyncResult<S> sendAndAwait(S stanza, Function<E, S> stanzaMapper, final Predicate<S> filter, Function<S, SendTask<S>> sendFunction, Consumer<Consumer<E>> addListener, Consumer<Consumer<E>> removeListener, Duration timeout) { CompletableFuture<S> completableFuture = new CompletableFuture<>(); final Consumer<E> listener = e -> { S st = stanzaMapper.apply(e); if (filter.test(st)) { if (st.getError() != null) { completableFuture.completeExceptionally(new StanzaErrorException(st)); } completableFuture.complete(st); } }; addListener.accept(listener); SendTask<S> sendTask = sendFunction.apply(stanza); // When the sending failed, immediately complete the future with the exception. sendTask.onFailed((throwable, s) -> completableFuture.completeExceptionally(throwable)); return new AsyncResult<>(completableFuture // When a response has received, mark the requesting stanza as acknowledged. // This is especially important for Bind and Roster IQs, so that they won't be resend after login. .whenComplete((result, e) -> removeFromQueue(sendTask.getStanza())) .applyToEither(CompletionStages.timeoutAfter(timeout.toMillis(), TimeUnit.MILLISECONDS, () -> new NoResponseException("Timeout reached, while waiting on a response for request: " + stanza)), Function.identity())) // When either a timeout happened or response has received, remove the listener. .whenComplete((result, e) -> removeListener.accept(listener)); }
@Override protected CompletionStage<Void> closeStream() { final CompletableFuture<Void> future; final ExecutorService executorService; synchronized (this){ executorService = httpBindExecutor; } if (executorService != null && !executorService.isShutdown()) { final String sid = getSessionId(); if (sid != null) { // Terminate the BOSH session. Body.Builder bodyBuilder = Body.builder() .sessionId(sid) .type(Body.Type.TERMINATE); future = sendNewRequest(bodyBuilder, false) .applyToEither(CompletionStages.timeoutAfter(500, TimeUnit.MILLISECONDS), Function.identity()) .exceptionally(exc -> null); } else { future = CompletableFuture.completedFuture(null); } executorService.shutdown(); } else { future = CompletableFuture.completedFuture(null); } return future; }
return new AsyncResult<>(withFallbackStage.applyToEither(CompletionStages.timeoutAfter(xmppSession.getConfiguration().getDefaultResponseTimeout().toMillis() * 5, TimeUnit.MILLISECONDS), byteStreamSession -> { try { return new FileTransfer(xmppSession, byteStreamSession.getSessionId(), byteStreamSession.getInputStream(), outputStream, fileTransferOffer.getSize());