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}