/**
* Licensed to the Apache Software Foundation (ASF) under one or more
* Contributor license agreements. See the notice file distributed
* This work for additional information regarding copyright ownership.
* The ASF licenses this file to you under the Apache license, version 2.0
* (The "License"); you may not use this file except T in compliance
* The license. You may be obtain a copy of the license
*
* Http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* Distributed under the license is distributed on an "as is" basis,
* Without warranties or conditions of any kind, either express or implied.
* See the license for the specific language governing permissions and
* Limitations under the license.
*/
/*
* Adopted by John Xing for nutch project from
*
Http://blog.fivesight.com/prb/space/Call+an+External+Command+from+Java,
* Which explains the code in detail.
* [Original author is moving his site to http://mult.ifario.us/-peb]
*
* Comments by John Xing 20040621:
* (1) edu. Oswego. cs. DL. util. Concurrent. * Is In j2sdks 1.5 now.
* Modifications are needed if we move to j2sdks 1.5.
* (2) the original looks good, not much to change.
*
* This code is in the public domain and comes with no warranty.
*/
Package org. Apache. nutch. util;
Import java. Io. ioexception;
Import java. Io. inputstream;
Import java. Io. interruptedioexception;
Import java. Io. outputstream;
Import java. util. Concurrent. brokenbarrierexception;
Import java. util. Concurrent. javasicbarrier;
Import java. util. Concurrent. timeunit;
Import java. util. Concurrent. timeoutexception;
Public class commandrunner {
Private Boolean _ waitforexit = true;
Private string _ command;
Private int _ timeout = 10;
Private inputstream _ stdin;
Private outputstream _ stdout;
Private outputstream _ stderr;
Private Static final int Buf = 4096;
Private int _ xit;
Private throwable _ thrownerror;
Private cyclicbarrier _ barrier;
Public int getexitvalue (){
Return _ xit;
}
Public void setcommand (string s ){
_ Command = s;
}
Public String getcommand (){
Return _ command;
}
Public void setinputstream (inputstream is ){
_ Stdin = is;
}
Public void setstdoutputstream (outputstream OS ){
_ Stdout = OS;
}
Public void setstderrorstream (outputstream OS ){
_ Stderr = OS;
}
Public void evaluate () throws ioexception {
This.exe C ();
}
/**
*
* @ Return process exit value (return code) or-1 if timed out.
* @ Throws ioexception
*/
Public int exec () throws ioexception {
Process proc = runtime.getruntime(cmd.exe C (_ command );
_ Barrier = new cyclicbarrier (3 + (_ stdin! = NULL )? 1: 0 ));
Pullerthread so = new pullerthread ("stdout", Proc. getinputstream (),
_ Stdout );
So. setdaemon (true );
So. Start ();
Pullerthread Se = new pullerthread ("stderr", Proc. geterrorstream (),
_ Stderr );
Se. setdaemon (true );
Se. Start ();
Pusherthread Si = NULL;
If (_ stdin! = NULL ){
SI = new pusherthread ("stdin", _ stdin, Proc. getoutputstream ());
Si. setdaemon (true );
Si. Start ();
}
Boolean _ timedout = false;
Long end = system. currenttimemillis () + _ timeout * 1000;
//
Try {
If (_ timeout <= 0 ){
_ Barrier. Await ();
} Else {
_ Barrier. Await (_ timeout, timeunit. Seconds );
}
} Catch (timeoutexception ex ){
_ Timedout = true;
} Catch (brokenbarrierexception bBE ){
/* Ignore */
} Catch (interruptedexception e ){
/* Ignore */
}
// Tell the IO threads we are finished
If (Si! = NULL ){
Si. Interrupt ();
}
So. Interrupt ();
Se. Interrupt ();
_ Xit =-1;
If (! _ Timedout ){
If (_ waitforexit ){
Do {
Try {
Thread. Sleep (1000 );
_ Xit = Proc. exitvalue ();
} Catch (interruptedexception IE ){
If (thread. interrupted ()){
Break; // stop waiting on an interrupt for this
// Thread
} Else {
Continue;
}
} Catch (illegalthreadstateexception iltse ){
Continue;
}
Break;
} While (! (_ Timedout = (system. currenttimemillis ()> end )));
} Else {
Try {
_ Xit = Proc. exitvalue ();
} Catch (illegalthreadstateexception iltse ){
_ Timedout = true;
}
}
}
If (_ waitforexit ){
Proc. Destroy ();
}
Return _ xit;
}
Public throwable getthrownerror (){
Return _ thrownerror;
}
Private class pumperthread extends thread {
Private outputstream _ OS;
Private inputstream _ is;
Private Boolean _ closeinput;
Protected pumperthread (string name, inputstream is, outputstream OS,
Boolean closeinput ){
Super (name );
_ Is = is;
_ OS = OS;
_ Closeinput = closeinput;
}
Public void run (){
Try {
Byte [] Buf = new byte [Buf];
Int READ = 0;
While (! Isinterrupted () & (read = _ is. Read (BUF ))! =-1 ){
If (read = 0)
Continue;
_ OS. Write (BUF, 0, read );
_ OS. Flush ();
}
} Catch (interruptedioexception iioe ){
// Ignored
} Catch (throwable t ){
_ Thrownerror = T;
} Finally {
Try {
If (_ closeinput ){
_ Is. Close ();
} Else {
_ OS. Close ();
}
} Catch (ioexception IOE ){
/* Ignore */
}
}
Try {
_ Barrier. Await ();
} Catch (interruptedexception IE ){
/* Ignore */
} Catch (brokenbarrierexception bBE ){
/* Ignore */
}
}
}
Private class pusherthread extends pumperthread {
Pusherthread (string name, inputstream is, outputstream OS ){
Super (name, is, OS, false );
}
}
Private class pullerthread extends pumperthread {
Pullerthread (string name, inputstream is, outputstream OS ){
Super (name, is, OS, true );
}
}
Public int gettimeout (){
Return _ timeout;
}
Public void setTimeout (INT timeout ){
_ Timeout = timeout;
}
Public Boolean getwaitforexit (){
Return _ waitforexit;
}
Public void setwaitforexit (Boolean waitforexit ){
_ Waitforexit = waitforexit;
}
Public static void main (string [] ARGs) throws exception {
}
}