001 002package io.vrap.rmf.base.client.http; 003 004import java.util.ArrayList; 005import java.util.Arrays; 006import java.util.List; 007import java.util.concurrent.CompletableFuture; 008import java.util.function.Function; 009 010import io.vrap.rmf.base.client.ApiHttpRequest; 011import io.vrap.rmf.base.client.ApiHttpResponse; 012import io.vrap.rmf.base.client.AutoCloseableService; 013import io.vrap.rmf.base.client.VrapHttpClient; 014 015/** 016 * The HandlerStack is used to execute the middlewares in order and transfer the request using the specified {@link HttpHandler} 017 */ 018public class HandlerStack extends AutoCloseableService implements VrapHttpClient { 019 public String CLOSED_MESSAGE = "Handler is already closed."; 020 021 private final HttpHandler handler; 022 023 private final List<Middleware> middlewares; 024 025 private Function<ApiHttpRequest, CompletableFuture<ApiHttpResponse<byte[]>>> cached; 026 027 private HandlerStack(final HttpHandler handler, final List<Middleware> middlewares) { 028 this.handler = handler; 029 this.middlewares = middlewares; 030 this.cached = null; 031 } 032 033 public static HandlerStack create(final HttpHandler handler, final List<Middleware> middlewares) { 034 return new HandlerStack(handler, middlewares); 035 } 036 037 public static HandlerStack create(final HttpHandler handler) { 038 return create(handler, new ArrayList<>()); 039 } 040 041 public void addMiddleware(final Middleware middleware) { 042 this.middlewares.add(middleware); 043 this.cached = null; 044 } 045 046 public void addMiddlewares(final List<Middleware> middlewares) { 047 this.middlewares.addAll(middlewares); 048 this.cached = null; 049 } 050 051 public void addMiddlewares(final Middleware... middlewares) { 052 this.middlewares.addAll(Arrays.asList(middlewares)); 053 this.cached = null; 054 } 055 056 Function<ApiHttpRequest, CompletableFuture<ApiHttpResponse<byte[]>>> resolve() { 057 if (cached == null) { 058 List<Middleware> stack = new ArrayList<>(middlewares); 059 060 Function<ApiHttpRequest, CompletableFuture<ApiHttpResponse<byte[]>>> prev = handler::execute; 061 062 for (Middleware middleware : stack) { 063 Function<ApiHttpRequest, CompletableFuture<ApiHttpResponse<byte[]>>> finalPrev = prev; 064 prev = (request) -> middleware.invoke(request, finalPrev); 065 } 066 067 cached = prev; 068 } 069 070 return cached; 071 } 072 073 @Override 074 public CompletableFuture<ApiHttpResponse<byte[]>> execute(ApiHttpRequest request) { 075 rejectExecutionIfClosed(CLOSED_MESSAGE); 076 return invoke(request); 077 } 078 079 public CompletableFuture<ApiHttpResponse<byte[]>> invoke(final ApiHttpRequest request) { 080 final Function<ApiHttpRequest, CompletableFuture<ApiHttpResponse<byte[]>>> handler = resolve(); 081 082 return handler.apply(request); 083 } 084 085 @Override 086 protected void internalClose() { 087 handler.close(); 088 middlewares.forEach(middleware -> { 089 if (middleware instanceof AutoCloseable) { 090 closeQuietly((AutoCloseable) middleware); 091 } 092 }); 093 } 094}