简体   繁体   中英

Catching Perl exception in Java

I have been trying to run a Perl script through Java. I even found the script how to do so, but the problem is I want the exception thrown by Perl to be returned in Java.

import java.io.IOException;

public class Log {
    public static void main(String[] args) throws IOException {
        Process proc = null;
        try
        {
            proc = Runtime.getRuntime().exec("perl C:\\Users\\myscript.pl");
            int returncode = proc.exitValue();
            System.out.println("Process Executed"+returncode);

        }catch(Exception ae)
        {

            System.out.println("Exception is "+ae.toString());
        }
        finally
        {
            proc.destroy(); 
        }
    }
}

When I try to run this code the exception I receive is:

Exception is java.lang.IllegalThreadStateException: process has not exited

Can somebody help me here? What am I doing wrong?

You need to call Process.waitFor() before exitValue(). Also I'd highly recommend reading When Runtime.exec() won't , it has lots of useful info on calling external processes in a more robust way.

proc.waitFor();  // <======= blocks until process exit

int returncode = proc.exitValue();

System.out.println("Process Executed"+returncode)

Documentation for Process.waitFor()

Causes the current thread to wait, if necessary, until the process represented by this Process object has terminated. This method returns immediately if the subprocess has already terminated. If the subprocess has not yet terminated, the calling thread will be blocked until the subprocess exits.

Whenever you run a child process, the following tow things need to be ensured:

a) The parent process should monitor the child process. b) The parent process should wait for the child process to complete to check its state.

To achieve the first, you should make a mandatory commitment to consume the child process output stream and the error streams, at the same time. Apart from this, the parent process needs to wait for the child process to complete its execution before getting its exit code.

To consume the Output and error streams, you could create a runnable which reads both these streams simaltaneously, and logs the output to a file.

class StreamConsumer implements Runnable
{
    private InputStream is;
    private String outputFile;


    StreamConsumer(InputStream is, String outputFile)
    {
        this.is = is;
        this.outputFile = outputFile;
    }

    public void run()
    {
        InputStreamReader isr = null;
        BufferedReader br = null;
        FileOutputStream fos = null;
        BufferedWriter bufferedWriter = null;
        char[] characterBuffer = null;
        try
        {
            characterBuffer = new char[1024];
            isr = new InputStreamReader(is,"UTF-8");
            br = new BufferedReader(isr);
            fos = new FileOutputStream(outputFile);
            bufferedWriter = new BufferedWriter(new OutputStreamWriter(fos,"UTF-8"));
            LOGGER.info("Writing to op file: "+ this.outputFile);
            int readCharacters = -1;
            while ((readCharacters = br.read(characterBuffer,0,1024)) != -1)
            {
                String sw = new String(characterBuffer,0,readCharacters);
                /*
                 * To ignore empty chunks
                 */
                if(sw != null && sw.trim().length() > 0)
                {
                    bufferedWriter.write(sw.toString());
                }
                characterBuffer = new char[1024];
            }
            LOGGER.info("Done Writing to op file: "+ this.outputFile);
        }
        catch (Exception ioe)
          {
            LOGGER.error("IOException ", ioe);
          }
        finally
        {
            if(br != null)
            {
                try {
                    br.close();
                } catch (IOException e) {
                    LOGGER.error("IOException ", e);
                }
            }
            if(bufferedWriter != null)
            {
                try {
                    bufferedWriter.close();
                } catch (IOException e) {
                    LOGGER.error("IOException ", e);
                }
            }
        }

    }
}

Consume using:

StreamConsumer errorStreamConsumer = new StreamConsumer(proc.getErrorStream(),"errorfilepath");
            StreamConsumer outputStreamConsumer = new StreamConsumer(proc.getInputStream(),"outputFilepath");

Doing the above will make sure the child process never hangs and is effectively monitored by the parent process.

See Also:

Process.waitFor(), threads, and InputStreams http://www.javaworld.com/article/2071275/core-javahen-runtime-exec---won-t/core-java/when-runtime-exec---won-t.html

To acheive the second, the parent process needs to wait for the child process to complete its execution:

proc.waitFor(); 

causes the current thread to wait, if necessary, until the process represented by this Process object has terminated. This method returns immediately if the subprocess has already terminated. If the subprocess has not yet terminated, the calling thread will be blocked until the subprocess exits.

this is mandatory before you ask for the child process return code.

int returncode = proc.exitValue();

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM