Hi Marc, I think i might have solved two problems that jboss had. 1. The minimum number of jars you need to boot jboss off the network includes all the jars in the \lib dir ~ 480K. 2. Integrating (or embeding) jboss into the process space of an existing app is hard since jboss does so much classloader juggling.
I crated a "Boot" class that lets you start multiple main(String[]) applications each with it's own classloader and in it's own threadgroup. The classpath to the applications are in URL format so we should be able to use this Boot class load the jboss minimum jars from the network (like crimson and jmxri). Anyways.. I tested it out with JBoss, to see if my Boot class could boot the org.jboss.Main and it worked after a small tweak of the UnifiedClassLoader. The commnd line of the jboss boot looks something like: java -classpath mboot.jar chirino.mboot.Boot -cp file:../lib/jmxri.jar,file:../lib/jboss-boot.jar,file:../lib/jaxp.jar,file:../lib/getopt.jar,file:../lib/crimson.jar,file:run.jar org.jboss.Main default Yeah I know, I should read in the manifest to make it easier. I'm going to attach the sources. Let me know what you think. Is it a value add to the jboss boot process?? Regards, Hiram _________________________________________________________________ Chat with friends online, try MSN Messenger: http://messenger.msn.com
package chirino.mboot; import java.net.*; import java.lang.reflect.*; import java.io.*; import java.util.*; /** * Starts multiple applications using seperate classloaders. * This allows multiple applications to co-exist even if they typicaly could not due to * class version problems. Each application is started in it's own thread. * * Usage is Boot [-debug] -cp app-classpath app-class-name app-arguments ( , -cp app-classpath app-class-name app-arguments )* * * Where: * app-classpath is a comma seperated URL form classpath to the application classes. * app-class-name is the class that will be started * app-arguments will be the String[] that will be passed to the main method of the application class * * example: * * Main -mbuss-app -cp file:./app1.jar,file:./util.jar test.App1TEST arg1 arg2 -mbuss-app -cp file:./app2.jar,file:./util.jar test.App2TEST arg1 arg2 * Would start two application class main methods: App1TEST.main() and App2TEST.main() * */ public class Boot { /** * Indicates whether this instance is running in debug mode. */ protected boolean debug = false; protected LinkedList applicationBoots; // constants private static final String DEBUG = "-debug"; private static final String BOOT_APP_SEPERATOR = System.getProperty("mbus.boot.BOOT_APP_SEPERATOR", ","); private static final String CP = "-cp"; /** * @param args the command line arguments */ public static void main(String[] args) { try { new Boot().run(args); } catch (Throwable e) { System.err.println("Exception launching the application(s):"); e.printStackTrace(System.err); } } /** * Data that is extracted for each mbus app that is specified on the command line */ class ApplicationBoot implements Runnable { LinkedList classpath = new LinkedList(); String applicationClass; LinkedList passThruArgs = new LinkedList(); URLClassLoader classloader; boolean isRunning; public void run() { try { boot(); } catch ( Throwable e ) { System.err.println("Exception durring "+applicationClass+" application run: "); e.printStackTrace(System.err); } } public void boot() throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException { URL urls[] = new URL[classpath.size()]; urls = (URL[])classpath.toArray(urls); String args[] = new String[passThruArgs.size()]; args = (String[])passThruArgs.toArray(args); classloader = new URLClassLoader(urls, Thread.currentThread().getContextClassLoader()); Class appClass = classloader.loadClass(applicationClass); Method mainMethod = appClass.getMethod("main", new Class[] {String[].class} ); try { isRunning = true; mainMethod.invoke(null, new Object[] {args}); } catch (InvocationTargetException e) { if (e.getTargetException() instanceof Error) throw (Error)e.getTargetException(); else throw e; } finally { isRunning = false; } } } /** * Runs the applications to be launched. * * @param args the arguments to pass to the application * @exception thrown if a problem occurs during launching */ public void run(String[] args) throws Exception { // Put the args in a linked list since it easier to work with. LinkedList llargs = new LinkedList(); for( int i=0; i < args.length; i++ ) { llargs.add(args[i]); } applicationBoots = processCommandLine(llargs); Iterator i = applicationBoots.iterator(); while( i.hasNext() ) { ApplicationBoot bootData = (ApplicationBoot)i.next(); bootApplication( bootData ); } } public void bootApplication( ApplicationBoot bootData) throws Exception { ThreadGroup threads = new ThreadGroup(bootData.applicationClass); new Thread(threads, bootData, "main").start(); } /** * Processes the command line arguments * * @return a linked list with ApplicationBoot objects * @param args the command line arguments */ protected LinkedList processCommandLine(LinkedList args) throws Exception { LinkedList rc = new LinkedList(); processBootOptions( args ); while( args.size() > 0 ) { ApplicationBoot d = processAppBootCommandLine( args ); if( d != null ) rc.add(d); } if( rc.size() == 0 ) { throw new Exception("Invlid usage: An application class name must be provided."); } return rc; } protected void processBootOptions(LinkedList args) throws Exception { Iterator i = args.iterator(); while( i.hasNext() ) { String arg = (String)i.next(); if( arg.equalsIgnoreCase(DEBUG) ) { debug = true; i.remove(); continue; } // Didn't recognize it a boot option, then we must have started the application // boot options. return; } } protected ApplicationBoot processAppBootCommandLine(LinkedList args) throws Exception { ApplicationBoot rc = new ApplicationBoot(); Iterator i = args.iterator(); while( i.hasNext() ) { String arg = (String)i.next(); i.remove(); if( rc.applicationClass == null ) { if( arg.equalsIgnoreCase(CP) ) { if( !i.hasNext() ) throw new Exception("Invalid option: classpath missing after the "+CP+" option."); String cp = (String)i.next(); i.remove(); StringTokenizer st = new StringTokenizer(cp, ",", false); while( st.hasMoreTokens() ) { String t = st.nextToken(); if( t.length() == 0 ) continue; try { URL u = new URL(t); rc.classpath.add(u); } catch ( MalformedURLException e ) { throw new Exception("Application classpath value was invalid: "+e.getMessage()); } } continue; } rc.applicationClass = arg; continue; } else { if( arg.equalsIgnoreCase(BOOT_APP_SEPERATOR) ) { break; } rc.passThruArgs.add( arg ); } } if( rc.applicationClass == null ) return null; return rc; } }