Save This Page
Home » jboss-5.0.0.CR1-src » org » jboss » tools » [javadoc | source]
    1   /*
    2    * JBoss, the OpenSource J2EE webOS
    3    *
    4    * Distributable under LGPL license.
    5    * See terms of license at gnu.org.
    6    */
    7   
    8   package org.jboss.tools;
    9   
   10   import java.net;
   11   import java.lang.reflect;
   12   import java.io;
   13   import java.util;
   14   
   15   /**
   16    * Starts multiple applications using seperate classloaders.
   17    * This allows multiple applications to co-exist even if they typicaly could not due to 
   18    * class version problems.  Each application is started in it's own thread.
   19    * 
   20    * Usage is Boot [-debug] -cp app-classpath app-class-name app-arguments ( , -cp app-classpath app-class-name app-arguments )*
   21    * 
   22    * Where:
   23    * 	app-classpath is a comma seperated URL form classpath to the application classes.
   24    * 	app-class-name is the class that will be started
   25    * 	app-arguments will be the String[] that will be passed to the main method of the application class
   26    * 
   27    * Jboss + Another Application boot example:
   28    *     Boot -cp file:run.jar org.jboss.Main default , -cp file:./myapp.jar,file:./util.jar test.App2TEST arg1 arg2
   29    * Would start the JBoss Server using the default configuration and it would
   30    * start the test.App2TEST application.  
   31    * Important Note: Notice that there are spaces before and after the ","!!!
   32    * 
   33    * You can now boot other applications via ths Boot class from withing one of the applications 
   34    * that was booted by the Boot.
   35    * 
   36    * Example usage:
   37    * <code>
   38    * Boot b = Boot.getInstance();
   39    * Boot.ApplicationBoot ab = b.createApplicationBoot();
   40    * ab.applicationClass = "org.jboss.Main"
   41    * ab.classpath.add(new URL("file:run.jar"));
   42    * ab.args.add("default");
   43    * 
   44    * // this would start the application in a new thread.
   45    * b.startApplication( ab );
   46    * 
   47    * // Would boot the appp in the current thread.
   48    * ab.boot();
   49    * 
   50    * </code>
   51    * 
   52    * @author <a href="mailto:cojonudo14@hotmail.com">Hiram Chirino</a>
   53    */
   54   public class Boot
   55   {
   56      /**
   57       * Indicates whether this instance is running in debug mode.
   58       */
   59      protected boolean verbose = false;
   60   
   61      /**
   62       * For each booted application, we will store a ApplicationBoot object in this linked list.
   63       */
   64      protected LinkedList applicationBoots = new LinkedList();
   65   	static Boot instance;
   66   	ThreadGroup bootThreadGroup;
   67   
   68   	/**
   69   	 * If boot is accessed via an API, force the use of the getInstance() method.
   70   	 */
   71   	protected Boot () {
   72   	   instance = this;
   73   	   bootThreadGroup = Thread.currentThread().getThreadGroup();
   74   	}
   75   	
   76   	public static Boot getInstance() {
   77   	   if( instance == null )
   78   		   instance = new Boot();
   79   	   return instance;
   80   	}
   81   
   82      /**
   83       * Represents an application that can be booted.
   84       */
   85      public class ApplicationBoot implements Runnable
   86      {
   87   		/** LinkedList of URL that will be used to load the application's classes and resources */
   88         public LinkedList classpath = new LinkedList();
   89   		/** The applications class that will be executed. */
   90         public String applicationClass;
   91   		/** The aruments that will appsed to the application. */
   92         public LinkedList args = new LinkedList();
   93         
   94         protected URLClassLoader classloader;
   95         protected Thread bootThread;
   96   
   97         /**
   98          * This is what actually loads the application classes and
   99          * invokes the main method.  We send any unhandled exceptions to 
  100          * System.err
  101          */
  102         public void run()
  103         {
  104            try
  105            {
  106               boot();
  107            }
  108            catch (Throwable e)
  109            {
  110               System.err.println("Exception durring " + applicationClass + " application run: ");
  111               e.printStackTrace(System.err);
  112            }
  113         }
  114   
  115         /**
  116          * This is what actually loads the application classes and
  117          * invokes the main method.
  118          */
  119         public void boot()
  120            throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException
  121         {
  122   	   	verbose("Booting: "+applicationClass);
  123   	   	verbose("Classpath: "+classpath);
  124   	   	verbose("Arguments: "+args);
  125   	   	
  126            bootThread = Thread.currentThread();
  127            URL urls[] = new URL[classpath.size()];
  128            urls = (URL[]) classpath.toArray(urls);
  129   
  130            String passThruArgs[] = new String[args.size()];
  131            passThruArgs = (String[]) args.toArray(passThruArgs);
  132   
  133   			// Save the current loader so we can restore it.
  134   			ClassLoader oldCL = Thread.currentThread().getContextClassLoader();
  135   			
  136            try {
  137               
  138               classloader = new URLClassLoader(urls); // The parent is the system CL
  139               Thread.currentThread().setContextClassLoader(classloader);
  140               
  141               Class appClass = classloader.loadClass(applicationClass);
  142               Method mainMethod = appClass.getMethod("main", new Class[] { String[].class });
  143   
  144               mainMethod.invoke(null, new Object[] { passThruArgs });
  145            }
  146            catch (InvocationTargetException e)
  147            {
  148               if (e.getTargetException() instanceof Error)
  149                  throw (Error) e.getTargetException();
  150               else
  151                  throw e;
  152            }
  153            finally
  154            {
  155               // Restore the previous classloader ( in case we were called directly 
  156               // an not via a Thread.start() )
  157               Thread.currentThread().setContextClassLoader(oldCL);
  158            }
  159         }
  160      }
  161      
  162      /**
  163       * This can be used to boot another application 
  164       * From within another one.
  165       * 
  166       * @returns ApplicationBoot data structure that must be configured before the application can be booted.
  167       */
  168      public ApplicationBoot createApplicationBoot() {
  169         return new ApplicationBoot();
  170      } 
  171   
  172      /**
  173       * Boots the application in a new threadgroup and thread.
  174       * 
  175       * @param bootData the application to boot.
  176       * @exception thrown if a problem occurs during launching
  177       */
  178      synchronized public void startApplication(ApplicationBoot bootData) throws Exception
  179      {
  180         if( bootData == null )
  181         	throw new NullPointerException("Invalid argument: bootData argument was null");
  182      
  183         applicationBoots.add(bootData);
  184         ThreadGroup threads = new ThreadGroup(bootThreadGroup, bootData.applicationClass);
  185         new Thread(threads, bootData, "main").start();
  186      }
  187      
  188      synchronized public ApplicationBoot[] getStartedApplications() {
  189         ApplicationBoot rc[] = new ApplicationBoot[applicationBoots.size()];
  190         return (ApplicationBoot[])applicationBoots.toArray(rc);
  191      }
  192         
  193   	/** logs verbose message to the console */   
  194      protected void verbose(String msg) {
  195         if( verbose )
  196         	System.out.println("[Boot] "+msg);
  197      }
  198      
  199   	//////////////////////////////////////////////////////////////////////
  200   	//
  201   	// THE FOLLOWING SET OF FUNCTIONS ARE RELATED TO PROCESSING COMMAND LINE
  202   	// ARGUMENTS.
  203   	//	
  204   	//////////////////////////////////////////////////////////////////////
  205      protected static final String HELP = "-help";
  206      protected static final String VERBOSE = "-verbose";
  207      protected static final String BOOT_APP_SEPERATOR = System.getProperty("org.jboss.Boot.APP_SEPERATOR", ",");
  208      protected static final String CP = "-cp";
  209   
  210      protected static class InvalidCommandLineException extends Exception {
  211         /**
  212          * Constructor for InvalidCommandLineException.
  213          * @param s
  214          */
  215         public InvalidCommandLineException(String s)
  216         {
  217            super(s);
  218         }
  219   	}
  220      
  221      /**
  222       * Main entry point when called from the command line
  223       * @param args the command line arguments
  224       */
  225      public static void main(String[] args)
  226      {
  227         Boot boot = Boot.getInstance();
  228         
  229         // Put the args in a linked list since it easier to work with.
  230         LinkedList llargs = new LinkedList();
  231         for (int i = 0; i < args.length; i++)
  232            llargs.add(args[i]);
  233   
  234   		try {
  235            
  236            LinkedList ab = boot.processCommandLine(llargs);
  237            Iterator i = ab.iterator();
  238            while (i.hasNext())
  239            {
  240               ApplicationBoot bootData = (ApplicationBoot) i.next();
  241               boot.startApplication(bootData);
  242            }
  243            
  244   		} catch ( InvalidCommandLineException e ) {
  245   		   System.err.println("Invalid Usage: "+e.getMessage());
  246   		   System.err.println();
  247   		   showUsage();
  248   		   System.exit(1);
  249   		} catch ( Throwable e ) {
  250            System.err.println("Failure occured while executing application: ");
  251            e.printStackTrace(System.err);
  252   		   System.exit(1);
  253   		}
  254      }
  255      
  256      /**
  257       * This method is here so that if JBoss is running under
  258       * Alexandria (An NT Service Installer), Alexandria can shutdown
  259       * the system down correctly.
  260       */
  261      public static void systemExit(String argv[])
  262      {
  263         System.exit(0);
  264      }
  265   
  266      /**
  267       * Processes the Boot class's command line arguments
  268       * 
  269       * @return a linked list with ApplicationBoot objects
  270       * @param args the command line arguments
  271       */
  272      protected LinkedList processCommandLine(LinkedList args) throws Exception
  273      {
  274         LinkedList rc = new LinkedList();
  275   
  276         processBootOptions(args);
  277         while (args.size() > 0)
  278         {
  279            ApplicationBoot d = processAppBootCommandLine(args);
  280            if (d != null)
  281               rc.add(d);
  282         }
  283   
  284         if (rc.size() == 0)
  285         {
  286            throw new InvalidCommandLineException("An application class name must be provided.");
  287         }
  288   
  289         return rc;
  290      }
  291   
  292      /**
  293       * Processes to global options.
  294       * 
  295       * @param args the command line arguments
  296       */
  297      protected void processBootOptions(LinkedList args) throws Exception
  298      {
  299         Iterator i = args.iterator();
  300         while (i.hasNext())
  301         {
  302            String arg = (String) i.next();
  303            if (arg.equalsIgnoreCase(VERBOSE))
  304            {
  305               verbose = true;
  306               i.remove();
  307               continue;
  308            }
  309            if (arg.equalsIgnoreCase(HELP))
  310            {
  311               showUsage();
  312               System.exit(0);
  313            }
  314   
  315            // Didn't recognize it a boot option, then we must have started the application 
  316            // boot options.
  317            return;
  318         }
  319      }
  320   
  321      protected static void showUsage()
  322      {
  323         String programName = System.getProperty("org.jboss.Boot.proces-name", "boot");
  324         
  325         System.out.println("usage: " + programName + " [boot-options] [app-options] class [args..]");
  326         System.out.println("       to execute a class");
  327         System.out.println("   or  " + programName + " [boot-options] [app-options] class-1 [args..] , ... , [app-options] class-n [args..]");
  328         System.out.println("       to execute multiple classes");
  329         System.out.println();
  330         System.out.println("boot-options:");
  331         System.out.println("    -help         show this help message");
  332         System.out.println("    -verbose      display detail messages regarding the boot process.");
  333         System.out.println("app-options:");
  334         System.out.println("    -cp <directories and zip/jar urls separated by ,> ");
  335         System.out.println("                  set search path for application classes and resources");
  336         System.out.println();
  337      }
  338   
  339      /**
  340       * Processes the command line argumenst for the next application on the command line.
  341       * 
  342       * @param args the command line arguments
  343       */
  344      protected ApplicationBoot processAppBootCommandLine(LinkedList args) throws Exception
  345      {
  346         ApplicationBoot rc = new ApplicationBoot();
  347         Iterator i = args.iterator();
  348   
  349         while (i.hasNext())
  350         {
  351            String arg = (String) i.next();
  352            i.remove();
  353   
  354            if (rc.applicationClass == null)
  355            {
  356               if (arg.equalsIgnoreCase(CP))
  357               {
  358                  if (!i.hasNext())
  359                     throw new InvalidCommandLineException("Invalid option: classpath missing after the " + CP + " option.");
  360                  String cp = (String) i.next();
  361                  i.remove();
  362   
  363                  StringTokenizer st = new StringTokenizer(cp, ",", false);
  364                  while (st.hasMoreTokens())
  365                  {
  366                     String t = st.nextToken();
  367                     if (t.length() == 0)
  368                        continue;
  369                     try
  370                     {
  371                        URL u = new URL(t);
  372                        rc.classpath.add(u);
  373                     }
  374                     catch (MalformedURLException e)
  375                     {
  376                        throw new InvalidCommandLineException("Application classpath value was invalid: " + e.getMessage());
  377                     }
  378                  }
  379                  continue;
  380               }
  381   
  382               rc.applicationClass = arg;
  383               continue;
  384            }
  385            else
  386            {
  387               if (arg.equalsIgnoreCase(BOOT_APP_SEPERATOR))
  388               {
  389                  break;
  390               }
  391               rc.args.add(arg);
  392            }
  393   
  394         }
  395   
  396         if (rc.applicationClass == null)
  397            return null;
  398   
  399         return rc;
  400      }
  401   
  402   }

Save This Page
Home » jboss-5.0.0.CR1-src » org » jboss » tools » [javadoc | source]