summaryrefslogblamecommitdiffstats
path: root/api/src/main/java/org/openslx/taskmanager/api/SystemCommandTask.java
blob: ed47336f012a6a430fcec63689d8bc7b51cbd8ae (plain) (tree)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16















                                                                                      
 
                                       
































                                                                                                                                          
                                                                 















                                                                                                                                          
                                                                 







                                              
                                          









                                                                  


















                                                                                                           
 





                                                                                     
                                                      















                                                                                     
                                                      























                                                                                   
                  


















                                                                                     
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 ( Exception 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 ( Exception e ) {
					}
				}
			} );

			stdout.start();
			stderr.start();

			// Wait for everything
			process.waitFor();
			try {
				process.getErrorStream().close();
			} catch ( Throwable t ) {
			}
			try {
				process.getOutputStream().close();
			} catch ( Throwable t ) {
			}
			stdout.join( 2000 );
			stderr.join( 2000 );

			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 );

}