
de.saumya.mojo.ruby.script.EmbeddedLauncher Maven / Gradle / Ivy
/**
*
*/
package de.saumya.mojo.ruby.script;
import java.io.File;
import java.io.IOException;
import java.io.PrintStream;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.MalformedURLException;
import java.util.List;
import java.util.Map;
import org.codehaus.classworlds.ClassRealm;
import org.codehaus.classworlds.DuplicateRealmException;
import org.codehaus.classworlds.NoSuchRealmException;
import de.saumya.mojo.ruby.Logger;
class EmbeddedLauncher extends AbstractLauncher {
private static final Class>[] No_ARG_TYPES = new Class[0];
private static final Object[] NO_ARGS = new Object[0];
private final ClassRealm classRealm;
private final ScriptFactory factory;
private final Logger logger;
public EmbeddedLauncher(final Logger logger, final ScriptFactory factory)
throws ScriptException {
this.logger = logger;
this.factory = factory;
if (factory.classRealm != null) {
this.classRealm = cloneClassRealm(factory.jrubyJar,
factory.classpathElements,
factory.classRealm);
}
else {
this.classRealm = null;
}
}
private ClassRealm cloneClassRealm(final File jrubyJar,
final List classpathElements, final ClassRealm classRealm)
throws ScriptException {
// TODO how to reuse the plugin realm ?
// for (final String classpath : classpathElements) {
// if (classpath.equals(jrubyJar.getAbsolutePath())) {
// return null;
// }
// }
ClassRealm newClassRealm;
try {
ClassRealm jruby;
try {
jruby = classRealm.getWorld().getRealm("jruby");
}
catch (final NoSuchRealmException e) {
jruby = classRealm.getWorld().newRealm("jruby");
if(jrubyJar != null){
jruby.addConstituent(jrubyJar.toURI().toURL());
}
}
try {
jruby.getWorld().disposeRealm("pom");
}
catch (final NoSuchRealmException e) {
// ignored
}
newClassRealm = jruby.createChildRealm("pom");
for (final String classpath : classpathElements) {
if (!classpath.contains("jruby-complete") || factory.jrubyJar == null) {
newClassRealm.addConstituent(new File(classpath).toURI()
.toURL());
}
}
}
catch (final DuplicateRealmException e) {
throw new ScriptException("error in naming realms", e);
}
catch (final MalformedURLException e) {
throw new ScriptException("hmm. found some malformed URL", e);
}
return newClassRealm;
}
@Override
protected void doExecute(final File launchDirectory,
final List args, final File outputFile)
throws ScriptException, IOException {
doExecute(launchDirectory, outputFile, args, true);
}
private void doExecute(final File launchDirectory, final File outputFile,
final List args, final boolean warn)
throws ScriptException, IOException {
final String currentDir;
if (launchDirectory != null) {
currentDir = System.getProperty("user.dir");
logger.debug("launch directory: "
+ launchDirectory.getAbsolutePath());
System.setProperty("user.dir", launchDirectory.getAbsolutePath());
}
else {
currentDir = null;
}
args.addAll(0, this.factory.switches.list);
if (warn) {
if (this.factory.jvmArgs.list.size() > 0) {
this.logger.warn("have to ignore jvm arguments and properties in the current setup");
}
if (this.factory.environment().size() > 0) {
this.logger.warn("have to ignore environment settings in the current setup");
}
}
final PrintStream output = System.out;
ClassLoader current = null;
try {
if (outputFile != null) {
final PrintStream writer = new PrintStream(outputFile);
System.setOut(writer);
this.logger.debug("output file: " + outputFile);
}
this.logger.debug("args: " + args);
if (this.classRealm != null) {
current = Thread.currentThread().getContextClassLoader();
Thread.currentThread()
.setContextClassLoader(this.classRealm.getClassLoader());
}
// use reflection to avoid having jruby as plugin dependency
final Class> clazz = Thread.currentThread()
.getContextClassLoader()
.loadClass("org.jruby.Main");
final Object main = clazz.newInstance();
final Method m = clazz.getMethod("run", String[].class);
final long start = System.currentTimeMillis();
final Object result = m.invoke(main,
(Object) args.toArray(new String[args.size()]));
final long end = System.currentTimeMillis();
this.logger.debug("time " + (end - start));
final int status;
if (result instanceof Integer) {
// jruby before version 1.5
status = ((Integer) result);
}
else {
// jruby from version 1.5 onwards
// TODO better error handling like error messages and . . .
// TODO see org.jruby.Main
final Method statusMethod = result.getClass()
.getMethod("getStatus", No_ARG_TYPES);
status = (Integer) statusMethod.invoke(result, NO_ARGS);
}
if (status != 0) {
throw new ScriptException("some error in script " + args
+ ": " + status);
}
}
catch (final InstantiationException e) {
throw new ScriptException(e);
}
catch (final IllegalAccessException e) {
throw new ScriptException(e);
}
catch (final ClassNotFoundException e) {
throw new ScriptException(e);
}
catch (final NoSuchMethodException e) {
throw new ScriptException(e);
}
catch (final InvocationTargetException e) {
throw new ScriptException(e);
}
finally {
if (current != null) {
Thread.currentThread().setContextClassLoader(current);
}
System.setOut(output);
if (currentDir != null) {
System.setProperty("user.dir", currentDir);
}
if (this.classRealm != null) {
try {
this.classRealm.getWorld().disposeRealm("pom");
// jrubyClassRealm.setParent(null);
}
catch (final NoSuchRealmException e) {
// ignore
}
}
}
}
public void executeScript(final File launchDirectory, final String script,
final List args, final File outputFile)
throws ScriptException, IOException {
final StringBuilder buf = new StringBuilder();
for (final Map.Entry entry : this.factory.environment().entrySet()) {
if (entry.getValue() != null) {
buf.append("ENV['")
.append(entry.getKey())
.append("']='")
.append(entry.getValue())
.append("';");
}
}
buf.append(script);
args.add(0, "-e");
args.add(1, buf.toString());
args.add(2, "--");
doExecute(launchDirectory, outputFile, args, false);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy