001package org.kuali.common.util.channel.impl; 002 003import java.io.IOException; 004 005import org.codehaus.plexus.util.cli.StreamFeeder; 006import org.kuali.common.util.Assert; 007import org.kuali.common.util.channel.model.CommandContext; 008import org.kuali.common.util.stream.StreamPumper; 009 010import com.google.common.base.Optional; 011import com.jcraft.jsch.ChannelExec; 012 013public final class StreamHandler { 014 015 public StreamHandler(CommandContext context) { 016 Assert.noNulls(context); 017 this.context = context; 018 } 019 020 private final CommandContext context; 021 022 private Optional<StreamFeeder> inputFeeder; 023 private StreamPumper outputPumper; 024 private StreamPumper errorPumper; 025 026 private boolean open = false; 027 private boolean pumping = false; 028 private boolean done = false; 029 030 public void openStreams(ChannelExec exec, String encoding) throws IOException { 031 Assert.isFalse(open, "Already open"); 032 Assert.noNulls(exec); 033 this.inputFeeder = getInputFeeder(context, exec); 034 this.outputPumper = new StreamPumper(exec.getInputStream(), encoding, context.getStdout()); 035 this.errorPumper = new StreamPumper(exec.getErrStream(), encoding, context.getStderr()); 036 this.open = true; 037 } 038 039 public void startPumping() { 040 Assert.isTrue(open, "Not open"); 041 Assert.isFalse(pumping, "Already pumping"); 042 Assert.noNulls(inputFeeder, outputPumper, errorPumper); 043 if (inputFeeder.isPresent()) { 044 inputFeeder.get().start(); 045 } 046 errorPumper.start(); 047 outputPumper.start(); 048 this.pumping = true; 049 } 050 051 public void waitUntilDone() throws InterruptedException { 052 Assert.isTrue(open, "Not open"); 053 Assert.isTrue(pumping, "Not pumping"); 054 Assert.isFalse(done, "Already done"); 055 if (inputFeeder.isPresent()) { 056 inputFeeder.get().waitUntilDone(); 057 } 058 outputPumper.waitUntilDone(); 059 errorPumper.waitUntilDone(); 060 this.done = true; 061 } 062 063 public void validate() throws InterruptedException { 064 Assert.isTrue(done, "Not done"); 065 if (outputPumper.getException() != null) { 066 throw new IllegalStateException("Error inside systemOut parser", outputPumper.getException()); 067 } 068 if (errorPumper.getException() != null) { 069 throw new IllegalStateException("Error inside systemErr parser", errorPumper.getException()); 070 } 071 } 072 073 public void disableQuietly() { 074 if (inputFeeder != null && inputFeeder.isPresent()) { 075 inputFeeder.get().disable(); 076 } 077 if (errorPumper != null) { 078 errorPumper.disable(); 079 } 080 if (outputPumper != null) { 081 outputPumper.disable(); 082 } 083 } 084 085 public void closeQuietly() { 086 if (inputFeeder != null && inputFeeder.isPresent()) { 087 inputFeeder.get().close(); 088 } 089 if (errorPumper != null) { 090 errorPumper.close(); 091 } 092 if (outputPumper != null) { 093 outputPumper.close(); 094 } 095 } 096 097 public CommandContext getContext() { 098 return context; 099 } 100 101 protected Optional<StreamFeeder> getInputFeeder(CommandContext context, ChannelExec exec) throws IOException { 102 if (context.getStdin().isPresent()) { 103 StreamFeeder feeder = new StreamFeeder(context.getStdin().get(), exec.getOutputStream()); 104 return Optional.of(feeder); 105 } else { 106 return Optional.absent(); 107 } 108 } 109 110}