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

de.objektkontor.wsc.container.Pipeline Maven / Gradle / Ivy

package de.objektkontor.wsc.container;

import static java.lang.String.format;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelPipeline;

import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;

public class Pipeline {

    private final String name;

    private final LinkedList handlers = new LinkedList<>();

    public Pipeline(String name) {
        this.name = name;
    }

    public String name() {
        return name;
    }

    public void init(ChannelPipeline channelPipeline) {
        for (Handler handler : handlers) {
            ChannelHandler channelHandler = handler.create();
            if (channelHandler != null)
                channelPipeline.addLast(channelHandler);
        }
    }

    public void addFirst(Handler handler) {
        handlers.addFirst(handler);
    }

    public void addLast(Handler handler) {
        handlers.addLast(handler);
    }

    public Handler removeHandler(String name) {
        Iterator i = handlers.iterator();
        while (i.hasNext()) {
            Handler handler = i.next();
            if (handler.name().equals(name)) {
                i.remove();
                return handler;
            }
        }
        return null;
    }

    public SplittedPipeline split() {
        return new SplittedPipeline();
    }

    public void validate() throws Exception {
        SplittedPipeline splittedPipeline = split();
        List errors = new LinkedList<>();
        validateInboundHandlers(splittedPipeline.inboundHandlers(), errors);
        validateOutboundHandlers(splittedPipeline.outboundHandlers(), errors);
        if (errors.size() > 0)
            throw new InvalidPipelineException(errors);
    }

    private void validateInboundHandlers(List hadlers, List errors) {
        for (int i = 0; i < hadlers.size(); i++) {
            InboundHandler handler = hadlers.get(i);
            if (i < handlers.size() - 2)
                if (handler.outputInboundType() == null)
                    errors.add(new PipelineValidationError(handler, "Consuming handler allowed only at end of pipeline"));
            if (i > 1) {
                boolean matches = false;
                Class inputType = handler.inputInboundType();
                for (int j = i - 1; j > 0; j--) {
                    InboundHandler previousHandler = hadlers.get(j);
                    Class outputType = previousHandler.outputInboundType();
                    if (inputType.isAssignableFrom(outputType)) {
                        matches = true;
                        break;
                    }
                }
                if (!matches)
                    errors.add(new PipelineValidationError(handler, "Handler's input message type is not compatible with output message type of any previous handlers"));
            }
            if (i == handlers.size() - 1)
                if (handler.outputInboundType() != null)
                    errors.add(new PipelineValidationError(handler, "Pipeline must end with a consuming handler"));
        }
    }

    private void validateOutboundHandlers(List hadlers, List errors) {
        for (int i = 0; i < hadlers.size(); i++) {
            OutboundHandler handler = hadlers.get(i);
            if (handler.outputOutboundType() == null)
                errors.add(new PipelineValidationError(handler, "Consuming handler is not allowed in output pipeline"));
            if (i > 1) {
                boolean matches = false;
                Class inputType = handler.inputOutboundType();
                for (int j = i - 1; j > 0; j--) {
                    OutboundHandler previousHandler = hadlers.get(j);
                    Class outputType = previousHandler.outputOutboundType();
                    if (inputType.isAssignableFrom(outputType)) {
                        matches = true;
                        break;
                    }
                }
                if (!matches)
                    errors.add(new PipelineValidationError(handler, "Handler's input message type is not compatible with output message type of any previous handlers"));
            }
        }
    }

    @Override
    public String toString() {
        SplittedPipeline splittedPipeline = split();
        StringBuilder buffer = new StringBuilder("\n");
        buffer.append("------------------------------------------------------------------------------------------------------------------------------------------------\n");
        buffer.append(" ").append(name()).append("\n");
        buffer.append("------------------------------------------------------------------------------------------------------------------------------------------------\n");
        buffer.append(" Inbound                       Message Type(s)                         | Outbound                      Message Type(s)\n");
        buffer.append("-----------------------------------------------------------------------|------------------------------------------------------------------------\n");
        int length = Math.max(splittedPipeline.inboundHandlers().size(), splittedPipeline.outboundHandlers().size());
        for (int i = 0; i < length; i++) {
            buffer.append(format(" %-70s", i < splittedPipeline.inboundHandlers().size() ? toString(splittedPipeline.inboundHandlers().get(i)) : ""));
            buffer.append(format("| %-70s", i < splittedPipeline.outboundHandlers().size() ? toString(splittedPipeline.outboundHandlers().get(i)) : ""));
            buffer.append("\n");
        }
        return buffer.toString();
    }

    private String toString(InboundHandler handler) {
        return format("%-30s", handler.name()) + "[" +
                handler.inputInboundType().getSimpleName() +
                (handler.outputInboundType() == null ? "" : " > " + handler.outputInboundType().getSimpleName()) + "]";
    }

    private String toString(OutboundHandler handler) {
        return format("%-30s", handler.name()) + "[" +
                handler.inputOutboundType().getSimpleName() +
                (handler.outputOutboundType() == null ? "" : " > " + handler.outputOutboundType().getSimpleName()) + "]";
    }

    public class SplittedPipeline {

        private final LinkedList inboundHandlers = new LinkedList<>();
        private final LinkedList outboundHandlers = new LinkedList<>();

        public SplittedPipeline() {
            for (Handler handler : handlers) {
                if (handler instanceof InboundHandler)
                    inboundHandlers.addLast((InboundHandler) handler);
                if (handler instanceof OutboundHandler)
                    outboundHandlers.addFirst((OutboundHandler) handler);
            }
        }

        public LinkedList inboundHandlers() {
            return inboundHandlers;
        }

        public LinkedList outboundHandlers() {
            return outboundHandlers;
        }
    }

    public class PipelineValidationError {

        private final Handler handler;
        private final String cause;

        public PipelineValidationError(Handler handler, String cause) {
            this.handler = handler;
            this.cause = cause;
        }

        public Handler getHandler() {
            return handler;
        }

        public String getCause() {
            return cause;
        }

        @Override
        public String toString() {
            return handler.name() + ": " + cause + "]";
        }
    }

    public class InvalidPipelineException extends Exception {

        private static final long serialVersionUID = -3567200380068538023L;

        private final List errors;

        public InvalidPipelineException(List errors) {
            this.errors = errors;
        }

        @Override
        public String getMessage() {
            StringBuilder buffer = new StringBuilder("Invalid pipeline:\n");
            for (PipelineValidationError error : errors)
                buffer.append(" - ").append(error).append("\n");
            buffer.append("Pipeline dump: ").append(Pipeline.this);
            return buffer.toString();
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy