Permalink
Browse files

Merge remote-tracking branch 'kares/runnable' into gh-130

Conflicts:
	.gitignore
	Gemfile
	ext/JarMain.java
	spec/sample_war/Rakefile
  • Loading branch information...
2 parents e5e41e8 + 509b71c commit ff10266b2652242ff331b63bb0350c7d857ce69c @BanzaiMan BanzaiMan committed Jan 31, 2013
View
@@ -1,9 +1,6 @@
source "http://rubygems.org/"
-gem "rake"
-gem "rubyzip"
-gem "jruby-jars"
-gem "jruby-rack"
+gemspec
group :development do
gem "jruby-openssl", :platform => :jruby
View
@@ -7,9 +7,10 @@
begin
require 'bundler/setup'
-rescue LoadError
- puts $!
- puts "Please install Bundler and run 'bundle install' to ensure you have all dependencies"
+rescue LoadError => e
+ require('rubygems') && retry
+ puts "Please `gem install bundler' and run `bundle install' to ensure you have all dependencies"
+ raise e
end
require 'bundler/gem_helper'
View
@@ -8,111 +8,164 @@
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
+import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.URI;
+import java.net.URISyntaxException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Enumeration;
+import java.util.HashMap;
import java.util.List;
+import java.util.Map;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
public class JarMain implements Runnable {
- public static final String MAIN = "/" + JarMain.class.getName().replace('.', '/') + ".class";
-
- private String[] args;
- private String path, jarfile;
- private boolean debug;
- private File extractRoot;
-
- public JarMain(String[] args) throws Exception {
+
+ static final String MAIN = "/" + JarMain.class.getName().replace('.', '/') + ".class";
+
+ final boolean debug = isDebug();
+
+ protected final String[] args;
+ protected final String archive;
+ private final String path;
+
+ protected File extractRoot;
+
+ JarMain(String[] args) {
this.args = args;
URL mainClass = getClass().getResource(MAIN);
- this.path = mainClass.toURI().getSchemeSpecificPart();
- this.jarfile = this.path.replace("!" + MAIN, "").replace("file:", "");
- this.debug = isDebug();
- this.extractRoot = File.createTempFile("jruby", "extract");
- this.extractRoot.delete();
- this.extractRoot.mkdirs();
+ try {
+ this.path = mainClass.toURI().getSchemeSpecificPart();
+ }
+ catch (URISyntaxException e) {
+ throw new RuntimeException(e);
+ }
+ archive = this.path.replace("!" + MAIN, "").replace("file:", "");
+
Runtime.getRuntime().addShutdownHook(new Thread(this));
}
+
+ protected URL[] extractArchive() throws Exception {
+ final JarFile jarFile = new JarFile(archive);
+ try {
+ Map<String, JarEntry> jarNames = new HashMap<String, JarEntry>();
+ for (Enumeration<JarEntry> e = jarFile.entries(); e.hasMoreElements(); ) {
+ JarEntry entry = e.nextElement();
+ String extractPath = getExtractEntryPath(entry);
+ if ( extractPath != null ) jarNames.put(extractPath, entry);
+ }
+
+ extractRoot = File.createTempFile("jruby", "extract");
+ extractRoot.delete(); extractRoot.mkdirs();
- private URL[] extractJRuby() throws Exception {
- JarFile jf = new JarFile(this.jarfile);
- List<String> jarNames = new ArrayList<String>();
- for (Enumeration<JarEntry> eje = jf.entries(); eje.hasMoreElements(); ) {
- String name = eje.nextElement().getName();
- if (name.startsWith("META-INF/lib") && name.endsWith(".jar")) {
- jarNames.add("/" + name);
+ final List<URL> urls = new ArrayList<URL>();
+ for (Map.Entry<String, JarEntry> e : jarNames.entrySet()) {
+ URL entryURL = extractEntry(e.getValue(), e.getKey());
+ if (entryURL != null) urls.add( entryURL );
}
+ return (URL[]) urls.toArray(new URL[urls.size()]);
}
-
- List<URL> urls = new ArrayList<URL>();
- for (String name : jarNames) {
- urls.add(extractJar(name));
+ finally {
+ jarFile.close();
}
-
- return (URL[]) urls.toArray(new URL[urls.size()]);
}
- private URL extractJar(String jarpath) throws Exception {
- InputStream jarStream = new URI("jar", path.replace(MAIN, jarpath), null).toURL().openStream();
- String jarname = jarpath.substring(jarpath.lastIndexOf("/") + 1, jarpath.lastIndexOf("."));
- File jarFile = new File(extractRoot, jarname + ".jar");
- jarFile.deleteOnExit();
- FileOutputStream outStream = new FileOutputStream(jarFile);
+ protected String getExtractEntryPath(final JarEntry entry) {
+ final String name = entry.getName();
+ if ( name.startsWith("META-INF/lib") && name.endsWith(".jar") ) {
+ return name.substring(name.lastIndexOf("/") + 1);
+ }
+ return null; // do not extract entry
+ }
+
+ protected URL extractEntry(final JarEntry entry, final String path) throws Exception {
+ final File file = new File(extractRoot, path);
+ if ( entry.isDirectory() ) {
+ file.mkdirs();
+ return null;
+ }
+ final String entryPath = entryPath(entry.getName());
+ final InputStream entryStream;
+ try {
+ entryStream = new URI("jar", entryPath, null).toURL().openStream();
+ }
+ catch (IllegalArgumentException e) {
+ // TODO gems '%' file name "encoding" ?!
+ debug("failed to open jar:" + entryPath + " skipping entry: " + entry.getName(), e);
+ return null;
+ }
+ final File parent = file.getParentFile();
+ if ( parent != null ) parent.mkdirs();
+ FileOutputStream outStream = new FileOutputStream(file);
+ final byte[] buf = new byte[65536];
try {
- byte[] buf = new byte[65536];
int bytesRead = 0;
- while ((bytesRead = jarStream.read(buf)) != -1) {
+ while ((bytesRead = entryStream.read(buf)) != -1) {
outStream.write(buf, 0, bytesRead);
}
- } finally {
- jarStream.close();
+ }
+ finally {
+ entryStream.close();
outStream.close();
+ file.deleteOnExit();
}
- debug(jarname + ".jar extracted to " + jarFile.getPath());
- return jarFile.toURI().toURL();
+ if (false) debug(entry.getName() + " extracted to " + file.getPath());
+ return file.toURI().toURL();
+ }
+
+ protected String entryPath(String name) {
+ if ( ! name.startsWith("/") ) name = "/" + name;
+ return path.replace(MAIN, name);
}
- private int launchJRuby(URL[] jars) throws Exception {
+ protected Object newScriptingContainer(final URL[] jars) throws Exception {
System.setProperty("org.jruby.embed.class.path", "");
- URLClassLoader loader = new URLClassLoader(jars);
+ ClassLoader loader = new URLClassLoader(jars);
Class scriptingContainerClass = Class.forName("org.jruby.embed.ScriptingContainer", true, loader);
Object scriptingContainer = scriptingContainerClass.newInstance();
-
- Method argv = scriptingContainerClass.getDeclaredMethod("setArgv", new Class[] {String[].class});
- argv.invoke(scriptingContainer, new Object[] {args});
- Method setClassLoader = scriptingContainerClass.getDeclaredMethod("setClassLoader", new Class[] {ClassLoader.class});
- setClassLoader.invoke(scriptingContainer, new Object[] {loader});
- debug("invoking " + jarfile + " with: " + Arrays.deepToString(args));
-
- Method runScriptlet = scriptingContainerClass.getDeclaredMethod("runScriptlet", new Class[] {String.class});
- return ((Number) runScriptlet.invoke(scriptingContainer, new Object[] {
- "begin\n" +
- "require 'META-INF/init.rb'\n" +
- "require 'META-INF/main.rb'\n" +
- "0\n" +
- "rescue SystemExit => e\n" +
- "e.status\n" +
- "end"
- })).intValue();
+ debug("scripting container class loader urls: " + Arrays.toString(jars));
+ invokeMethod(scriptingContainer, "setArgv", (Object) args);
+ invokeMethod(scriptingContainer, "setClassLoader", new Class[] { ClassLoader.class }, loader);
+ return scriptingContainer;
+ }
+
+ protected int launchJRuby(final URL[] jars) throws Exception {
+ final Object scriptingContainer = newScriptingContainer(jars);
+ debug("invoking " + archive + " with: " + Arrays.deepToString(args));
+ Object outcome = invokeMethod(scriptingContainer, "runScriptlet", launchScript());
+ return ( outcome instanceof Number ) ? ( (Number) outcome ).intValue() : 0;
}
- private int start() throws Exception {
- URL[] u = extractJRuby();
- return launchJRuby(u);
+ protected String launchScript() {
+ return
+ "begin\n" +
+ " require 'META-INF/init.rb'\n" +
+ " require 'META-INF/main.rb'\n" +
+ " 0\n" +
+ "rescue SystemExit => e\n" +
+ " e.status\n" +
+ "end";
+ }
+
+ protected int start() throws Exception {
+ final URL[] jars = extractArchive();
+ return launchJRuby(jars);
}
- private void debug(String msg) {
- if (debug) {
- System.out.println(msg);
- }
+ protected void debug(String msg) {
+ debug(msg, null);
}
- private void delete(File f) {
+ protected void debug(String msg, Throwable t) {
+ if (debug) System.out.println(msg);
+ if (debug && t != null) t.printStackTrace(System.out);
+ }
+
+ protected void delete(File f) {
if (f.isDirectory()) {
File[] children = f.listFiles();
for (int i = 0; i < children.length; i++) {
@@ -121,30 +174,57 @@ private void delete(File f) {
}
f.delete();
}
-
+
public void run() {
- delete(extractRoot);
+ if ( extractRoot != null ) delete(extractRoot);
}
public static void main(String[] args) {
+ doStart(new JarMain(args));
+ }
+
+ protected static void doStart(final JarMain main) {
try {
int exit = new JarMain(args).start();
if(isSystemExitEnabled()) System.exit(exit);
} catch (Exception e) {
+ System.err.println("error: " + e.toString());
Throwable t = e;
while (t.getCause() != null && t.getCause() != t) {
t = t.getCause();
}
-
if (isDebug()) {
t.printStackTrace();
}
System.exit(1);
}
}
+
+ protected static Object invokeMethod(final Object self, final String name, final Object... args)
+ throws NoSuchMethodException, IllegalAccessException, Exception {
+
+ final Class[] signature = new Class[args.length];
+ for ( int i = 0; i < args.length; i++ ) signature[i] = args[i].getClass();
+ return invokeMethod(self, name, signature, args);
+ }
- private static boolean isDebug() {
- return System.getProperty("warbler.debug") != null;
+ protected static Object invokeMethod(final Object self, final String name, final Class[] signature, final Object... args)
+ throws NoSuchMethodException, IllegalAccessException, Exception {
+ Method method = self.getClass().getDeclaredMethod(name, signature);
+ try {
+ return method.invoke(self, args);
+ }
+ catch (InvocationTargetException e) {
+ Throwable target = e.getTargetException();
+ if (target instanceof Exception) {
+ throw (Exception) target;
+ }
+ throw e;
+ }
+ }
+
+ static boolean isDebug() {
+ return Boolean.getBoolean("warbler.debug");
}
/**
@@ -155,4 +235,5 @@ private static boolean isDebug() {
private static boolean isSystemExitEnabled(){
return System.getProperty("warbler.skip_system_exit") == null; //omission enables System.exit use
}
+
}
Oops, something went wrong.

0 comments on commit ff10266

Please sign in to comment.