001package org.unix4j.processor;
002
003import java.util.List;
004
005import org.unix4j.command.ExitValueException;
006import org.unix4j.io.Input;
007import org.unix4j.line.Line;
008
009/**
010 * A line processor for multiple inputs processing the same operation for each
011 * input object individually. An operation here is another {@link LineProcessor}
012 * reading the lines passed to it from the standard input.
013 * <p>
014 * The {@link #processLine(Line)} method does nothing and returns false
015 * indicating that the (standard) input is not read by this processor. The
016 * {@link #finish()} method reads the lines from the {@link Input} object passed
017 * to the constructor and passes them as input to the delegate processor
018 * performing the real work.
019 */
020public class MultipleInputLineProcessor implements LineProcessor {
021
022        private final List<? extends Input> inputs;
023        private final InputProcessor processor;
024        private final LineProcessor output;
025
026        /**
027         * Constructor with input objects (usually file operands of the command) and
028         * the input processor of the command that reads from the standard input.
029         * 
030         * @param inputs
031         *            the input devices, usually file operands of the command
032         * @param processor
033         *            the operation applied to every input in the given
034         *            {@code inputs} list
035         */
036        public MultipleInputLineProcessor(List<? extends Input> inputs, InputProcessor processor, LineProcessor output) {
037                this.inputs = inputs;
038                this.processor = processor;
039                this.output = output;
040        }
041
042        @Override
043        public boolean processLine(Line line) {
044                return false;// we want no input, we have it already
045        }
046
047        /**
048         * Performs the following operations to process all {@code Input} objects
049         * that have been passed to the constructor:
050         * <ol>
051         * <li>Calls {@link #beginMultiple(List, LineProcessor) beginMultiple(..)}</li>
052         * <li>Iterates over all input objects in sequence</li>
053         * <li>Calls {@link InputProcessor#begin(Input, LineProcessor)}</li>
054         * <li>Calls {@link InputProcessor#processLine(Input, Line, LineProcessor)}
055         * for every line in the current input</li>
056         * <li>Calls {@link InputProcessor#finish(Input, LineProcessor)}</li>
057         * <li>Calls {@link #finishMultiple(List, LineProcessor) finishMultiple(..)}
058         * </li>
059         * </ol>
060         */
061        @Override
062        public void finish() {
063                beginMultiple(inputs, output);
064                for (int i = 0; i < inputs.size(); i++) {
065                        final Input input = inputs.get(i);
066                        try {
067                                processor.begin(input, output);
068                                for (final Line line : input) {
069                                        if (!processor.processLine(input, line, output)) {
070                                                break;// wants no more lines
071                                        }
072                                }
073                                processor.finish(input, output);
074                        } catch (ExitValueException e) {
075                                e.setInput(input);
076                                throw e;
077                        }
078                }
079                finishMultiple(inputs, output);
080        }
081
082        /**
083         * Called once at the beginning before iterating over the {@link Input}
084         * objects in the given {@code inputs} list.
085         * <p>
086         * The DEFAULT implementation performs no operation.
087         * 
088         * @param inputs
089         *            the input object being iterated next
090         * @param output
091         *            the output to write to
092         */
093        protected void beginMultiple(List<? extends Input> inputs, LineProcessor output) {
094                // default: no op
095        }
096
097        /**
098         * Called once at the end after iterating over the {@link Input} objects in
099         * the given {@code inputs} list.
100         * <p>
101         * The DEFAULT implementation calls {@link LineProcessor#finish()
102         * output.finish()}.
103         * 
104         * @param inputs
105         *            the input object being iterated next
106         * @param output
107         *            the output to write to
108         */
109        protected void finishMultiple(List<? extends Input> inputs, LineProcessor output) {
110                output.finish();
111        }
112
113}