package org.openslx.taskmanager.api; import java.io.BufferedReader; import java.io.File; import java.io.IOException; import java.io.InputStreamReader; import java.nio.charset.StandardCharsets; import org.apache.log4j.Logger; public abstract class SystemCommandTask extends AbstractTask { private static final Logger log = Logger.getLogger( SystemCommandTask.class ); private String[] command = null; private Process process = null; @Override protected final boolean execute() { command = initCommandLine(); if ( command == null || command.length == 0 ) { return processEnded( -1 ); } ProcessBuilder pb = new ProcessBuilder( command ); pb.directory( new File( "/" ) ); try { // Create process process = pb.start(); final Process p = process; processStarted(); p.getOutputStream(); // Read its stdout Thread stdout = new Thread( new Runnable() { @Override public void run() { try { BufferedReader reader = new BufferedReader( new InputStreamReader( p.getInputStream() ) ); String line; while ( ( line = reader.readLine() ) != null ) { synchronized ( p ) { processStdOut( line ); } } } catch ( IOException e ) { } } } ); // Read its stderr Thread stderr = new Thread( new Runnable() { @Override public void run() { try { BufferedReader reader = new BufferedReader( new InputStreamReader( p.getErrorStream() ) ); String line; while ( ( line = reader.readLine() ) != null ) { synchronized ( p ) { processStdErr( line ); } } } catch ( IOException e ) { } } } ); stdout.start(); stderr.start(); // Wait for everything stdout.join(); stderr.join(); process.waitFor(); return processEnded( process.exitValue() ); } catch ( IOException e ) { log.warn( "Process of task " + getId() + " died." ); processStdErr( e.toString() ); return processEnded( -2 ); } catch ( InterruptedException e ) { Thread.currentThread().interrupt(); return false; } catch ( Exception e ) { log.warn( "Unexpected exception when executing " + getId() + ": " + e.toString() ); processStdErr( e.toString() ); return processEnded( -3 ); } finally { if ( process != null ) process.destroy(); } } /** * Write data to the process's stdin. * * @param data stuff to write * @return success or failure mapped to a boolean in a really complicated way */ protected final boolean toStdIn(byte[] data) { try { process.getOutputStream().write( data ); } catch ( IOException e ) { e.printStackTrace(); return false; } return true; } /** * Write text to the process's stdin. * * @param text stuff to write * @return success or failure mapped to a boolean in a really complicated way */ protected final boolean toStdIn(String text) { return toStdIn( text.getBytes( StandardCharsets.UTF_8 ) ); } /** * Called to get the command line. Each argument should be a separate array * element. Returning null means the task should not run (as the arguments * were probably faulty). * * @return List of arguments. First element is the command itself. */ protected abstract String[] initCommandLine(); /** * Called when the process has been successfully started. */ protected void processStarted() { } /** * Called when the process has finished running * * @param exitCode the process' exit code * @return */ protected abstract boolean processEnded( int exitCode ); /** * Called when a line has been read from the process' stdout. * * @param line The line read from the process, without any newline characters */ protected abstract void processStdOut( String line ); /** * Called when a line has been read from the process' stderr. * Trailing newline is removed. * * @param line The line read from the process, without any newline characters */ protected abstract void processStdErr( String line ); }