View Javadoc

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