1 /*
2 * JBoss, Home of Professional Open Source
3 * Copyright 2005, JBoss Inc., and individual contributors as indicated
4 * by the @authors tag. See the copyright.txt in the distribution for a
5 * full listing of individual contributors.
6 *
7 * This is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU Lesser General Public License as
9 * published by the Free Software Foundation; either version 2.1 of
10 * the License, or (at your option) any later version.
11 *
12 * This software is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this software; if not, write to the Free
19 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
20 * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
21 */
22 package org.jboss.system;
23
24 import java.net.URL;
25 import java.util.List;
26
27 import javax.management.MBeanServer;
28 import javax.management.ObjectInstance;
29 import javax.management.ObjectName;
30 import javax.management.StandardMBean;
31
32 import org.jboss.deployment.DeploymentException;
33 import org.jboss.logging.Logger;
34 import org.jboss.mx.server.ServerConstants;
35 import org.jboss.mx.server.registry.MBeanEntry;
36 import org.jboss.mx.service.ServiceConstants;
37 import org.jboss.mx.util.JMXExceptionDecoder;
38 import org.jboss.mx.util.ObjectNameFactory;
39 import org.jboss.system.metadata.ServiceConstructorMetaData;
40 import org.jboss.system.metadata.ServiceMetaData;
41 import org.jboss.system.metadata.ServiceMetaDataParser;
42 import org.jboss.util.UnreachableStatementException;
43 import org.w3c.dom.Element;
44
45 /**
46 * A helper class for the controller.
47 *
48 * @see Service
49 *
50 * @author <a href="mailto:marc.fleury@jboss.org">Marc Fleury</a>
51 * @author <a href="mailto:d_jencks@users.sourceforge.net">David Jencks</a>
52 * @author <a href="adrian@jboss.com">Adrian Brock</a>
53 * @version $Revision: 57108 $
54 */
55 public class ServiceCreator
56 {
57 /** Instance logger. */
58 private static final Logger log = Logger.getLogger(ServiceCreator.class);
59
60 /** The MBean Registry Object Name */
61 private static ObjectName MBEAN_REGISTRY = ObjectNameFactory.create(ServerConstants.MBEAN_REGISTRY);
62
63 /** The server */
64 private MBeanServer server;
65
66 /**
67 * Install an MBean
68 *
69 * @todo expand the meta data to include a pre-instantiated object
70 * @param server the mbean server
71 * @param objectName the object name
72 * @param metaData the service metadata
73 * @param mbean any mbean instance
74 * @return the installed instance
75 * @throws Exception for any error
76 */
77 public static ServiceInstance install(MBeanServer server, ObjectName objectName, ServiceMetaData metaData, Object mbean) throws Exception
78 {
79 if (server == null)
80 throw new IllegalArgumentException("Null MBeanServer");
81 if (objectName == null)
82 throw new IllegalArgumentException("Null ObjectName");
83 if (metaData == null && mbean == null)
84 throw new IllegalArgumentException("Either metadata or an mbean object must be supplied");
85
86 // Check for duplicate
87 if (server.isRegistered(objectName))
88 throw new DeploymentException("Trying to install an already registered mbean: " + objectName);
89
90 try
91 {
92 ServiceInstance result = null;
93
94 // No meta data just register directly
95 if (metaData == null)
96 {
97 ObjectInstance instance = server.registerMBean(mbean, objectName);
98 result = new ServiceInstance(instance, mbean);
99 }
100 else
101 {
102 String code = metaData.getCode();
103 if (code == null || code.trim().length() == 0)
104 throw new ConfigurationException("Missing or empty code for mbean " + objectName);
105
106 String xmbeanDD = metaData.getXMBeanDD();
107
108 // Not an XMBean
109 if (xmbeanDD == null)
110 {
111 String interfaceName = metaData.getInterfaceName();
112 if (interfaceName != null)
113 result = installStandardMBean(server, objectName, metaData);
114 else
115 result = installPlainMBean(server, objectName, metaData);
116 }
117 // Embedded XMBean Descriptor
118 else if (xmbeanDD.length() == 0)
119 result = installEmbeddedXMBean(server, objectName, metaData);
120 // Reference to external XMBean descriptor
121 else
122 result = installExternalXMBean(server, objectName, metaData);
123 }
124
125 log.debug("Created mbean: " + objectName);
126 return result;
127 }
128 catch (Throwable e)
129 {
130 Throwable newE = JMXExceptionDecoder.decode(e);
131
132 // didn't work, unregister in case the jmx agent is screwed.
133 try
134 {
135 server.unregisterMBean(objectName);
136 }
137 catch (Throwable ignore)
138 {
139 }
140
141 DeploymentException.rethrowAsDeploymentException("Unable to createMBean for " + objectName, newE);
142 throw new UnreachableStatementException();
143 }
144 }
145
146 /**
147 * Install a StandardMBean
148 *
149 * @param server the mbean server
150 * @param objectName the object name
151 * @param metadata the service metadata
152 * @return the installed instance
153 * @throws Exception for any error
154 */
155 private static ServiceInstance installStandardMBean(MBeanServer server, ObjectName objectName, ServiceMetaData metaData) throws Exception
156 {
157 ObjectName loaderName = metaData.getClassLoaderName();
158 ClassLoader loader = server.getClassLoader(loaderName);
159 String code = metaData.getCode();
160 ServiceConstructorMetaData constructor = metaData.getConstructor();
161 String interfaceName = metaData.getInterfaceName();
162
163 Class intf = loader.loadClass(interfaceName);
164 log.debug("About to create bean resource: " + objectName + " with code: " + code + " and interface " + interfaceName);
165 Object resource = server.instantiate(code,
166 loaderName,
167 constructor.getParameters(loader),
168 constructor.getSignature());
169
170 log.debug("About to register StandardMBean : " + objectName);
171 ObjectInstance instance = server.createMBean(StandardMBean.class.getName(),
172 objectName,
173 loaderName,
174 new Object[] { resource, intf },
175 new String[] { Object.class.getName() , Class.class.getName() });
176 return new ServiceInstance(instance, resource);
177 }
178
179 /**
180 * Install a plain MBean
181 *
182 * @param server the mbean server
183 * @param objectName the object name
184 * @param metadata the service metadata
185 * @return the installed instance
186 * @throws Exception for any error
187 */
188 private static ServiceInstance installPlainMBean(MBeanServer server, ObjectName objectName, ServiceMetaData metaData) throws Exception
189 {
190 ObjectName loaderName = metaData.getClassLoaderName();
191 ClassLoader loader = server.getClassLoader(loaderName);
192 String code = metaData.getCode();
193 ServiceConstructorMetaData constructor = metaData.getConstructor();
194
195 // This is a standard or dynamic mbean
196 log.debug("About to create bean: " + objectName + " with code: " + code);
197 ObjectInstance instance = server.createMBean(code,
198 objectName,
199 loaderName,
200 constructor.getParameters(loader),
201 constructor.getSignature());
202
203 MBeanEntry entry = (MBeanEntry) server.invoke(MBEAN_REGISTRY, "get", new Object[] { objectName }, new String[] { ObjectName.class.getName() });
204 Object resource = entry.getResourceInstance();
205 return new ServiceInstance(instance, resource);
206 }
207
208 /**
209 * Install an embedded XMBean
210 *
211 * @param server the mbean server
212 * @param objectName the object name
213 * @param metadata the service metadata
214 * @return the installed instance
215 * @throws Exception for any error
216 */
217 private static ServiceInstance installEmbeddedXMBean(MBeanServer server, ObjectName objectName, ServiceMetaData metaData) throws Exception
218 {
219 ObjectName loaderName = metaData.getClassLoaderName();
220 ClassLoader loader = server.getClassLoader(loaderName);
221 String code = metaData.getCode();
222 ServiceConstructorMetaData constructor = metaData.getConstructor();
223
224 // This is an xmbean with an embedded mbean descriptor
225 log.debug("About to create xmbean object: " + objectName + " with code: " + code + " with embedded descriptor");
226 //xmbean: construct object first.
227 Object resource = server.instantiate(code,
228 loaderName,
229 constructor.getParameters(loader),
230 constructor.getSignature());
231
232 String xmbeanCode = metaData.getXMBeanCode();
233 Element mbeanDescriptor = metaData.getXMBeanDescriptor();
234 Object[] args = { resource, mbeanDescriptor, ServiceConstants.PUBLIC_JBOSSMX_XMBEAN_DTD_1_0 };
235 String[] sig = { Object.class.getName(), Element.class.getName(), String.class.getName() };
236 ObjectInstance instance = server.createMBean(xmbeanCode,
237 objectName,
238 loaderName,
239 args,
240 sig);
241 return new ServiceInstance(instance, resource);
242 }
243
244 /**
245 * Install an external XMBean
246 *
247 * @param server the mbean server
248 * @param objectName the object name
249 * @param metadata the service metadata
250 * @return the installed instance
251 * @throws Exception for any error
252 */
253 private static ServiceInstance installExternalXMBean(MBeanServer server, ObjectName objectName, ServiceMetaData metaData) throws Exception
254 {
255 ObjectName loaderName = metaData.getClassLoaderName();
256 ClassLoader loader = server.getClassLoader(loaderName);
257 String code = metaData.getCode();
258 ServiceConstructorMetaData constructor = metaData.getConstructor();
259 String xmbeanDD = metaData.getXMBeanDD();
260
261 // This is an xmbean with an external descriptor
262 log.debug("About to create xmbean object: " + objectName + " with code: " + code + " with descriptor: " + xmbeanDD);
263 //xmbean: construct object first.
264 Object resource = server.instantiate(code,
265 loaderName,
266 constructor.getParameters(loader),
267 constructor.getSignature());
268 // Try to find the dd first as a resource then as a URL
269 URL xmbeanddUrl = null;
270 try
271 {
272 xmbeanddUrl = resource.getClass().getClassLoader().getResource(xmbeanDD);
273 }
274 catch (Exception e)
275 {
276 }
277
278 if (xmbeanddUrl == null)
279 xmbeanddUrl = new URL(xmbeanDD);
280
281 String xmbeanCode = metaData.getXMBeanCode();
282
283 //now create the mbean
284 Object[] args = { resource, xmbeanddUrl };
285 String[] sig = { Object.class.getName(), URL.class.getName() };
286 ObjectInstance instance = server.createMBean(xmbeanCode,
287 objectName,
288 loaderName,
289 args,
290 sig);
291 return new ServiceInstance(instance, resource);
292 }
293
294 /**
295 * Uninstall an MBean
296 *
297 * @param server the mbean server
298 * @param objectName the object name
299 */
300 public static void uninstall(MBeanServer server, ObjectName objectName)
301 {
302 if (server == null)
303 throw new IllegalArgumentException("Null MBeanServer");
304 if (objectName == null)
305 throw new IllegalArgumentException("Null ObjectName");
306 try
307 {
308 log.debug("Removing mbean from server: " + objectName);
309 server.unregisterMBean(objectName);
310 }
311 catch (Throwable t)
312 {
313 log.debug("Error unregistering mbean " + objectName, t);
314 }
315 }
316
317 /**
318 * Create a new ServiceCreator
319 *
320 * @deprecated This is no longer used and will be going away
321 * @param server the mbean server
322 */
323 public ServiceCreator(final MBeanServer server)
324 {
325 if (server == null)
326 throw new IllegalArgumentException("Null MBeanServer");
327 this.server = server;
328 }
329
330 /**
331 * Clean shutdown
332 */
333 public void shutdown()
334 {
335 this.server = null;
336 }
337
338 /**
339 * Parses the given configuration document and creates MBean
340 * instances in the current MBean server.
341 *
342 * @deprecated This is no longer used and will be going away
343 * @param mbeanName the object name
344 * @param loaderName the classloader
345 * @param mbeanElement the config
346 * @return the created object instance
347 * @throws Exception for any error
348 */
349 public ObjectInstance install(ObjectName mbeanName, ObjectName loaderName, Element mbeanElement) throws Exception
350 {
351 if (mbeanName == null)
352 throw new IllegalArgumentException("Null mbeanName");
353 if (mbeanElement == null)
354 throw new IllegalArgumentException("Null mbean element");
355
356 ServiceMetaDataParser parser = new ServiceMetaDataParser(mbeanElement);
357 List<ServiceMetaData> metaDatas = parser.parse();
358 if (metaDatas.isEmpty())
359 throw new DeploymentException("No mbeans found in passed configuration for " + mbeanName);
360 ServiceMetaData metaData = metaDatas.get(0);
361 metaData.setClassLoaderName(loaderName);
362 ServiceInstance instance = install(server, mbeanName, metaData, null);
363 return instance.getObjectInstance();
364 }
365
366 /**
367 * Remove the installed object
368 *
369 * @param name the object name
370 * @throws Exception for any error
371 */
372 public void remove(ObjectName name) throws Exception
373 {
374 if (name == null)
375 throw new IllegalArgumentException("Null name");
376 uninstall(server, name);
377 }
378 }