Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Consider a structured approach to enriching/modifying endpoint behavior #416

Closed
markelliot opened this issue Jun 11, 2019 · 0 comments
Closed

Comments

@markelliot
Copy link
Contributor

What happened?

No built-in way to modify endpoint behavior today. #406 proposes a way to wholesale replace functionality.

What did you want to happen?

Consider a structured aspect approach to enriching/modifying endpoint behavior:

interface EndpointAspect<C> {
    interface Factory {
        /** 
         * Returns an {@link Optional} containing a new {@link EndpointAspect} instance for 
         * {@link Endpoint} if this aspect is relevant for the specified endpoint, and empty otherwise.
         */
        <Context> Optional<? extends EndpointAspect<Context>> create(Endpoint endpoint);
    }

    /**
     * Invoked prior to the underlying {@link HttpHandler#handle(HttpServerExchange)} call
     * and returns a context object of type {@code C}.
     */
    default C before(HttpServerExchange exchange) {
        return null;
    }

    /** 
     * Returns true to prevent calling the underlying {@link HttpHandler} implementation.
     * Defaults to {@code false}.
     */
    default boolean haltCall(C context, HttpServerExchange exchange) {
        return false;
    }

    /**
     * Invoked after the underlying {@link HttpHandler#handle(HttpServerExchange)} call,
     * if the call does not throw, and returns a context object of type {@code C}.
     */
    default C onSuccess(C context, HttpServerExchange exchange) {
        return null;
    }

    /**
     * Invoked after the underlying {@link HttpHandler#handle(HttpServerExchange)} call,
     * if the call throws, and returns a context object of type {@code C}.
     */
    default C onThrow(C context, HttpServerExchange exchange, Exception e) {
        return null;
    }

    /**
     * Invoked as a completion listener to the the handler call chain.
     */
    default void completion(C context, HttpServerExchange exchange) {}
}

Which is implemented as:

service.endpoints(runtime).stream()
    .map(endpoint ->
        factory.create(endpoint)
            .map(aspect ->
                Endpoint.builder()
                    .from(endpoint)
                    .handler(exchange -> {
                        Object context = aspect.before(exchange);
                        if (!aspect.haltCall(context, exchange) {
                            try {
                                endpoint.handler().handleRequest(exchange);
                                onSuccess(context, exchange);
                                exchange.addCompletionListener(completion(context, exchange));
                            } catch (Exception e) {
                                onThrow(context, exchange, e);
                            }
                        }
                    })
                    .build())
            })
            .orElse(endpoint.handler())
    .collect(ImmutableList.toImmutableList()));
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant