001/**
002 * Copyright 2010-2013 The Kuali Foundation
003 *
004 * Licensed under the Educational Community License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.opensource.org/licenses/ecl2.php
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016package org.kuali.common.util.channel.model;
017
018import java.io.ByteArrayInputStream;
019import java.io.InputStream;
020import java.util.List;
021
022import org.codehaus.plexus.util.cli.StreamConsumer;
023import org.kuali.common.util.Assert;
024import org.kuali.common.util.Encodings;
025import org.kuali.common.util.Str;
026import org.kuali.common.util.stream.NoOpStreamConsumer;
027
028import com.google.common.base.Optional;
029import com.google.common.collect.ImmutableList;
030
031public final class CommandContext {
032
033        private final byte[] command;
034        private final Optional<InputStream> stdin;
035        private final Optional<Integer> timeout;
036        private final StreamConsumer stdout;
037        private final StreamConsumer stderr;
038        private final List<Integer> successCodes;
039        private final boolean ignoreExitValue;
040
041        public static class Builder {
042
043                private static final int SUCCESS = 0;
044                private static final String UTF8 = Encodings.UTF8;
045
046                // Required
047                private final byte[] command;
048
049                // Optional
050                private Optional<InputStream> stdin = Optional.absent(); // Don't supply anything to stdin by default
051                private Optional<Integer> timeout = Optional.absent(); // Default is to wait forever
052                private StreamConsumer stdout = NoOpStreamConsumer.INSTANCE; // Ignore anything produced on stdout, by default
053                private StreamConsumer stderr = NoOpStreamConsumer.INSTANCE; // Ignore anything produced on stderr, by default
054                private List<Integer> successCodes = ImmutableList.of(SUCCESS); // Expect zero as an exit value
055                private boolean ignoreExitValue = false; // Set this to true if you want to ignore the exit value of the process
056
057                /**
058                 * Pass this command to a remote server as a sequence of bytes encoded using UTF-8
059                 */
060                public Builder(String command) {
061                        this(command, UTF8);
062                }
063
064                /**
065                 * Pass this command to a remote server as a sequence of bytes encoded using the indicated encoding
066                 */
067                public Builder(String command, String encoding) {
068                        this(Str.getBytes(command, encoding));
069                }
070
071                public Builder(byte[] command) {
072                        this.command = command;
073                }
074
075                /**
076                 * Convert the string into a <code>byte[]</code> using UTF-8 encoding
077                 */
078                public Builder stdin(String stdin) {
079                        return stdin(stdin, UTF8);
080                }
081
082                /**
083                 * Convert the string into a <code>byte[]</code> using the indicated encoding
084                 */
085                public Builder stdin(String stdin, String encoding) {
086                        Assert.noBlanks(stdin, encoding);
087                        byte[] bytes = Str.getBytes(stdin, encoding);
088                        return stdin(new ByteArrayInputStream(bytes));
089                }
090
091                public Builder stdin(InputStream stdin) {
092                        this.stdin = Optional.of(stdin);
093                        return this;
094                }
095
096                public Builder timeout(int timeout) {
097                        this.timeout = Optional.of(timeout);
098                        return this;
099                }
100
101                public Builder stdout(StreamConsumer stdout) {
102                        this.stdout = stdout;
103                        return this;
104                }
105
106                public Builder stderr(StreamConsumer stderr) {
107                        this.stderr = stderr;
108                        return this;
109                }
110
111                public Builder ignoreExitValue(boolean ignoreExitValue) {
112                        this.ignoreExitValue = ignoreExitValue;
113                        return this;
114                }
115
116                public Builder successCodes(List<Integer> successCodes) {
117                        this.successCodes = successCodes;
118                        return this;
119                }
120
121                public CommandContext build() {
122                        Assert.noNulls(command, stdin, timeout, stdout, stderr, successCodes);
123                        if (timeout.isPresent()) {
124                                Assert.notNegative(timeout.get());
125                        }
126                        this.successCodes = ImmutableList.copyOf(successCodes);
127                        return new CommandContext(this);
128                }
129
130        }
131
132        private CommandContext(Builder builder) {
133                this.command = builder.command;
134                this.stdin = builder.stdin;
135                this.timeout = builder.timeout;
136                this.stderr = builder.stderr;
137                this.stdout = builder.stdout;
138                this.successCodes = builder.successCodes;
139                this.ignoreExitValue = builder.ignoreExitValue;
140
141        }
142
143        public byte[] getCommand() {
144                return command;
145        }
146
147        public Optional<InputStream> getStdin() {
148                return stdin;
149        }
150
151        public Optional<Integer> getTimeout() {
152                return timeout;
153        }
154
155        public StreamConsumer getStdout() {
156                return stdout;
157        }
158
159        public StreamConsumer getStderr() {
160                return stderr;
161        }
162
163        public List<Integer> getSuccessCodes() {
164                return successCodes;
165        }
166
167        public boolean isIgnoreExitValue() {
168                return ignoreExitValue;
169        }
170
171}