public CompletableFuture<ClientSecureChannel> getChannel() { State currentState = state.get(); logger.trace("getChannel(), currentState={}", currentState.getClass().getSimpleName()); if (currentState instanceof Idle) { Connecting nextState = new Connecting(); if (state.compareAndSet(currentState, nextState)) { CompletableFuture<ClientSecureChannel> connected = nextState.connected; connect(true, connected); return connected.whenCompleteAsync( (sc, ex) -> { if (sc != null) { if (state.compareAndSet(nextState, new Connected(connected))) { sc.getChannel().pipeline().addLast(new InactivityHandler()); } } else { state.compareAndSet(nextState, new Idle()); } }); } else { return getChannel(); } } else if (currentState instanceof Connecting) { return ((Connecting) currentState).connected; } else if (currentState instanceof Connected) { return ((Connected) currentState).connected; } else if (currentState instanceof Reconnecting) { return ((Reconnecting) currentState).reconnected; } else if (currentState instanceof Disconnecting) { CompletableFuture<ClientSecureChannel> future = new CompletableFuture<>(); CompletableFuture<Unit> disconnectFuture = ((Disconnecting) currentState).disconnectFuture; disconnectFuture.whenCompleteAsync( (u, ex) -> getChannel() .whenCompleteAsync( (sc, ex2) -> { if (sc != null) future.complete(sc); else future.completeExceptionally(ex2); }), client.getExecutorService()); return future; } else { throw new IllegalStateException(currentState.getClass().getSimpleName()); } }
// debuging: Intellij issue to see variable: // http://stackoverflow.com/questions/26895708/debugger-cannot-see-local-variable-in-a-lambda /// vs anon class: variable visible. new instances?? // stack traces: we see "lambda" as method name. maybe meth reference? but closures are not // possible ... ////////////////// read further: // http://baddotrobot.com/blog/2014/02/18/method-references-in-java8/ @GET public void findById(@QueryParam("id") int id, @Suspended AsyncResponse asyncResponse) { asyncResponse.setTimeout(10, TimeUnit.SECONDS); final CompletableFuture<Product> product = productDao.findNameById(id); final CompletableFuture<ProductWithGroups> finalResult = product.thenCompose( productFound -> { if (asyncResponse.isDone()) { final CompletableFuture<ProductWithGroups> error = new CompletableFuture<>(); error.completeExceptionally(new IllegalStateException("Response already done")); return error; } else { final CompletableFuture<List<ProductGroup>> productGroups = productDao.findProductGroupsById(id); return productGroups.thenApply( productGroupsFound -> ProductWithGroups.createProductWithGroups( productFound, productGroupsFound)); } }); finalResult.whenCompleteAsync( (productWithGroups, error) -> { consumeProductWithGroupOrError(asyncResponse, productWithGroups, error); }, executorToCompleteCalls); }
private void reconnect(Reconnecting reconnectState, long delaySeconds) { logger.debug("Scheduling reconnect for +{} seconds...", delaySeconds); Stack.sharedScheduledExecutor() .schedule( () -> { logger.debug("{} seconds elapsed; reconnecting...", delaySeconds); CompletableFuture<ClientSecureChannel> reconnected = reconnectState.reconnected; connect(true, reconnected); reconnected.whenCompleteAsync( (sc, ex) -> { if (sc != null) { logger.debug("Reconnect succeeded, channelId={}", sc.getChannelId()); if (state.compareAndSet(reconnectState, new Connected(reconnected))) { sc.getChannel().pipeline().addLast(new InactivityHandler()); } } else { logger.debug("Reconnect failed: {}", ex.getMessage(), ex); Reconnecting nextState = new Reconnecting(); if (state.compareAndSet(reconnectState, nextState)) { reconnect(nextState, nextDelay(delaySeconds)); } } }); }, delaySeconds, TimeUnit.SECONDS); }