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}