001package org.codehaus.plexus.util.cli;
002
003public class CLICallable implements CommandLineCallable {
004
005        public CLICallable(int timeoutInSeconds, StreamFeeder inputFeeder, StreamPumper outputPumper, StreamPumper errorPumper, Process p, ProcessHook processHook) {
006                this.timeoutInSeconds = timeoutInSeconds;
007                this.inputFeeder = inputFeeder;
008                this.outputPumper = outputPumper;
009                this.errorPumper = errorPumper;
010                this.p = p;
011                this.processHook = processHook;
012        }
013
014        private final int timeoutInSeconds;
015        private final StreamFeeder inputFeeder;
016        private final StreamPumper outputPumper;
017        private final StreamPumper errorPumper;
018        private final Process p;
019        private final ProcessHook processHook;
020
021        @Override
022        public Integer call() throws CommandLineException {
023                try {
024                        int returnValue;
025                        if (timeoutInSeconds <= 0) {
026                                returnValue = p.waitFor();
027                        } else {
028                                long now = System.currentTimeMillis();
029                                long timeoutInMillis = 1000L * timeoutInSeconds;
030                                long finish = now + timeoutInMillis;
031                                while (CommandLineUtils.isAlive(p) && (System.currentTimeMillis() < finish)) {
032                                        Thread.sleep(10);
033                                }
034                                if (CommandLineUtils.isAlive(p)) {
035                                        throw new InterruptedException("Process timeout out after " + timeoutInSeconds + " seconds");
036                                }
037                                returnValue = p.exitValue();
038                        }
039
040                        CommandLineUtils.waitForAllPumpers(inputFeeder, outputPumper, errorPumper);
041
042                        if (outputPumper.getException() != null) {
043                                throw new CommandLineException("Error inside systemOut parser", outputPumper.getException());
044                        }
045
046                        if (errorPumper.getException() != null) {
047                                throw new CommandLineException("Error inside systemErr parser", errorPumper.getException());
048                        }
049
050                        return returnValue;
051                } catch (InterruptedException ex) {
052                        if (inputFeeder != null) {
053                                inputFeeder.disable();
054                        }
055                        outputPumper.disable();
056                        errorPumper.disable();
057                        throw new CommandLineTimeOutException("Error while executing external command, process killed.", ex);
058                } finally {
059                        ShutdownHookUtils.removeShutdownHook(processHook);
060
061                        processHook.run();
062
063                        if (inputFeeder != null) {
064                                inputFeeder.close();
065                        }
066
067                        outputPumper.close();
068
069                        errorPumper.close();
070                }
071        }
072
073        public int getTimeoutInSeconds() {
074                return timeoutInSeconds;
075        }
076
077        public StreamFeeder getInputFeeder() {
078                return inputFeeder;
079        }
080
081        public StreamPumper getOutputPumper() {
082                return outputPumper;
083        }
084
085        public StreamPumper getErrorPumper() {
086                return errorPumper;
087        }
088
089        public Process getP() {
090                return p;
091        }
092
093        public ProcessHook getProcessHook() {
094                return processHook;
095        }
096
097}