View Javadoc

1   /*
2    * $Id: MuleServer.java 10659 2008-02-01 10:05:39Z dirk.olmes $
3    * --------------------------------------------------------------------------------------
4    * Copyright (c) MuleSource, Inc.  All rights reserved.  http://www.mulesource.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.config.ConfigurationBuilder;
14  import org.mule.config.ExceptionHelper;
15  import org.mule.config.i18n.CoreMessages;
16  import org.mule.config.i18n.Message;
17  import org.mule.umo.UMOException;
18  import org.mule.util.ClassUtils;
19  import org.mule.util.IOUtils;
20  import org.mule.util.MuleUrlStreamHandlerFactory;
21  import org.mule.util.StringMessageUtils;
22  import org.mule.util.SystemUtils;
23  
24  import java.net.URL;
25  import java.util.ArrayList;
26  import java.util.Collections;
27  import java.util.Date;
28  import java.util.List;
29  import java.util.Map;
30  
31  import org.apache.commons.logging.Log;
32  import org.apache.commons.logging.LogFactory;
33  
34  /**
35   * <code>MuleServer</code> is a simple application that represents a local Mule
36   * Server daemon. It is initialised with a mule-config.xml file.
37   */
38  public class MuleServer implements Runnable
39  {
40  
41      public static final String CLI_OPTIONS[][] = {
42              {"builder", "true", "Configuration Builder Type"},
43              {"config", "true", "Configuration File"},
44              {"main", "true", "Main Class"},
45              {"mode", "true", "Run Mode"},
46              {"version", "false", "Show product and version information"},
47              {"debug", "false", "Configure Mule for JPDA remote debugging."},
48              {"props", "true", "Startup Properties"}
49      };
50  
51      /**
52       * Don't use a class object so the core doesn't depend on mule-module-builders.
53       */
54      protected static final String CLASSNAME_DEFAULT_CONFIG_BUILDER = "org.mule.config.builders.MuleXmlConfigurationBuilder";
55  
56      /**
57       * Required to support the '-config spring' shortcut. Don't use a class object so
58       * the core doesn't depend on mule-module-spring. TODO this may not be a problem
59       * for Mule 2.x
60       */
61      protected static final String CLASSNAME_SPRING_CONFIG_BUILDER = "org.mule.extras.spring.config.SpringConfigurationBuilder";
62  
63      /**
64       * logger used by this class
65       */
66      private static Log logger = LogFactory.getLog(MuleServer.class);
67  
68      public static final String DEFAULT_CONFIGURATION = "mule-config.xml";
69  
70      /**
71       * the message to display when the server shuts down
72       */
73      private static String shutdownMessage = null;
74  
75      /**
76       * one or more configuration urls or filenames separated by commas
77       */
78      private String configurationResources = null;
79  
80      /**
81       * A FQN of the #configBuilder class, required in case MuleServer is
82       * reinitialised.
83       */
84      private static String configBuilderClassName = null;
85  
86      /**
87       * A properties file to be read at startup. This can be useful for setting
88       * properties which depend on the run-time environment (dev, test, production).
89       */
90      private static String startupPropertiesFile = null;
91  
92      /**
93       * Application entry point.
94       *
95       * @param args command-line args
96       */
97      public static void main(String[] args)
98      {
99  
100         Map options = Collections.EMPTY_MAP;
101 
102         try
103         {
104             options = SystemUtils.getCommandLineOptions(args, CLI_OPTIONS);
105         }
106         catch (MuleException me)
107         {
108             System.err.println(me.toString());
109             System.exit(1);
110         }
111 
112         // print version string
113         if (options.containsKey("version"))
114         {
115             System.out.println(CoreMessages.productInformation().toString());
116             return;
117         }
118 
119         MuleServer server = new MuleServer();
120 
121         // set our own UrlStreamHandlerFactory to become more independent of system properties
122         MuleUrlStreamHandlerFactory.installUrlStreamHandlerFactory();
123 
124         String config = (String) options.get("config");
125         // Try default if no config file was given.
126         if (config == null)
127         {
128             logger.warn("A configuration file was not set, using default: " + DEFAULT_CONFIGURATION);
129             // try to load the config as a file as well
130             URL configUrl = IOUtils.getResourceAsUrl(DEFAULT_CONFIGURATION, MuleServer.class, true);
131             if (configUrl != null)
132             {
133                 config = configUrl.toExternalForm();
134             }
135         }
136 
137         if (config != null)
138         {
139             server.setConfigurationResources(config);
140         }
141         else
142         {
143             Message message = CoreMessages.configNotFoundUsage();
144             System.err.println(message.toString());
145             System.exit(1);
146         }
147 
148         // Configuration builder
149         String cfgBuilderClassName = (String) options.get("builder");
150         if (cfgBuilderClassName != null)
151         {
152             try
153             {
154                 // Provide a shortcut for Spring: "-builder spring"
155                 if (cfgBuilderClassName.equalsIgnoreCase("spring"))
156                 {
157                     cfgBuilderClassName = CLASSNAME_SPRING_CONFIG_BUILDER;
158                 }
159                 setConfigBuilderClassName(cfgBuilderClassName);
160             }
161             catch (Exception e)
162             {
163                 logger.fatal(e);
164                 final Message message = CoreMessages.failedToLoad("Builder: " + cfgBuilderClassName);
165                 System.err.println(StringMessageUtils.getBoilerPlate("FATAL: " + message.toString()));
166                 System.exit(1);
167             }
168         }
169 
170         // Startup properties
171         String propertiesFile = (String) options.get("props");
172         if (propertiesFile != null)
173         {
174             setStartupPropertiesFile(propertiesFile);
175         }
176 
177         server.start(false);
178     }
179 
180     public MuleServer()
181     {
182         super();
183     }
184 
185     public MuleServer(String configResources)
186     {
187         this();
188         setConfigurationResources(configResources);
189     }
190 
191     /**
192      * Start the mule server
193      *
194      * @param ownThread determines if the server will run in its own daemon thread or
195      *                  the current calling thread
196      */
197     public void start(boolean ownThread)
198     {
199         if (ownThread)
200         {
201             Thread serverThread = new Thread(this, "MuleServer");
202             serverThread.setDaemon(true);
203             serverThread.start();
204         }
205         else
206         {
207             run();
208         }
209     }
210 
211     /**
212      * Overloaded the [main] thread run method. This calls initialise and shuts down
213      * if an exception occurs
214      */
215     public void run()
216     {
217         try
218         {
219             initialize();
220         }
221         catch (Throwable e)
222         {
223             shutdown(e);
224         }
225     }
226 
227     /**
228      * Sets the configuration builder to use for this server. Note that if a builder
229      * is not set and the server's start method is called the default is an instance
230      * of <code>MuleXmlConfigurationBuilder</code>.
231      *
232      * @param builderClassName the configuration builder FQN to use
233      * @throws ClassNotFoundException if the class with the given name can not be
234      *                                loaded
235      */
236     public static void setConfigBuilderClassName(String builderClassName) throws ClassNotFoundException
237     {
238         if (builderClassName != null)
239         {
240             Class cls = ClassUtils.loadClass(builderClassName, MuleServer.class);
241             if (ConfigurationBuilder.class.isAssignableFrom(cls))
242             {
243                 MuleServer.configBuilderClassName = builderClassName;
244             }
245             else
246             {
247                 throw new IllegalArgumentException("Not a usable ConfigurationBuilder class: "
248                                                    + builderClassName);
249             }
250         }
251         else
252         {
253             MuleServer.configBuilderClassName = null;
254         }
255     }
256 
257     /**
258      * Returns the class name of the configuration builder used to create this
259      * MuleServer.
260      *
261      * @return FQN of the current config builder
262      */
263     public static String getConfigBuilderClassName()
264     {
265         if (configBuilderClassName != null)
266         {
267             return configBuilderClassName;
268         }
269         else
270         {
271             return CLASSNAME_DEFAULT_CONFIG_BUILDER;
272         }
273     }
274 
275     /**
276      * Initializes this daemon. Derived classes could add some extra behaviour if
277      * they wish.
278      *
279      * @throws Exception if failed to initialize
280      */
281     protected void initialize() throws Exception
282     {
283         logger.info("Mule Server starting...");
284 
285         Runtime.getRuntime().addShutdownHook(new ShutdownThread());
286 
287         // create a new ConfigurationBuilder that is disposed afterwards
288         Class cfgBuilderClass = ClassUtils.loadClass(getConfigBuilderClassName(), MuleServer.class);
289         ConfigurationBuilder cfgBuilder = (ConfigurationBuilder) cfgBuilderClass.newInstance();
290 
291         if (!cfgBuilder.isConfigured())
292         {
293             if (configurationResources == null)
294             {
295                 logger.warn("A configuration file was not set, using default: " + DEFAULT_CONFIGURATION);
296                 configurationResources = DEFAULT_CONFIGURATION;
297             }
298             cfgBuilder.configure(configurationResources, getStartupPropertiesFile());
299         }
300         logger.info("Mule Server initialized.");
301     }
302 
303     /**
304      * Will shut down the server displaying the cause and time of the shutdown
305      *
306      * @param e the exception that caused the shutdown
307      */
308     public void shutdown(Throwable e)
309     {
310         Message msg = CoreMessages.fatalErrorWhileRunning();
311         UMOException muleException = ExceptionHelper.getRootMuleException(e);
312         if (muleException != null)
313         {
314             logger.fatal(muleException.getDetailedMessage());
315         }
316         else
317         {
318             logger.fatal(msg.toString() + " " + e.getMessage(), e);
319         }
320         List msgs = new ArrayList();
321         msgs.add(msg.getMessage());
322         Throwable root = ExceptionHelper.getRootException(e);
323         msgs.add(root.getMessage() + " (" + root.getClass().getName() + ")");
324         msgs.add(" ");
325         msgs.add(CoreMessages.fatalErrorInShutdown());
326         msgs.add(CoreMessages.serverStartedAt(MuleManager.getInstance().getStartDate()));
327         msgs.add(CoreMessages.serverShutdownAt(new Date()));
328 
329         shutdownMessage = StringMessageUtils.getBoilerPlate(msgs, '*', 80);
330         logger.fatal(shutdownMessage);
331 
332         // make sure that Mule is shutdown correctly.
333         MuleManager.getInstance().dispose();
334         System.exit(0);
335     }
336 
337     /**
338      * shutdown the server. This just displays the time the server shut down
339      */
340     public void shutdown()
341     {
342         logger.info("Mule server shutting dow due to normal shutdown request");
343         List msgs = new ArrayList();
344         msgs.add(CoreMessages.normalShutdown());
345         msgs.add(CoreMessages.serverStartedAt(MuleManager.getInstance().getStartDate()).getMessage());
346         msgs.add(CoreMessages.serverShutdownAt(new Date()).getMessage());
347         shutdownMessage = StringMessageUtils.getBoilerPlate(msgs, '*', 80);
348         logger.info(shutdownMessage);
349 
350         // make sure that Mule is shutdown correctly.
351         MuleManager.getInstance().dispose();
352         System.exit(0);
353 
354     }
355 
356     // /////////////////////////////////////////////////////////////////
357     // Getters and setters
358     // /////////////////////////////////////////////////////////////////
359 
360     /**
361      * Getter for property messengerURL.
362      *
363      * @return Value of property messengerURL.
364      */
365     public String getConfigurationResources()
366     {
367         return configurationResources;
368     }
369 
370     /**
371      * Setter for property messengerURL.
372      *
373      * @param configurationResources New value of property configurationResources.
374      */
375     public void setConfigurationResources(String configurationResources)
376     {
377         this.configurationResources = configurationResources;
378     }
379 
380     public static String getStartupPropertiesFile()
381     {
382         return startupPropertiesFile;
383     }
384 
385     public static void setStartupPropertiesFile(String startupPropertiesFile)
386     {
387         MuleServer.startupPropertiesFile = startupPropertiesFile;
388     }
389 
390     /**
391      * This class is installed only for MuleServer running as commandline app. A clean Mule
392      * shutdown can be achieved by disposing the {@link MuleManager}.
393      */
394     private class ShutdownThread extends Thread
395     {
396         public void run()
397         {
398             if (MuleManager.isInstanciated())
399             {
400                 MuleManager.getInstance().dispose();
401             }
402         }
403     }
404 }