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.mx.server;
23
24 import java.io.ByteArrayInputStream;
25 import java.io.IOException;
26 import java.io.ObjectInputStream;
27 import java.lang.reflect.Constructor;
28 import java.lang.reflect.InvocationTargetException;
29 import java.util.ArrayList;
30 import java.util.HashMap;
31 import java.util.HashSet;
32 import java.util.Iterator;
33 import java.util.List;
34 import java.util.Map;
35 import java.util.Set;
36 import java.security.ProtectionDomain;
37 import java.security.AccessController;
38 import java.security.PrivilegedAction;
39 import java.security.PrivilegedExceptionAction;
40 import java.security.PrivilegedActionException;
41
42 import javax.management.Attribute;
43 import javax.management.AttributeList;
44 import javax.management.AttributeNotFoundException;
45 import javax.management.InstanceAlreadyExistsException;
46 import javax.management.InstanceNotFoundException;
47 import javax.management.IntrospectionException;
48 import javax.management.InvalidAttributeValueException;
49 import javax.management.JMException;
50 import javax.management.ListenerNotFoundException;
51 import javax.management.MBeanException;
52 import javax.management.MBeanInfo;
53 import javax.management.MBeanParameterInfo;
54 import javax.management.MBeanRegistrationException;
55 import javax.management.MBeanServer;
56 import javax.management.MBeanServerDelegate;
57 import javax.management.NotCompliantMBeanException;
58 import javax.management.NotificationBroadcaster;
59 import javax.management.NotificationFilter;
60 import javax.management.NotificationListener;
61 import javax.management.ObjectInstance;
62 import javax.management.ObjectName;
63 import javax.management.OperationsException;
64 import javax.management.QueryExp;
65 import javax.management.ReflectionException;
66 import javax.management.RuntimeErrorException;
67 import javax.management.RuntimeMBeanException;
68 import javax.management.RuntimeOperationsException;
69 import javax.management.JMRuntimeException;
70 import javax.management.MBeanPermission;
71 import javax.management.MalformedObjectNameException;
72 import javax.management.MBeanTrustPermission;
73 import javax.management.loading.ClassLoaderRepository;
74 import javax.management.modelmbean.DescriptorSupport;
75 import javax.management.modelmbean.ModelMBean;
76 import javax.management.modelmbean.ModelMBeanAttributeInfo;
77 import javax.management.modelmbean.ModelMBeanConstructorInfo;
78 import javax.management.modelmbean.ModelMBeanInfo;
79 import javax.management.modelmbean.ModelMBeanInfoSupport;
80 import javax.management.modelmbean.ModelMBeanNotificationInfo;
81 import javax.management.modelmbean.ModelMBeanOperationInfo;
82
83 import org.jboss.logging.Logger;
84 import org.jboss.mx.loading.LoaderRepository;
85 import org.jboss.mx.modelmbean.ModelMBeanConstants;
86 import org.jboss.mx.modelmbean.RequiredModelMBeanInstantiator;
87 import org.jboss.mx.notification.MBeanServerListenerRegistry;
88 import org.jboss.mx.server.registry.MBeanEntry;
89 import org.jboss.mx.server.registry.MBeanRegistry;
90 import org.jboss.mx.service.ServiceConstants;
91 import org.jboss.mx.util.JMXExceptionDecoder;
92 import org.jboss.mx.util.PropertyAccess;
93 import org.jboss.util.NestedRuntimeException;
94
95 /**
96 * MBean server implementation.
97 *
98 * The MBean server behaviour can be configured by setting the following
99 * system properties: <ul>
100 * <li><tt>jbossmx.loader.repository.class</tt>
101 ({@link ServerConstants#LOADER_REPOSITORY_CLASS_PROPERTY LOADER_REPOSITORY_CLASS_PROPERTY})</li>
102 * <li><tt>jbossmx.mbean.registry.class</tt>
103 ({@link ServerConstants#MBEAN_REGISTRY_CLASS_PROPERTY MBEAN_REGISTRY_CLASS_PROPERTY})</li>
104 * <li><tt>jbossmx.required.modelmbean.class</tt>
105 ({@link ServerConstants#REQUIRED_MODELMBEAN_CLASS_PROPERTY REQUIRED_MODELMBEAN_CLASS_PROPERTY})</li>
106 * </ul>
107 *
108 * The loader repository is used for managing class loaders in the MBean server.
109 * The default repository uses the <tt>UnifiedLoaderRepository</tt> implementation
110 * ({@link ServerConstants#DEFAULT_LOADER_REPOSITORY_CLASS DEFAULT_LOADER_REPOSITORY_CLASS}).<p>
111 *
112 * The default registry is
113 * ({@link ServerConstants#DEFAULT_MBEAN_REGISTRY_CLASS DEFAULT_MBEAN_REGISTRY_CLASS}).<p>
114 *
115 * The <tt>RequiredModelMBean</tt> uses <tt>XMBean</tt> implementation by default
116 * ({@link ServerConstants#DEFAULT_REQUIRED_MODELMBEAN_CLASS DEFAULT_REQUIRED_MODELMBEAN_CLASS}).
117 *
118 * @see javax.management.MBeanServer
119 * @see javax.management.modelmbean.RequiredModelMBean
120 * @see org.jboss.mx.server.ServerConstants
121 * @see org.jboss.mx.loading.LoaderRepository
122 * @see org.jboss.mx.loading.UnifiedLoaderRepository3
123 * @see org.jboss.mx.modelmbean.XMBean
124 *
125 * @author <a href="mailto:juha@jboss.org">Juha Lindfors</a>.
126 * @author <a href="mailto:trevor@protocool.com">Trevor Squires</a>.
127 * @author <a href="mailto:Adrian.Brock@HappeningTimes.com">Adrian Brock</a>.
128 * @author <a href="mailto:thomas.diesler@jboss.com">Thomas Diesler</a>.
129 * @author Scott.Stark@jboss.org
130 * @version $Revision: 57108 $
131 */
132 public class MBeanServerImpl
133 implements MBeanServer, ServerConstants, ServiceConstants, ModelMBeanConstants
134 {
135 // Constants ------------------------------------------------------
136
137 /**
138 * No parameters array
139 */
140 private static final Object[] NOPARAMS = new Object[0];
141
142 /**
143 * No signature array
144 */
145 private static final String[] NOSIG = new String[0];
146
147 // Attributes ----------------------------------------------------
148
149 /**
150 * The wrapping MBeanServer
151 */
152 protected MBeanServer outer = null;
153
154 /**
155 * Registry used by this server to map MBean object names to resource references.
156 */
157 protected MBeanRegistry registry = null;
158
159 /**
160 * The notification registrations
161 */
162 private MBeanServerListenerRegistry listeners = new MBeanServerListenerRegistry();
163
164 /**
165 * This server's class loader repository
166 */
167 private ClassLoaderRepository classLoaderRepository;
168
169 // Static --------------------------------------------------------
170
171 /**
172 * The logger
173 */
174 private static Logger log = Logger.getLogger(MBeanServerImpl.class);
175
176
177 // Constructors --------------------------------------------------
178
179 /**
180 * Creates an MBean server implementation with a given default domain name and
181 * registers the mandatory server delegate MBean to the server
182 * ({@link ServerConstants#MBEAN_SERVER_DELEGATE MBEAN_SERVER_DELEGATE}).
183 *
184 * @param defaultDomain default domain name
185 * @param outer the wrapping MBeanServer, passed to MBeans
186 * at registration.
187 * @param delegate the delegate to use
188 * for Notifications.
189 */
190 public MBeanServerImpl(String defaultDomain, MBeanServer outer, MBeanServerDelegate delegate)
191 {
192 // Determine the MBeanServer to pass to MBeans
193 if (outer == null)
194 this.outer = this;
195 else
196 this.outer = outer;
197
198 // the very first thing to do is to create a class loader repository
199 this.classLoaderRepository = getClassLoaderRepository();
200
201 // the second first thing to do is to create a registry instance
202 this.registry = createRegistry(defaultDomain);
203
204 // The first MBean to be registered should be the server delegate
205 // to guarantee correct functionality (other MBeans may be dependent
206 // on the existence of the delegate).
207 try
208 {
209 // the magic token that allows us to register to the
210 // protected JMImplementation domain
211 HashMap valueMap = new HashMap();
212 valueMap.put(JMI_DOMAIN, JMI_DOMAIN);
213
214 // register the delegate
215 registry.registerMBean(delegate,
216 new ObjectName(MBEAN_SERVER_DELEGATE),
217 valueMap);
218
219 // We expose the registry as an MBean for other components
220 ModelMBean rmm = RequiredModelMBeanInstantiator.instantiate();
221 rmm.setModelMBeanInfo(getRegistryManagementInterface());
222 rmm.setManagedResource(registry, "ObjectReference");
223
224 // register the registry MBean
225 registry.registerMBean(rmm, new ObjectName(MBEAN_REGISTRY), valueMap);
226
227 // register the loader repository
228 //String loaderClassMBeanName = classLoaderRepository.getClass().getName() + "MBean";
229 //ClassLoader cl = classLoaderRepository.getClass().getClassLoader();
230 //Class mbean = cl.loadClass(loaderClassMBeanName);
231
232 //there must be a class with the MBean extension.
233 ObjectName loaderName = new ObjectName(DEFAULT_LOADER_NAME);
234 registry.registerMBean(classLoaderRepository, loaderName, valueMap);
235
236 }
237 catch (Exception e)
238 {
239 throw new RuntimeException("Cannot create MBeanServer", e);
240 }
241 }
242
243 // MBeanServer implementation ------------------------------------
244
245 public Object instantiate(String className)
246 throws ReflectionException, MBeanException
247 {
248 return instantiate(className, (ClassLoader) null, NOPARAMS, NOSIG);
249 }
250
251 public Object instantiate(String className, Object[] params, String[] signature)
252 throws ReflectionException, MBeanException
253 {
254 return instantiate(className, (ClassLoader) null, params, signature);
255 }
256
257 public Object instantiate(String className, ObjectName loaderName)
258 throws ReflectionException, MBeanException, InstanceNotFoundException
259 {
260 return instantiate(className, loaderName, NOPARAMS, NOSIG);
261 }
262
263 public Object instantiate(String className, ObjectName loaderName, Object[] params, String[] signature)
264 throws ReflectionException, MBeanException, InstanceNotFoundException
265 {
266 ClassLoader cl = null;
267
268 // if instantiate() is called with null loader name, we use the cl that
269 // loaded the MBean server (see javadoc)
270
271 try
272 {
273 if (loaderName != null)
274 cl = (ClassLoader) registry.get(loaderName).getResourceInstance();
275 }
276 catch (ClassCastException e)
277 {
278 throw new ReflectionException(e, loaderName + " is not a class loader.");
279 }
280
281 if (cl == null)
282 cl = this.getClass().getClassLoader();
283 if (cl == null)
284 cl = ClassLoader.getSystemClassLoader();
285
286 return instantiate(className, cl, params, signature);
287 }
288
289 public ObjectInstance createMBean(String className, ObjectName name)
290 throws ReflectionException, InstanceAlreadyExistsException, MBeanRegistrationException, MBeanException, NotCompliantMBeanException
291 {
292 try
293 {
294 Object mbean = instantiate(className);
295 return registerMBean(mbean, name, (ClassLoader) null);
296 }
297 catch (SecurityException e)
298 {
299 throw e;
300 }
301 catch (ReflectionException refex)
302 {
303 // Note, the CTS wants a NotCompliantMBeanException for this case
304 if (refex.getCause() instanceof InstantiationException)
305 throw new NotCompliantMBeanException("Cannot instanciate MBean: " + className);
306 else
307 throw refex;
308 }
309 }
310
311 public ObjectInstance createMBean(String className, ObjectName name, Object[] params, String[] signature)
312 throws ReflectionException, InstanceAlreadyExistsException, MBeanRegistrationException, MBeanException, NotCompliantMBeanException
313 {
314 try
315 {
316 Object mbean = instantiate(className, params, signature);
317 return registerMBean(mbean, name, (ClassLoader) null);
318 }
319 catch (ReflectionException refex)
320 {
321 return handleExceptionOnCreate(refex, className);
322 }
323 }
324
325 public ObjectInstance createMBean(String className, ObjectName name, ObjectName loaderName)
326 throws ReflectionException, InstanceAlreadyExistsException, MBeanRegistrationException, MBeanException, NotCompliantMBeanException, InstanceNotFoundException
327 {
328 try
329 {
330 Object mbean = instantiate(className, loaderName);
331 return registerMBean(mbean, name, loaderName);
332 }
333 catch (ReflectionException refex)
334 {
335 return handleExceptionOnCreate(refex, className);
336 }
337 }
338
339 public ObjectInstance createMBean(String className, ObjectName name, ObjectName loaderName, Object[] params, String[] signature)
340 throws ReflectionException, InstanceAlreadyExistsException, MBeanRegistrationException, MBeanException, NotCompliantMBeanException, InstanceNotFoundException
341 {
342 try
343 {
344 Object mbean = instantiate(className, loaderName, params, signature);
345 return registerMBean(mbean, name, loaderName);
346 }
347 catch (ReflectionException refex)
348 {
349 return handleExceptionOnCreate(refex, className);
350 }
351 }
352
353 /**
354 * The CTS wants a NotCompliantMBeanException in case the MBean cannot be created.
355 * We need this, because instanciate cannot throw NotCompliantMBeanException.
356 */
357 private ObjectInstance handleExceptionOnCreate(ReflectionException refex, String className)
358 throws NotCompliantMBeanException, ReflectionException
359 {
360 if (refex.getCause() instanceof InstantiationException)
361 throw new NotCompliantMBeanException("Cannot instanciate MBean: " + className);
362
363 throw refex;
364 }
365
366 /**
367 * Registers a pre-existing object as an MBean with the MBean server. If the object name given is null,
368 * the MBean must provide its own name by implementing the MBeanRegistration interface and returning the name
369 * from the preRegister method.
370 */
371 public ObjectInstance registerMBean(Object object, ObjectName name)
372 throws InstanceAlreadyExistsException,
373 MBeanRegistrationException,
374 NotCompliantMBeanException
375 {
376 return registerMBean(object, name, (ClassLoader) null);
377 }
378
379 public void unregisterMBean(ObjectName name)
380 throws InstanceNotFoundException, MBeanRegistrationException
381 {
382 // Get the mbean to remove
383 MBeanEntry entry = registry.get(name);
384 Object mbean = entry.getResourceInstance();
385 name = entry.getObjectName();
386
387 checkMBeanPermission(entry.getResourceClassName(), null, name, "unregisterMBean");
388
389 try
390 {
391 final Object[] args = {name};
392 final String[] sig = {ObjectName.class.getName()};
393 try
394 {
395 AccessController.doPrivileged(
396 new PrivilegedExceptionAction()
397 {
398 public Object run() throws Exception
399 {
400 return invoke(new ObjectName(MBEAN_REGISTRY),
401 "unregisterMBean", args, sig);
402 }
403 }
404 );
405 }
406 catch(PrivilegedActionException e)
407 {
408 throw e.getException();
409 }
410 }
411 catch (Throwable t)
412 {
413 Throwable result = JMXExceptionDecoder.decodeToJMXException(t);
414 if (result instanceof InstanceNotFoundException)
415 throw (InstanceNotFoundException) result;
416 if (result instanceof MBeanRegistrationException)
417 throw (MBeanRegistrationException) result;
418 if ( result instanceof JMRuntimeException )
419 throw (JMRuntimeException) result;
420 if (result instanceof MBeanException)
421 {
422 MBeanException e = (MBeanException) result;
423 t = e.getTargetException();
424 if (t instanceof InstanceNotFoundException)
425 throw (InstanceNotFoundException) t;
426 if (t instanceof MBeanRegistrationException)
427 throw (MBeanRegistrationException) t;
428 }
429 if (result instanceof RuntimeException)
430 throw new RuntimeMBeanException((RuntimeException) result);
431 if (result instanceof Error)
432 throw new RuntimeErrorException((Error) result);
433
434 // for some other reason, unregistration failed
435 throw new MBeanRegistrationException(new InvocationTargetException(t), "Cannot unregister MBean");
436 }
437
438 // Unregistration worked, remove any proxies for a broadcaster
439 if (mbean instanceof NotificationBroadcaster)
440 listeners.remove(name);
441 }
442
443 public ObjectInstance getObjectInstance(ObjectName name)
444 throws InstanceNotFoundException
445 {
446 ObjectInstance oi = registry.getObjectInstance(name);
447 checkMBeanPermission(oi.getClassName(), null, name,
448 "getObjectInstance");
449
450 return oi;
451 }
452
453 public Set queryMBeans(ObjectName name, QueryExp query)
454 {
455 // At least one mbean must be queriable
456 checkMBeanPermission(null, null, null, "queryMBeans");
457
458 // Set up the query
459 Set result = new HashSet();
460 if (query != null)
461 query.setMBeanServer(outer);
462
463 SecurityManager sm = System.getSecurityManager();
464 // Get the possible MBeans
465 List entries = registry.findEntries(name);
466 Iterator iterator = entries.iterator();
467 while (iterator.hasNext())
468 {
469 // Check each MBean against the query
470 MBeanEntry entry = (MBeanEntry) iterator.next();
471 ObjectName objectName = entry.getObjectName();
472 // The permission check must be done before the query is applied
473 if( sm != null )
474 {
475 try
476 {
477 checkMBeanPermission(entry.getResourceClassName(), null,
478 objectName, "queryMBeans");
479 }
480 catch(SecurityException e)
481 {
482 if( log.isTraceEnabled() )
483 log.trace("Excluded mbean due to security: "+objectName);
484 continue;
485 }
486 }
487 // Check the mbean against the query
488 if (queryMBean(objectName, query) == true)
489 {
490 try
491 {
492 ObjectInstance instance = registry.getObjectInstance(objectName);
493 result.add(instance);
494 }
495 catch (InstanceNotFoundException ignored)
496 {
497 }
498 }
499 }
500
501 return result;
502 }
503
504 public Set queryNames(ObjectName name, QueryExp query)
505 {
506 // At least one mbean must be queriable
507 checkMBeanPermission(null, null, null, "queryNames");
508
509 // Set up the query
510 Set result = new HashSet();
511 if (query != null)
512 query.setMBeanServer(outer);
513
514 SecurityManager sm = System.getSecurityManager();
515 // Get the possible MBeans
516 List entries = registry.findEntries(name);
517 Iterator iterator = entries.iterator();
518 while (iterator.hasNext())
519 {
520 // Check each MBean against the query
521 MBeanEntry entry = (MBeanEntry) iterator.next();
522 ObjectName objectName = entry.getObjectName();
523 // The permission check must be done before the query is applied
524 if( sm != null )
525 {
526 try
527 {
528 checkMBeanPermission(entry.getResourceClassName(), null,
529 objectName, "queryNames");
530 }
531 catch(SecurityException e)
532 {
533 if( log.isTraceEnabled() )
534 log.trace("Excluded mbean due to security: "+objectName);
535 continue;
536 }
537 }
538 // Check the mbean against the query
539 if (queryMBean(objectName, query) == true)
540 result.add(objectName);
541 }
542
543 return result;
544 }
545
546 public boolean isRegistered(ObjectName name)
547 {
548 return registry.contains(name);
549 }
550
551 public java.lang.Integer getMBeanCount()
552 {
553 return new Integer(registry.getSize());
554 }
555
556 public Object getAttribute(ObjectName name, String attribute)
557 throws MBeanException, AttributeNotFoundException, InstanceNotFoundException, ReflectionException
558 {
559 MBeanEntry entry = registry.get(name);
560 checkMBeanPermission(entry.getResourceClassName(), attribute, name,
561 "getAttribute");
562
563 MBeanInvoker mbean = entry.getInvoker();
564
565 return mbean.getAttribute(attribute);
566 }
567
568 public AttributeList getAttributes(ObjectName name, String[] attributes)
569 throws InstanceNotFoundException, ReflectionException
570 {
571 MBeanEntry entry = registry.get(name);
572 String className = entry.getResourceClassName();
573 /* Access to an attribute is required and this check will fail only
574 if access to no attributes are allowed and will result in a security
575 exception rather than an empty list.
576 */
577 checkMBeanPermission(className, null, name, "getAttribute");
578
579 MBeanInvoker mbean = entry.getInvoker();
580 AttributeList list = mbean.getAttributes(attributes);
581 SecurityManager sm = System.getSecurityManager();
582 if( sm != null )
583 {
584 // Remove any attributes that are not allowed
585 Iterator iter = list.iterator();
586 while( iter.hasNext() )
587 {
588 Attribute attr = (Attribute) iter.next();
589 String aname = attr.getName();
590 try
591 {
592 checkMBeanPermission(className, aname, name, "getAttribute");
593 }
594 catch(SecurityException e)
595 {
596 if( log.isTraceEnabled() )
597 log.trace("Excluded attribute due to security: "+aname);
598 iter.remove();
599 }
600 }
601 }
602 return list;
603 }
604
605 public void setAttribute(ObjectName name, Attribute attribute)
606 throws InstanceNotFoundException, AttributeNotFoundException, InvalidAttributeValueException, MBeanException, ReflectionException
607 {
608 MBeanEntry entry = registry.get(name);
609 String attributeName = null;
610 if (attribute != null)
611 attributeName = attribute.getName();
612 checkMBeanPermission(entry.getResourceClassName(), attributeName,
613 name, "setAttribute");
614
615 MBeanInvoker mbean = entry.getInvoker();
616
617 mbean.setAttribute(attribute);
618 }
619
620 public AttributeList setAttributes(ObjectName name, AttributeList attributes)
621 throws InstanceNotFoundException, ReflectionException
622 {
623 MBeanEntry entry = registry.get(name);
624
625 String className = entry.getResourceClassName();
626 /* Access to an attribute is required and this check will fail only
627 if access to no attributes are allowed and will result in a security
628 exception rather than an empty list.
629 */
630 checkMBeanPermission(className, null, name, "setAttribute");
631
632 MBeanInvoker mbean = entry.getInvoker();
633 AttributeList list = mbean.setAttributes(attributes);
634 SecurityManager sm = System.getSecurityManager();
635 if( sm != null )
636 {
637 // Remove any attributes that are not allowed
638 Iterator iter = list.iterator();
639 while( iter.hasNext() )
640 {
641 Attribute attr = (Attribute) iter.next();
642 String aname = attr.getName();
643 try
644 {
645 checkMBeanPermission(className, aname, name, "setAttribute");
646 }
647 catch(SecurityException e)
648 {
649 if( log.isTraceEnabled() )
650 log.trace("Excluded attribute due to security: "+aname);
651 iter.remove();
652 }
653 }
654 }
655 return list;
656 }
657
658 public Object invoke(ObjectName name, String operationName, Object[] params,
659 String[] signature)
660 throws InstanceNotFoundException, MBeanException, ReflectionException
661 {
662 MBeanEntry entry = registry.get(name);
663 checkMBeanPermission(entry.getResourceClassName(), operationName, name,
664 "invoke");
665
666 MBeanInvoker mbean = entry.getInvoker();
667
668 return mbean.invoke(operationName, params, signature);
669 }
670
671 public MBeanInfo getMBeanInfo(ObjectName name)
672 throws InstanceNotFoundException, IntrospectionException,
673 ReflectionException
674 {
675 MBeanEntry entry = registry.get(name);
676 checkMBeanPermission(entry.getResourceClassName(), null, name,
677 "getMBeanInfo");
678 try
679 {
680 MBeanInvoker invoker = entry.getInvoker();
681 return invoker.getMBeanInfo();
682 }
683 catch (Exception e)
684 {
685 JMException result = ExceptionHandler.handleException(e);
686 if (result instanceof InstanceNotFoundException)
687 throw (InstanceNotFoundException) result;
688 if (result instanceof IntrospectionException)
689 throw (IntrospectionException) result;
690 if (result instanceof ReflectionException)
691 throw (ReflectionException) result;
692 throw new RuntimeException("Cannot obtain MBeanInfo " + name, result);
693 }
694 }
695
696 public String getDefaultDomain()
697 {
698 return registry.getDefaultDomain();
699 }
700
701 public String[] getDomains()
702 {
703 checkMBeanPermission(null, null, null, "getDomains");
704 String[] domains = registry.getDomains();
705 SecurityManager sm = System.getSecurityManager();
706 if( sm != null )
707 {
708 ArrayList tmp = new ArrayList();
709 // Remove any domains that are not allowed
710 int length = domains != null ? domains.length : 0;
711 for(int n = 0; n < length; n ++)
712 {
713 String domain = domains[n];
714 try
715 {
716 ObjectName name = new ObjectName(domain, "x", "x");
717 checkMBeanPermission(null, null, name, "getDomains");
718 tmp.add(domain);
719 }
720 catch(MalformedObjectNameException e)
721 {
722 // Should not be possible
723 }
724 catch(SecurityException e)
725 {
726 if( log.isTraceEnabled() )
727 log.trace("Excluded domain due to security: "+domain);
728 }
729 }
730 domains = new String[tmp.size()];
731 tmp.toArray(domains);
732 }
733 return domains;
734 }
735
736 /**
737 * Adds a listener to a registered MBean.
738 *
739 * A notification emitted by the MBean will be forwarded by the MBeanServer to the listener.
740 * If the source of the notification is a reference to the MBean object, the MBean server will replace
741 * it by the MBean's ObjectName. Otherwise the source is unchanged.
742 */
743 public void addNotificationListener(ObjectName name, NotificationListener listener, NotificationFilter filter, Object handback)
744 throws InstanceNotFoundException
745 {
746 MBeanEntry entry = registry.get(name);
747 if (NotificationBroadcaster.class.isInstance(entry.getResourceInstance()) == false)
748 throw new RuntimeOperationsException(new IllegalArgumentException("The MBean " + name + " exists but does not implement the NotificationBroadcaster interface."));
749
750 if (listener == null)
751 throw new RuntimeOperationsException(new IllegalArgumentException("Cannot add null listener"));
752
753 checkMBeanPermission(entry.getResourceClassName(), null, name,
754 "addNotificationListener");
755
756 ClassLoader newTCL = entry.getClassLoader();
757 NotificationBroadcaster broadcaster = entry.getInvoker();
758
759 ClassLoader oldTCL = TCLAction.UTIL.getContextClassLoader();
760 final boolean setCl = newTCL != oldTCL && newTCL != null;
761 try
762 {
763 if (setCl)
764 TCLAction.UTIL.setContextClassLoader(newTCL);
765
766 listeners.add(entry.getObjectName(), broadcaster, listener, filter, handback);
767 }
768 finally
769 {
770 if (setCl)
771 TCLAction.UTIL.setContextClassLoader(oldTCL);
772 }
773 }
774
775 /**
776 * Adds a listener to a registered MBean.
777 *
778 * A notification emitted by the MBean will be forwarded by the MBeanServer to the listener.
779 * If the source of the notification is a reference to the MBean object, the MBean server will replace
780 * it by the MBean's ObjectName. Otherwise the source is unchanged.
781 *
782 * The listener object that receives notifications is the one that is registered with the given name at the time this
783 * method is called. Even if it is subsequently unregistered, it will continue to receive notifications.
784 */
785 public void addNotificationListener(ObjectName name, ObjectName listener, NotificationFilter filter, Object handback)
786 throws InstanceNotFoundException
787 {
788 MBeanEntry entry = registry.get(name);
789 if (NotificationBroadcaster.class.isInstance(entry.getResourceInstance()) == false)
790 throw new RuntimeOperationsException(new IllegalArgumentException("The MBean " + name + " exists but does not implement the NotificationBroadcaster interface."));
791
792 MBeanEntry listenerEntry = registry.get(listener);
793 if (NotificationListener.class.isInstance(listenerEntry.getResourceInstance()) == false)
794 throw new RuntimeOperationsException(new IllegalArgumentException("The MBean " + listener + " exists but does not implement the NotificationListener interface."));
795
796 checkMBeanPermission(entry.getResourceClassName(), null, name,
797 "addNotificationListener");
798
799 ClassLoader newTCL = entry.getClassLoader();
800 NotificationBroadcaster broadcaster = entry.getInvoker();
801
802 ClassLoader oldTCL = TCLAction.UTIL.getContextClassLoader();
803 final boolean setCl = newTCL != oldTCL && newTCL != null;
804 try
805 {
806 if (setCl)
807 TCLAction.UTIL.setContextClassLoader(newTCL);
808
809 listeners.add(entry.getObjectName(), broadcaster,
810 (NotificationListener) registry.get(listener).getResourceInstance(), filter, handback);
811 }
812 finally
813 {
814 if (setCl)
815 TCLAction.UTIL.setContextClassLoader(oldTCL);
816 }
817 }
818
819 /**
820 * Removes a listener from a registered MBean.
821 *
822 * If the listener is registered more than once, perhaps with different filters or callbacks,
823 * this method will remove all those registrations.
824 */
825 public void removeNotificationListener(ObjectName name, NotificationListener listener)
826 throws InstanceNotFoundException, ListenerNotFoundException
827 {
828 MBeanEntry entry = registry.get(name);
829 if (NotificationBroadcaster.class.isInstance(entry.getResourceInstance()) == false)
830 throw new RuntimeOperationsException(new IllegalArgumentException("The MBean " + name + " exists but does not implement the NotificationBroadcaster interface."));
831
832 checkMBeanPermission(entry.getResourceClassName(), null, name,
833 "removeNotificationListener");
834
835 ClassLoader newTCL = entry.getClassLoader();
836
837 ClassLoader oldTCL = TCLAction.UTIL.getContextClassLoader();
838 final boolean setCl = newTCL != oldTCL && newTCL != null;
839 try
840 {
841 if (setCl)
842 TCLAction.UTIL.setContextClassLoader(newTCL);
843
844 listeners.remove(entry.getObjectName(), listener);
845 }
846 finally
847 {
848 if (setCl)
849 TCLAction.UTIL.setContextClassLoader(oldTCL);
850 }
851 }
852
853 /**
854 * Removes a listener from a registered MBean.
855 *
856 * If the listener is registered more than once, perhaps with different filters or callbacks,
857 * this method will remove all those registrations.
858 */
859 public void removeNotificationListener(ObjectName name, ObjectName listener)
860 throws InstanceNotFoundException, ListenerNotFoundException
861 {
862 MBeanEntry entry = registry.get(name);
863 if (NotificationBroadcaster.class.isInstance(entry.getResourceInstance()) == false)
864 throw new RuntimeOperationsException(new IllegalArgumentException("The MBean " + name + " exists but does not implement the NotificationBroadcaster interface."));
865
866 MBeanEntry listenerEntry = registry.get(listener);
867 if (NotificationListener.class.isInstance(listenerEntry.getResourceInstance()) == false)
868 throw new RuntimeOperationsException(new IllegalArgumentException("The MBean " + listener + " exists but does not implement the NotificationListener interface."));
869
870 checkMBeanPermission(entry.getResourceClassName(), null, name,
871 "removeNotificationListener");
872
873 ClassLoader newTCL = entry.getClassLoader();
874
875 ClassLoader oldTCL = TCLAction.UTIL.getContextClassLoader();
876 final boolean setCl = newTCL != oldTCL && newTCL != null;
877 try
878 {
879 if (setCl)
880 TCLAction.UTIL.setContextClassLoader(newTCL);
881
882 listeners.remove(entry.getObjectName(), (NotificationListener) registry.get(listener).getResourceInstance());
883 }
884 finally
885 {
886 if (setCl)
887 TCLAction.UTIL.setContextClassLoader(oldTCL);
888 }
889 }
890
891 /**
892 * Removes a listener from a registered MBean.
893 *
894 * The MBean must have a listener that exactly matches the given listener, filter, and handback parameters.
895 * If there is more than one such listener, only one is removed.
896 *
897 * The filter and handback parameters may be null if and only if they are null in a listener to be removed.
898 */
899 public void removeNotificationListener(ObjectName name,
900 NotificationListener listener, NotificationFilter filter, Object handback)
901 throws InstanceNotFoundException, ListenerNotFoundException
902 {
903 MBeanEntry entry = registry.get(name);
904 if (NotificationBroadcaster.class.isInstance(entry.getResourceInstance()) == false)
905 throw new RuntimeOperationsException(new IllegalArgumentException("The MBean " + name + " exists but does not implement the NotificationBroadcaster interface."));
906
907 checkMBeanPermission(entry.getResourceClassName(), null, name,
908 "removeNotificationListener");
909
910 ClassLoader newTCL = entry.getClassLoader();
911
912 ClassLoader oldTCL = TCLAction.UTIL.getContextClassLoader();
913 final boolean setCl = newTCL != oldTCL && newTCL != null;
914 try
915 {
916 if (setCl)
917 TCLAction.UTIL.setContextClassLoader(newTCL);
918
919 listeners.remove(entry.getObjectName(), listener, filter, handback);
920 }
921 finally
922 {
923 if (setCl)
924 TCLAction.UTIL.setContextClassLoader(oldTCL);
925 }
926 }
927
928 /**
929 * Removes a listener from a registered MBean.
930 *
931 * The MBean must have a listener that exactly matches the given listener, filter, and handback parameters.
932 * If there is more than one such listener, only one is removed.
933 *
934 * The filter and handback parameters may be null if and only if they are null in a listener to be removed.
935 */
936 public void removeNotificationListener(ObjectName name, ObjectName listener,
937 NotificationFilter filter, Object handback)
938 throws InstanceNotFoundException, ListenerNotFoundException
939 {
940 MBeanEntry entry = registry.get(name);
941 if (NotificationBroadcaster.class.isInstance(entry.getResourceInstance()) == false)
942 throw new RuntimeOperationsException(new IllegalArgumentException("The MBean " + name + " exists but does not implement the NotificationBroadcaster interface."));
943
944 MBeanEntry listenerEntry = registry.get(listener);
945 if (NotificationListener.class.isInstance(listenerEntry.getResourceInstance()) == false)
946 throw new RuntimeOperationsException(new IllegalArgumentException("The MBean " + listener + " exists but does not implement the NotificationListener interface."));
947
948 checkMBeanPermission(entry.getResourceClassName(), null, name,
949 "removeNotificationListener");
950
951 ClassLoader newTCL = entry.getClassLoader();
952
953 ClassLoader oldTCL = TCLAction.UTIL.getContextClassLoader();
954 final boolean setCl = newTCL != oldTCL && newTCL != null;
955 try
956 {
957 if (setCl)
958 TCLAction.UTIL.setContextClassLoader(newTCL);
959
960 listeners.remove(entry.getObjectName(), (NotificationListener) registry.get(listener).getResourceInstance(),
961 filter, handback);
962 }
963 finally
964 {
965 if (setCl)
966 TCLAction.UTIL.setContextClassLoader(oldTCL);
967 }
968 }
969
970 public boolean isInstanceOf(ObjectName name, String className)
971 throws InstanceNotFoundException
972 {
973 // Get the MBean's class name
974 MBeanEntry entry = registry.get(name);
975 String mbeanClassName = entry.getResourceClassName();
976 checkMBeanPermission(mbeanClassName, null, name, "isInstanceOf");
977
978 // The names are the same
979 if (className.equals(mbeanClassName))
980 return true;
981
982 // Try to load both classes
983 Class mbeanClass = null;
984 Class testClass = null;
985 ClassLoader cl = getClassLoaderFor(name);
986 try
987 {
988 mbeanClass = cl.loadClass(mbeanClassName);
989 testClass = cl.loadClass(className);
990 }
991 catch (ClassNotFoundException e)
992 {
993 return false;
994 }
995
996 // Check whether it is assignable
997 if (testClass.isAssignableFrom(mbeanClass))
998 return true;
999 else
1000 return false;
1001 }
1002
1003 /**
1004 * @deprecated
1005 */
1006 public ObjectInputStream deserialize(ObjectName name, byte[] data) throws InstanceNotFoundException, OperationsException
1007 {
1008 try
1009 {
1010 ClassLoader cl = this.getClassLoaderFor(name);
1011 return new ObjectInputStreamWithClassLoader(new ByteArrayInputStream(data), cl);
1012 }
1013 catch (IOException e)
1014 {
1015 throw new OperationsException("I/O exception deserializing: " + e.getMessage());
1016 }
1017 }
1018
1019 /**
1020 * @deprecated
1021 */
1022 public ObjectInputStream deserialize(String className, byte[] data)
1023 throws OperationsException, ReflectionException
1024 {
1025 try
1026 {
1027 Class c = this.getClassLoaderRepository().loadClass(className);
1028 ClassLoader cl = c.getClassLoader();
1029 return new ObjectInputStreamWithClassLoader(new ByteArrayInputStream(data), cl);
1030 }
1031 catch (IOException e)
1032 {
1033 throw new OperationsException("I/O exception deserializing: " + e.getMessage());
1034 }
1035 catch (ClassNotFoundException e)
1036 {
1037 throw new ReflectionException(e, "Class not found from default repository: " + className);
1038 }
1039 }
1040
1041 /**
1042 * @deprecated
1043 */
1044 public ObjectInputStream deserialize(String className, ObjectName loaderName,
1045 byte[] data)
1046 throws InstanceNotFoundException, OperationsException, ReflectionException
1047 {
1048 try
1049 {
1050 ClassLoader cl = this.getClassLoader(loaderName);
1051 return new ObjectInputStreamWithClassLoader(new ByteArrayInputStream(data), cl);
1052 }
1053 catch (IOException e)
1054 {
1055 throw new OperationsException("I/O exception deserializing: " + e.getMessage());
1056 }
1057 }
1058
1059 public ClassLoader getClassLoaderFor(ObjectName name)
1060 throws InstanceNotFoundException
1061 {
1062 MBeanEntry entry = registry.get(name);
1063 checkMBeanPermission(entry.getResourceClassName(), null, name,
1064 "getClassLoaderFor");
1065
1066 ClassLoader cl = entry.getClassLoader();
1067 if (cl == null)
1068 cl = entry.getResourceInstance().getClass().getClassLoader();
1069 if (cl == null)
1070 cl = ClassLoader.getSystemClassLoader();
1071 return cl;
1072 }
1073
1074 /**
1075 *
1076 * @param name The ObjectName of the ClassLoader. May be null, in which case
1077 * the MBean server's own ClassLoader is returned.
1078 * @return
1079 * @throws InstanceNotFoundException
1080 */
1081 public ClassLoader getClassLoader(ObjectName name)
1082 throws InstanceNotFoundException
1083 {
1084 Object loader = null;
1085 if( name == null )
1086 {
1087 checkMBeanPermission(null, null, name, "getClassLoader");
1088 loader = getClass().getClassLoader();
1089 if (loader == null)
1090 loader = ClassLoader.getSystemClassLoader();
1091 }
1092 else
1093 {
1094 MBeanEntry entry = registry.get(name);
1095 checkMBeanPermission(entry.getResourceClassName(), null, name,
1096 "getClassLoader");
1097 loader = entry.getResourceInstance();
1098 }
1099
1100 if ((loader instanceof ClassLoader) == false)
1101 throw new InstanceNotFoundException("Not a classloader " + name);
1102 return (ClassLoader) loader;
1103 }
1104
1105 /**
1106 * Retrieve the classloader repository for this mbean server
1107 *
1108 * @return the classloader repository
1109 */
1110 public ClassLoaderRepository getClassLoaderRepository()
1111 {
1112 checkMBeanPermission(null, null, null, "getClassLoaderRepository");
1113
1114 // we don't need to synchronize, because this is the first thing we do in the constructor
1115 if (classLoaderRepository == null)
1116 {
1117 ClassLoader cl = Thread.currentThread().getContextClassLoader();
1118 String className = PropertyAccess.getProperty(LOADER_REPOSITORY_CLASS_PROPERTY, DEFAULT_LOADER_REPOSITORY_CLASS);
1119 PropertyAccess.setProperty(LOADER_REPOSITORY_CLASS_PROPERTY, className);
1120
1121 try
1122 {
1123 Class repository = cl.loadClass(className);
1124 classLoaderRepository = (LoaderRepository) repository.newInstance();
1125 }
1126 catch (ClassNotFoundException e)
1127 {
1128 throw new Error("Cannot instantiate loader repository class: " + className);
1129 }
1130 catch (ClassCastException e)
1131 {
1132 throw new Error("Loader repository is not an instance of LoaderRepository: " + className);
1133 }
1134 catch (Exception e)
1135 {
1136 throw new Error("Error creating loader repository: " + e);
1137 }
1138 }
1139
1140 return classLoaderRepository;
1141 }
1142
1143
1144 public void releaseServer()
1145 {
1146 // shutdown the loader repository
1147 // try
1148 // {
1149 // invoke(new ObjectName(DEFAULT_LOADER_NAME),
1150 // "releaseLoaderRepository",
1151 // new Object[0],
1152 // new String[0] );
1153 // }
1154 // catch (Exception e)
1155 // {
1156 // log.error("Unable to shutdown loader repository");
1157 // e.printStackTrace();
1158 // }
1159
1160 registry.releaseRegistry();
1161 listeners.removeAll();
1162 listeners = null;
1163 registry = null;
1164 }
1165
1166
1167 // Protected -----------------------------------------------------
1168
1169 /**
1170 * Instantiate an object, the passed classloader is set as the
1171 * thread's context classloader for the duration of this method.
1172 *
1173 * @param className the class name of the object to instantiate
1174 * @param cl the thread classloader, pass null to use the ClassLoaderRepository
1175 * @param params the parameters for the constructor
1176 * @param signature the signature of the constructor
1177 * @exception ReflectionException wraps a ClassCastException or
1178 * any Exception trying to invoke the constructor
1179 * @exception MBeanException wraps any exception thrown by the constructor
1180 * @exception RuntimeOperationsException Wraps an IllegalArgument for a
1181 * null className
1182 */
1183 protected Object instantiate(String className, ClassLoader cl, Object[] params, String[] signature)
1184 throws ReflectionException, MBeanException
1185 {
1186 if (className == null)
1187 throw new RuntimeOperationsException(new IllegalArgumentException("Null className"));
1188
1189 if (className.equals(""))
1190 throw new ReflectionException(new ClassNotFoundException("empty class name"));
1191
1192 if (params == null)
1193 params = NOPARAMS;
1194
1195 if (signature == null)
1196 signature = NOSIG;
1197
1198 checkMBeanPermission(className, null, null, "instantiate");
1199
1200 ClassLoader oldTCL = TCLAction.UTIL.getContextClassLoader();
1201
1202 boolean setCl = false;
1203 try
1204 {
1205 Class clazz = null;
1206 if (cl != null)
1207 {
1208 if (cl != oldTCL)
1209 {
1210 setCl = true;
1211 TCLAction.UTIL.setContextClassLoader(cl);
1212 }
1213 clazz = cl.loadClass(className);
1214 }
1215 else
1216 clazz = classLoaderRepository.loadClass(className);
1217
1218 Class[] sign = new Class[signature.length];
1219 for (int i = 0; i < signature.length; ++i)
1220 {
1221 if (LoaderRepository.getNativeClassForName(signature[i]) == null)
1222 {
1223 try
1224 {
1225 if (cl != null)
1226 sign[i] = cl.loadClass(signature[i]);
1227 else
1228 sign[i] = classLoaderRepository.loadClass(signature[i]);
1229 }
1230 catch (ClassNotFoundException e)
1231 {
1232 throw new ReflectionException(e, "Constructor parameter class not found: " + signature[i]);
1233 }
1234 }
1235 else
1236 {
1237 sign[i] = LoaderRepository.getNativeClassForName(signature[i]);
1238 }
1239 }
1240
1241 Constructor constructor = clazz.getConstructor(sign);
1242 return constructor.newInstance(params);
1243 }
1244 catch (Throwable t)
1245 {
1246 handleInstantiateExceptions(t, className);
1247 log.error("Unhandled exception instantiating class: " + className, t);
1248 return null;
1249 }
1250 finally
1251 {
1252 if (setCl)
1253 TCLAction.UTIL.setContextClassLoader(oldTCL);
1254 }
1255 }
1256
1257 /**
1258 * Handles errors thrown during class instantiation
1259 */
1260 protected void handleInstantiateExceptions(Throwable t, String className)
1261 throws ReflectionException, MBeanException
1262 {
1263 if (t instanceof ReflectionException)
1264 throw (ReflectionException) t;
1265
1266 else if (t instanceof ClassNotFoundException)
1267 throw new ReflectionException((Exception) t, "Class not found: " + className);
1268
1269 else if (t instanceof InstantiationException)
1270 throw new ReflectionException((Exception) t, "Cannot instantiate: " + className);
1271
1272 else if (t instanceof IllegalAccessException)
1273 throw new ReflectionException((Exception) t, "Illegal access to constructor: " + className);
1274
1275 else if (t instanceof NoSuchMethodException)
1276 throw new ReflectionException((Exception) t, "Cannot find such a public constructor: " + className);
1277
1278 else if (t instanceof SecurityException)
1279 throw new ReflectionException((Exception) t, "Can't access constructor for " + className);
1280
1281 else if (t instanceof InvocationTargetException)
1282 {
1283 Throwable root = ((InvocationTargetException) t).getTargetException();
1284
1285 if (root instanceof RuntimeException)
1286 throw new RuntimeMBeanException((RuntimeException) root, className + " constructor has thrown an exception: " + root.toString());
1287 else if (root instanceof Error)
1288 throw new RuntimeErrorException((Error) root, className + " constructor has thrown an error: " + root.toString());
1289 else if (root instanceof Exception)
1290 throw new MBeanException((Exception) root, className + " constructor has thrown an exception: " + root.toString());
1291
1292 throw new Error("Something went wrong with handling the exception from " + className + " default constructor.");
1293 }
1294
1295 else if (t instanceof ExceptionInInitializerError)
1296 {
1297 Throwable root = ((ExceptionInInitializerError) t).getException();
1298
1299 // the root cause can be only a runtime exception
1300 if (root instanceof RuntimeException)
1301 throw new RuntimeMBeanException((RuntimeException) root, "Exception in class " + className + " static initializer: " + root.toString());
1302 else
1303 // shouldn't get here
1304 throw new Error("ERROR: it turns out the root cause is not always a runtime exception!");
1305 }
1306
1307 else if (t instanceof IllegalArgumentException)
1308 {
1309 // if mismatch between constructor instance args and supplied args -- shouldn't happen
1310 throw new Error("Error in the server: mismatch between expected constructor arguments and supplied arguments.");
1311 }
1312
1313 else if (t instanceof Error)
1314 {
1315 throw new RuntimeErrorException((Error) t, "instantiating " + className + " failed: " + t.toString());
1316 }
1317 }
1318
1319
1320 /**
1321 * Register an MBean<p>
1322 *
1323 * The classloader is used as the thread context classloader during
1324 * access to the mbean and it's interceptors
1325 *
1326 * @param mbean the mbean to register
1327 * @param name the object name to register
1328 * @param loaderName the object name of a class loader also used as
1329 * as the MBeans TCL
1330 * @exception InstanceAlreadyExistsException when already registered
1331 * @exception MBeanRegistrationException when
1332 * preRegister(MBeanServer, ObjectName) throws an exception
1333 * @exception NotCompliantMBeanException when the object is not an MBean
1334 */
1335 protected ObjectInstance registerMBean(Object mbean, ObjectName name, ObjectName loaderName)
1336 throws ReflectionException, InstanceAlreadyExistsException, MBeanRegistrationException, MBeanException, NotCompliantMBeanException, InstanceNotFoundException
1337 {
1338 ClassLoader cl = null;
1339
1340 // If the loader name is null, the ClassLoader that loaded the MBean Server will be used.
1341 if (loaderName == null)
1342 {
1343 cl = getClass().getClassLoader();
1344 if (cl == null)
1345 cl = ClassLoader.getSystemClassLoader();
1346 }
1347 else
1348 {
1349 try
1350 {
1351 cl = (ClassLoader) registry.get(loaderName).getResourceInstance();
1352 }
1353 catch (ClassCastException e)
1354 {
1355 throw new ReflectionException(e, loaderName + " is not a class loader.");
1356 }
1357 }
1358
1359 return registerMBean(mbean, name, cl);
1360 }
1361
1362 /**
1363 * Register an MBean<p>
1364 *
1365 * The classloader is used as the thread context classloader during
1366 * access to the mbean and it's interceptors
1367 *
1368 * @param object the mbean to register
1369 * @param name the object name to register
1370 * @param cl the thread classloader, pass null for the current one
1371 * @exception InstanceAlreadyExistsException when already registered
1372 * @exception MBeanRegistrationException when
1373 * preRegister(MBeanServer, ObjectName) throws an exception
1374 * @exception NotCompliantMBeanException when the object is not an MBean
1375 */
1376 protected ObjectInstance registerMBean(Object object, ObjectName name,
1377 ClassLoader cl)
1378 throws InstanceAlreadyExistsException,
1379 MBeanRegistrationException,
1380 NotCompliantMBeanException
1381 {
1382 final Class objectClass = object.getClass();
1383 String className = objectClass.getName();
1384
1385 // Check that the caller has the ability to create/register mbeans
1386 checkMBeanPermission(className, null, name, "registerMBean");
1387
1388 // Check that the mbean class is from a trusted source
1389 if( System.getSecurityManager() != null )
1390 {
1391 ProtectionDomain pd = (ProtectionDomain) AccessController.doPrivileged(
1392 new PrivilegedAction()
1393 {
1394 public Object run()
1395 {
1396 return objectClass.getProtectionDomain();
1397 }
1398 }
1399 );
1400 if( pd != null )
1401 {
1402 MBeanTrustPermission p = new MBeanTrustPermission("register");
1403 if( pd.implies(p) == false )
1404 {
1405 String msg = "MBeanTrustPermission(register) not implied by "
1406 + "protection domain of mbean class: "+className+", pd: "+pd;
1407 throw new SecurityException(msg);
1408 }
1409 }
1410 }
1411
1412 HashMap valueMap = null;
1413 if (cl != null)
1414 {
1415 valueMap = new HashMap();
1416 valueMap.put(CLASSLOADER, cl);
1417 }
1418
1419 try
1420 {
1421 final Object[] args = {object, name, valueMap};
1422 final String[] sig = {Object.class.getName(),
1423 ObjectName.class.getName(), Map.class.getName()};
1424 try
1425 {
1426 ObjectInstance oi = (ObjectInstance) AccessController.doPrivileged(
1427 new PrivilegedExceptionAction()
1428 {
1429 public Object run() throws Exception
1430 {
1431 return invoke(new ObjectName(MBEAN_REGISTRY),
1432 "registerMBean", args, sig);
1433 }
1434 }
1435 );
1436 return oi;
1437 }
1438 catch(PrivilegedActionException e)
1439 {
1440 throw e.getException();
1441 }
1442 }
1443 catch (Throwable t)
1444 {
1445 Throwable result = JMXExceptionDecoder.decodeToJMXException(t);
1446 if (result instanceof InstanceAlreadyExistsException)
1447 throw (InstanceAlreadyExistsException) result;
1448 if (result instanceof MBeanRegistrationException)
1449 throw (MBeanRegistrationException) result;
1450 if (result instanceof NotCompliantMBeanException)
1451 throw (NotCompliantMBeanException) result;
1452 if ( result instanceof JMRuntimeException )
1453 throw (JMRuntimeException) result;
1454 if (result instanceof MBeanException)
1455 {
1456 MBeanException e = (MBeanException) result;
1457 t = e.getTargetException();
1458 if (t instanceof InstanceAlreadyExistsException)
1459 throw (InstanceAlreadyExistsException) t;
1460 if (t instanceof MBeanRegistrationException)
1461 throw (MBeanRegistrationException) t;
1462 if (t instanceof NotCompliantMBeanException)
1463 throw (NotCompliantMBeanException) t;
1464 }
1465 if (result instanceof RuntimeException)
1466 throw new RuntimeMBeanException((RuntimeException) result);
1467 if (result instanceof Error)
1468 throw new RuntimeErrorException((Error) result);
1469
1470 // for some other reason, registration failed
1471 throw new MBeanRegistrationException(new InvocationTargetException(t), "Cannot register MBean");
1472 }
1473 }
1474
1475 // Private -------------------------------------------------------
1476
1477 /**
1478 * Query an MBean against the query
1479 *
1480 * @param objectName the object name of the mbean to check
1481 * @param queryExp the query expression to test
1482 * @return true when the query applies to the MBean or the query is null,
1483 * false otherwise.
1484 */
1485 protected boolean queryMBean(ObjectName objectName, QueryExp queryExp)
1486 {
1487 if (queryExp == null)
1488 return true;
1489
1490 try
1491 {
1492 return queryExp.apply(objectName);
1493 }
1494 catch (Exception e)
1495 {
1496 return false;
1497 }
1498 }
1499
1500
1501 protected MBeanRegistry createRegistry(String defaultDomain)
1502 {
1503 // Find the registry implementation class: can be configured via
1504 // MBEAN_REGISTRY_CLASS_PROPERTY by the client -- if not found use
1505 // the class defined in DEFAULT_MBEAN_REGISTRY_CLASS (see ServerConstants)
1506 String registryClass = PropertyAccess.getProperty(ServerConstants.MBEAN_REGISTRY_CLASS_PROPERTY,
1507 ServerConstants.DEFAULT_MBEAN_REGISTRY_CLASS);
1508
1509 try
1510 {
1511 // Try loading registry class via thread context classloader
1512 ClassLoader cl = Thread.currentThread().getContextClassLoader();
1513 Class clazz = cl.loadClass(registryClass);
1514
1515 // retrieve the constructor <init>(MBeanServer srvr, String defaultDomain, ClassLoaderRepository clr)
1516 Constructor constructor = clazz.getConstructor(new Class[] {MBeanServer.class, String.class, ClassLoaderRepository.class});
1517
1518 // instantiate registry
1519 return (MBeanRegistry) constructor.newInstance(new Object[] {outer, defaultDomain, classLoaderRepository});
1520 }
1521 // Any exception preventing the registry to be created will cause the agent to fail.
1522 // However, try to give detailed exception messages to indicate config errors.
1523 catch (ClassNotFoundException e)
1524 {
1525 throw new NestedRuntimeException("The MBean registry implementation class " + registryClass +
1526 " was not found: ", e);
1527 }
1528 catch (NoSuchMethodException e)
1529 {
1530 throw new NestedRuntimeException("The MBean registry implementation class " + registryClass +
1531 " must contain a default <init>(MBeanServer srvr, String domain) " +
1532 " constructor.", e);
1533 }
1534 catch (InstantiationException e)
1535 {
1536 throw new NestedRuntimeException("Cannot instantiate class " + registryClass + ": ", e);
1537 }
1538 catch (IllegalAccessException e)
1539 {
1540 throw new NestedRuntimeException("Unable to create the MBean registry instance. Illegal access " +
1541 "to class " + registryClass + " constructor: ", e);
1542 }
1543 catch (InvocationTargetException e)
1544 {
1545 throw new NestedRuntimeException("Unable to create the MBean registry instance. Class " + registryClass +
1546 " has raised an exception in constructor: ", e.getTargetException());
1547 }
1548 }
1549
1550
1551 // Private -------------------------------------------------------
1552
1553 // FIXME: externalize this
1554 private ModelMBeanInfo getRegistryManagementInterface()
1555 {
1556 final boolean READABLE = true;
1557 final boolean WRITABLE = true;
1558 final boolean BOOLEAN = true;
1559
1560 // Default Domain attribute
1561 DescriptorSupport descDefaultDomain = new DescriptorSupport();
1562 descDefaultDomain.setField("name", "DefaultDomain");
1563 descDefaultDomain.setField("descriptorType", "attribute");
1564 descDefaultDomain.setField("displayName", "Default Domain");
1565 descDefaultDomain.setField("default", getDefaultDomain());
1566 descDefaultDomain.setField("currencyTimeLimit", "-1");
1567 ModelMBeanAttributeInfo defaultDomainInfo =
1568 new ModelMBeanAttributeInfo
1569 ("DefaultDomain", String.class.getName(),
1570 "The domain to use when an object name has no domain",
1571 READABLE, !WRITABLE, !BOOLEAN,
1572 descDefaultDomain);
1573
1574 // Size attribute
1575 DescriptorSupport descSize = new DescriptorSupport();
1576 descSize.setField("name", "Size");
1577 descSize.setField("descriptorType", "attribute");
1578 descSize.setField("displayName", "Size");
1579 descSize.setField("getMethod", "getSize");
1580 ModelMBeanAttributeInfo sizeInfo =
1581 new ModelMBeanAttributeInfo
1582 ("Size", Integer.TYPE.getName(),
1583 "The number of MBeans registered in the MBean Server",
1584 READABLE, !WRITABLE, !BOOLEAN,
1585 descSize);
1586
1587 // registerMBean operation
1588 DescriptorSupport descRegisterMBean = new DescriptorSupport();
1589 descRegisterMBean.setField("name", "registerMBean");
1590 descRegisterMBean.setField("descriptorType", "operation");
1591 descRegisterMBean.setField("role", "operation");
1592 MBeanParameterInfo[] registerMBeanParms =
1593 new MBeanParameterInfo[]
1594 {
1595 new MBeanParameterInfo
1596 ("Resource",
1597 Object.class.getName(),
1598 "A compliant MBean to be registered in the MBean Server"),
1599 new MBeanParameterInfo
1600 ("ObjectName",
1601 ObjectName.class.getName(),
1602 "The object name of the MBean"),
1603 new MBeanParameterInfo
1604 ("ValueMap",
1605 Map.class.getName(),
1606 "Values associated with the registration"),
1607 };
1608 ModelMBeanOperationInfo registerMBeanInfo =
1609 new ModelMBeanOperationInfo
1610 ("registerMBean",
1611 "Adds an MBean in the MBeanServer",
1612 registerMBeanParms,
1613 ObjectInstance.class.getName(),
1614 ModelMBeanOperationInfo.ACTION_INFO,
1615 descRegisterMBean);
1616
1617 // unregisterMBean operation
1618 DescriptorSupport descUnregisterMBean = new DescriptorSupport();
1619 descUnregisterMBean.setField("name", "unregisterMBean");
1620 descUnregisterMBean.setField("descriptorType", "operation");
1621 descUnregisterMBean.setField("role", "operation");
1622 MBeanParameterInfo[] unregisterMBeanParms =
1623 new MBeanParameterInfo[]
1624 {
1625 new MBeanParameterInfo
1626 ("ObjectName",
1627 ObjectName.class.getName(),
1628 "The object name of the MBean to remove")
1629 };
1630 ModelMBeanOperationInfo unregisterMBeanInfo =
1631 new ModelMBeanOperationInfo
1632 ("unregisterMBean",
1633 "Removes an MBean from the MBeanServer",
1634 unregisterMBeanParms,
1635 Void.TYPE.getName(),
1636 ModelMBeanOperationInfo.ACTION,
1637 descUnregisterMBean);
1638
1639 // getSize operation
1640 DescriptorSupport descGetSize = new DescriptorSupport();
1641 descGetSize.setField("name", "getSize");
1642 descGetSize.setField("descriptorType", "operation");
1643 descGetSize.setField("role", "getter");
1644 MBeanParameterInfo[] getSizeParms = new MBeanParameterInfo[0];
1645 ModelMBeanOperationInfo getSizeInfo =
1646 new ModelMBeanOperationInfo
1647 ("getSize",
1648 "Gets the number of MBeans registered",
1649 getSizeParms,
1650 Integer.TYPE.getName(),
1651 ModelMBeanOperationInfo.INFO,
1652 descGetSize);
1653
1654 // get operation
1655 DescriptorSupport descGet = new DescriptorSupport();
1656 descGet.setField("name", "get");
1657 descGet.setField("descriptorType", "operation");
1658 descGet.setField("role", "operation");
1659 MBeanParameterInfo[] getParam = new MBeanParameterInfo[1];
1660 getParam[0] = new MBeanParameterInfo("ObjectName", ObjectName.class.getName(), "object name to find");
1661 ModelMBeanOperationInfo getInfo =
1662 new ModelMBeanOperationInfo
1663 ("get",
1664 "Gets the MBeanEntry for a given ObjectName",
1665 getParam,
1666 MBeanEntry.class.getName(),
1667 ModelMBeanOperationInfo.INFO,
1668 descGet);
1669
1670 // getValue operation
1671 DescriptorSupport descGetValue = new DescriptorSupport();
1672 descGetValue.setField("name", "getValue");
1673 descGetValue.setField("descriptorType", "operation");
1674 descGetValue.setField("role", "operation");
1675 MBeanParameterInfo[] getValueParms = new MBeanParameterInfo[]
1676 {
1677 new MBeanParameterInfo
1678 ("ObjectName",
1679 ObjectName.class.getName(),
1680 "The object name of the registered MBean"),
1681 new MBeanParameterInfo
1682 ("Key",
1683 String.class.getName(),
1684 "The key to the value stored")
1685 };
1686 ModelMBeanOperationInfo getValueInfo =
1687 new ModelMBeanOperationInfo
1688 ("getValue",
1689 "Get a value stored in the MBean's registration",
1690 getValueParms,
1691 Object.class.getName(),
1692 ModelMBeanOperationInfo.INFO,
1693 descGetValue);
1694
1695 // Construct the modelmbean
1696 DescriptorSupport descMBean = new DescriptorSupport();
1697 descMBean.setField("name", RequiredModelMBeanInstantiator.getClassName());
1698 descMBean.setField("descriptorType", "MBean");
1699 descMBean.setField("displayName", "MBeanServer Registry");
1700 ModelMBeanAttributeInfo[] attrInfo = new ModelMBeanAttributeInfo[]
1701 {
1702 defaultDomainInfo,
1703 sizeInfo
1704 };
1705 ModelMBeanConstructorInfo[] ctorInfo = null;
1706 ModelMBeanOperationInfo[] opInfo = new ModelMBeanOperationInfo[]
1707 {
1708 registerMBeanInfo,
1709 unregisterMBeanInfo,
1710 getSizeInfo,
1711 getValueInfo,
1712 getInfo
1713 };
1714 ModelMBeanNotificationInfo[] notifyInfo = null;
1715 ModelMBeanInfoSupport info = new ModelMBeanInfoSupport
1716 (RequiredModelMBeanInstantiator.getClassName(),
1717 "Managed Bean Registry",
1718 attrInfo,
1719 ctorInfo,
1720 opInfo,
1721 notifyInfo,
1722 descMBean);
1723
1724 return info;
1725 }
1726
1727 private void checkMBeanPermission(String className, String member,
1728 ObjectName objectName, String action)
1729 {
1730 SecurityManager sm = System.getSecurityManager();
1731 if( sm != null )
1732 {
1733 MBeanPermission p = new MBeanPermission(className, member, objectName,
1734 action);
1735 sm.checkPermission(p);
1736 }
1737 }
1738
1739 // Object overrides ----------------------------------------------
1740
1741 /**
1742 * Simple toString() revealing default domain
1743 */
1744 public String toString()
1745 {
1746 return super.toString() + "[ defaultDomain='" + this.getDefaultDomain() + "' ]";
1747 }
1748 }