package netflix.karyon.transport.http; import com.google.inject.Injector; import io.netty.handler.codec.http.HttpMethod; import io.reactivex.netty.protocol.http.server.HttpServerRequest; import io.reactivex.netty.protocol.http.server.HttpServerResponse; import netflix.karyon.transport.interceptor.AbstractAttacher; import netflix.karyon.transport.interceptor.AbstractInterceptorSupport; import netflix.karyon.transport.interceptor.DuplexInterceptor; import netflix.karyon.transport.interceptor.InboundInterceptor; import netflix.karyon.transport.interceptor.InterceptorHolder; import netflix.karyon.transport.interceptor.InterceptorKey; import netflix.karyon.transport.interceptor.OutboundInterceptor; import rx.functions.Action1; import java.util.ArrayList; import java.util.List; /** * * @author Nitesh Kant */ public class GovernatorHttpInterceptorSupport<I, O> extends AbstractInterceptorSupport<HttpServerRequest<I>, HttpServerResponse<O>, HttpKeyEvaluationContext, GovernatorHttpInterceptorSupport.GovernatorHttpAttacher<I, O>, GovernatorHttpInterceptorSupport<I, O>> { protected final List<HttpInClassHolder<I, O>> inboundInterceptorClasses; protected final List<HttpOutClassHolder<I, O>> outboundInterceptorClasses; private Action1<GovernatorHttpInterceptorSupport<I, O>> finishListener; public GovernatorHttpInterceptorSupport() { inboundInterceptorClasses = new ArrayList<HttpInClassHolder<I, O>>(); outboundInterceptorClasses = new ArrayList<HttpOutClassHolder<I, O>>(); } @Override protected GovernatorHttpAttacher<I, O> newAttacher(InterceptorKey<HttpServerRequest<I>, HttpKeyEvaluationContext> key) { return new GovernatorHttpAttacher<I, O>(this, key); } public GovernatorHttpAttacher<I, O> forUri(String uri) { if (null == uri || uri.isEmpty()) { throw new IllegalArgumentException("Uri can not be null or empty."); } return getAttacherForKey(new ServletStyleUriConstraintKey<I>(uri, "")); } public GovernatorHttpAttacher<I, O> forUriRegex(String uriRegEx) { if (null == uriRegEx || uriRegEx.isEmpty()) { throw new IllegalArgumentException("Uri regular expression can not be null or empty."); } return getAttacherForKey(new RegexUriConstraintKey<I>(uriRegEx)); } public GovernatorHttpAttacher<I, O> forHttpMethod(HttpMethod method) { if (null == method) { throw new IllegalArgumentException("Uri can not be null or empty."); } return getAttacherForKey(new MethodConstraintKey<I>(method)); } public GovernatorHttpInterceptorSupport<I, O> finish(Injector injector) { if (!finished) { for (HttpInClassHolder<I, O> holder : inboundInterceptorClasses) { HttpInboundHolder<I, O> ins = new HttpInboundHolder<I, O>(holder.getKey()); for (Class<? extends InboundInterceptor<HttpServerRequest<I>, HttpServerResponse<O>>> interceptor : holder .getInterceptors()) { ins.addIn(injector.getInstance(interceptor)); } inboundInterceptors.add(ins.buildHolder()); } for (HttpOutClassHolder<I, O> holder : outboundInterceptorClasses) { HttpOutboundHolder<I, O> outs = new HttpOutboundHolder<I, O>(holder.getKey()); for (Class<? extends OutboundInterceptor<HttpServerResponse<O>>> interceptor : holder.getInterceptors()) { outs.addOut(injector.getInstance(interceptor)); } outboundInterceptors.add(outs.buildHolder()); } _finish(); finished = true; if (null != finishListener) { finishListener.call(this); } } return this; } public void setFinishListener(Action1<GovernatorHttpInterceptorSupport<I, O>> finishListener) { this.finishListener = finishListener; } public static class GovernatorHttpAttacher<I, O> extends AbstractAttacher<HttpServerRequest<I>, HttpServerResponse<O>, HttpKeyEvaluationContext, GovernatorHttpInterceptorSupport<I, O>> { public GovernatorHttpAttacher(GovernatorHttpInterceptorSupport<I, O> support, InterceptorKey<HttpServerRequest<I>, HttpKeyEvaluationContext> key) { super(support, key); } public GovernatorHttpInterceptorSupport<I, O> interceptIn(Class<? extends InboundInterceptor<HttpServerRequest<I>, HttpServerResponse<O>>> interceptor) { ArrayList<Class<? extends InboundInterceptor<HttpServerRequest<I>, HttpServerResponse<O>>>> interceptors = new ArrayList<Class<? extends InboundInterceptor<HttpServerRequest<I>, HttpServerResponse<O>>>>(); interceptors.add(interceptor); return interceptIn(interceptors); } public GovernatorHttpInterceptorSupport<I, O> interceptIn( List<Class<? extends InboundInterceptor<HttpServerRequest<I>, HttpServerResponse<O>>>> interceptors) { HttpInClassHolder<I, O> holder = new HttpInClassHolder<I, O>(key, interceptors); interceptorSupport.inboundInterceptorClasses.add(holder); return interceptorSupport; } public GovernatorHttpInterceptorSupport<I, O> interceptOut(Class<? extends OutboundInterceptor<HttpServerResponse<O>>> interceptor) { ArrayList<Class<? extends OutboundInterceptor<HttpServerResponse<O>>>> interceptors = new ArrayList<Class<? extends OutboundInterceptor<HttpServerResponse<O>>>>(); interceptors.add(interceptor); return interceptOut(interceptors); } public GovernatorHttpInterceptorSupport<I, O> interceptOut(List<Class<? extends OutboundInterceptor<HttpServerResponse<O>>>> interceptors) { HttpOutClassHolder<I, O> holder = new HttpOutClassHolder<I, O>(key, interceptors); interceptorSupport.outboundInterceptorClasses.add(holder); return interceptorSupport; } @SuppressWarnings("unchecked") public GovernatorHttpInterceptorSupport<I, O> intercept(Class<? extends DuplexInterceptor<HttpServerRequest<I>, HttpServerResponse<O>>> interceptor) { ArrayList<Class<? extends DuplexInterceptor<HttpServerRequest<I>, HttpServerResponse<O>>>> interceptors = new ArrayList<Class<? extends DuplexInterceptor<HttpServerRequest<I>, HttpServerResponse<O>>>>(); interceptors.add(interceptor); return intercept(interceptors); } public GovernatorHttpInterceptorSupport<I, O> intercept(List<Class<? extends DuplexInterceptor<HttpServerRequest<I>, HttpServerResponse<O>>>> interceptors) { ArrayList<Class<? extends InboundInterceptor<HttpServerRequest<I>, HttpServerResponse<O>>>> ins = new ArrayList<Class<? extends InboundInterceptor<HttpServerRequest<I>, HttpServerResponse<O>>>>(); ArrayList<Class<? extends OutboundInterceptor<HttpServerResponse<O>>>> outs = new ArrayList<Class<? extends OutboundInterceptor<HttpServerResponse<O>>>>(); for (Class<? extends DuplexInterceptor<HttpServerRequest<I>, HttpServerResponse<O>>> interceptor : interceptors) { ins.add(interceptor); outs.add(interceptor); } HttpInClassHolder<I, O> inHolder = new HttpInClassHolder<I, O>(key, ins); interceptorSupport.inboundInterceptorClasses.add(inHolder); HttpOutClassHolder<I, O> outHolder = new HttpOutClassHolder<I, O>(key, outs); interceptorSupport.outboundInterceptorClasses.add(outHolder); return interceptorSupport; } } private static class HttpInboundHolder<I, O> { private final InterceptorKey<HttpServerRequest<I>, HttpKeyEvaluationContext> key; private final List<InboundInterceptor<HttpServerRequest<I>, HttpServerResponse<O>>> interceptors; private HttpInboundHolder(InterceptorKey<HttpServerRequest<I>, HttpKeyEvaluationContext> key) { this.key = key; interceptors = new ArrayList<InboundInterceptor<HttpServerRequest<I>, HttpServerResponse<O>>>(); } private void addIn(InboundInterceptor<HttpServerRequest<I>, HttpServerResponse<O>> interceptor) { interceptors.add(interceptor); } private InterceptorHolder<HttpServerRequest<I>, HttpKeyEvaluationContext, InboundInterceptor<HttpServerRequest<I>, HttpServerResponse<O>>> buildHolder() { return new InterceptorHolder<HttpServerRequest<I>, HttpKeyEvaluationContext, InboundInterceptor<HttpServerRequest<I>, HttpServerResponse<O>>>(key, interceptors); } } private static class HttpOutboundHolder<I, O> { private final InterceptorKey<HttpServerRequest<I>, HttpKeyEvaluationContext> key; private final List<OutboundInterceptor<HttpServerResponse<O>>> interceptors; private HttpOutboundHolder(InterceptorKey<HttpServerRequest<I>, HttpKeyEvaluationContext> key) { this.key = key; interceptors = new ArrayList<OutboundInterceptor<HttpServerResponse<O>>>(); } private void addOut(OutboundInterceptor<HttpServerResponse<O>> interceptor) { interceptors.add(interceptor); } private InterceptorHolder<HttpServerRequest<I>, HttpKeyEvaluationContext, OutboundInterceptor<HttpServerResponse<O>>> buildHolder() { return new InterceptorHolder<HttpServerRequest<I>, HttpKeyEvaluationContext, OutboundInterceptor<HttpServerResponse<O>>>(key, interceptors); } } private static class HttpInClassHolder<I, O> extends InterceptorHolder<HttpServerRequest<I>, HttpKeyEvaluationContext, Class<? extends InboundInterceptor<HttpServerRequest<I>, HttpServerResponse<O>>>> { private HttpInClassHolder(InterceptorKey<HttpServerRequest<I>, HttpKeyEvaluationContext> key, List<Class<? extends InboundInterceptor<HttpServerRequest<I>, HttpServerResponse<O>>>> interceptors) { super(key, interceptors); } } private static class HttpOutClassHolder<I, O> extends InterceptorHolder<HttpServerRequest<I>, HttpKeyEvaluationContext, Class<? extends OutboundInterceptor<HttpServerResponse<O>>>> { private HttpOutClassHolder(InterceptorKey<HttpServerRequest<I>, HttpKeyEvaluationContext> key, List<Class<? extends OutboundInterceptor<HttpServerResponse<O>>>> interceptors) { super(key, interceptors); } } }