1 /*------------------------------------------------------------------------------
  2 Name:      Main.java
  3 Project:   xmlBlaster.org
  4 Copyright: xmlBlaster.org, see xmlBlaster-LICENSE file
  5 Comment:   Main class to invoke the xmlBlaster server
  6 ------------------------------------------------------------------------------*/
  7 package org.xmlBlaster;
  8 
  9 import java.io.BufferedReader;
 10 import java.io.IOException;
 11 import java.io.InputStreamReader;
 12 import java.util.logging.Level;
 13 import java.util.logging.Logger;
 14 
 15 import org.xmlBlaster.engine.ServerScope;
 16 import org.xmlBlaster.engine.runlevel.I_RunlevelListener;
 17 import org.xmlBlaster.engine.runlevel.RunlevelManager;
 18 import org.xmlBlaster.protocol.I_Authenticate;
 19 import org.xmlBlaster.protocol.I_Driver;
 20 import org.xmlBlaster.protocol.I_XmlBlaster;
 21 import org.xmlBlaster.util.FileLocator;
 22 import org.xmlBlaster.util.Global;
 23 import org.xmlBlaster.util.I_SignalListener;
 24 import org.xmlBlaster.util.I_XmlBlasterExceptionHandler;
 25 import org.xmlBlaster.util.ReplaceVariable;
 26 import org.xmlBlaster.util.SignalCatcher;
 27 import org.xmlBlaster.util.ThreadLister;
 28 import org.xmlBlaster.util.Timestamp;
 29 import org.xmlBlaster.util.XmlBlasterException;
 30 import org.xmlBlaster.util.admin.extern.JmxWrapper;
 31 import org.xmlBlaster.util.def.ErrorCode;
 32 import org.xmlBlaster.util.log.StdoutStderrRedirector;
 33 import org.xmlBlaster.util.log.XbFormatter;
 34 import org.xmlBlaster.util.property.Property;
 35 
 36 /**
 37  * Main class to invoke the xmlBlaster server.
 38  * <p />
 39  * There are many command line parameters supported
 40  * please invoke with "-?" to get a complete list of the supported parameters.
 41  * <br />
 42  * Every parameter may be set in the xmlBlaster.property file as a system property or at the command line,
 43  * the command line is strongest, xmlBlaster.properties weakest. The leading "-" from the command line key
 44  * parameters are stripped (see Property.java).
 45  * <p />
 46  * Examples how to start the xmlBlaster server:
 47  * <p />
 48  * <code>   java org.xmlBlaster.Main -bootstrapPort 3412</code>
 49  * <p />
 50  * <code>   java org.xmlBlaster.Main -plugin/ior/iorFile /tmp/XmlBlaster_Ref</code>
 51  * <p />
 52  * <code>   java org.xmlBlaster.Main -logging FINEST</code>
 53  * <p />
 54  * <code>   java org.xmlBlaster.Main -plugin/xmlrpc/hostname 102.24.64.60 -plugin/xmlrpc/port 8081</code>
 55  * <p />
 56  * <code>   java org.xmlBlaster.Main -?</code>
 57  *
 58  * @author <a href="mailto:xmlBlaster@marcelruff.info">Marcel Ruff</a>.
 59  * @see <a href="http://www.xmlblaster.org/xmlBlaster/doc/requirements/admin.telnet.html" target="others">admin.telnet</a>
 60  * @see <a href="http://www.xmlblaster.org/xmlBlaster/doc/requirements/util.property.html" target="others">util.property</a>
 61  */
 62 public class Main implements I_RunlevelListener, I_Main, I_SignalListener, I_XmlBlasterExceptionHandler
 63 {
 64    private String ME = "Main";
 65 
 66    private ServerScope glob = null;
 67 
 68    private static Logger log = Logger.getLogger(Main.class.getName());
 69 
 70    /** Starts/stops xmlBlaster */
 71    private RunlevelManager runlevelManager = null;
 72 
 73    private boolean showUsage = false;
 74    
 75    /** Incarnation time of this object instance in millis */
 76    private long startupTime;
 77 
 78    private boolean inShutdownProcess = false;
 79    private SignalCatcher signalCatcher;
 80    /**
 81     * Comma separate list of errorCodes which to an immediate System.exit(1);
 82     * Used by our default implementation of I_XmlBlasterExceptionHandler
 83     * TODO: If you use JdbcManagerCommonTableDelegate.java you may NOT
 84     * use ErrorCode.RESOURCE_DB_UNKNOWN as this will retry one time the operation!
 85     * How to assure this if configured different???
 86     */
 87    //private String panicErrorCodes = ErrorCode.RESOURCE_DB_UNAVAILABLE.getErrorCode();
 88    private String panicErrorCodes = ErrorCode.RESOURCE_DB_UNKNOWN.getErrorCode()+","+ErrorCode.RESOURCE_DB_UNAVAILABLE.getErrorCode();
 89 
 90    /**
 91     * true: If instance created by control panel<br />
 92     * false: running without GUI
 93     */
 94    static MainGUI controlPanel = null;
 95    
 96    private StdoutStderrRedirector stdoutStderrRedirector;
 97 
 98    /**
 99     * You need to call init() after construction.
100     * Currently used by XmlBlasterClassLoader
101     */
102     public Main() {
103        //System.out.println("Default constructor called ...");
104     }
105 
106 
107    public Main(ServerScope glob, MainGUI controlPanel_) {
108       controlPanel = controlPanel_;
109       controlPanel.xmlBlasterMain = this;
110       init(glob);
111    }
112 
113 
114    /**
115     * Start xmlBlaster using the properties from utilGlob
116     * without loading xmlBlaster.properties again
117     * @param utilGlob The environment for this server instance
118     */
119    public Main(Global utilGlob) {
120       if (utilGlob instanceof ServerScope)
121          init(utilGlob);
122       else
123          init(new ServerScope(Property.propsToArgs(utilGlob.getProperty().getProperties())));
124    }
125 
126    /**
127     * Start xmlBlaster using the given properties
128     * and load xmlBlaster.properties.
129     * @param args The command line parameters
130     */
131    public Main(String[] args) {
132       // The setting 'java -DxmlBlaster/initClassName=mypackage.MyClass ...' allows to load an initial class instance
133       String initClass = System.getProperty("xmlBlaster/initClassName", "");
134       if (initClass.length() > 0) {
135         try {
136           this.getClass().getClassLoader().loadClass(initClass).newInstance();
137          } catch (Exception e) {
138             e.printStackTrace();
139          }
140       }
141       init(new ServerScope(args));
142    }
143 
144    public ServerScope getGlobal() {
145       return this.glob;
146    }
147 
148    /*
149     * Start xmlBlaster using the properties from utilGlob
150     * without loading <tt>xmlBlaster.properties</tt> again
151     * @param utilGlob The environment for this server instance
152     */
153    public void init(org.xmlBlaster.util.Global utilGlob) {
154       org.xmlBlaster.engine.ServerScope gg =
155           new org.xmlBlaster.engine.ServerScope(utilGlob.getProperty().getProperties(), false);
156       utilGlob.setId(gg.getId()); // Inherit backwards the cluster node id
157       init(gg);
158    }
159 
160    /*
161     * Start xmlBlaster using the given properties
162     * and load <tt>xmlBlaster.properties</tt>.
163     * @param props The environment for this server instance
164     */
165    public void init(java.util.Properties props) {
166       this.init(new org.xmlBlaster.engine.ServerScope(props, true));
167    }
168 
169    public final void init(ServerScope glob)
170    {
171       this.startupTime = System.currentTimeMillis();
172 
173       this.glob = glob;
174 
175       this.ME = "Main" + glob.getLogPrefixDashed();
176       //try { log.info(ME, glob.getDump()); } catch (Throwable e) { System.out.println(ME + ": " + e.toString()); e.printStackTrace(); }
177 
178       showUsage = glob.wantsHelp();
179       Thread.currentThread().setName("XmlBlaster.MainThread");
180 
181       if (glob.wantsHelp())
182          showUsage = true;
183       else if (glob.getErrorText() != null) {
184          usage();
185          log.severe(glob.getErrorText());
186          if (glob.isEmbedded())
187             throw new IllegalArgumentException(glob.getErrorText());
188          else
189             System.exit(0);
190       }
191       
192       boolean redirect = glob.getProperty().get("xmlBlaster/stdoutStderrToLogging", false);
193       if (redirect) {
194           String filterSetOut = glob.getProperty().get("xmlBlaster/stdoutSuppressSet", (String)null);
195           String filterSetErr = glob.getProperty().get("xmlBlaster/stderrSuppressSet", (String)null);
196           log.info("Redirecting stdout and stderr to java.util.logging as -xmlBlaster/stdoutStderrToLogging=" + redirect + " -xmlBlaster/stdoutSuppressSet=" + filterSetOut + " -xmlBlaster/stderrSuppressSet=" + filterSetErr);
197         this.stdoutStderrRedirector = new StdoutStderrRedirector(filterSetOut, filterSetErr, ";");
198         this.stdoutStderrRedirector.redirect();
199         //System.out.println("First stdout redirect test");
200         //System.err.println("First stderr redirect test");
201         //Exception e = new Exception("First stderr exception redirect test");
202         //e.printStackTrace();
203       }
204 
205       long sleepOnStartup = glob.getProperty().get("xmlBlaster/sleepOnStartup", 0L);
206       if (sleepOnStartup > 0L) {
207         log.info("Going to sleep as configured xmlBlaster/sleepOnStartup=" + sleepOnStartup);
208         try { Thread.sleep(sleepOnStartup);
209         } catch(InterruptedException e) { log.warning("Caught exception during xmlBlaster/sleepOnStartup=" + sleepOnStartup + ": " + e.toString()); }
210       }
211 
212       boolean useJdbcManagerDelegate = glob.getProperty().get("xmlBlaster/useJdbcManagerDelegate", true);
213       if (useJdbcManagerDelegate) {
214          this.panicErrorCodes = ErrorCode.RESOURCE_DB_UNAVAILABLE.getErrorCode();
215       }
216       else {
217          this.panicErrorCodes = ErrorCode.RESOURCE_DB_UNKNOWN.getErrorCode()+","+ErrorCode.RESOURCE_DB_UNAVAILABLE.getErrorCode();
218       }
219 
220       this.panicErrorCodes = glob.getProperty().get("xmlBlaster/panicErrorCodes", this.panicErrorCodes);
221       log.fine("Following errorCodes do an immediate exit: " + this.panicErrorCodes);
222       if (useJdbcManagerDelegate && this.panicErrorCodes.indexOf(ErrorCode.RESOURCE_DB_UNKNOWN.toString()) != -1)
223           log.severe("You can not use 'xmlBlaster/panicErrorCodes' " +
224                           ErrorCode.RESOURCE_DB_UNKNOWN.toString() +
225                           " with xmlBlaster/useJdbcManagerDelegate=true. This could result in DB-less operation with persistent entries handled as transient entries which are lost on restart");
226       // Add us as an I_XmlBlasterExceptionHandler ... (done again in changeRunlevel() below, but this is too late as first JDBC access can be in RL0
227       if (XmlBlasterException.getExceptionHandler() == null)
228          XmlBlasterException.setExceptionHandler(this); // see public void newException(XmlBlasterException e);
229 
230       int runlevel = glob.getProperty().get("runlevel", RunlevelManager.RUNLEVEL_RUNNING);
231       try {
232          runlevelManager = glob.getRunlevelManager();
233          runlevelManager.addRunlevelListener(this);
234          runlevelManager.initPluginManagers();
235          runlevelManager.changeRunlevel(runlevel, false);
236       } catch (Throwable e) {
237          if (e instanceof XmlBlasterException) {
238             log.severe(e.getMessage());
239          }
240          else {
241             e.printStackTrace();
242             log.severe(e.toString());
243          }
244          if (glob.isEmbedded()) {
245             throw new IllegalArgumentException(e.toString());
246          }
247          else {
248             log.severe("Changing runlevel to '" + RunlevelManager.toRunlevelStr(runlevel) + "' failed, good bye");
249             System.exit(1);
250          }
251       }
252 
253       boolean useKeyboard = glob.getProperty().get("useKeyboard", true);
254       if (!useKeyboard) {
255          blockThread();
256       }
257 
258       // Used by testsuite to switch off blocking, this Main method is by default never returning:
259       boolean doBlocking = glob.getProperty().get("doBlocking", true);
260 
261       if (doBlocking) {
262          checkForKeyboardInput();
263       }
264    }
265 
266    public void blockThread() {
267       while (true) {
268          try { Thread.sleep(100000000L);
269          } catch(InterruptedException e) { log.warning("Caught exception: " + e.toString()); }
270       }
271       /*
272       //  Exception in thread "main" java.lang.IllegalMonitorStateException:
273       try { Thread.currentThread().wait();
274       } catch(InterruptedException e) { log.warn(ME, "Caught exception: " + e.toString()); }
275       */
276       //orb.run();
277    }
278 
279    /** Same as shutdown() but does additionally an engine.global.shutdown() */
280    public synchronized void destroy() {
281       shutdown();
282       if (this.glob != null) {
283          this.glob.shutdown();
284          this.glob = null;
285       }
286    }
287 
288    /**
289     * Instructs the RunlevelManager to shut down, which causes all object adapters to shut down.
290     * <p />
291     * The drivers are removed.
292     */
293    public synchronized void shutdown()
294    {
295       if (inShutdownProcess)
296          return;
297 
298       inShutdownProcess = true;
299 
300       int errors = 0;
301       try {
302          errors = runlevelManager.changeRunlevel(RunlevelManager.RUNLEVEL_HALTED, true);
303       }
304       catch(XmlBlasterException e) {
305          log.severe("Problem during shutdown: " + e.toString());
306       }
307       if (errors > 0) {
308          log.warning("There were " + errors + " errors during shutdown.");
309       }
310       else {
311          if (log.isLoggable(Level.FINE)) log.fine("shutdown() done");
312       }
313    }
314 
315    /**
316     * Access the authentication singleton.
317     */
318    public I_Authenticate getAuthenticate() {
319       return glob.getAuthenticate();
320    }
321 
322    /**
323     * Access the xmlBlaster singleton.
324     */
325    public I_XmlBlaster getXmlBlaster() {
326       return getAuthenticate().getXmlBlaster();
327    }
328 
329    /**
330     * Check for keyboard entries from console.
331     * <p />
332     * Supported input is:
333     * &lt;ul>
334     *    &lt;li>'g' to pop up the control panel GUI&lt;/li>
335     *    &lt;li>'d' to dump the internal state of xmlBlaster&lt;/li>
336     *    &lt;li>'q' to quit xmlBlaster&lt;/li>
337     * &lt;/ul>
338     * <p />
339     * NOTE: This method never returns, only on exit for 'q'
340     */
341    private void checkForKeyboardInput() {
342       BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
343       while (true) {
344          // orbacus needs this !!! Michele?
345          // if (orb.work_pending()) orb.perform_work();
346          try {
347             String line = in.readLine(); // Blocking in I/O
348             if (line == null) continue;
349             line = line.trim();
350             if (line.toLowerCase().equals("g")) {
351                if (controlPanel == null) {
352                   log.info("Invoking control panel GUI ...");
353                   controlPanel = new MainGUI(glob, this); // the constructor sets the variable controlPanel
354                   controlPanel.run();
355                }
356                else
357                   controlPanel.showWindow();
358             }
359             else if (line.toLowerCase().equals("gc")) {
360                long totalMem = Runtime.getRuntime().totalMemory();
361                long freeMem = (Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory());
362                System.gc();
363                log.info("Garbage collector has run, total/free bytes before="+totalMem+"/"+freeMem+", after="+Runtime.getRuntime().totalMemory()+"/"+(Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory()));
364             }
365             else if (line.toLowerCase().startsWith("r")) {
366                if (line.length() > 1) {
367                   String tmp = line.substring(1).trim();
368                   int runlevel = -10;
369                   try { runlevel = Integer.parseInt(tmp.trim()); } catch(NumberFormatException e) { log.severe("Invalid run level '" + tmp + "', it should be a number."); };
370                   try { runlevelManager.changeRunlevel(runlevel, true); } catch(XmlBlasterException e) { log.severe(e.toString()); }
371                }
372                else
373                   log.info("Current runlevel is " + RunlevelManager.toRunlevelStr(runlevelManager.getCurrentRunlevel()) + "=" + runlevelManager.getCurrentRunlevel() + "");
374             }
375             else if (line.toLowerCase().startsWith("j")) {
376                if (line.length() > 1) {
377                   // ObjectName = org.xmlBlaster:nodeClass=node,node="heron"
378                   // j org.xmlBlaster:nodeClass=node,node="heron"/action=getFreeMemStr
379                   // j org.xmlBlaster:nodeClass=node,node="heron"/action=usage?action=usage
380 
381                   // java  -Djmx.invoke.getters=set ... org.xmlBlaster.Main
382                   // j org.xmlBlaster:nodeClass=node,node="heron"/action=getLastWarning?action=getLastWarning
383                   // j org.xmlBlaster:nodeClass=node,node="heron"/action=getLastWarning
384                   // j org.xmlBlaster:nodeClass=node,node="avalon_mycomp_com",clientClass=client,client="heron.mycomp.com",sessionClass=session,session="1"/action=getConnectionState
385                   String tmp = line.substring(1).trim();
386                   try {
387                      System.out.println("Invoking: " + tmp);
388                      Object obj = JmxWrapper.getInstance(this.glob).invokeCommand(tmp);
389                      if (obj instanceof String[]) {
390                         String[] str = (String[])obj;
391                         for(int i=0; i<str.length; i++)
392                            System.out.println(str[i]);
393                      }
394                      else {
395                         System.out.println(obj);
396                      }
397                   } catch(XmlBlasterException e) { log.severe(e.toString()); }
398                }
399                else
400                   log.info("Please pass a JMX object name to query");
401             }
402             else if (line.toLowerCase().startsWith("d")) {
403                try {
404                   String fileName = null;
405                   if (line.length() > 1) fileName = line.substring(1).trim();
406 
407                   if (fileName == null) {
408                      System.out.println(glob.getDump());
409                      log.info("Dump done");
410                   }
411                   else {
412                      FileLocator.writeFile(fileName, glob.getDump());
413                      log.info("Dumped internal state to '" + fileName + "'");
414                   }
415                }
416                catch(XmlBlasterException e) {
417                   log.severe("Sorry, dump failed: " + e.getMessage());
418                }
419                catch(Throwable e) {
420                   log.severe("Sorry, dump failed: " + e.toString());
421                }
422             }
423             else if (line.toLowerCase().equals("q")) {
424                shutdown();
425                if (glob == null || !glob.isEmbedded())
426                   System.exit(0);
427             }
428             else // if (keyChar == '?' || Character.isLetter(keyChar) || Character.isDigit(keyChar))
429                keyboardUsage();
430          }
431          catch (IOException e) {
432             log.warning(e.toString() + " Keyboard input is disabled, we block this thread now");
433             break;
434          }
435       }
436       blockThread();
437    }
438 
439    public boolean isHalted() {
440       if( runlevelManager != null )
441          return runlevelManager.isHalted();
442       else return true;
443    }
444 
445    /**
446     * A human readable name of the listener for logging.
447     * <p />
448     * Enforced by I_RunlevelListener
449     */
450    public String getName() {
451       return ME;
452    }
453 
454    /**
455     * Invoked on run level change, see RunlevelManager.RUNLEVEL_HALTED and RunlevelManager.RUNLEVEL_RUNNING
456     * <p />
457     * Enforced by I_RunlevelListener
458     * @see org.xmlBlaster.engine.runlevel.I_RunlevelListener#runlevelChange(int, int, boolean)
459     */
460    public void runlevelChange(int from, int to, boolean force) throws XmlBlasterException {
461       //if (log.isLoggable(Level.FINER)) log.call(ME, "Changing from run level=" + from + " to level=" + to + " with force=" + force);
462       if (to == from)
463          return;
464 
465       if (to > from) { // startup
466          //if (to == RunlevelManager.RUNLEVEL_HALTED) {
467          //   log.error(ME, "DEBUG ONLY ........");
468          //   if (glob.getNodeId() == null)
469          //      glob.setUniqueNodeIdName(createNodeId());
470          //}
471          if (to == RunlevelManager.RUNLEVEL_HALTED_POST) {
472             this.startupTime = System.currentTimeMillis();
473             boolean useSignalCatcher = glob.getProperty().get("useSignalCatcher", true);
474             if (useSignalCatcher) {
475                try {
476                   this.signalCatcher = SignalCatcher.instance();
477                   this.signalCatcher.register(this);
478                   this.signalCatcher.catchSignals();
479                }
480                catch (Throwable e) {
481                   log.warning("Can't register signal catcher: " + e.toString());
482                }
483             }
484             // Add us as an I_XmlBlasterExceptionHandler ...
485             if (XmlBlasterException.getExceptionHandler() == null)
486                XmlBlasterException.setExceptionHandler(this); // see public void newException(XmlBlasterException e);
487          }
488          if (to == RunlevelManager.RUNLEVEL_STANDBY) {
489          }
490          if (to == RunlevelManager.RUNLEVEL_STANDBY_POST) {
491             if (showUsage) {
492                usage();  // Now we can display the complete usage of all loaded drivers
493                shutdown();
494                if (!glob.isEmbedded())
495                   System.exit(0);
496             }
497          }
498          if (to == RunlevelManager.RUNLEVEL_CLEANUP) {
499          }
500          if (to == RunlevelManager.RUNLEVEL_RUNNING) {
501          }
502          if (to == RunlevelManager.RUNLEVEL_RUNNING_POST) {
503             log.info(Global.getMemoryStatistic());
504             String duration = Timestamp.millisToNice(System.currentTimeMillis() - this.startupTime);
505             // TEST
506             //new XmlBlasterException(this.glob, ErrorCode.RESOURCE_DB_UNAVAILABLE, ME + ".getXBStore", "", null); 
507             if (controlPanel == null) {
508                if (XbFormatter.withXtermColors()) System.out.println(XbFormatter.BLACK_GREEN);
509                final String bound = "|";
510                String ver = bound + " XmlBlaster cluster node <" + glob.getId() + "> v" + glob.getReleaseId() + " " + glob.getBuildTimestamp();
511                int width = ver.length() + 6;
512                if (width < 48) width = 48;
513                ReplaceVariable sh = new ReplaceVariable();
514                String line = sh.charChain('-', width-2);
515                System.out.println("");
516                System.out.println(" "+line+" ");
517                System.out.println(ver + sh.charChain(' ', width-ver.length()-1) + bound);
518                boolean useKeyboard = glob.getProperty().get("useKeyboard", true);
519                if (useKeyboard) {
520                  String help = bound + " READY " + duration + " - press <enter> for options";
521                  System.out.println(help + sh.charChain(' ', width-help.length()-1) + bound);
522                } else {
523                  String help = bound + " READY " + duration + " - no keyboard input available";
524                  System.out.println(help + sh.charChain(' ', width-help.length()-1) + bound);
525                }
526                System.out.println(" "+line+" ");
527                if (XbFormatter.withXtermColors()) System.out.println(XbFormatter.ESC);
528             }
529             else
530                log.info("xmlBlaster is ready for requests " + duration);
531          }
532       }
533       if (to <= from) { // shutdown
534          if (to == RunlevelManager.RUNLEVEL_RUNNING_PRE) {
535             if (log.isLoggable(Level.FINE)) log.fine("Shutting down xmlBlaster to runlevel " + RunlevelManager.toRunlevelStr(to) + " ...");
536          }
537          if (to == RunlevelManager.RUNLEVEL_HALTED_PRE) {
538             synchronized (this) {
539                if (this.glob != null) {
540                  this.glob.shutdown();
541                }
542             }
543             log.info("XmlBlaster halted.");
544          }
545 
546          if (to == RunlevelManager.RUNLEVEL_HALTED) {
547             synchronized (this) {
548                if (this.signalCatcher != null) {
549                   this.signalCatcher.removeSignalCatcher();
550                   this.signalCatcher = null;
551                }
552             }
553          }
554       }
555    }
556 
557    public void newException(XmlBlasterException e) {
558       boolean serverScope = (e.getGlobal() != null && e.getGlobal().getObjectEntry("org.xmlBlaster.engine.Global") != null);
559       if (!e.isServerSide() && !serverScope) // isServerSide checks if we are ServerScope implementation, serverScope checks if we are a util.Global in the context of a server
560          return;
561       // Typically if the DB is lost: ErrorCode.RESOURCE_DB_UNKNOWN
562       if (this.panicErrorCodes.indexOf(e.getErrorCodeStr()) != -1) {
563          log.severe("PANIC: Doing immediate shutdown caused by exception: " + e.getMessage());
564          e.printStackTrace();
565          log.severe(Global.getStackTraceAsString(e));
566          log.severe("Complete stack trace (all threads at the time of shutdown: " + ThreadLister.getAllStackTraces());
567          SignalCatcher sc = this.signalCatcher;
568          if (sc != null) {
569             sc.removeSignalCatcher();
570          }
571          System.exit(1);
572       }
573    }
574 
575    /**
576    * You will be notified when the runtime exits.
577    * @see I_SignalListener#shutdownHook()
578    */
579    public void shutdownHook() {
580       destroy();
581    }
582 
583    /**
584     * Keyboard input usage.
585     */
586    private void keyboardUsage() {
587       if (XbFormatter.withXtermColors()) System.out.println(XbFormatter.BLACK_LTGREEN);
588       System.out.println("");
589       System.out.println("----------------------------------------------------------");
590       System.out.println("XmlBlaster " + ((glob != null) ? glob.getVersion() : "") +
591                     ((glob != null) ? (" build " + glob.getBuildTimestamp()) : ""));
592       System.out.println("Following interactive keyboard input is recognized:");
593       System.out.println("Key:");
594       System.out.println("   g             Popup the control panel GUI.");
595       System.out.println("   r <run level> Change to run level (0,3,6,9).");
596       try {
597          if (JmxWrapper.getInstance(this.glob).isActivated())
598             System.out.println("   j <JMX call>  For example 'j org.xmlBlaster:nodeClass=node,node=\""+this.glob.getStrippedId()+"\"/action=getFreeMemStr'");
599       } catch (XmlBlasterException e) {
600          e.printStackTrace();
601       }
602       System.out.println("   d <file name> Dump internal state of xmlBlaster to file.");
603       System.out.println("   q             Quit xmlBlaster.");
604       System.out.println("----------------------------------------------------------");
605       if (XbFormatter.withXtermColors()) System.out.println(XbFormatter.ESC);
606    }
607 
608    /**
609     * Command line usage.
610     */
611    private void usage() {
612       System.out.println("-----------------------" + glob.getVersion() + "-------------------------------");
613       System.out.println("java org.xmlBlaster.Main <options>");
614       System.out.println("----------------------------------------------------------");
615       System.out.println("   -h                  Show the complete usage.");
616       System.out.println("");
617 //      try { System.out.println(glob.getProtocolManager().usage()); } catch (XmlBlasterException e) { log.warn(ME, "No usage: " + e.toString()); }
618       // Depending on the current run level not all drivers may be visible:
619       I_Driver[] drivers = glob.getPluginRegistry().getPluginsOfInterfaceI_Driver(); // getPluginsOfGroup("protocol");
620       for (int i=0; i < drivers.length; i++)
621          System.out.println(drivers[i].usage());
622 
623       System.out.println("");
624       System.out.println(org.xmlBlaster.engine.cluster.ClusterManager.staticUsage());
625       System.out.println("");
626       System.out.println(glob.usage());
627       System.out.println("");
628       System.out.println("Other stuff:");
629       System.out.println("   -xmlBlaster/acceptWrongSenderAddress/<subjectId>  <subjectId> is for example 'joe' [false]");
630       System.out.println("                              true: Allows user 'joe' to send wrong sender address in PublishQos");
631       System.out.println("   -xmlBlaster/sleepOnStartup Number of milli seconds to sleep before startup [0]");
632       System.out.println("   -useKeyboard false         Switch off keyboard input, to allow xmlBlaster running in background [true]");
633       System.out.println("   -doBlocking  false         Switch off blocking, the main method is by default never returning [true]");
634       System.out.println("   -admin.remoteconsole.port  If port > 1000 a server is started which is available with telnet [2702]");
635       System.out.println("   -xmlBlaster.isEmbedded     If set to true no System.exit() is possible [false]");
636       System.out.println("   -wipeOutJdbcDB true        Destroy the complete JDBC persistence store entries of prefix=XMLBLASTER (DANGER)");
637       System.out.println("   -xmlBlaster/jmx/HtmlAdaptor       Set to true to enable JMX HTTP access on 'http://localhost:8082' [false]");
638       System.out.println("   -xmlBlaster/jmx/XmlBlasterAdaptor Set to true to enable JMX xmlBlaster adaptor access for swing GUI 'org.xmlBlaster.jmxgui.Main' [false].");
639       System.out.println("   java -Dcom.sun.management.jmxremote ...  Switch on JMX support with jconsole (JDK >= 1.5).");
640       System.out.println("   -xmlBlaster/jmx/observeLowMemory      Write a log error when 90% of the JVM memory is used (JDK >= 1.5) [true]");
641       System.out.println("   -xmlBlaster/jmx/memoryThresholdFactor Configure the log error memory threshhold (defaults to 90%) (JDK >= 1.5) [0.9]");
642       System.out.println("   -xmlBlaster/jmx/exitOnMemoryThreshold If true xmlBlaster stops if the memoryThresholdFactor is reached (JDK >= 1.5) [false]");
643       System.out.println("----------------------------------------------------------");
644       System.out.println("Example:");
645       System.out.println("   java org.xmlBlaster.Main -cluster false");
646       System.out.println("   java org.xmlBlaster.Main -cluster.node.id heron");
647       System.out.println("   java org.xmlBlaster.Main -propertyFile somewhere/xmlBlaster.properties -pluginsFile somewhere/plugins.xml");
648       System.out.println("   java org.xmlBlaster.Main -bootstrapPort 3412");
649       System.out.println("   java org.xmlBlaster.Main -plugin/ior/iorFile /tmp/XmlBlaster_Ref.ior");
650       System.out.println("   java org.xmlBlaster.Main -logging/org.xmlBlaster.engine FINE");
651       System.out.println("   java org.xmlBlaster.Main -logging/org.xmlBlaster.util.protocol.RequestReplyExecutor FINEST   (dumps SOCKET messages)");
652       System.out.println("   java org.xmlBlaster.Main -plugin/xmlrpc/hostname 102.24.64.60 -plugin/xmlrpc/port 8081");
653       System.out.println("   java -Dcom.sun.management.jmxremote org.xmlBlaster.Main");
654       System.out.println("   java -Djava.util.logging.config.file=config/logging.properties org.xmlBlaster.Main");
655       System.out.println("   java org.xmlBlaster.Main -?");
656       System.out.println("See xmlBlaster.properties for more options");
657       System.out.println("");
658    }
659 
660 
661    /**
662     *  Invoke: java org.xmlBlaster.Main
663     */
664    public static void main( String[] args )
665    {
666       new Main(args);
667    }
668 }


syntax highlighted by Code2HTML, v. 0.9.1