All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.undertow.predicate.PredicatesHandler Maven / Gradle / Ivy

Go to download

This artifact provides a single jar that contains all classes required to use remote EJB and JMS, including all dependencies. It is intended for use by those not using maven, maven users should just import the EJB and JMS BOM's instead (shaded JAR's cause lots of problems with maven, as it is very easy to inadvertently end up with different versions on classes on the class path).

There is a newer version: 34.0.0.Final
Show newest version
/*
 * JBoss, Home of Professional Open Source.
 * Copyright 2014 Red Hat, Inc., and individual contributors
 * as indicated by the @author tags.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */

package io.undertow.predicate;

import io.undertow.UndertowLogger;
import io.undertow.server.HandlerWrapper;
import io.undertow.server.HttpHandler;
import io.undertow.server.HttpServerExchange;
import io.undertow.server.handlers.builder.HandlerBuilder;
import io.undertow.server.handlers.builder.PredicatedHandler;
import io.undertow.util.AttachmentKey;

import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;

/**
 * Handler that can deal with a large number of predicates. chaining together a large number of {@link io.undertow.predicate.PredicatesHandler.Holder}
 * instances will make the stack grow to large, so this class is used that can deal with a large number of predicates.
 *
 * @author Stuart Douglas
 */
public class PredicatesHandler implements HttpHandler {

    /**
     * static done marker. If this is attached to the exchange it will drop out immediately.
     */
    public static final AttachmentKey DONE = AttachmentKey.create(Boolean.class);
    public static final AttachmentKey RESTART = AttachmentKey.create(Boolean.class);
    private static final boolean traceEnabled;

    static {
        traceEnabled = UndertowLogger.PREDICATE_LOGGER.isTraceEnabled();
    }

    private volatile Holder[] handlers = new Holder[0];
    private volatile HttpHandler next;
    private final boolean outerHandler;

    //non-static, so multiple handlers can co-exist
    private final AttachmentKey CURRENT_POSITION = AttachmentKey.create(Integer.class);

    public PredicatesHandler(HttpHandler next) {
        this.next = next;
        this.outerHandler = true;
    }
    public PredicatesHandler(HttpHandler next, boolean outerHandler) {
        this.next = next;
        this.outerHandler = outerHandler;
    }

    @Override
    public String toString() {
        return "PredicatesHandler with " + handlers.length + " predicates";
    }

    @Override
    public void handleRequest(HttpServerExchange exchange) throws Exception {
        final int length = handlers.length;
        Integer current = exchange.getAttachment(CURRENT_POSITION);
        do {
            int pos;
            if (current == null) {
                if (outerHandler) {
                    exchange.removeAttachment(RESTART);
                    exchange.removeAttachment(DONE);
                    if (exchange.getAttachment(Predicate.PREDICATE_CONTEXT) == null) {
                        exchange.putAttachment(Predicate.PREDICATE_CONTEXT, new TreeMap());
                    }
                }
                pos = 0;
            } else {
                //if it has been marked as done
                if (exchange.getAttachment(DONE) != null) {
                    if (traceEnabled && outerHandler) {
                        UndertowLogger.PREDICATE_LOGGER.tracef("Predicate chain marked done. Next handler is [%s] for %s.", next.toString(), exchange);
                    }
                    exchange.removeAttachment(CURRENT_POSITION);
                    next.handleRequest(exchange);
                    return;
                }
                pos = current;
            }
            for (; pos < length; ++pos) {
                final Holder handler = handlers[pos];
                if (handler.predicate.resolve(exchange)) {
                    if(traceEnabled) {
                        if( handler.predicate.toString().equals("true") ) {
                            UndertowLogger.PREDICATE_LOGGER.tracef("Executing handler [%s] for %s.", handler.handler.toString(), exchange);
                        } else {
                            UndertowLogger.PREDICATE_LOGGER.tracef("Predicate [%s] resolved to true. Next handler is [%s] for %s.", handler.predicate.toString(), handler.handler.toString(), exchange);
                        }
                    }
                    exchange.putAttachment(CURRENT_POSITION, pos + 1);
                    handler.handler.handleRequest(exchange);
                    if(shouldRestart(exchange, current)) {
                        if(traceEnabled) {
                            UndertowLogger.PREDICATE_LOGGER.tracef("Restarting predicate resolution for %s.", exchange);
                        }
                        break;
                    } else {
                        return;
                    }
                } else if(handler.elseBranch != null) {
                    if(traceEnabled) {
                        UndertowLogger.PREDICATE_LOGGER.tracef("Predicate [%s] resolved to false. Else branch is [%s] for %s.", handler.predicate.toString(), handler.elseBranch.toString(), exchange);
                    }
                    exchange.putAttachment(CURRENT_POSITION, pos + 1);
                    handler.elseBranch.handleRequest(exchange);
                    if(shouldRestart(exchange, current)) {
                        if(traceEnabled) {
                            UndertowLogger.PREDICATE_LOGGER.tracef("Restarting predicate resolution for %s.", exchange);
                        }
                        break;
                    } else {
                        return;
                    }
                } else if(traceEnabled) {
                    UndertowLogger.PREDICATE_LOGGER.tracef("Predicate [%s] resolved to false for %s.", handler.predicate.toString(), exchange);
                }
            }
        } while (shouldRestart(exchange, current));
        next.handleRequest(exchange);

    }

    private boolean shouldRestart(HttpServerExchange exchange, Integer current) {
        return exchange.getAttachment(RESTART) != null && outerHandler && current == null;
    }

    /**
     * Adds a new predicated handler.
     * 

* * @param predicate * @param handlerWrapper */ public PredicatesHandler addPredicatedHandler(final Predicate predicate, final HandlerWrapper handlerWrapper, final HandlerWrapper elseBranch) { Holder[] old = handlers; Holder[] handlers = new Holder[old.length + 1]; System.arraycopy(old, 0, handlers, 0, old.length); HttpHandler elseHandler = elseBranch != null ? elseBranch.wrap(this) : null; handlers[old.length] = new Holder(predicate, handlerWrapper.wrap(this), elseHandler); this.handlers = handlers; return this; } /** * Adds a new predicated handler. *

* * @param predicate * @param handlerWrapper */ public PredicatesHandler addPredicatedHandler(final Predicate predicate, final HandlerWrapper handlerWrapper) { this.addPredicatedHandler(predicate, handlerWrapper, null); return this; } public PredicatesHandler addPredicatedHandler(final PredicatedHandler handler) { return addPredicatedHandler(handler.getPredicate(), handler.getHandler(), handler.getElseHandler()); } public void setNext(HttpHandler next) { this.next = next; } public HttpHandler getNext() { return next; } private static final class Holder { final Predicate predicate; final HttpHandler handler; final HttpHandler elseBranch; private Holder(Predicate predicate, HttpHandler handler, HttpHandler elseBranch) { this.predicate = predicate; this.handler = handler; this.elseBranch = elseBranch; } } public static final class DoneHandlerBuilder implements HandlerBuilder { @Override public String name() { return "done"; } @Override public Map> parameters() { return Collections.emptyMap(); } @Override public Set requiredParameters() { return Collections.emptySet(); } @Override public String defaultParameter() { return null; } @Override public HandlerWrapper build(Map config) { return new HandlerWrapper() { @Override public HttpHandler wrap(final HttpHandler handler) { return new HttpHandler() { @Override public void handleRequest(HttpServerExchange exchange) throws Exception { exchange.putAttachment(DONE, true); handler.handleRequest(exchange); } @Override public String toString() { return "done"; } }; } }; } } public static final class RestartHandlerBuilder implements HandlerBuilder { private static final AttachmentKey RESTART_COUNT = AttachmentKey.create(Integer.class); private static final int MAX_RESTARTS = Integer.getInteger("io.undertow.max_restarts", 1000); @Override public String name() { return "restart"; } @Override public Map> parameters() { return Collections.emptyMap(); } @Override public Set requiredParameters() { return Collections.emptySet(); } @Override public String defaultParameter() { return null; } @Override public HandlerWrapper build(Map config) { return new HandlerWrapper() { @Override public HttpHandler wrap(final HttpHandler handler) { return new HttpHandler() { @Override public void handleRequest(HttpServerExchange exchange) throws Exception { Integer restarts = exchange.getAttachment(RESTART_COUNT); if(restarts == null) { restarts = 1; } else { restarts++; } exchange.putAttachment(RESTART_COUNT, restarts); if(restarts > MAX_RESTARTS) { throw UndertowLogger.ROOT_LOGGER.maxRestartsExceeded(MAX_RESTARTS); } exchange.putAttachment(RESTART, true); } @Override public String toString() { return "restart"; } }; } }; } } public static class Wrapper implements HandlerWrapper { private final List handlers; private final boolean outerHandler; public Wrapper(List handlers, boolean outerHandler) { this.handlers = handlers; this.outerHandler = outerHandler; } @Override public HttpHandler wrap(HttpHandler handler) { PredicatesHandler h = new PredicatesHandler(handler, outerHandler); for(PredicatedHandler pred : handlers) { h.addPredicatedHandler(pred.getPredicate(), pred.getHandler()); } return h; } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy