package com.stuartsierra;

import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;
import java.net.MalformedURLException;
import java.io.File;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import com.martiansoftware.nailgun.NGContext;

public class ClasspathManager {
    private static final String CLASSPATH_FILE_NAME = "classpath";

    private static List<URL> readClasspath(File classpathFile)
	throws IOException {

	List<URL> urls = new ArrayList<URL>();
	BufferedReader reader = new BufferedReader(new FileReader(classpathFile));
	try {
	    while(true) {
		String line = reader.readLine();
		if (line == null) break;
		StringBuilder sb = new StringBuilder();
		sb.append("file:");
		if (!line.startsWith("/")) {
		    sb.append(classpathFile.getParentFile().getAbsolutePath());
		    sb.append("/");
		}
		sb.append(line);
		try {
		    URL url = new URL(sb.toString());
		    urls.add(url);
		} catch (MalformedURLException e) {
		    System.out.println(e.toString());
		}
	    }
	} finally {
	    reader.close();
	}
	return urls;
    }

    public static void sharedMain(String working_dir, String[] args) {
	if (args.length == 0) {
	    System.out.println("Usage: ClasspathManager <main-class>");
	    System.exit(1);
	}

	String mainClassName = args[0];
	
	File classpathFile = new File(working_dir, CLASSPATH_FILE_NAME);

	List<URL> urls = null;
	try {
	    urls = readClasspath(classpathFile);
	} catch (IOException e) {
	    System.out.println(e.toString());
	    System.exit(-1);
	}

	URL[] urlArray = urls.toArray(new URL[0]);
	ClassLoader classloader = URLClassLoader.newInstance(urlArray);
	Thread.currentThread().setContextClassLoader(classloader);
	try {
	    Class mainClass = classloader.loadClass(mainClassName);
	    Class[] mainSignature = new Class[] { String[].class };
	    Method mainMethod = mainClass.getMethod("main", mainSignature);
	    String[] mainArgs = Arrays.copyOfRange(args, 1, args.length);
	    mainMethod.invoke(null, (Object)mainArgs);
	} catch (Exception e) {
	    e.printStackTrace();
	    System.exit(-1);
	}	    
    }
    
    public static void main(String[] args) {
	sharedMain(System.getProperty("user.dir"), args);
    }

    public static void nailMain(NGContext context) {
	sharedMain(context.getWorkingDirectory(), context.getArgs());
    }
}

@@ -514,16 +514,106 @@
 path%22;%0A%0A
+    private static final Class%5B%5D MAIN_METHOD_SIGNATURE = new Class%5B%5D %7B String%5B%5D.class %7D;%0A%0A
     priv
@@ -1503,16 +1503,22 @@
 );%0A%09%7D%0A%0A%09
+final 
 String m
@@ -1541,16 +1541,85 @@
 rgs%5B0%5D;%0A
+%09final String%5B%5D mainArgs = Arrays.copyOfRange(args, 1, args.length);%0A
 %09%0A%09File 
@@ -1845,16 +1845,22 @@
 );%0A%09%7D%0A%0A%09
+final 
 URL%5B%5D ur
@@ -1894,17 +1894,77 @@
 RL%5B0%5D);%0A
-%09
+%0A%09Thread thread = new Thread() %7B%0A%09%09public void run() %7B%0A%09%09    
 ClassLoa
@@ -2020,16 +2020,21 @@
 rray);%0A%09
+%09    
 Thread.c
@@ -2085,27 +2085,30 @@
 ader);%0A%09
+%09    
 try %7B%0A%09
-    
+%09%09
 Class ma
@@ -2160,249 +2160,281 @@
 );%0A%09
-    Class%5B%5D mainSignature = new Class%5B%5D %7B String%5B%5D.class %7D;%0A%09    Method mainMethod = mainClass.getMethod(%22main%22, mainSignature
+%09%09Method mainMethod = mainClass.getMethod(%22main%22,%0A%09%09%09%09%09%09%09%09MAIN_METHOD_SIGNATURE);%0A%09%09%09mainMethod.invoke(null, (Object)mainArgs
 );%0A
+%09
 %09    
-String%5B%5D mainArgs = Arrays.copyOfRange(args, 1, args.length);%0A%09    mainMethod.invoke(null, (Object)mainArgs
+%7D catch (Exception e) %7B%0A%09%09%09e.printStackTrace();%0A%09%09%09System.exit(-1);%0A%09%09    %7D%09    %0A%09%09%7D%0A%09    %7D;%0A%0A%09try %7B%0A%09    thread.start();%0A%09    thread.join(
 );%0A%09
@@ -2434,32 +2434,43 @@
 in();%0A%09%7D catch (
+Interrupted
 Exception e) %7B%0A%09
@@ -2518,21 +2518,16 @@
 (-1);%0A%09%7D
-%09    
 %0A    %7D%0A 

Set classpath on new thread to avoid PermGen memory leak