View Javadoc

1   /*
2    * $Id: MuleContainer.java 22647 2011-08-10 22:08:13Z mike.schilling $
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.module.launcher;
12  
13  import org.mule.MuleCoreExtension;
14  import org.mule.api.DefaultMuleException;
15  import org.mule.api.MuleException;
16  import org.mule.config.ExceptionHelper;
17  import org.mule.config.StartupContext;
18  import org.mule.config.i18n.CoreMessages;
19  import org.mule.config.i18n.Message;
20  import org.mule.module.launcher.log4j.ApplicationAwareRepositorySelector;
21  import org.mule.util.ClassUtils;
22  import org.mule.util.MuleUrlStreamHandlerFactory;
23  import org.mule.util.StringMessageUtils;
24  import org.mule.util.SystemUtils;
25  
26  import java.net.URL;
27  import java.util.ArrayList;
28  import java.util.Enumeration;
29  import java.util.HashMap;
30  import java.util.LinkedList;
31  import java.util.List;
32  import java.util.Map;
33  import java.util.Properties;
34  
35  import org.apache.commons.logging.Log;
36  import org.apache.commons.logging.LogFactory;
37  import org.apache.log4j.LogManager;
38  
39  /**
40   *
41   */
42  public class MuleContainer
43  {
44      public static final String CLI_OPTIONS[][] = {
45          {"builder", "true", "Configuration Builder Type"},
46          {"config", "true", "Configuration File"},
47          {"idle", "false", "Whether to run in idle (unconfigured) mode"},
48          {"main", "true", "Main Class"},
49          {"mode", "true", "Run Mode"},
50          {"props", "true", "Startup Properties"},
51          {"production", "false", "Production Mode"},
52          {"debug", "false", "Configure Mule for JPDA remote debugging."},
53          {"app", "true", "Application to start"}
54      };
55  
56      public static final String SERVICE_PATH = "META-INF/services/org/mule/config/";
57  
58      public static final String CORE_EXTENSION_PROPERTIES = "core-extensions.properties";
59  
60      /**
61       * logger used by this class
62       */
63      private static Log logger;
64  
65      /**
66       * A properties file to be read at startup. This can be useful for setting
67       * properties which depend on the run-time environment (dev, test, production).
68       */
69      private static String startupPropertiesFile = null;
70  
71      /**
72       * The Runtime shutdown thread used to undeploy this server
73       */
74      private static MuleShutdownHook muleShutdownHook;
75  
76      protected DeploymentService deploymentService;
77  
78      protected Map<Class<? extends MuleCoreExtension>, MuleCoreExtension> coreExtensions = new HashMap<Class<? extends MuleCoreExtension>, MuleCoreExtension>();
79  
80      static
81      {
82          if (System.getProperty("mule.simpleLog") == null)
83          {
84              // TODO save this guard ref for later
85              LogManager.setRepositorySelector(new ApplicationAwareRepositorySelector(), new Object());
86          }
87          logger = LogFactory.getLog(MuleContainer.class);
88      }
89  
90      /**
91       * Application entry point.
92       *
93       * @param args command-line args
94       */
95      public static void main(String[] args) throws Exception
96      {
97          MuleContainer container = new MuleContainer(args);
98          container.start(true);
99      }
100 
101     public MuleContainer()
102     {
103         init(new String[0]);
104     }
105 
106     /**
107      * Configure the server with command-line arguments.
108      */
109     public MuleContainer(String[] args) throws IllegalArgumentException
110     {                                                                                                                                                           
111         init(args);
112     }
113 
114     protected void init(String[] args) throws IllegalArgumentException
115     {
116         Map<String, Object> commandlineOptions;
117 
118         try
119         {
120             commandlineOptions = SystemUtils.getCommandLineOptions(args, CLI_OPTIONS);
121         }
122         catch (DefaultMuleException me)
123         {
124             throw new IllegalArgumentException(me.toString());
125         }
126 
127         // set our own UrlStreamHandlerFactory to become more independent of system
128         // properties
129         MuleUrlStreamHandlerFactory.installUrlStreamHandlerFactory();
130 
131         // Startup properties
132         String propertiesFile = (String) commandlineOptions.get("props");
133         if (propertiesFile != null)
134         {
135             setStartupPropertiesFile(propertiesFile);
136         }
137         StartupContext.get().setStartupOptions(commandlineOptions);
138     }
139 
140     public void start(boolean registerShutdownHook)
141     {
142         if (registerShutdownHook)
143         {
144             registerShutdownHook();
145         }
146 
147         final MuleContainerStartupSplashScreen splashScreen = new MuleContainerStartupSplashScreen();
148         splashScreen.doBody();
149         logger.info(splashScreen.toString());
150 
151         try
152         {
153             loadCoreExtensions();
154 
155             // TODO pluggable deployer
156             deploymentService = new DeploymentService(coreExtensions);
157             deploymentService.start();
158         }
159         catch (Throwable e)
160         {
161             shutdown(e);
162         }
163     }
164 
165     /**
166      * Load all core extensions defined in the classpath
167      */
168     private void loadCoreExtensions() throws MuleException
169     {
170         Enumeration<?> e = ClassUtils.getResources(SERVICE_PATH + CORE_EXTENSION_PROPERTIES, getClass());
171         List<Properties> extensions = new LinkedList<Properties>();
172 
173         // load ALL of the extension files first
174         while (e.hasMoreElements())
175         {
176             try
177             {
178                 URL url = (URL) e.nextElement();
179                 if (logger.isDebugEnabled())
180                 {
181                     logger.debug("Reading extension file: " + url.toString());
182                 }
183                 Properties p = new Properties();
184                 p.load(url.openStream());
185                 extensions.add(p);
186             }
187             catch (Exception ex)
188             {
189                 throw new DefaultMuleException("Error loading Mule core extensions", ex);
190             }
191         }
192 
193         for (Properties extProps : extensions)
194         {
195             for (Map.Entry entry : extProps.entrySet())
196             {
197                 String extName = (String) entry.getKey();
198                 String extClass = (String) entry.getValue();
199                 try
200                 {
201                     MuleCoreExtension extension = (MuleCoreExtension) ClassUtils.instanciateClass(extClass);
202                     extension.initialise();
203                     coreExtensions.put(extension.getClass(), extension);
204                 }
205                 catch (Exception ex)
206                 {
207                     throw new DefaultMuleException("Error starting Mule core extension " + extName, ex);
208                 }
209             }
210         }
211     }
212 
213     /**
214      * Will shut down the server displaying the cause and time of the shutdown
215      *
216      * @param e the exception that caused the shutdown
217      */
218     public void shutdown(Throwable e)
219     {
220         Message msg = CoreMessages.fatalErrorWhileRunning();
221         MuleException muleException = ExceptionHelper.getRootMuleException(e);
222         if (muleException != null)
223         {
224             logger.fatal(muleException.getDetailedMessage());
225         }
226         else
227         {
228             logger.fatal(msg.toString() + " " + e.getMessage(), e);
229         }
230         List<String> msgs = new ArrayList<String>();
231         msgs.add(msg.getMessage());
232         Throwable root = ExceptionHelper.getRootException(e);
233         msgs.add(root.getMessage() + " (" + root.getClass().getName() + ")");
234         msgs.add(" ");
235         msgs.add(CoreMessages.fatalErrorInShutdown().getMessage());
236         String shutdownMessage = StringMessageUtils.getBoilerPlate(msgs, '*', 80);
237         logger.fatal(shutdownMessage);
238 
239         unregisterShutdownHook();
240         doShutdown();
241     }
242 
243     /**
244      * shutdown the server. This just displays the time the server shut down
245      */
246     public void shutdown()
247     {
248         logger.info("Mule container shutting down due to normal shutdown request");
249 
250         unregisterShutdownHook();
251         doShutdown();
252     }
253 
254     protected void doShutdown()
255     {
256         if (deploymentService != null)
257         {
258             deploymentService.stop();
259         }
260 
261         for (MuleCoreExtension extension : coreExtensions.values())
262         {
263             try
264             {
265                 extension.dispose();
266             }
267             catch (Exception ex)
268             {
269                 logger.fatal("Error shutting down core extension " + extension.getName());
270             }
271         }
272 
273         System.exit(0);
274     }
275 
276     public Log getLogger()
277     {
278         return logger;
279     }
280 
281     public void registerShutdownHook()
282     {
283         if (muleShutdownHook == null)
284         {
285             muleShutdownHook = new MuleShutdownHook();
286         }
287         else
288         {
289             Runtime.getRuntime().removeShutdownHook(muleShutdownHook);
290         }
291         Runtime.getRuntime().addShutdownHook(muleShutdownHook);
292     }
293 
294     public void unregisterShutdownHook()
295     {
296         if (muleShutdownHook != null)
297         {
298             Runtime.getRuntime().removeShutdownHook(muleShutdownHook);
299         }
300     }
301 
302     // /////////////////////////////////////////////////////////////////
303     // Getters and setters
304     // /////////////////////////////////////////////////////////////////
305 
306 
307     public static String getStartupPropertiesFile()
308     {
309         return startupPropertiesFile;
310     }
311 
312     public static void setStartupPropertiesFile(String startupPropertiesFile)
313     {
314         MuleContainer.startupPropertiesFile = startupPropertiesFile;
315     }
316 
317     /**
318      * This class is installed only for MuleContainer running as commandline app. A
319      * clean Mule shutdown can be achieved by disposing the
320      * {@link org.mule.DefaultMuleContext}.
321      */
322     private class MuleShutdownHook extends Thread
323     {
324         public MuleShutdownHook()
325         {
326             super("Mule.shutdown.hook");
327         }
328 
329         @Override
330         public void run()
331         {
332             doShutdown();
333         }
334     }
335 }
336