Wednesday, January 22, 2014

Start a java program from another java program programmatically

That's the thing I had to perform today. Let's introduce the need : I developed last year a standalone java program that I can start from command line. Now, I want to start it from a web application. As the program is complex (some Spring Batch stuffs), I don't want to make an heavy integration. So, I decided to embed its jar in my webapp (WEB-INF/lib). All I had to do was to find an elegant way to start a dedicated java virtual machine from my webapp to run my program without consequence on my web application.

The most elegant way I found was to use ANT... programmatically. In the following example, I wrote two classes. The MainProgram represents my webapp and the ProgramToRun represents my Spring Batch application. To simplify the code,  I didn't create a specific classpath for the ANT task but keep in mind that it's possible.

Look at the code, isn't it easy and cool?


public class MainProgram {

public static void main(String[] args) {
Project project = new Project();
project.setBaseDir(new File(System.getProperty("user.dir")));
project.init();
DefaultLogger logger = new DefaultLogger();
project.addBuildListener(logger);
logger.setOutputPrintStream(System.out);
logger.setErrorPrintStream(System.err);
logger.setMessageOutputLevel(Project.MSG_INFO);
project.fireBuildStarted();
System.out.println("running");
Throwable caught = null;
try {
Echo echo = new Echo();
echo.setTaskName("Echo");
echo.setProject(project);
echo.init();
echo.setMessage("Launching Some Class");
echo.execute();

Java javaTask = new Java();
javaTask.setTaskName("runjava");
javaTask.setProject(project);
javaTask.setFork(true);
javaTask.setCloneVm(true);
javaTask.setFailonerror(true);
javaTask.setClassname(ProgramToRun.class.getName());
Variable aParam = new Variable();
aParam.setKey("myParam");
StringBuilder builder = new StringBuilder();
builder.append("Yeah!! I catched the param");
aParam.setValue(builder.toString());
javaTask.addSysproperty(aParam);
javaTask.init();
int ret = javaTask.executeJava();
System.out.println("java task return code: " + ret);

} catch (BuildException e) {
caught = e;
}
project.log("finished");
project.fireBuildFinished(caught);
}
}


public class ProgramToRun {


public static void main(String[] args) {
System.out.println("Well done!!!");
System.out.println(System.getProperty("myParam"));
}

}


Did you see the tip? No? I passed a parameter to my external program with a system property. Let's have a look to the console output :



running
     [Echo] Launching Some Class
  [runjava] Well done!!!
  [runjava] Yeah!! I catched the param
java task return code: 0
finished

BUILD SUCCESSFUL
Total time: 0 seconds




A really nice ANT use case I discovered !!!