Execute a shell script from a Java WAR file

This is slightly insane, but you may find yourself in a situation where you need to do this. The example I've been testing executes a shell script provided in the WAR file of a webapp, and uses an SSH key, also provided in the WAR file. The security implications of this solution aren't encouraging, but let's assume you actually do need to do this. Some notes:
  • Proper error/exception handling to be added by end user.
  • If you want the shell script to work properly, you will probably have to make sure it uses proper Unix line endings. In Eclipse, you can ensure this is done for new text files by going to Project | Properties | Resource and set "New text file line delimiter" to "Unix".
  • The files apparently need to be located either in the WAR file's root, or in WEB-INF/classes. The root is not a good idea if you are providing an ssh key.
  • There is no good way to set file permissions, so for this example - where we have an SSH key - we will have to execute an extra command to change the file permissions for the key and appease ssh.
  • I've provided two exposed methods below, simply for reasons of convenience. For this actual example, only one of them is needed.
package se.pp.liss.webtest;
 
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
 
public class Executor {
 
	String makeFileFromResource(String resname) throws IOException {
		InputStream is = Executor.class.getClassLoader().getResourceAsStream(resname);
 
		// If no source stream is able to be located
		if (is == null) {
			throw new IOException("Unable to load resource:" + resname);
		}
 
		File tmpfile = File.createTempFile("xec", "sh");
 
		String tmpfilename=tmpfile.getAbsolutePath();
 
		BufferedInputStream bis = new BufferedInputStream(is, 1024);
		FileOutputStream os = new FileOutputStream(tmpfile);
		BufferedOutputStream bos = new BufferedOutputStream(os, 1024);
		byte buffer[] = new byte[1024];
		while (true) {
			int n = bis.read(buffer);
			if (n <= 0) {
				break;
			}
			bos.write(buffer, 0, n);
		}
		bos.close();
		bis.close();
		return tmpfilename;
	}
 
	public int execShellscript(String pathname) throws IOException {
		String tmpfilename = makeFileFromResource(pathname);
		String command;
 
		command = "/bin/sh "+tmpfilename;
 
		Process p=Runtime.getRuntime().exec(command);
		int r=-1;
		try {
			r = p.waitFor();
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		new File(tmpfilename).delete();
		return r;
	}
 
	public int execShellscript(String pathname, String fileArgument) throws IOException {
		String tmpfilename = makeFileFromResource(pathname);
		String argfilename = makeFileFromResource(fileArgument);
		String command;
 
		command = "chmod 600 " + argfilename;
 
		Process p=Runtime.getRuntime().exec(command);
		try {
			p.waitFor();
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		command = "/bin/sh " + tmpfilename + " " + argfilename;
 
		p=Runtime.getRuntime().exec(command);
		int r=-1;
		try {
			r = p.waitFor();
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		new File(tmpfilename).delete();
		new File(argfilename).delete();
		return r;
	}
}