001    /*
002      Copyright (C) 2001-2002 Renaud Pawlak, Laurent Martelli, Lionel Seinturier.
003    
004      This program is free software; you can redistribute it and/or modify
005      it under the terms of the GNU Lesser General Public License as
006      published by the Free Software Foundation; either version 2 of the
007      License, or (at your option) any later version.
008    
009      This program is distributed in the hope that it will be useful,
010      but WITHOUT ANY WARRANTY; without even the implied warranty of
011      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
012      GNU Lesser General Public License for more details.
013    
014      You should have received a copy of the GNU Lesser General Public
015      License along with this program; if not, write to the Free Software
016      Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
017      USA */
018    
019    package org.objectweb.jac.core;
020    
021    
022    
023    import java.io.*;
024    import java.io.File;
025    import java.net.URL;
026    import java.net.URLClassLoader;
027    import java.util.*;
028    import org.apache.log4j.ConsoleAppender;
029    import org.apache.log4j.FileAppender;
030    import org.apache.log4j.Level;
031    import org.apache.log4j.Logger;
032    import org.apache.log4j.PatternLayout;
033    import org.objectweb.jac.util.*;
034    
035    /**
036     * This is the main class of org.objectweb.jac. It launches a JAC container/server
037     * that is called s0 by default.
038     *
039     * If an application descriptor is given as a last parameter, it runs
040     * the corresponding JAC program on the newly created JAC container by
041     * using a customized class loader <code>JacLoader</code>.
042     *
043     * <p>Use the following command to run <code>MyApp.main()</code> with
044     * <code>arg1, ...</code>:
045     *
046     * <pre>
047     * <b>% java org.objectweb.jac.core.Jac [options] [app.jac arg1, ...]</b>
048     *
049     * where 'app.jac' is a JAC application descriptor
050     *
051     * where options are:
052     *    -r (release): JAC displays the release number
053     *    -v (verbose): the JAC class loader is set to verbose
054     *    -d (debug)  : the JAC class loader is set to debugging mode
055     *    -c (clean)  : JAC cleans the tempory classes directory (previously 
056     *                  created with 'write' option)
057     *    -w (write)  : the JAC class loader writes on disk all the translated
058     *                  classes (and use them for the next run)
059     *    -V [server:]logname  : set the log to verbose mode
060     *    -L file     : redirect all the logs to a file
061     *    -D [name] (dist): JAC runs in distributed mode, i.e. it constructs a 
062     *                  distributed JAC system. If no name is given, the default is s0.
063     *    -M [name]   : defines a master site where all the bytecode will be
064     *                  fetched (by default, classes are loaded from the local
065     *                  file system).
066     *    -R dir      : specify jac_root directory
067     *    -G [gui,...] : launch a list of customized GUI
068     *    -G app@server:[gui,...] : launch a list of customized GUIs
069     *                  with the swing GUI on a remote server for an application
070     *    -A name     : launches an administration GUI on a remote server called 'name'
071     *                  and do not start org.objectweb.jac.
072     *    -W [gui[:port],...] : start the Web GUI server and provide access to some customized GUIs.
073     *    -C <clpath> : specify a particular classpath that will replace $CLASSPATH
074     *    -a application aspect server : reload the configuration for an aspect on a server.
075     *    -n application aspectClassName server aspectConfPath: create a new aspect on a server.
076     *    -u application aspect server : unweave an aspect on a server.
077     *    -x          : redirect ouput to out.txt
078     *    -h (help)   : display the help.
079     * </pre>
080     *
081     * @see JacLoader
082     * @author Renaud Pawlak
083     * @author Lionel Seinturier
084     * @author Laurent Martelli */
085    
086    public class Jac {
087    
088        /** Memorize when the JAC system was launched. */
089        static Date start_time = new Date();
090    
091        /**
092         * Returns the JRE version on which JAC is currently running. */
093        public static String getFullJavaVersion() {
094            return System.getProperties().getProperty("java.version");
095        }
096    
097        /**
098         * Returns the main JRE version (only the 2 first numbers, e.g. 1.3
099         * or 1.4) on which JAC is currently running. */
100        public static String getMainJavaVersion() {
101            return System.getProperties().getProperty("java.version").substring(0,3);
102        }
103    
104        /**
105         * Returns the date when the JAC system was launched.
106         *
107         * @return the date when JAC was launched */
108    
109        public static Date getStartTime() {
110            return start_time;
111        }
112    
113        /** Verbose flag. */
114        private static boolean verbose = false;
115    
116        /** Debug flag (more verbose). */
117        private static boolean debug = false;
118    
119        /** Generate flag. */
120        private static boolean gen = false;
121    
122        /** Clean flag. JAC cleans the temporary directory of translated
123            class files. */
124        private static boolean clean = false;
125    
126        /** Write flag. JAC writes the translated class files into a
127            temporary directory. */
128        private static boolean write = false;
129    
130        /** Server flag. JAC is launched in server mode. It waits for
131            remote call and instantiations. */
132        private static boolean server = false;
133    
134        /** Client flag. JAC binds to the namespace and the aspect-space. */
135        private static boolean client = false;
136    
137        /** Stores the client host name in client or bind mode */
138        private static String clientHost = "";
139    
140        /** Stores the server host name in bind mode */
141        private static String serverHost = "";
142    
143        /** Stores the master server host name */
144        private static String master = "";
145    
146        /** Distributed flag. JAC bootstraps a namespace and an
147            aspect-space on the topology (a set of JAC servers). Then, it
148            launches a deployment program. */
149        private static boolean distributed = false;
150    
151        /** Store the class repository container name. */
152        private static String classRepository = "";
153    
154        /** Internally used flag, starts a program if true. Set to false if
155            an error occurs when parsing the options. */
156        private static boolean start = true;
157    
158        /** The Javassist class loader. */
159        //public static javassist.Loader classLoader;
160        public static JacLoader classLoader;
161    
162    
163        /** The JAC root directory. */
164        private static String jac_root = "";
165    
166        /** The class that is launched when JAC is started. */
167        private static String launchedClass = "";
168    
169        /** A flag that tell if the GUI must be started. */
170        private static String[] startSwingGUI = null;
171    
172        /** A list of customized GUI IDs to be made available through the WEB */
173        private static String[] startWebGUI = null;
174    
175        private static Hashtable logLevels = new Hashtable();
176    
177        private static String logFileName;
178    
179        /** Stores the server host name in bind mode */
180        private static String remoteGuiServerName = null;
181    
182        /** alternative classpath, added with -C option */
183        public static ClassLoader otherClasspath;
184    
185        static final String version = "0.12";
186    
187        static Logger logger = Logger.getLogger("jac");
188        static Logger perf = Logger.getLogger("perf");
189        static Logger classpath = Logger.getLogger("classpath");
190        static Logger urlloader = Logger.getLogger("urlloader");
191    
192        /**
193         * The entry point of the JAC system.
194         *
195         * <p>Creates a JAC loader that will load the classes and translate them.
196         *
197         * @param args the command-line options
198         *
199         * @see JacLoader 
200         */
201        public static void main(String[] args) throws Throwable {
202            Logger root = Logger.getRootLogger();
203            root.addAppender(
204                new ConsoleAppender(
205                    new PatternLayout("%d %p %c: %x %m%n")));
206            root.setLevel(Level.WARN);
207            Logger.getLogger("jac").setLevel(Level.INFO);
208            Logger.getLogger("gui").setLevel(Level.INFO);
209            Logger.getLogger("dist").setLevel(Level.INFO);
210            Logger.getLogger("props").setLevel(Level.ERROR);
211            logger.info("JAC version "+version);
212          
213            args = parseOptions(args);
214    
215            classLoader = new JacLoader(write, clean, otherClasspath);
216    
217            if (remoteGuiServerName!=null) {
218                remoteInvoke(remoteGuiServerName,"launchGUI", new Object[0]);
219                System.exit(0);
220            }
221    
222            // launch RMI
223            //Process p = Runtime.getRuntime().exec("rmiregistry");
224            //p.waitFor();//Thread.currentThread().sleep(3000);
225    
226            Class daemon = null;
227    
228            /** Try to launch a Jac server on the local host */
229            if (!master.equals("")) {
230                try {
231                    ClassLoader cl =
232                        (ClassLoader)Class.forName("org.objectweb.jac.core.dist.DistdClassLoader")
233                        .newInstance ();
234                    Class jac = cl.loadClass("org.objectweb.jac.core.Jac");
235                    jac.getMethod("setJacRoot", new Class[] {String.class}).invoke(
236                        null,new Object[] {jac_root});
237    
238                    daemon = cl.loadClass("org.objectweb.jac.core.dist.rmi.RMIDistd");
239                    //System.out.println("-r "+master+" "+serverHost);
240                    daemon.getConstructor( new Class[] { String[].class } )
241                        .newInstance ( new Object [] {
242                            new String[] {"-r",master,serverHost} } );
243    
244                    Class bootstrap =
245                        cl.loadClass("org.objectweb.jac.aspects.distribution.bootstrap.DistBootstrap");
246                    bootstrap.getMethod("main", new Class[] {String[].class}).invoke(
247                        null,new Object[] {new String[0]});
248    
249                    if (start) {
250                        long _start_time = System.currentTimeMillis();
251    
252                        ///** start the Aspect Component manager */
253                        //classLoader.run ( "org.objectweb.jac.core.ACManager", null );
254                        Class acm = cl.loadClass("org.objectweb.jac.core.ACManager");
255                        acm.getMethod("main", new Class[] {String[].class}).invoke(
256                            null,new Object[] {new String[0]});
257    
258                        /** runs the application if any */
259                        if (args.length > 0) {
260                            Class appRep = cl.loadClass("org.objectweb.jac.core.ApplicationRepository");
261                            appRep.getMethod("main", new Class[] {String[].class}).invoke(
262                                null,new Object[] {args});
263                        }
264                        perf.info("application started in "+
265                                  (System.currentTimeMillis()-_start_time)+"ms");
266                        //Class jacObject = cl.loadClass ( "org.objectweb.jac.core.JacObject" );
267                        //jacObject.getMethod("main", new Class[] {String[].class}).invoke(
268                        //   null,new Object[] {new String[0]});
269                        //Semaphore waitingSemaphore = new Semaphore();
270                        //waitingSemaphore.acquire();
271                    }
272    
273                } catch (Exception e) {
274                    System.out.println ("Error: cannot launch Jac server.");
275                    e.printStackTrace();
276                    while (true) {}
277                }
278    
279            } else {
280    
281                long _start_time = System.currentTimeMillis();
282                if (distributed) {
283                    daemon = classLoader.loadClass("org.objectweb.jac.core.dist.rmi.RMIDistd");
284                    daemon.getConstructor(new Class[] { String[].class })
285                        .newInstance ( new Object [] { new String[] {serverHost} } );
286                }
287                if (client) {
288                    daemon = classLoader.loadClass("org.objectweb.jac.core.dist.rmi.RMIDistd");
289                    daemon.getConstructor(new Class[] { String[].class })
290                        .newInstance ( new Object [] { new String[] { clientHost } } );
291                }
292    
293                /*
294                  Class jac = classLoader.loadClass ( "org.objectweb.jac.core.Jac" );
295    
296                  Jac.getMethod( "setJacRoot", new Class[] { String.class } ).invoke(
297                  null, new Object[] { jac_root } );
298                  if ( startSwingGUI() ) {
299                  Jac.getMethod( "setStartSwingGUI", new Class[] {String[].class} ).invoke(
300                  null, new Object[] {startSwingGUI} );
301                  }
302                  if ( startWebGUI() ) {
303                  Jac.getMethod( "setStartWebGUI", new Class[] {String[].class} ).invoke(
304                  null, new Object[] {startWebGUI} );
305                  }
306                */
307    
308                if (start) {
309    
310                    classLoader.loadClass("org.objectweb.jac.util.Repository");
311                    if (distributed || client || server) {
312                        /** bootstrap the distributed JAC system */
313                        classLoader.run("org.objectweb.jac.aspects.distribution.bootstrap.DistBootstrap", null);
314                    }
315                    //if ( client ) {
316                    //   /** bind to the distributed JAC system */
317                    //   classLoader.run("org.objectweb.jac.aspects.distribution.bootstrap.BindClient",
318                    //                   new String[] {clientHost});
319                    //}
320                    /** start the Aspect Component manager */
321                    classLoader.run("org.objectweb.jac.core.ACManager",null);
322    
323                    /** runs the application if any */
324                    if (args.length > 0) {
325                        classLoader.run("org.objectweb.jac.core.ApplicationRepository", args);
326                    }
327                    //classLoader.run ( "org.objectweb.jac.core.JacObject", null );
328                    //Semaphore waitingSemaphore = new Semaphore();
329                    //waitingSemaphore.acquire();
330                }
331                perf.info("application started in "+
332                          (System.currentTimeMillis()-_start_time)+"ms");
333    
334            }
335        }
336    
337    
338        /**
339         * Transforms a classpath into a list of URLs
340         *
341         * @param path the classpath
342         */
343        private static URL[] parseClasspath(String path)
344        {
345            String[] tab = Strings.splitPath(path);
346    
347            URL[] result = new URL[tab.length];
348    
349            try {
350                for (int i = 0; i < tab.length; i++) {
351                    urlloader.info("adding "+new File(tab[i]).toURL());
352                    result[i] = new File(tab[i]).toURL();
353                }
354            } catch (Exception e) {
355                e.printStackTrace();
356            }
357    
358            return result;
359        }
360    
361        /**
362         * Parse the command line and extract the options to set the values
363         * of the appropriate fields.
364         *
365         * @param args the command-line options */
366    
367        private static String[] parseOptions(String[] args) {
368            int i = 0;
369            String[] ret = args;
370            if (args.length == 0) {
371                start = false;
372                displayLaunchingHelp();
373                return ret;
374            }
375            try {
376            parse:
377                while((i < args.length) && args[i].startsWith("-")) {
378                    String current =
379                        (args[i].length()>2)
380                        ? args[i].substring(2)
381                        : null;
382                    switch (args[i].charAt(1)) {
383                        case '-':
384                            i++;
385                            break parse;
386                        case 'r':
387                            System.out.println( "- JAC version "+version+" - " +
388                                                "Get new release at http://org.objectweb.jac.aopsys.com/ -" );
389                            break;
390                        case 'v':
391                            verbose = true;
392                            break;
393                        case 'd':
394                            debug = true;
395                            break;
396                        case 'g':
397                            gen = true;
398                            start = false;
399                            break;
400                        case 'w':
401                            write = true;
402                            break;
403                        case 'c':
404                            clean = true;
405                            break;
406                        case 'C': // new Classpath
407                            i++;
408                            String[] cp = Strings.splitPath(args[i]);
409                            String newClassPath = "";
410    
411                            // transform relative paths into absolute paths
412                            for (int j = 0; j < cp.length; j++)
413                            {
414                                File file = new File(cp[j]);
415                                cp[j] = file.getAbsolutePath();
416                                if (newClassPath.length() != 0)
417                                    newClassPath += System.getProperty("path.separator");
418                                newClassPath += cp[j];
419                            }
420    
421                            classpath.info("java.class.path="+System.getProperty("java.class.path"));
422                            // reset java.class.path for resources search
423                            System.setProperty("java.class.path",
424                                               newClassPath
425                                               + System.getProperty("path.separator")
426                                               + System.getProperty("java.class.path"));
427    
428                            otherClasspath =
429                                new URLClassLoader(parseClasspath(newClassPath));
430    
431                            break;
432                        case 'D':
433                            distributed = true;
434                            if( (i+1>=args.length) || args[i+1].startsWith("-") ||
435                                args[i+1].endsWith(".jac")) {
436                                serverHost = "s0";
437                            } else {
438                                i++;
439                                serverHost = args[i];
440                            }
441                            break;
442                        case 'M':
443                            i++;
444                            master = args[i];
445                            break;
446                        case 'V':
447                            {
448                                String category = current;
449                                if (category==null) {
450                                    i++;
451                                    category = args[i];
452                                }
453                                int index = category.indexOf(':');
454                                String serverName=null;
455                                if (index!=-1) {
456                                    serverName = category.substring(0,index);
457                                    category = category.substring(index+1);
458                                }
459                                int equalIndex = category.indexOf('=');
460                                Level level = Level.DEBUG;
461                                if (equalIndex!=-1) {
462                                    try {
463                                        level = 
464                                            level.toLevel(
465                                                Integer.parseInt(category.substring(equalIndex+1)));
466                                    } catch (NumberFormatException e) {
467                                        level = Level.toLevel(category.substring(equalIndex+1));
468                                    }
469                                    category = category.substring(0,equalIndex);
470                                }
471                                if (serverName!=null) {
472                                    remoteSetTrace("",serverName,category,level.toInt());
473                                    System.exit(0);
474                                } else {
475                                    Logger.getLogger(category).setLevel(level);
476                                }
477                            }
478                            break;
479                        case 'L':
480                            if (current==null) {
481                                i++;
482                                current = args[i];
483                            }
484                            logFileName = current;
485                            Logger.getRootLogger().addAppender(
486                                new FileAppender(
487                                    new PatternLayout(PatternLayout.TTCC_CONVERSION_PATTERN),
488                                    logFileName));
489                            break;
490                        case 'h':
491                            start = false;
492                            displayLaunchingHelp();
493                            break;
494                        case 'R':
495                            i++;
496                            Jac.setJacRoot(args[i]);
497                            break;
498                        case 'G':
499                            {
500                                if (current==null) {
501                                    i++;
502                                    current = args[i];
503                                }
504                                String guis = current;
505                                int index = guis.indexOf(':');
506                                String serverName = null;
507                                if (index!=-1) {
508                                    serverName = guis.substring(0,index);
509                                    guis = guis.substring(index+1);
510                                }
511                                if (serverName==null) {
512                                    Jac.setStartSwingGUI(Strings.split(guis,","));
513                                } else {
514                                    index = serverName.indexOf('@');
515                                    if (index!=-1) {
516                                        remoteStartSwingGUI(serverName.substring(0,index),
517                                                            serverName.substring(index+1),
518                                                            Strings.split(guis,","));
519                                        System.exit(0);
520                                    } else {
521                                        logger.fatal("No application name specified "+
522                                                     "(appName@sever:guiName");
523                                        System.exit(1);
524                                    }
525                                }
526                            }
527                            break;
528                        case 'x':
529                            PrintStream stream =
530                                new PrintStream(new FileOutputStream("out.txt"));
531                            System.setOut(stream);
532                            System.setErr(stream);
533                            break;
534                        case 'A':
535                            i++;
536                            remoteGuiServerName = args[i];
537    
538                            start = false;
539                            break;
540                        case 'a':
541                            {
542                                i++;
543                                String applicationName = args[i];
544                                i++;
545                                String aspectName = args[i];
546                                i++;
547                                String serverName = args[i];
548                                remoteReloadAspect(applicationName,serverName,aspectName);
549                                start = false;
550                                System.exit(0);
551                            }
552                            break;
553                        case 'u':
554                            {
555                                i++;
556                                String applicationName = args[i];
557                                i++;
558                                String aspectName = args[i];
559                                i++;
560                                String serverName = args[i];
561                                remoteUnweaveAspect(applicationName,serverName,aspectName);
562                                start = false;
563                                System.exit(0);
564                            }
565                            break;
566                        case 'n':
567                            {
568                                i++;
569                                String applicationName = args[i];
570                                i++;
571                                String aspectName = args[i];
572                                i++;
573                                String serverName = args[i];
574                                i++;
575                                String confPath = args[i];
576                                remoteWeaveAspect(applicationName,serverName,aspectName,confPath);
577                                start = false;
578                                System.exit(0);
579                            }
580                            break;
581                        case 'W':
582                            if (client || server) {
583                                System.out.println("Incompatible options "+
584                                                   "(-W, -S, and -C are incompatible)");
585                                displayLaunchingHelp();
586                            }
587                            i++;
588                            Jac.setStartWebGUI(Strings.split(args[i],","));
589                            break;
590                        case 't':
591                            String aspect = args[++i];
592                            String config = args[++i];
593                            try {
594                                ACManager.main(new String [0]);
595                                Logger.getLogger("aspects.config").setLevel(Level.DEBUG);
596                                Logger root = Logger.getRootLogger();                            
597                                root.removeAllAppenders();
598                                root.addAppender(
599                                    new ConsoleAppender(
600                                        new PatternLayout("%p %m%n")));
601                                AspectComponent ac = 
602                                    (AspectComponent)Class.forName(
603                                        ACManager.getACM().getACPathFromName(aspect)).newInstance();
604                                ac.configure(aspect,config);
605                            } catch (Throwable e) {
606                                e.printStackTrace();
607                            }
608                            System.exit(0);
609                            break;
610                        default:
611                            System.out.println("Wrong option: " + args[i]);
612                            displayLaunchingHelp();
613                    }
614                    if (args[i].startsWith("-S")) { i++; break; }
615                    if (args[i].equals("-g")) { break; }
616                    i++;
617                }
618            } catch (Exception e) {
619                e.printStackTrace();
620    
621                System.out.println("Error while arguments parsing");
622                displayLaunchingHelp();
623            }
624    
625            //if(i == args.length) {
626            //start = false;
627            //   return ret;
628            //}
629            if (i>0) {
630                ret = new String[args.length - i];
631                System.arraycopy(args, i, ret, 0, args.length - i);
632            }
633            return ret;
634        }
635    
636        /**
637         * Reload an aspect on a remote server
638         * @param application the application for which to reload an aspect
639         * @param server the name of the JAC server on which the application runs
640         * @param aspect the name of the aspect to reload
641         */
642        public static void remoteReloadAspect(String application, String server,
643                                              String aspect)
644            throws Exception
645        {
646            remoteInvoke(server,"reloadAspect",
647                         new Object[] { application, aspect });
648        }
649    
650        public static void remoteUnweaveAspect(String application, String server,
651                                               String aspect)
652            throws Exception
653        {
654            remoteInvoke(server,"unweaveAspect",
655                         new Object[] { application, aspect });
656        }
657    
658        public static void remoteWeaveAspect(String application, String server,
659                                             String aspect,String aspectConfPath)
660            throws Exception
661        {
662            remoteInvoke(server,"weaveAspect",
663                         new Object[] { application, aspect, aspectConfPath });
664        }
665    
666    
667    
668        /**
669         * Sets a trace loggin level on a remote server.
670         *
671         * @param application the application for which to reload an aspect
672         * @param server the name of the JAC server on which the application runs
673         * @param category the trace category
674         * @param level the trace level to set for the category
675         */
676        public static void remoteSetTrace(String application, String server,
677                                          String category, int level)
678            throws Exception
679        {
680            remoteInvoke(
681                server,
682                "setTrace",
683                new Object[] { application, category, new Integer(level) });
684        }
685    
686        /**
687         * Starts a swing GUI on a remote server.
688         *
689         * @param application the application for which start the GUI
690         * @param server the name of the JAC server on which the application runs
691         * @param guiNames the names of the GUI windows to start
692         */
693        public static void remoteStartSwingGUI(String application, String server,
694                                               String[] guiNames)
695            throws Exception
696        {
697            remoteInvoke(
698                server,
699                "startSwingGUI",
700                new Object[] { application, guiNames });
701        }
702    
703        /**
704         * Invoke a distant method on the JAC_topology object.
705         *
706         * @param server server name where to find the JAC_topology object
707         * @param method name of the method to invoke
708         * @param args parameters for method invocation
709         */
710        static Object remoteInvoke(String server, String method, Object[] args) 
711            throws Exception 
712        {
713            // Argl!! I hate reflection in Java!
714            try {
715                Class rcClass = Class.forName("org.objectweb.jac.core.dist.RemoteContainer");
716                Object rc = rcClass.
717                    getMethod("resolve",new Class[] {String.class}).
718                    invoke(null,new Object[] {server} );
719                if (rc==null) {
720                    throw new RuntimeException("Could not find a JAC server with that name: "+server);
721                } else {
722                    Object topology = rcClass.
723                        getMethod("bindTo",new Class[] {String.class}).
724                        invoke(rc,new Object[] {"JAC_topology"} );
725                    return Class.forName("org.objectweb.jac.core.dist.RemoteRef")
726                        .getMethod("invoke",new Class[]{String.class,Object[].class})
727                        .invoke(topology, new Object[] { method, args });
728                }
729            } catch (Exception e) {
730                logger.error("remoteInvoke("+server+"."+method+") failed",e);
731                throw e;
732            }
733        }
734    
735        /**
736         * Print the help (displayed when the -h option is set). 
737         */
738        public static void displayLaunchingHelp() {
739            System.err.println(
740                "Launch a JAC container with :\n"+
741                "% java org.objectweb.jac.core.Jac [options] [app.jac arg1, ...]\n" +
742                "  where 'app.jac' is a JAC application descriptor\n" +
743                "  where options are:\n" +
744                "    -r (release): JAC displays the release number\n" +
745                "    -v (verbose): set JAC class loader to verbose\n" +
746                "    -d (debug)  : the JAC class loader is set to debugging mode\n" +
747                "    -c (clean)  : JAC cleans the tempory classes directory (previously created\n"+
748                "                  with 'write' option)\n" +
749                "    -w (write)  : the JAC class loader writes on disk all the translated classes\n"+
750                "                  (and use them for the next run)\n" +
751                "    -V [server:]log: JAC activates the corresponding log on server\n"+
752                "    -L file     : redirect all the logs to the given file\n"+
753                "    -D [name] (dist): launches precises the name of the JAC container's daemon\n"+
754                "                  for distributed mode. If no name is given, default is s0.\n"+
755                "    -M [name]   : defines a master site where all the bytecode will be\n"+
756                "                  fetched (by default, classes are loaded from the local\n"+
757                "                  file system).\n"+
758                "    -R dir      : specify jac_root directory\n"+
759                "    -G [gui,...] : launch a list of customized GUIs with the swing GUI\n"+
760                "    -G app@server:[gui,...] : launch a list of customized GUIs with the swing GUI\n"+
761                "                  on a remote server for an application\n"+
762                "    -A <name>   : launches an administration GUI on a remote server called 'name'\n"+
763                "                  and do not start org.objectweb.jac.\n"+
764                "    -W gui[:port][,...] : launch the GUI web server for a list of customized GUIs\n"+
765                "    -C <clpath>  : specify a particular classpath that will replace $CLASSPATH\n" +
766                "    -a application aspect server : reload the configuration for an aspect on a server\n"+
767                "    -n application aspectClassName server aspectConfPath: create a new aspect\n"+
768                "       on a server for a given application.\n"+
769                "    -u application aspect server : unweave an aspect on a server.\n"+
770                "    -x          : redirect ouput to out.txt\n"+
771                "    -t <aspect> <config> : test loading of a config file\n"+
772                "    -h (help)   : display the help\n");
773            System.exit( 0 );
774        }
775    
776        /**
777         * This method is internally used to clean the cache directory of
778         * the translated classes (to use the cache, use the -w option and
779         * clean it with the -c option).
780         *
781         * @param dir the directory to clean 
782         */
783        protected static void cleanDirectory(File dir) {
784            if (debug) 
785                System.out.println("Deleting dir " + dir.getPath() + "...");
786    
787            File[] in_d = dir.listFiles();
788    
789            for (int i=0; i<in_d.length; i++) {
790                if (in_d[i].isDirectory()) {
791                    cleanDirectory(in_d[i]);
792                } else {
793                    if (debug) System.out.println("Deleting file " + dir.getPath() + "...");
794                    in_d[i].delete();
795                }
796            }
797            dir.delete();
798        }
799    
800        /* like cleanDirectory(), but only remove files
801           if the original class file is newer */
802    
803        /*
804          protected static void autoCleanDirectory(String dirName) {
805    
806    
807          File dirFile = new File(getClassesTmp()+dirName);
808          if (!dirFile.exists())
809          return;
810          if (debug) System.out.println("Auto cleaning dir " + dirFile.getPath() + "...");
811          File[] in_d = dirFile.listFiles();
812    
813          if (!dirName.equals(""))
814          dirName += "/";
815          for (int i=0; i<in_d.length; i++) {
816          if (in_d[i].isDirectory()) {
817          autoCleanDirectory(dirName+in_d[i].getName());
818          } else {
819          File orig = new File(getJacRoot()+"classes/"+dirName+in_d[i].getName());
820          if (debug) System.out.println(in_d[i]+" : "+orig.lastModified()+" / "+in_d[i].lastModified());
821          if (orig.lastModified()>in_d[i].lastModified()) {
822          if (debug) System.out.println("Deleting file " + in_d[i] + "...");
823          in_d[i].delete();
824          }
825          }
826          }
827          dirFile.delete();
828          }
829        */
830    
831        /**
832         * Returns the JAC root directory.<p>
833         *
834         * The root directory is usually defined by an environment variable
835         * that is set to <code>$HOME/jac</code> where $HOME is the home
836         * directory of the current user.<p>
837         *
838         * It can also be defined at launching time with the
839         * <code>-R</code> option.<p>
840         *
841         * @return the JAC root directory value
842         * @see #setJacRoot(String) */
843    
844        public static String getJacRoot() {
845            if (jac_root==null) {
846                System.err.println("No JAC_ROOT. Cannot continue.");
847                System.exit(-1);
848            }
849            return jac_root;
850        }
851    
852        /**
853         * Sets the JAC root directory.<p>
854         *
855         * @param dir the path of the JAC root directory
856         * @see #getJacRoot()
857         */
858    
859        public static void setJacRoot(String dir) {
860            String fileSep = System.getProperty("file.separator");
861            if (!dir.endsWith(fileSep))
862                dir += fileSep;
863            jac_root = dir;
864        }
865    
866        /**
867         * Gets the name of the class that has been launched when JAC was
868         * started (in an autonomous or a distributed mode).<p>
869         *
870         * The launched class is the class that contains the static
871         * <code>run</code> method.<p>
872         *
873         * @return the launched class name
874         * @see #setLaunchedClass(String) */
875    
876        public static String getLaunchedClass() {
877            return launchedClass;
878        }
879    
880        /**
881         * Sets the launched class.<p>
882         *
883         * @param className the launched class name
884         * @see #getLaunchedClass() */
885    
886        public static void setLaunchedClass(String className) {
887            launchedClass = className;
888        }
889    
890        /**
891         * Returns the logical name of the program that was launched when
892         * the JAC system started.<p>
893         *
894         * The logical program name is by convention the package name of
895         * the class that runs the launched program.<p>
896         *
897         * For instance, if the command line is:<p>
898         *
899         * <ul><pre>jac -c -D org.objectweb.jac.samples.agenda.Run</pre></ul><p>
900         *
901         * Then the launched program is <code>org.objectweb.jac.samples.agenda</code><p>
902         *
903         * @return the launched program name
904         * @see #getLaunchedClass() */
905    
906        public static String getLaunchedProgram() {
907            String lc = getLaunchedClass();
908            if (lc == null || lc.equals("")) {
909                return "";
910            }
911            String lp = lc;
912            int ndx = 0;
913            if ((ndx = lp.indexOf(' ')) != -1) {
914                lp = lc.substring(0, ndx);
915            }
916            if ((ndx = lp.lastIndexOf('.')) != -1) {
917                lp = lc.substring(0, ndx);
918            }
919    
920            return lp;
921        }
922    
923        /**
924         * Tells if the JAC system must try to launch the GUI of the
925         * program is exist (see the <code>-G</code> option).<p>
926         *
927         * If the program does not provides a GUI aspect, then the default
928         * GUI is launched.<p>
929         *
930         * @return true if the GUI must be launched
931         * @see #setStartSwingGUI(String[]) */
932    
933        public static boolean startSwingGUI() {
934            return startSwingGUI!=null && startSwingGUI.length>0;
935        }
936    
937        /**
938         * Tells if the JAC system must try to launch the Web GUI of the
939         * program is exist (see the <code>-G</code> option).<p>
940         *
941         * If the program does not provides a Web GUI aspect, then the default
942         * GUI is launched.<p>
943         *
944         * @return true if the Web GUI must be launched
945         * @see #setStartWebGUI(String[]) */
946    
947        public static boolean startWebGUI() {
948            return startWebGUI!=null && startWebGUI.length>0;
949        }
950    
951        /**
952         * Tells the JAC system to start the GUI.<p>
953         *
954         * @see #startSwingGUI() */
955    
956        public static void setStartSwingGUI(String[] start) {
957            startSwingGUI = start;
958        }
959    
960        /**
961         * Returns the array of of customized GUI ids to be shown with the
962         * Swing interface
963         */
964        public static String[] getStartSwingGUI() {
965            return startSwingGUI;
966        }
967    
968        /**
969         * Tells the JAC system to start the GUI.<p>
970         *
971         * @see #startWebGUI() */
972    
973        public static void setStartWebGUI(String[] customizedGUIs) {
974            startWebGUI = customizedGUIs;
975        }
976    
977        /**
978         * Returns the array of of customized GUI ids to be made available
979         * on the web gui.
980         */
981        public static String[] getStartWebGUI() {
982            return startWebGUI;
983        }
984    
985    }