001package org.unix4j.builder;
002
003import org.unix4j.command.Command;
004import org.unix4j.command.ExitValueException;
005import org.unix4j.command.NoOp;
006import org.unix4j.context.DefaultExecutionContext;
007import org.unix4j.context.ExecutionContextFactory;
008import org.unix4j.io.BufferedOutput;
009import org.unix4j.io.FileOutput;
010import org.unix4j.io.NullOutput;
011import org.unix4j.io.Output;
012import org.unix4j.io.StdOutput;
013import org.unix4j.io.StreamOutput;
014import org.unix4j.io.StringOutput;
015import org.unix4j.io.WriterOutput;
016import org.unix4j.line.Line;
017import org.unix4j.operation.AdHocCommand;
018import org.unix4j.operation.LineOperation;
019
020import java.io.File;
021import java.io.OutputStream;
022import java.io.Writer;
023import java.util.ArrayList;
024import java.util.List;
025import java.util.stream.Stream;
026
027/**
028 * Default implementation for a {@link CommandBuilder}. Builds a {@link NoOp}
029 * command if no command is {@link #join(Command) joined} to the command chain
030 * of this builder.
031 */
032public class DefaultCommandBuilder implements CommandBuilder {
033
034        private final ExecutionContextFactory contextFactory;
035        private Command<?> command = NoOp.INSTANCE;
036
037        /**
038         * Default constructor initialized to build a {@link NoOp} command if no
039         * command is {@link #join(Command) joined} to this builder's command chain.
040         * Uses a {@link DefaultExecutionContext} to execute commands.
041         */
042        public DefaultCommandBuilder() {
043                this(DefaultExecutionContext.FACTORY);
044        }
045
046        /**
047         * Constructor using the specified factory to create contexts for command
048         * execution. The builder is initialized with a {@link NoOp} command which
049         * will be replaced by the first command {@link #join(Command) joined} to 
050         * this builder's command chain. 
051         * 
052         * @param contextFactory
053         *            the factory used to create execution contexts that are passed
054         *            to the execute method when a command is executed
055         */
056        public DefaultCommandBuilder(ExecutionContextFactory contextFactory) {
057                this.contextFactory = contextFactory;
058        }
059
060        /**
061         * Returns the context factory used to create contexts for command
062         * execution. The returned factory has usually been passed to the
063         * constructor of this builder.
064         * 
065         * @return the factory used to create execution contexts that are passed to
066         *         the execute method when a command is executed
067         */
068        public ExecutionContextFactory getContextFactory() {
069                return contextFactory;
070        }
071
072        @Override
073        public CommandBuilder join(Command<?> command) {
074                if (command == null) {
075                        throw new NullPointerException("command argument cannot be null");
076                }
077                this.command = this.command.join(command);
078                return this;
079        }
080        
081        @Override
082        public CommandBuilder apply(LineOperation operation) {
083                return join(new AdHocCommand(operation));
084        }
085
086        @Override
087        public CommandBuilder reset() {
088                command = NoOp.INSTANCE;
089                return this;
090        }
091
092        @Override
093        public Command<?> build() {
094                return command;
095        }
096
097        @Override
098        public String toString() {
099                return command.toString();
100        }
101
102        @Override
103        public void toStdOut() {
104                toOutput(new StdOutput());
105        }
106
107        @Override
108        public List<Line> toLineList() {
109                final List<Line> lines = new ArrayList<Line>();
110                toOutput(new BufferedOutput(lines));
111                return lines;
112        }
113
114        @Override
115        public List<String> toStringList() {
116                final List<String> lines = new ArrayList<String>();
117                toOutput(new Output() {
118                        @Override
119                        public boolean processLine(Line line) {
120                                lines.add(line.getContent());
121                                return true;// we want more lines
122                        }
123
124                        @Override
125                        public void finish() {
126                                // no op
127                        }
128                });
129                return lines;
130        }
131
132        @Override
133        public Stream<Line> toLineStream() {
134                return toLineList().stream();
135        }
136
137        @Override
138        public Stream<String> toStringStream() {
139                return toStringList().stream();
140        }
141
142        @Override
143        public void toOutput(Output output) {
144                final Command<?> command = build();
145                command.execute(getContextFactory().createExecutionContext(), output).finish();
146        }
147
148        @Override
149        public void toFile(String file) {
150                toFile(new File(file));
151        }
152
153        @Override
154        public void toFile(File file) {
155                toOutput(new FileOutput(file));
156        }
157
158        @Override
159        public void toOutputStream(OutputStream stream) {
160                toOutput(new StreamOutput(stream));
161        }
162
163        @Override
164        public void toWriter(Writer writer) {
165                toOutput(new WriterOutput(writer));
166        }
167
168        @Override
169        public void toDevNull() {
170                toOutput(NullOutput.DEFAULT);
171        }
172
173        @Override
174        public String toStringResult() {
175                final StringOutput out = new StringOutput();
176                toOutput(out);
177                return out.toString();
178        }
179
180        @Override
181        public int toExitValue() {
182                try {
183                        toDevNull();
184                        return 0;
185                } catch (ExitValueException e) {
186                        return e.getExitValue();
187                }
188        }
189}