View Javadoc
1   /*
2    * Copyright (c) MuleSoft, Inc.  All rights reserved.  http://www.mulesoft.com
3    * The software in this package is published under the terms of the CPAL v1.0
4    * license, a copy of which has been included with this distribution in the
5    * LICENSE.txt file.
6    */
7   package org.mule.module.management.agent;
8   
9   import org.mule.AbstractAgent;
10  import org.mule.api.MuleException;
11  import org.mule.api.lifecycle.InitialisationException;
12  import org.mule.config.MuleManifest;
13  import org.mule.config.i18n.CoreMessages;
14  import org.mule.config.i18n.MessageFactory;
15  import org.mule.module.management.mbean.MBeanServerFactory;
16  import org.mule.module.management.support.AutoDiscoveryJmxSupportFactory;
17  import org.mule.module.management.support.JmxSupport;
18  import org.mule.module.management.support.JmxSupportFactory;
19  import org.mule.module.xml.util.XMLUtils;
20  import org.mule.util.BeanUtils;
21  import org.mule.util.ClassUtils;
22  import org.mule.util.StringUtils;
23  import org.mule.util.SystemUtils;
24  
25  import java.net.URI;
26  import java.util.HashMap;
27  import java.util.Map;
28  
29  import javax.management.InstanceNotFoundException;
30  import javax.management.MBeanException;
31  import javax.management.MBeanRegistrationException;
32  import javax.management.MBeanServer;
33  import javax.management.MalformedObjectNameException;
34  import javax.management.ObjectName;
35  import javax.management.ReflectionException;
36  import javax.xml.transform.TransformerFactoryConfigurationError;
37  
38  import mx4j.log.CommonsLogger;
39  import mx4j.log.Log;
40  import mx4j.tools.adaptor.http.HttpAdaptor;
41  import mx4j.tools.adaptor.http.XSLTProcessor;
42  import mx4j.tools.adaptor.ssl.SSLAdaptorServerSocketFactory;
43  import mx4j.tools.adaptor.ssl.SSLAdaptorServerSocketFactoryMBean;
44  import org.apache.commons.logging.LogFactory;
45  
46  /**
47   * <code>Mx4jAgent</code> configures an Mx4J Http Adaptor for Jmx management,
48   * statistics and configuration viewing of a Mule instance.
49   */
50  public class Mx4jAgent extends AbstractAgent
51  {
52      public static final String HTTP_ADAPTER_OBJECT_NAME = "name=Mx4jHttpAdapter";
53  
54      protected static final String DEFAULT_PATH_IN_JAR = 
55          StringUtils.replaceChars(ClassUtils.getPackageName(Mx4jAgent.class), '.', '/') + "/http/xsl";
56  
57      private static final org.apache.commons.logging.Log logger = LogFactory.getLog(Mx4jAgent.class);
58  
59      private static final String PROTOCOL_PREFIX = "http://";
60      public static final String DEFAULT_HOSTNAME = "localhost";
61      public static final int DEFAULT_PORT = 9999;
62      public static final String DEFAULT_JMX_ADAPTOR_URL = PROTOCOL_PREFIX + DEFAULT_HOSTNAME + ":" + DEFAULT_PORT;
63  
64      private String jmxAdaptorUrl;
65      private String host;
66      private String port;
67  
68      private HttpAdaptor adaptor;
69      private MBeanServer mBeanServer;
70      private ObjectName adaptorName;
71  
72      // Adaptor overrides
73      private String login;
74  
75      private String password;
76  
77      private String authenticationMethod = "basic";
78  
79      // TODO AH check how an embedded scenario can be handled (no mule home) 
80      private String xslFilePath = System.getProperty("mule.home") + "/lib/mule/mule-module-management-" +
81              MuleManifest.getProductVersion() + ".jar";
82  
83      private String pathInJar = DEFAULT_PATH_IN_JAR;
84  
85      private boolean cacheXsl = true;
86  
87      // SSL/TLS socket factory config
88      private Map socketFactoryProperties = new HashMap();
89  
90      private JmxSupportFactory jmxSupportFactory = AutoDiscoveryJmxSupportFactory.getInstance();
91      private JmxSupport jmxSupport;
92  
93  
94      public Mx4jAgent()
95      {
96          super("jmx-mx4j-adaptor");
97      }
98  
99      protected HttpAdaptor createAdaptor() throws Exception
100     {
101         Log.redirectTo(new CommonsLogger());
102         URI uri = new URI(StringUtils.stripToEmpty(jmxAdaptorUrl));
103         adaptor = new HttpAdaptor(uri.getPort(), uri.getHost());
104 
105         // Set the XSLT Processor with any local overrides
106         XSLTProcessor processor;
107         try
108         {
109             processor = new XSLTProcessor();
110         }
111         catch (TransformerFactoryConfigurationError e)
112         {
113             System.setProperty("javax.xml.transform.TransformerFactory", XMLUtils.TRANSFORMER_FACTORY_JDK5);
114             processor = new XSLTProcessor();
115         }
116 
117         if (StringUtils.isNotBlank(xslFilePath))
118         {
119             processor.setFile(xslFilePath.trim());
120         }
121 
122         if (StringUtils.isNotBlank(pathInJar))
123         {
124             processor.setPathInJar(pathInJar.trim());
125         }
126 
127         processor.setUseCache(cacheXsl);
128 
129         adaptor.setProcessor(processor);
130 
131         // Set endpoint authentication if required
132         if (login != null)
133         {
134             adaptor.addAuthorization(login, password);
135             adaptor.setAuthenticationMethod(authenticationMethod);
136         }
137 
138         if (socketFactoryProperties != null && !socketFactoryProperties.isEmpty())
139         {
140             SSLAdaptorServerSocketFactoryMBean factory;
141             if (SystemUtils.isIbmJDK())
142             {
143                 factory = new IBMSslAdapterServerSocketFactory();
144             }
145             else
146             {
147                 // BEA are using Sun's JSSE, so no extra checks necessary
148                 factory = new SSLAdaptorServerSocketFactory();
149             }
150             BeanUtils.populateWithoutFail(factory, socketFactoryProperties, true);
151             adaptor.setSocketFactory(factory);
152         }
153 
154         return adaptor;
155     }
156 
157     public void initialise() throws InitialisationException
158     {
159         try
160         {
161             jmxSupport = jmxSupportFactory.getJmxSupport();
162             mBeanServer = MBeanServerFactory.getOrCreateMBeanServer();
163 
164             if (StringUtils.isBlank(jmxAdaptorUrl))
165             {
166                 if (StringUtils.isNotBlank(host) && StringUtils.isNotBlank(port))
167                 {
168                     jmxAdaptorUrl = PROTOCOL_PREFIX + host + ":" + port;
169                 }
170                 else
171                 {
172                     jmxAdaptorUrl = DEFAULT_JMX_ADAPTOR_URL;
173                 }
174             }
175 
176             adaptor = createAdaptor();
177             adaptorName = jmxSupport.getObjectName(jmxSupport.getDomainName(muleContext) + ":" + HTTP_ADAPTER_OBJECT_NAME);
178 
179             unregisterMBeansIfNecessary();
180             mBeanServer.registerMBean(adaptor, adaptorName);
181         }
182         catch (Exception e)
183         {
184             throw new InitialisationException(CoreMessages.failedToStart("mx4j agent"), e, this);
185         }
186     }
187 
188     public void start() throws MuleException
189     {
190         if (mBeanServer == null)
191         {
192             throw new InitialisationException(MessageFactory.createStaticMessage("mBeanServer has not yet been created"), this);
193         }
194         
195         try
196         {
197             mBeanServer.invoke(adaptorName, "start", null, null);
198         }
199         catch (InstanceNotFoundException e)
200         {
201             throw new JmxManagementException(
202                 CoreMessages.failedToStart("Mx4j agent"), adaptorName, e);
203         }
204         catch (MBeanException e)
205         {
206             throw new JmxManagementException(
207                 CoreMessages.failedToStart("Mx4j agent"), adaptorName, e);
208         }
209         catch (ReflectionException e)
210         {
211             // ignore
212         }
213     }
214 
215     public void stop() throws MuleException
216     {
217         if (mBeanServer == null)
218         {
219             return;
220         }
221         try
222         {
223             mBeanServer.invoke(adaptorName, "stop", null, null);
224         }
225         catch (InstanceNotFoundException e)
226         {
227             throw new JmxManagementException(
228                 CoreMessages.failedToStop("Mx4j agent"), adaptorName, e);
229         }
230         catch (MBeanException e)
231         {
232             throw new JmxManagementException(
233                 CoreMessages.failedToStop("Mx4j agent"), adaptorName, e);
234         }
235         catch (ReflectionException e)
236         {
237             // ignore
238         }
239     }
240 
241     /**
242      * Unregister all Mx4j MBeans if there are any left over the old deployment
243      */
244     protected void unregisterMBeansIfNecessary()
245         throws MalformedObjectNameException, InstanceNotFoundException, MBeanRegistrationException
246     {
247         if (mBeanServer != null && mBeanServer.isRegistered(adaptorName))
248         {
249             mBeanServer.unregisterMBean(adaptorName);
250         }
251     }
252 
253     public void dispose()
254     {
255         try
256         {
257             stop();
258         }
259         catch (Exception e)
260         {
261             logger.warn("Failed to stop Mx4jAgent: " + e.getMessage());
262         }
263         finally
264         {
265             try
266             {
267                 unregisterMBeansIfNecessary();
268             }
269             catch (Exception e)
270             {
271                 logger.error("Couldn't unregister MBean: "
272                              + (adaptorName != null ? adaptorName.getCanonicalName() : "null"), e);
273             }
274         }
275     }
276 
277     // /////////////////////////////////////////////////////////////////////////
278     // Getters and setters
279     // /////////////////////////////////////////////////////////////////////////
280     @Override
281     public String getDescription()
282     {
283         return "MX4J Http adaptor: " + jmxAdaptorUrl;
284     }
285 
286     public String getJmxAdaptorUrl()
287     {
288         return jmxAdaptorUrl;
289     }
290 
291     public void setJmxAdaptorUrl(String jmxAdaptorUrl)
292     {
293         this.jmxAdaptorUrl = jmxAdaptorUrl;
294     }
295 
296     public Map getSocketFactoryProperties()
297     {
298         return socketFactoryProperties;
299     }
300 
301     public void setSocketFactoryProperties(Map socketFactoryProperties)
302     {
303         this.socketFactoryProperties = socketFactoryProperties;
304     }
305 
306     public String getLogin()
307     {
308         return login;
309     }
310 
311     public void setLogin(String login)
312     {
313         this.login = login;
314     }
315 
316     public String getPassword()
317     {
318         return password;
319     }
320 
321     public void setPassword(String password)
322     {
323         this.password = password;
324     }
325 
326     public String getAuthenticationMethod()
327     {
328         return authenticationMethod;
329     }
330 
331     public void setAuthenticationMethod(String authenticationMethod)
332     {
333         this.authenticationMethod = authenticationMethod;
334     }
335 
336     public String getXslFilePath()
337     {
338         return xslFilePath;
339     }
340 
341     public void setXslFilePath(String xslFilePath)
342     {
343         this.xslFilePath = xslFilePath;
344     }
345 
346     public String getPathInJar()
347     {
348         return pathInJar;
349     }
350 
351     public void setPathInJar(String pathInJar)
352     {
353         this.pathInJar = pathInJar;
354     }
355 
356     public boolean isCacheXsl()
357     {
358         return cacheXsl;
359     }
360 
361     public void setCacheXsl(boolean cacheXsl)
362     {
363         this.cacheXsl = cacheXsl;
364     }
365 
366     public String getHost()
367     {
368         return host;
369     }
370 
371     public void setHost(String host)
372     {
373         this.host = host;
374     }
375 
376     public String getPort()
377     {
378         return port;
379     }
380 
381     public void setPort(String port)
382     {
383         this.port = port;
384     }
385 }