jlibs.core.lang.JavaProcessBuilder Maven / Gradle / Ivy
/**
* Copyright 2015 Santhosh Kumar Tekuri
*
* The JLibs authors license this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package jlibs.core.lang;
import jlibs.core.io.FileNavigator;
import jlibs.core.io.FileUtil;
import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* Similar to {@link ProcessBuilder}, this class makes the java process creation easier.
*
* This class simply manages collection of java process attributes and help your to create command out of it.
*
* JavaProcessBuilder jvm = new JavaProcessBuilder();
*
* {@code JavaProcessBuilder} is pre-configured with current java home and current working directory initially.
* you can change them as below:
*
* jvm.javaHome(new File("c:/jdk5")); // to configure java home
* jvm.workingDir(new File("c:/myProject")); // to configure working directory
*
* To configure various attributes:
*
* // to configure classpath
* jvm.classpath("lib/jlibs-core.jar") // relative path from configured working dir
* .classpath(new File("c:/myproject/lib/jlibs-xml.jar");
*
* // to get configured classpath
* List classpath = jvm.classpath();
*
* // to configure additional classpath
* jvm.endorsedDir("lib/endorsed")
* .extDir("lib/ext")
* .libraryPath("lib/native")
* .bootClasspath("lib/boot/xerces.jar")
* .appendBootClasspath("lib/boot/xalan.jar")
* .prependBootClasspath("lib/boot/dom.jar");
*
* // to configure System Properties
* jvm.systemProperty("myprop", "myvalue")
* .systemProperty("myflag");
*
* // to configure heap and vmtype
* jvm.initialHeap(512); // or jvm.initialHeap("512m");
* jvm.maxHeap(1024); // or jvm.maxHeap("1024m");
* jvm.client(); // to use -client
* jvm.server(); // to use -server
*
* // to configure remote debugging
* jvm.debugPort(7000)
* .debugSuspend(true);
*
* // to configure any additional jvm args
* jvm.jvmArg("-Xgc:somealgo");
*
* // to configure mainclass and its arguments
* jvm.mainClass("example.MyTest")
* .arg("-xvf")
* .arg("testDir");
*
* To get the created command:
*
* String command[] = jvm.command();
*
* Any relative paths specified, will get resolved relative to working directory during command creation.
*
* To launch it:
*
* Process p = jvm.{@link #launch(java.io.OutputStream, java.io.OutputStream) launch}(System.out, System.err);
*
* the two arguments to {@link #launch(java.io.OutputStream, java.io.OutputStream) launch(...)} specify to which process output and error streams to be redirected.
* These arguments can be null, if you don't want them to be redirected.
*
* @author Santhosh Kumar T
*/
public class JavaProcessBuilder{
/*-------------------------------------------------[ java-home ]---------------------------------------------------*/
private File javaHome = FileUtil.JAVA_HOME;
public JavaProcessBuilder javaHome(File javaHome){
this.javaHome = javaHome;
return this;
}
public File javaHome(){
return javaHome;
}
/*-------------------------------------------------[ working-dir ]---------------------------------------------------*/
private File workingDir = FileUtil.USER_DIR;
public JavaProcessBuilder workingDir(String dir){
return workingDir(new File(dir));
}
public JavaProcessBuilder workingDir(File dir){
workingDir = dir;
return this;
}
public File workingDir(){
return workingDir;
}
/*-------------------------------------------------[ classpath ]---------------------------------------------------*/
private List classpath = new ArrayList();
public JavaProcessBuilder classpath(String resource){
return classpath(new File(resource));
}
public JavaProcessBuilder classpath(File resource){
classpath.add(resource);
return this;
}
public List classpath(){
return classpath;
}
/*-------------------------------------------------[ endorsed-dirs ]---------------------------------------------------*/
private List endorsedDirs = new ArrayList();
public JavaProcessBuilder endorsedDir(String dir){
return endorsedDir(new File(dir));
}
public JavaProcessBuilder endorsedDir(File dir){
endorsedDirs.add(dir);
return this;
}
public List endorsedDirs(){
return endorsedDirs;
}
/*-------------------------------------------------[ ext-dirs ]---------------------------------------------------*/
private List extDirs = new ArrayList();
public JavaProcessBuilder extDir(String dir){
return extDir(new File(dir));
}
public JavaProcessBuilder extDir(File dir){
extDirs.add(dir);
return this;
}
public List extDirs(){
return extDirs;
}
/*-------------------------------------------------[ library-path ]---------------------------------------------------*/
private List libraryPath = new ArrayList();
public JavaProcessBuilder libraryPath(String dir){
return libraryPath(new File(dir));
}
public JavaProcessBuilder libraryPath(File dir){
libraryPath.add(dir);
return this;
}
public List libraryPath(){
return libraryPath;
}
/*-------------------------------------------------[ boot-classpath ]---------------------------------------------------*/
private List bootClasspath = new ArrayList();
public JavaProcessBuilder bootClasspath(String resource){
return bootClasspath(new File(resource));
}
public JavaProcessBuilder bootClasspath(File resource){
bootClasspath.add(resource);
return this;
}
public List bootClasspath(){
return bootClasspath;
}
/*-------------------------------------------------[ append-boot-classpath ]---------------------------------------------------*/
private List appendBootClasspath = new ArrayList();
public JavaProcessBuilder appendBootClasspath(String resource){
return appendBootClasspath(new File(resource));
}
public JavaProcessBuilder appendBootClasspath(File resource){
appendBootClasspath.add(resource);
return this;
}
public List appendBootClasspath(){
return appendBootClasspath;
}
/*-------------------------------------------------[ prepend-boot-classpath ]---------------------------------------------------*/
private List prependBootClasspath = new ArrayList();
public JavaProcessBuilder prependBootClasspath(String resource){
return prependBootClasspath(new File(resource));
}
public JavaProcessBuilder prependBootClasspath(File resource){
prependBootClasspath.add(resource);
return this;
}
public List prependBootClasspath(){
return prependBootClasspath;
}
/*-------------------------------------------------[ system-properties ]---------------------------------------------------*/
private Map systemProperties = new HashMap();
public JavaProcessBuilder systemProperty(String name, String value){
systemProperties.put(name, value);
return this;
}
public JavaProcessBuilder systemProperty(String name){
return systemProperty(name, null);
}
public Map systemProperties(){
return systemProperties;
}
/*-------------------------------------------------[ initial-heap ]---------------------------------------------------*/
private String initialHeap;
public JavaProcessBuilder initialHeap(int mb){
return initialHeap(mb+"m");
}
public JavaProcessBuilder initialHeap(String size){
initialHeap = size;
return this;
}
public String initialHeap(){
return initialHeap;
}
/*-------------------------------------------------[ max-heap ]---------------------------------------------------*/
private String maxHeap;
public JavaProcessBuilder maxHeap(int mb){
return maxHeap(mb+"m");
}
public JavaProcessBuilder maxHeap(String size){
maxHeap = size;
return this;
}
public String maxHeap(){
return maxHeap;
}
/*-------------------------------------------------[ vm-type ]---------------------------------------------------*/
private String vmType;
public JavaProcessBuilder client(){
vmType = "-client";
return this;
}
public JavaProcessBuilder server(){
vmType = "-server";
return this;
}
public String vmType(){
return vmType;
}
/*-------------------------------------------------[ jvm-args ]---------------------------------------------------*/
private List jvmArgs = new ArrayList();
public JavaProcessBuilder jvmArg(String arg){
jvmArgs.add(arg);
return this;
}
public List jvmArgs(){
return jvmArgs;
}
/*-------------------------------------------------[ main-class ]---------------------------------------------------*/
private String mainClass;
public JavaProcessBuilder mainClass(String mainClass){
this.mainClass = mainClass;
return this;
}
public String mainClass(){
return mainClass;
}
/*-------------------------------------------------[ debug ]---------------------------------------------------*/
private boolean debugSuspend;
public JavaProcessBuilder debugSuspend(boolean suspend){
this.debugSuspend = suspend;
return this;
}
public boolean debugSuspend(){
return debugSuspend;
}
private int debugPort = -1;
public JavaProcessBuilder debugPort(int port){
this.debugPort = port;
return this;
}
public int debugPort(){
return debugPort;
}
/*-------------------------------------------------[ arguments ]---------------------------------------------------*/
private List args = new ArrayList();
public JavaProcessBuilder arg(String arg){
args.add(arg);
return this;
}
public List args(){
return args;
}
/*-------------------------------------------------[ Command ]---------------------------------------------------*/
private static String toString(File fromDir, Iterable files) throws IOException{
StringBuilder buff = new StringBuilder();
for(File file: files){
if(buff.length()>0)
buff.append(FileUtil.PATH_SEPARATOR);
if(fromDir==null)
buff.append(file.getCanonicalPath());
else
buff.append(FileNavigator.INSTANCE.getRelativePath(fromDir, file));
}
return buff.toString();
}
/** Returns command with all its arguments */
public String[] command() throws IOException{
List cmd = new ArrayList();
String executable = javaHome.getCanonicalPath()+FileUtil.SEPARATOR+"bin"+FileUtil.SEPARATOR+"java";
if(OS.get().isWindows())
executable += ".exe";
cmd.add(executable);
String path = toString(workingDir, prependBootClasspath);
if(path.length()>0)
cmd.add("-Xbootclasspath/p:"+path);
path = toString(workingDir, bootClasspath);
if(path.length()>0)
cmd.add("-Xbootclasspath:"+path);
path = toString(workingDir, appendBootClasspath);
if(path.length()>0)
cmd.add("-Xbootclasspath/a:"+path);
path = toString(workingDir, classpath);
if(path.length()>0){
cmd.add("-classpath");
cmd.add(path);
}
path = toString(workingDir, extDirs);
if(path.length()>0)
cmd.add("-Djava.ext.dirs="+path);
path = toString(workingDir, endorsedDirs);
if(path.length()>0)
cmd.add("-Djava.endorsed.dirs="+path);
path = toString(workingDir, libraryPath);
if(path.length()>0)
cmd.add("-Djava.library.path="+path);
for(Map.Entry prop: systemProperties.entrySet()){
if(prop.getValue()==null)
cmd.add("-D"+prop.getKey());
else
cmd.add("-D"+prop.getKey()+"="+prop.getValue());
}
if(initialHeap!=null)
cmd.add("-Xms"+initialHeap);
if(maxHeap!=null)
cmd.add("-Xmx"+maxHeap);
if(vmType!=null)
cmd.add(vmType);
if(debugPort!=-1){
cmd.add("-Xdebug");
cmd.add("-Xnoagent");
cmd.add("-Xrunjdwp:transport=dt_socket,server=y,suspend="+(debugSuspend?'y':'n')+",address="+debugPort);
}
cmd.addAll(jvmArgs);
if(mainClass!=null){
cmd.add(mainClass);
cmd.addAll(args);
}
return cmd.toArray(new String[cmd.size()]);
}
/**
* launches jvm with current configuration.
*
* note that, the streams passed are not closed automatically.
*
* @param output outputstream to which process's input stream to be redirected.
* if null, it is not redirected
* @param error outputstream to which process's error stream to be redirected.
* if null, it is not redirected
* @return the process created
*
* @exception IOException if an I/O error occurs.
*
* @see jlibs.core.lang.RuntimeUtil#redirectStreams(Process, java.io.OutputStream, java.io.OutputStream)
*/
public Process launch(OutputStream output, OutputStream error) throws IOException{
Process process = Runtime.getRuntime().exec(command(), null, workingDir);
RuntimeUtil.redirectStreams(process, output, error);
return process;
}
}