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