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}