001    package org.codehaus.plexus.util.cli;
002    
003    public 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    }