001/** 002 * Copyright 2010-2014 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 Builder builder(String command) { 042 return new Builder(command); 043 } 044 045 public static class Builder { 046 047 private static final int SUCCESS = 0; 048 private static final String UTF8 = Encodings.UTF8; 049 050 // Required 051 private final byte[] command; 052 053 // Optional 054 private Optional<InputStream> stdin = Optional.absent(); // Don't supply anything to stdin by default 055 private Optional<Integer> timeout = Optional.absent(); // Default is to wait forever 056 private StreamConsumer stdout = NoOpStreamConsumer.INSTANCE; // Ignore anything produced on stdout, by default 057 private StreamConsumer stderr = NoOpStreamConsumer.INSTANCE; // Ignore anything produced on stderr, by default 058 private List<Integer> successCodes = ImmutableList.of(SUCCESS); // Expect zero as an exit value 059 private boolean ignoreExitValue = false; // Set this to true if you want to ignore the exit value of the process 060 061 /** 062 * Pass this command to a remote server as a sequence of bytes encoded using UTF-8 063 */ 064 public Builder(String command) { 065 this(command, UTF8); 066 } 067 068 /** 069 * Pass this command to a remote server as a sequence of bytes encoded using the indicated encoding 070 */ 071 public Builder(String command, String encoding) { 072 this(Str.getBytes(command, encoding)); 073 } 074 075 public Builder(byte[] command) { 076 this.command = command; 077 } 078 079 /** 080 * Convert the string into a <code>byte[]</code> using UTF-8 encoding 081 */ 082 public Builder stdin(String stdin) { 083 return stdin(stdin, UTF8); 084 } 085 086 /** 087 * Convert the string into a <code>byte[]</code> using the indicated encoding 088 */ 089 public Builder stdin(String stdin, String encoding) { 090 Assert.noBlanks(stdin, encoding); 091 byte[] bytes = Str.getBytes(stdin, encoding); 092 return stdin(new ByteArrayInputStream(bytes)); 093 } 094 095 public Builder stdin(InputStream stdin) { 096 this.stdin = Optional.of(stdin); 097 return this; 098 } 099 100 public Builder timeout(int timeout) { 101 this.timeout = Optional.of(timeout); 102 return this; 103 } 104 105 public Builder stdout(StreamConsumer stdout) { 106 this.stdout = stdout; 107 return this; 108 } 109 110 public Builder stderr(StreamConsumer stderr) { 111 this.stderr = stderr; 112 return this; 113 } 114 115 public Builder ignoreExitValue(boolean ignoreExitValue) { 116 this.ignoreExitValue = ignoreExitValue; 117 return this; 118 } 119 120 public Builder successCodes(List<Integer> successCodes) { 121 this.successCodes = successCodes; 122 return this; 123 } 124 125 public CommandContext build() { 126 Assert.noNulls(command, stdin, timeout, stdout, stderr, successCodes); 127 if (timeout.isPresent()) { 128 Assert.notNegative(timeout.get()); 129 } 130 this.successCodes = ImmutableList.copyOf(successCodes); 131 return new CommandContext(this); 132 } 133 134 } 135 136 private CommandContext(Builder builder) { 137 this.command = builder.command; 138 this.stdin = builder.stdin; 139 this.timeout = builder.timeout; 140 this.stderr = builder.stderr; 141 this.stdout = builder.stdout; 142 this.successCodes = builder.successCodes; 143 this.ignoreExitValue = builder.ignoreExitValue; 144 145 } 146 147 public byte[] getCommand() { 148 return command; 149 } 150 151 public Optional<InputStream> getStdin() { 152 return stdin; 153 } 154 155 public Optional<Integer> getTimeout() { 156 return timeout; 157 } 158 159 public StreamConsumer getStdout() { 160 return stdout; 161 } 162 163 public StreamConsumer getStderr() { 164 return stderr; 165 } 166 167 public List<Integer> getSuccessCodes() { 168 return successCodes; 169 } 170 171 public boolean isIgnoreExitValue() { 172 return ignoreExitValue; 173 } 174 175}