Coverage Report - org.mule.MuleServer
 
Classes in this File Line Coverage Branch Coverage Complexity
MuleServer
0%
0/144
0%
0/42
0
MuleServer$MuleShutdownHook
0%
0/6
N/A
0
 
 1  
 /*
 2  
  * $Id: MuleServer.java 19191 2010-08-25 21:05:23Z tcarlson $
 3  
  * --------------------------------------------------------------------------------------
 4  
  * Copyright (c) MuleSoft, Inc.  All rights reserved.  http://www.mulesoft.com
 5  
  *
 6  
  * The software in this package is published under the terms of the CPAL v1.0
 7  
  * license, a copy of which has been included with this distribution in the
 8  
  * LICENSE.txt file.
 9  
  */
 10  
 
 11  
 package org.mule;
 12  
 
 13  
 import org.mule.api.DefaultMuleException;
 14  
 import org.mule.api.MuleContext;
 15  
 import org.mule.api.MuleException;
 16  
 import org.mule.api.config.ConfigurationBuilder;
 17  
 import org.mule.api.config.ConfigurationException;
 18  
 import org.mule.config.ExceptionHelper;
 19  
 import org.mule.config.StartupContext;
 20  
 import org.mule.config.builders.SimpleConfigurationBuilder;
 21  
 import org.mule.config.i18n.CoreMessages;
 22  
 import org.mule.config.i18n.Message;
 23  
 import org.mule.context.DefaultMuleContextBuilder;
 24  
 import org.mule.context.DefaultMuleContextFactory;
 25  
 import org.mule.util.ClassUtils;
 26  
 import org.mule.util.IOUtils;
 27  
 import org.mule.util.MuleUrlStreamHandlerFactory;
 28  
 import org.mule.util.PropertiesUtils;
 29  
 import org.mule.util.StringMessageUtils;
 30  
 import org.mule.util.SystemUtils;
 31  
 
 32  
 import java.net.URL;
 33  
 import java.util.ArrayList;
 34  
 import java.util.List;
 35  
 import java.util.Map;
 36  
 import java.util.Properties;
 37  
 
 38  
 import org.apache.commons.logging.Log;
 39  
 import org.apache.commons.logging.LogFactory;
 40  
 
 41  
 /**
 42  
  * <code>MuleServer</code> is a simple application that represents a local Mule
 43  
  * Server daemon. It is initialised with a mule-config.xml file.
 44  
  */
 45  
 public class MuleServer implements Runnable
 46  
 {
 47  0
     public static final String CLI_OPTIONS[][] = {
 48  
         {"builder", "true", "Configuration Builder Type"},
 49  
         {"config", "true", "Configuration File"},
 50  
         {"idle", "false", "Whether to run in idle (unconfigured) mode"},
 51  
         {"main", "true", "Main Class"},
 52  
         {"mode", "true", "Run Mode"},
 53  
         {"props", "true", "Startup Properties"},
 54  
         {"production", "false", "Production Mode"},
 55  
         {"debug", "false", "Configure Mule for JPDA remote debugging."}
 56  
     };
 57  
 
 58  
     /**
 59  
      * Don't use a class object so the core doesn't depend on mule-module-spring-config.
 60  
      */
 61  
     protected static final String CLASSNAME_DEFAULT_CONFIG_BUILDER = "org.mule.config.builders.AutoConfigurationBuilder";
 62  
 
 63  
     /**
 64  
      * This builder sets up the configuration for an idle Mule node - a node that
 65  
      * doesn't do anything initially but is fed configuration during runtime
 66  
      */
 67  
     protected static final String CLASSNAME_DEFAULT_IDLE_CONFIG_BUILDER = "org.mule.config.builders.MuleIdleConfigurationBuilder";
 68  
 
 69  
     /**
 70  
      * Required to support the '-config spring' shortcut. Don't use a class object so
 71  
      * the core doesn't depend on mule-module-spring.
 72  
      * for Mule 2.x
 73  
      */
 74  
     protected static final String CLASSNAME_SPRING_CONFIG_BUILDER = "org.mule.config.spring.SpringXmlConfigurationBuilder";
 75  
 
 76  
     /**
 77  
      * If the annotations module is on the classpath, also enable annotations config builder
 78  
      */
 79  
     public static final String CLASSNAME_ANNOTATIONS_CONFIG_BUILDER = "org.mule.config.AnnotationsConfigurationBuilder";
 80  
 
 81  
     /**
 82  
      * logger used by this class
 83  
      */
 84  0
     private static final Log logger = LogFactory.getLog(MuleServer.class);
 85  
 
 86  
     public static final String DEFAULT_CONFIGURATION = "mule-config.xml";
 87  
 
 88  
     /**
 89  
      * one or more configuration urls or filenames separated by commas
 90  
      */
 91  0
     private String configurationResources = null;
 92  
 
 93  
     /**
 94  
      * A FQN of the #configBuilder class, required in case MuleServer is
 95  
      * reinitialised.
 96  
      */
 97  0
     private static String configBuilderClassName = null;
 98  
 
 99  
     /**
 100  
      * A properties file to be read at startup. This can be useful for setting
 101  
      * properties which depend on the run-time environment (dev, test, production).
 102  
      */
 103  0
     private static String startupPropertiesFile = null;
 104  
 
 105  
     /**
 106  
      * The Runtime shutdown thread used to dispose this server
 107  
      */
 108  
     private static MuleShutdownHook muleShutdownHook;
 109  
 
 110  
     /**
 111  
      * The MuleContext should contain anything which does not belong in the Registry.
 112  
      * There is one MuleContext per Mule instance. Assuming it has been created, a
 113  
      * handle to the local MuleContext can be obtained from anywhere by calling
 114  
      * MuleServer.getMuleContext()
 115  
      */
 116  0
     protected static MuleContext muleContext = null;
 117  
 
 118  
     /**
 119  
      * Application entry point.
 120  
      *
 121  
      * @param args command-line args
 122  
      * @throws Exception if there is an exception creating the MuleServer
 123  
      */
 124  
     public static void main(String[] args) throws Exception
 125  
     {
 126  0
         MuleServer server = new MuleServer(args);
 127  0
         server.start(false, true);
 128  
 
 129  0
     }
 130  
 
 131  
     public MuleServer()
 132  0
     {
 133  0
         init(new String[]{});
 134  0
     }
 135  
 
 136  
     public MuleServer(String configResources)
 137  0
     {
 138  
         // setConfigurationResources(configResources);
 139  0
         init(new String[]{"-config", configResources});
 140  0
     }
 141  
 
 142  
     /**
 143  
      * Configure the server with command-line arguments.
 144  
      * @param args Command line args passed in from the {@link #main(String[])} method
 145  
      * @throws IllegalArgumentException if an argument is passed in that is not recognised by the Mule Server
 146  
      */
 147  
     public MuleServer(String[] args) throws IllegalArgumentException
 148  0
     {
 149  0
         init(args);
 150  0
     }
 151  
 
 152  
     protected void init(String[] args) throws IllegalArgumentException
 153  
     {
 154  
         Map<String, Object> commandlineOptions;
 155  
 
 156  
         try
 157  
         {
 158  0
             commandlineOptions = SystemUtils.getCommandLineOptions(args, CLI_OPTIONS);
 159  
         }
 160  0
         catch (DefaultMuleException me)
 161  
         {
 162  0
             throw new IllegalArgumentException(me.toString());
 163  0
         }
 164  
 
 165  
         // set our own UrlStreamHandlerFactory to become more independent of system
 166  
         // properties
 167  0
         MuleUrlStreamHandlerFactory.installUrlStreamHandlerFactory();
 168  
 
 169  0
         String config = (String) commandlineOptions.get("config");
 170  
         // Try default if no config file was given.
 171  0
         if (config == null && !commandlineOptions.containsKey("idle"))
 172  
         {
 173  0
             logger.warn("A configuration file was not set, using default: " + DEFAULT_CONFIGURATION);
 174  
             // try to load the config as a file as well
 175  0
             URL configUrl = IOUtils.getResourceAsUrl(DEFAULT_CONFIGURATION, MuleServer.class, true, false);
 176  0
             if (configUrl != null)
 177  
             {
 178  0
                 config = configUrl.toExternalForm();
 179  
             }
 180  
             else
 181  
             {
 182  0
                 System.out.println(CoreMessages.configNotFoundUsage());
 183  0
                 System.exit(-1);
 184  
             }
 185  
         }
 186  
 
 187  0
         if (config != null)
 188  
         {
 189  0
             setConfigurationResources(config);
 190  
         }
 191  
 
 192  
         // Configuration builder
 193  0
         String cfgBuilderClassName = (String) commandlineOptions.get("builder");
 194  
 
 195  0
         if (commandlineOptions.containsKey("idle"))
 196  
         {
 197  0
             setConfigurationResources("IDLE");
 198  0
             cfgBuilderClassName = CLASSNAME_DEFAULT_IDLE_CONFIG_BUILDER;
 199  
         }
 200  
 
 201  
         // Configuration builder
 202  0
         if (cfgBuilderClassName != null)
 203  
         {
 204  
             try
 205  
             {
 206  
                 // Provide a shortcut for Spring: "-builder spring"
 207  0
                 if (cfgBuilderClassName.equalsIgnoreCase("spring"))
 208  
                 {
 209  0
                     cfgBuilderClassName = CLASSNAME_SPRING_CONFIG_BUILDER;
 210  
                 }
 211  0
                 setConfigBuilderClassName(cfgBuilderClassName);
 212  
             }
 213  0
             catch (Exception e)
 214  
             {
 215  0
                 logger.fatal(e);
 216  0
                 final Message message = CoreMessages.failedToLoad("Builder: " + cfgBuilderClassName);
 217  0
                 System.err.println(StringMessageUtils.getBoilerPlate("FATAL: " + message.toString()));
 218  0
                 System.exit(1);
 219  0
             }
 220  
         }
 221  
 
 222  
         // Startup properties
 223  0
         String propertiesFile = (String) commandlineOptions.get("props");
 224  0
         if (propertiesFile != null)
 225  
         {
 226  0
             setStartupPropertiesFile(propertiesFile);
 227  
         }
 228  
 
 229  0
         StartupContext.get().setStartupOptions(commandlineOptions);
 230  0
     }
 231  
 
 232  
     /**
 233  
      * Start the mule server
 234  
      *
 235  
      * @param ownThread determines if the server will run in its own daemon thread or
 236  
      *                  the current calling thread
 237  
      * @param registerShutdownHook whether to register the default Mule Server shutdown hock.  this will shut down mule cleanly if
 238  
      * the JVM is shutdown.  The only reason not to register this hook is to override it with a custom version
 239  
      */
 240  
     public void start(boolean ownThread, boolean registerShutdownHook)
 241  
     {
 242  0
         if (registerShutdownHook)
 243  
         {
 244  0
             registerShutdownHook();
 245  
         }
 246  0
         if (ownThread)
 247  
         {
 248  0
             Thread serverThread = new Thread(this, "MuleServer");
 249  0
             serverThread.setDaemon(true);
 250  0
             serverThread.start();
 251  0
         }
 252  
         else
 253  
         {
 254  0
             run();
 255  
         }
 256  0
     }
 257  
 
 258  
     /**
 259  
      * Overloaded the [main] thread run method. This calls initialise and shuts down
 260  
      * if an exception occurs
 261  
      */
 262  
     public void run()
 263  
     {
 264  
         try
 265  
         {
 266  0
             logger.info("Mule Server initializing...");
 267  0
             initialize();
 268  0
             logger.info("Mule Server starting...");
 269  0
             muleContext.start();
 270  
         }
 271  0
         catch (Throwable e)
 272  
         {
 273  0
             shutdown(e);
 274  0
         }
 275  0
     }
 276  
 
 277  
     /**
 278  
      * Sets the configuration builder to use for this server. Note that if a builder
 279  
      * is not set and the server's start method is called the default is an instance
 280  
      * of <code>SpringXmlConfigurationBuilder</code>.
 281  
      *
 282  
      * @param builderClassName the configuration builder FQN to use
 283  
      * @throws ClassNotFoundException if the class with the given name can not be
 284  
      *                                loaded
 285  
      */
 286  
     public static void setConfigBuilderClassName(String builderClassName) throws ClassNotFoundException
 287  
     {
 288  0
         if (builderClassName != null)
 289  
         {
 290  0
             Class cls = ClassUtils.loadClass(builderClassName, MuleServer.class);
 291  0
             if (ConfigurationBuilder.class.isAssignableFrom(cls))
 292  
             {
 293  0
                 MuleServer.configBuilderClassName = builderClassName;
 294  
             }
 295  
             else
 296  
             {
 297  0
                 throw new IllegalArgumentException("Not a usable ConfigurationBuilder class: "
 298  
                         + builderClassName);
 299  
             }
 300  0
         }
 301  
         else
 302  
         {
 303  0
             MuleServer.configBuilderClassName = null;
 304  
         }
 305  0
     }
 306  
 
 307  
     /**
 308  
      * Returns the class name of the configuration builder used to create this
 309  
      * MuleServer.
 310  
      *
 311  
      * @return FQN of the current config builder
 312  
      */
 313  
     public static String getConfigBuilderClassName()
 314  
     {
 315  0
         if (configBuilderClassName != null)
 316  
         {
 317  0
             return configBuilderClassName;
 318  
         }
 319  
         else
 320  
         {
 321  0
             return CLASSNAME_DEFAULT_CONFIG_BUILDER;
 322  
         }
 323  
     }
 324  
 
 325  
     /**
 326  
      * Initializes this daemon. Derived classes could add some extra behaviour if
 327  
      * they wish.
 328  
      *
 329  
      * @throws Exception if failed to initialize
 330  
      */
 331  
     public void initialize() throws Exception
 332  
     {
 333  0
         if (configurationResources == null)
 334  
         {
 335  0
             logger.warn("A configuration file was not set, using default: " + DEFAULT_CONFIGURATION);
 336  0
             configurationResources = DEFAULT_CONFIGURATION;
 337  
         }
 338  
 
 339  
         ConfigurationBuilder cfgBuilder;
 340  
 
 341  
         try
 342  
         {
 343  
             // create a new ConfigurationBuilder that is disposed afterwards
 344  0
             cfgBuilder = (ConfigurationBuilder) ClassUtils.instanciateClass(getConfigBuilderClassName(),
 345  
                     new Object[]{configurationResources}, MuleServer.class);
 346  
         }
 347  0
         catch (Exception e)
 348  
         {
 349  0
             throw new ConfigurationException(CoreMessages.failedToLoad(getConfigBuilderClassName()), e);
 350  0
         }
 351  
 
 352  0
         if (!cfgBuilder.isConfigured())
 353  
         {
 354  0
             List<ConfigurationBuilder> builders = new ArrayList<ConfigurationBuilder>(2);
 355  
 
 356  
             // If the annotations module is on the classpath, add the annotations config builder to the list
 357  
             // This will enable annotations config for this instance
 358  
             //We need to add this builder before spring so that we can use Mule annotations in Spring
 359  0
             if (ClassUtils.isClassOnPath(CLASSNAME_ANNOTATIONS_CONFIG_BUILDER, getClass()))
 360  
             {
 361  0
                 Object configBuilder = ClassUtils.instanciateClass(
 362  
                     CLASSNAME_ANNOTATIONS_CONFIG_BUILDER, ClassUtils.NO_ARGS, getClass());
 363  0
                 builders.add((ConfigurationBuilder) configBuilder);
 364  
             }
 365  
 
 366  
 
 367  0
             Properties startupProperties = null;
 368  0
             if (getStartupPropertiesFile() != null)
 369  
             {
 370  0
                 startupProperties = PropertiesUtils.loadProperties(getStartupPropertiesFile(), getClass());
 371  
             }
 372  0
             builders.add(new SimpleConfigurationBuilder(startupProperties));
 373  
 
 374  0
             builders.add(cfgBuilder);
 375  
 
 376  0
             DefaultMuleContextFactory muleContextFactory = new DefaultMuleContextFactory();
 377  0
             muleContext = muleContextFactory.createMuleContext(builders, new DefaultMuleContextBuilder());
 378  
         }
 379  0
     }
 380  
 
 381  
     /**
 382  
      * Will shut down the server displaying the cause and time of the shutdown
 383  
      *
 384  
      * @param e the exception that caused the shutdown
 385  
      */
 386  
     public void shutdown(Throwable e)
 387  
     {
 388  0
         doShutdown();
 389  0
         unregisterShutdownHook();
 390  
 
 391  0
         Message msg = CoreMessages.fatalErrorWhileRunning();
 392  0
         MuleException muleException = ExceptionHelper.getRootMuleException(e);
 393  0
         int exitCode = 1;
 394  0
         if (muleException != null)
 395  
         {
 396  0
             logger.fatal(muleException.getDetailedMessage());
 397  0
             exitCode = muleException.getExceptionCode();
 398  
         }
 399  
         else
 400  
         {
 401  0
             logger.fatal(msg.toString() + " " + e.getMessage(), e);
 402  
         }
 403  0
         List<String> msgs = new ArrayList<String>();
 404  0
         msgs.add(msg.getMessage());
 405  0
         Throwable root = ExceptionHelper.getRootException(e);
 406  0
         msgs.add(root.getMessage() + " (" + root.getClass().getName() + ")");
 407  0
         msgs.add(" ");
 408  0
         msgs.add(CoreMessages.fatalErrorInShutdown().getMessage());
 409  0
         String shutdownMessage = StringMessageUtils.getBoilerPlate(msgs, '*', 80);
 410  0
         logger.fatal(shutdownMessage);
 411  
 
 412  0
         System.exit(exitCode);
 413  
 
 414  
 
 415  0
     }
 416  
 
 417  
     /**
 418  
      * shutdown the server. This just displays the time the server shut down
 419  
      */
 420  
     public void shutdown()
 421  
     {
 422  0
         logger.info("Mule server shutting down due to normal shutdown request");
 423  
 
 424  0
         unregisterShutdownHook();
 425  0
         doShutdown();
 426  0
         System.exit(0);
 427  0
     }
 428  
 
 429  
     protected void doShutdown()
 430  
     {
 431  0
         if (muleContext != null)
 432  
         {
 433  0
             muleContext.dispose();
 434  0
             muleContext = null;
 435  
         }
 436  0
     }
 437  
 
 438  
     public Log getLogger()
 439  
     {
 440  0
         return logger;
 441  
     }
 442  
 
 443  
     public void registerShutdownHook()
 444  
     {
 445  0
         if (muleShutdownHook == null)
 446  
         {
 447  0
             muleShutdownHook = new MuleShutdownHook();
 448  
         }
 449  
         else
 450  
         {
 451  0
             Runtime.getRuntime().removeShutdownHook(muleShutdownHook);
 452  
         }
 453  0
         Runtime.getRuntime().addShutdownHook(muleShutdownHook);
 454  0
     }
 455  
 
 456  
     public void unregisterShutdownHook()
 457  
     {
 458  0
         if (muleShutdownHook != null)
 459  
         {
 460  0
             Runtime.getRuntime().removeShutdownHook(muleShutdownHook);
 461  
         }
 462  0
     }
 463  
 
 464  
     // /////////////////////////////////////////////////////////////////
 465  
     // Getters and setters
 466  
     // /////////////////////////////////////////////////////////////////
 467  
 
 468  
     /**
 469  
      * Getter for property messengerURL.
 470  
      *
 471  
      * @return Value of property messengerURL.
 472  
      */
 473  
     public String getConfigurationResources()
 474  
     {
 475  0
         return configurationResources;
 476  
     }
 477  
 
 478  
     /**
 479  
      * Setter for property configurationResources.
 480  
      *
 481  
      * @param configurationResources New value of property configurationResources.
 482  
      */
 483  
     public void setConfigurationResources(String configurationResources)
 484  
     {
 485  0
         this.configurationResources = configurationResources;
 486  0
     }
 487  
 
 488  
     public static String getStartupPropertiesFile()
 489  
     {
 490  0
         return startupPropertiesFile;
 491  
     }
 492  
 
 493  
     public static void setStartupPropertiesFile(String startupPropertiesFile)
 494  
     {
 495  0
         MuleServer.startupPropertiesFile = startupPropertiesFile;
 496  0
     }
 497  
 
 498  
     public MuleContext getMuleContext()
 499  
     {
 500  0
         return muleContext;
 501  
     }
 502  
 
 503  
     /**
 504  
      * This class is installed only for MuleServer running as commandline app. A
 505  
      * clean Mule shutdown can be achieved by disposing the
 506  
      * {@link org.mule.DefaultMuleContext}.
 507  
      */
 508  
     private class MuleShutdownHook extends Thread
 509  
     {
 510  
         public MuleShutdownHook()
 511  0
         {
 512  0
             super();
 513  0
         }
 514  
         
 515  
         @Override
 516  
         public void run()
 517  
         {
 518  0
             doShutdown();
 519  0
             System.exit(0);
 520  0
         }
 521  
     }
 522  
 }