001package org.unix4j.operation;
002
003import org.unix4j.command.AbstractCommand;
004import org.unix4j.command.Arguments;
005import org.unix4j.context.ExecutionContext;
006import org.unix4j.line.Line;
007import org.unix4j.operation.AdHocCommand.Args;
008import org.unix4j.processor.LineProcessor;
009
010/**
011 * Implementation of an ad-hoc command based on a {@link LineOperation}.
012 */
013public class AdHocCommand extends AbstractCommand<Args> {
014
015        /**
016         * The "adhoc" name for this command.
017         */
018        public static final String NAME = "adhoc";
019
020        public AdHocCommand(LineOperation operation) {
021                super(NAME, new Args(operation));
022        }
023
024        /**
025         * Arguments for {@link AdHocCommand}.
026         */
027        public static final class Args implements Arguments<Args> {
028                private final LineOperation operation;
029
030                /**
031                 * Constructor with the single operation argument passed to the
032                 * constructor of {@link AdHocCommand}.
033                 * 
034                 * @param operation
035                 *            the operation argument
036                 */
037                public Args(LineOperation operation) {
038                        if (operation == null) {
039                                throw new NullPointerException("operation cannot be null");
040                        }
041                        this.operation = operation;
042                }
043
044                public final LineOperation getOperation() {
045                        return operation;
046                }
047
048                @Override
049                public Args getForContext(ExecutionContext context) {
050                        return this;// no variable args, hence the same for all contexts
051                }
052
053                @Override
054                public String toString() {
055                        return "--operation " + operation;
056                }
057        }
058
059        @Override
060        public LineProcessor execute(final ExecutionContext context, final LineProcessor output) {
061                return new LineProcessor() {
062                        final OperationOutput operationOutput = new OperationOutput(output);
063                        final LineOperation operation = getArguments(context).getOperation();
064
065                        @Override
066                        public boolean processLine(Line line) {
067                                operation.operate(context, line, operationOutput);
068                                return operationOutput.isOpen();
069                        }
070
071                        @Override
072                        public void finish() {
073                                operationOutput.close();
074                        }
075                };
076        }
077
078        private static class OperationOutput implements LineProcessor {
079                private final LineProcessor output;
080                private boolean open = true;
081
082                public OperationOutput(LineProcessor output) {
083                        this.output = output;
084                }
085
086                @Override
087                public boolean processLine(Line line) {
088                        if (open) {
089                                open = output.processLine(line);
090                                return open;
091                        }
092                        return false;
093                }
094
095                @Override
096                public void finish() {
097                        open = false;
098                }
099
100                public boolean isOpen() {
101                        return open;
102                }
103
104                public void close() {
105                        finish();
106                        output.finish();
107                }
108        }
109
110}