package org.grails.maven.plugin.tools;
import groovy.lang.GroovyRuntimeException;
import org.codehaus.groovy.grails.io.support.GrailsIOUtils;
import org.grails.launcher.GrailsLauncher;
import org.grails.maven.plugin.AbstractGrailsMojo;
import java.io.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
*
* Allows for Grails commands to be executed in a Forked VM
*
* @author Graeme Rocher
* @since 2.1
*/
public class ForkedGrailsRuntime extends AbstractGrailsRuntime {
private int maxMemory = 1024;
private int minMemory = 512;
private int maxPerm = 256;
private boolean debug;
private File reloadingAgent;
public ForkedGrailsRuntime(ExecutionContext executionContext) {
super(executionContext);
}
public void setMaxMemory(int maxMemory) {
this.maxMemory = maxMemory;
}
public void setMinMemory(int minMemory) {
this.minMemory = minMemory;
}
public void setMaxPerm(int maxPerm) {
this.maxPerm = maxPerm;
}
public void setDebug(boolean debug) {
this.debug = debug;
}
public void run() {
ProcessBuilder processBuilder = new ProcessBuilder();
StringBuilder cp = new StringBuilder();
cp.append(GrailsIOUtils.findJarFile(ForkedGrailsRuntime.class)).append(File.pathSeparatorChar);
for (File file : executionContext.getBuildDependencies()) {
cp.append(file).append(File.pathSeparatorChar);
}
FileOutputStream fos = null;
File tempFile = null;
try {
String baseName = executionContext.getBaseDir().getCanonicalFile().getName();
tempFile = File.createTempFile(baseName, "grails-execution-context");
tempFile.deleteOnExit();
fos = new FileOutputStream(tempFile);
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(executionContext);
List<String> cmd = new ArrayList<String>(Arrays.asList("java", "-Xmx" + maxMemory + "M", "-Xms" + minMemory + "M", "-XX:MaxPermSize=" + maxPerm + "m", "-Dgrails.build.execution.context=" + tempFile.getCanonicalPath(), "-cp", cp.toString()));
if(debug) {
cmd.addAll(Arrays.asList("-Xdebug","-Xnoagent","-Dgrails.full.stacktrace=true", "-Djava.compiler=NONE", "-Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=5005"));
}
if(reloadingAgent != null) {
cmd.addAll(Arrays.asList("-javaagent:" + reloadingAgent.getCanonicalPath(), "-noverify", "-Dspringloaded=profile=grails"));
}
if(null != executionContext.getForkedVmArgs()
&& executionContext.getForkedVmArgs().size() > 0) {
cmd.addAll(executionContext.getForkedVmArgs());
}
// For use inside of IDEs
if (executionContext.getGrailsBuildListener() != null) {
cmd.add("-D" + AbstractGrailsMojo.GRAILS_BUILD_LISTENERS + "=" + executionContext.getGrailsBuildListener());
}
// For use inside of IDEs
if (executionContext.getDependencyFileLocation() != null) {
cmd.add("-D" + AbstractGrailsMojo.DEPENDENCY_FILE_LOC + "=" + executionContext.getDependencyFileLocation());
}
cmd.add(getClass().getName());
processBuilder
.directory(executionContext.getBaseDir())
.redirectErrorStream(false)
.command(cmd);
Process process = processBuilder.start();
InputStream is = process.getInputStream();
InputStream es = process.getErrorStream();
Thread t1 = new Thread(new TextDumper(is, System.out));
Thread t2 = new Thread(new TextDumper(es, System.err));
t1.start();
t2.start();
int result = process.waitFor();
if(result == 1) {
try { t1.join(); } catch (InterruptedException ignore) {}
try { t1.join(); } catch (InterruptedException ignore) {}
try { es.close(); } catch (IOException ignore) {}
try { is.close(); } catch (IOException ignore) {}
System.out.flush();
System.err.flush();
throw new RuntimeException("Forked Grails VM exited with error");
}
} catch (FileNotFoundException e) {
throw new RuntimeException("Fatal error forking Grails JVM: " + e.getMessage() , e);
} catch (IOException e) {
throw new RuntimeException("Fatal error forking Grails JVM: " + e.getMessage() , e);
} catch (InterruptedException e) {
throw new RuntimeException("Fatal error forking Grails JVM: " + e.getMessage() , e);
} finally {
if(fos != null) try {
fos.close();
} catch (IOException e) {
// ignore
}
}
}
public static void main(String[] args) {
String location = System.getProperty("grails.build.execution.context");
if(location != null) {
File f = new File(location);
FileInputStream fis = null;
try {
fis = new FileInputStream(f);
ObjectInputStream ois = new ObjectInputStream(fis);
ExecutionContext ec = (ExecutionContext) ois.readObject();
GrailsLauncher launcher = createGrailsLauncher(ec);
System.exit( launcher.launch(ec.getScriptName(), ec.getArgs(), ec.getEnv()) );
} catch (FileNotFoundException e) {
fatalError(e);
} catch (ClassNotFoundException e) {
fatalError(e);
} catch (IOException e) {
fatalError(e);
} catch( Throwable e) {
fatalError(e);
}
finally {
if(fis != null) {
try {
fis.close();
} catch (IOException e) {
// ignore
}
}
}
}
else {
System.exit(1);
}
}
public void setReloadingAgent(File file) {
this.reloadingAgent = file;
}
private static class TextDumper implements Runnable {
InputStream in;
Appendable app;
public TextDumper(InputStream in, Appendable app) {
this.in = in;
this.app = app;
}
public void run() {
InputStreamReader isr = new InputStreamReader(in);
BufferedReader br = new BufferedReader(isr);
String next;
try {
while ((next = br.readLine()) != null) {
if (app != null) {
app.append(next);
app.append("\n");
}
}
} catch (IOException e) {
throw new GroovyRuntimeException("exception while reading process stream", e);
}
}
}
}