1 /* 2 * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package com.sun.jmx.interceptor; 27 28 29 // JMX RI 30 import static com.sun.jmx.defaults.JmxProperties.MBEANSERVER_LOGGER; 31 import com.sun.jmx.mbeanserver.DynamicMBean2; 32 import com.sun.jmx.mbeanserver.Introspector; 33 import com.sun.jmx.mbeanserver.MBeanInstantiator; 34 import com.sun.jmx.mbeanserver.ModifiableClassLoaderRepository; 35 import com.sun.jmx.mbeanserver.NamedObject; 36 import com.sun.jmx.mbeanserver.Repository; 37 import com.sun.jmx.mbeanserver.Repository.RegistrationContext; 38 import com.sun.jmx.mbeanserver.Util; 39 import com.sun.jmx.remote.util.EnvHelp; 40 41 import java.io.ObjectInputStream; 42 import java.lang.ref.WeakReference; 43 import java.security.AccessControlContext; 44 import java.security.AccessController; 45 import java.security.Permission; 46 import java.security.PrivilegedAction; 47 import java.security.ProtectionDomain; 48 import java.util.ArrayList; 49 import java.util.HashSet; 50 import java.util.List; 51 import java.util.Set; 52 import java.util.WeakHashMap; 53 import java.util.logging.Level; 54 55 // JMX import 56 import javax.management.Attribute; 57 import javax.management.AttributeList; 58 import javax.management.AttributeNotFoundException; 59 import javax.management.DynamicMBean; 60 import javax.management.InstanceAlreadyExistsException; 61 import javax.management.InstanceNotFoundException; 62 import javax.management.IntrospectionException; 63 import javax.management.InvalidAttributeValueException; 64 import javax.management.JMRuntimeException; 65 import javax.management.ListenerNotFoundException; 66 import javax.management.MBeanException; 67 import javax.management.MBeanInfo; 68 import javax.management.MBeanPermission; 69 import javax.management.MBeanRegistration; 70 import javax.management.MBeanRegistrationException; 71 import javax.management.MBeanServer; 72 import javax.management.MBeanServerDelegate; 73 import javax.management.MBeanServerNotification; 74 import javax.management.MBeanTrustPermission; 75 import javax.management.NotCompliantMBeanException; 76 import javax.management.Notification; 77 import javax.management.NotificationBroadcaster; 78 import javax.management.NotificationEmitter; 79 import javax.management.NotificationFilter; 80 import javax.management.NotificationListener; 81 import javax.management.ObjectInstance; 82 import javax.management.ObjectName; 83 import javax.management.OperationsException; 84 import javax.management.QueryEval; 85 import javax.management.QueryExp; 86 import javax.management.ReflectionException; 87 import javax.management.RuntimeErrorException; 88 import javax.management.RuntimeMBeanException; 89 import javax.management.RuntimeOperationsException; 90 import javax.management.loading.ClassLoaderRepository; 91 92 /** 93 * This is the default class for MBean manipulation on the agent side. It 94 * contains the methods necessary for the creation, registration, and 95 * deletion of MBeans as well as the access methods for registered MBeans. 96 * This is the core component of the JMX infrastructure. 97 * <P> 98 * Every MBean which is added to the MBean server becomes manageable: its attributes and operations 99 * become remotely accessible through the connectors/adaptors connected to that MBean server. 100 * A Java object cannot be registered in the MBean server unless it is a JMX compliant MBean. 101 * <P> 102 * When an MBean is registered or unregistered in the MBean server an 103 * {@link javax.management.MBeanServerNotification MBeanServerNotification} 104 * Notification is emitted. To register an object as listener to MBeanServerNotifications 105 * you should call the MBean server method {@link #addNotificationListener addNotificationListener} with <CODE>ObjectName</CODE> 106 * the <CODE>ObjectName</CODE> of the {@link javax.management.MBeanServerDelegate MBeanServerDelegate}. 107 * This <CODE>ObjectName</CODE> is: 108 * <BR> 109 * <CODE>JMImplementation:type=MBeanServerDelegate</CODE>. 110 * 111 * @since 1.5 112 */ 113 public class DefaultMBeanServerInterceptor implements MBeanServerInterceptor { 114 115 /** The MBeanInstantiator object used by the 116 * DefaultMBeanServerInterceptor */ 117 private final transient MBeanInstantiator instantiator; 118 119 /** The MBean server object that is associated to the 120 * DefaultMBeanServerInterceptor */ 121 private transient MBeanServer server = null; 122 123 /** The MBean server delegate object that is associated to the 124 * DefaultMBeanServerInterceptor */ 125 private final transient MBeanServerDelegate delegate; 126 127 /** The Repository object used by the DefaultMBeanServerInterceptor */ 128 private final transient Repository repository; 129 130 /** Wrappers for client listeners. */ 131 /* See the comment before addNotificationListener below. */ 132 private final transient 133 WeakHashMap<ListenerWrapper, WeakReference<ListenerWrapper>> 134 listenerWrappers = 135 new WeakHashMap<ListenerWrapper, 136 WeakReference<ListenerWrapper>>(); 137 138 /** The default domain of the object names */ 139 private final String domain; 140 141 /** The sequence number identifying the notifications sent */ 142 // Now sequence number is handled by MBeanServerDelegate. 143 // private int sequenceNumber=0; 144 145 /** 146 * Creates a DefaultMBeanServerInterceptor with the specified 147 * repository instance. 148 * <p>Do not forget to call <code>initialize(outer,delegate)</code> 149 * before using this object. 150 * @param outer A pointer to the MBeanServer object that must be 151 * passed to the MBeans when invoking their 152 * {@link javax.management.MBeanRegistration} interface. 153 * @param delegate A pointer to the MBeanServerDelegate associated 154 * with the new MBeanServer. The new MBeanServer must register 155 * this MBean in its MBean repository. 156 * @param instantiator The MBeanInstantiator that will be used to 157 * instantiate MBeans and take care of class loading issues. 158 * @param repository The repository to use for this MBeanServer. 159 */ 160 public DefaultMBeanServerInterceptor(MBeanServer outer, 161 MBeanServerDelegate delegate, 162 MBeanInstantiator instantiator, 163 Repository repository) { 164 if (outer == null) throw new 165 IllegalArgumentException("outer MBeanServer cannot be null"); 166 if (delegate == null) throw new 167 IllegalArgumentException("MBeanServerDelegate cannot be null"); 168 if (instantiator == null) throw new 169 IllegalArgumentException("MBeanInstantiator cannot be null"); 170 if (repository == null) throw new 171 IllegalArgumentException("Repository cannot be null"); 172 173 this.server = outer; 174 this.delegate = delegate; 175 this.instantiator = instantiator; 176 this.repository = repository; 177 this.domain = repository.getDefaultDomain(); 178 } 179 180 public ObjectInstance createMBean(String className, ObjectName name) 181 throws ReflectionException, InstanceAlreadyExistsException, 182 MBeanRegistrationException, MBeanException, 183 NotCompliantMBeanException { 184 185 return createMBean(className, name, (Object[]) null, (String[]) null); 186 187 } 188 189 public ObjectInstance createMBean(String className, ObjectName name, 190 ObjectName loaderName) 191 throws ReflectionException, InstanceAlreadyExistsException, 192 MBeanRegistrationException, MBeanException, 193 NotCompliantMBeanException, InstanceNotFoundException { 194 195 return createMBean(className, name, loaderName, (Object[]) null, 196 (String[]) null); 197 } 198 199 public ObjectInstance createMBean(String className, ObjectName name, 200 Object[] params, String[] signature) 201 throws ReflectionException, InstanceAlreadyExistsException, 202 MBeanRegistrationException, MBeanException, 203 NotCompliantMBeanException { 204 205 try { 206 return createMBean(className, name, null, true, 207 params, signature); 208 } catch (InstanceNotFoundException e) { 209 /* Can only happen if loaderName doesn't exist, but we just 210 passed null, so we shouldn't get this exception. */ 211 throw EnvHelp.initCause( 212 new IllegalArgumentException("Unexpected exception: " + e), e); 213 } 214 } 215 216 public ObjectInstance createMBean(String className, ObjectName name, 217 ObjectName loaderName, 218 Object[] params, String[] signature) 219 throws ReflectionException, InstanceAlreadyExistsException, 220 MBeanRegistrationException, MBeanException, 221 NotCompliantMBeanException, InstanceNotFoundException { 222 223 return createMBean(className, name, loaderName, false, 224 params, signature); 225 } 226 227 private ObjectInstance createMBean(String className, ObjectName name, 228 ObjectName loaderName, 229 boolean withDefaultLoaderRepository, 230 Object[] params, String[] signature) 231 throws ReflectionException, InstanceAlreadyExistsException, 232 MBeanRegistrationException, MBeanException, 233 NotCompliantMBeanException, InstanceNotFoundException { 234 235 Class<?> theClass; 236 237 if (className == null) { 238 final RuntimeException wrapped = 239 new IllegalArgumentException("The class name cannot be null"); 240 throw new RuntimeOperationsException(wrapped, 241 "Exception occurred during MBean creation"); 242 } 243 244 if (name != null) { 245 if (name.isPattern()) { 246 final RuntimeException wrapped = 247 new IllegalArgumentException("Invalid name->" + 248 name.toString()); 249 final String msg = "Exception occurred during MBean creation"; 250 throw new RuntimeOperationsException(wrapped, msg); 251 } 252 253 name = nonDefaultDomain(name); 254 } 255 256 checkMBeanPermission(className, null, null, "instantiate"); 257 checkMBeanPermission(className, null, name, "registerMBean"); 258 259 /* Load the appropriate class. */ 260 if (withDefaultLoaderRepository) { 261 if (MBEANSERVER_LOGGER.isLoggable(Level.FINER)) { 262 MBEANSERVER_LOGGER.logp(Level.FINER, 263 DefaultMBeanServerInterceptor.class.getName(), 264 "createMBean", 265 "ClassName = " + className + ", ObjectName = " + name); 266 } 267 theClass = 268 instantiator.findClassWithDefaultLoaderRepository(className); 269 } else if (loaderName == null) { 270 if (MBEANSERVER_LOGGER.isLoggable(Level.FINER)) { 271 MBEANSERVER_LOGGER.logp(Level.FINER, 272 DefaultMBeanServerInterceptor.class.getName(), 273 "createMBean", "ClassName = " + className + 274 ", ObjectName = " + name + ", Loader name = null"); 275 } 276 277 theClass = instantiator.findClass(className, 278 server.getClass().getClassLoader()); 279 } else { 280 loaderName = nonDefaultDomain(loaderName); 281 282 if (MBEANSERVER_LOGGER.isLoggable(Level.FINER)) { 283 MBEANSERVER_LOGGER.logp(Level.FINER, 284 DefaultMBeanServerInterceptor.class.getName(), 285 "createMBean", "ClassName = " + className + 286 ", ObjectName = " + name + 287 ", Loader name = " + loaderName); 288 } 289 290 theClass = instantiator.findClass(className, loaderName); 291 } 292 293 checkMBeanTrustPermission(theClass); 294 295 // Check that the MBean can be instantiated by the MBeanServer. 296 Introspector.testCreation(theClass); 297 298 // Check the JMX MBean compliance of the class 299 Introspector.checkCompliance(theClass); 300 301 Object moi= instantiator.instantiate(theClass, params, signature, 302 server.getClass().getClassLoader()); 303 304 final String infoClassName = getNewMBeanClassName(moi); 305 306 return registerObject(infoClassName, moi, name); 307 } 308 309 public ObjectInstance registerMBean(Object object, ObjectName name) 310 throws InstanceAlreadyExistsException, MBeanRegistrationException, 311 NotCompliantMBeanException { 312 313 // ------------------------------ 314 // ------------------------------ 315 Class<?> theClass = object.getClass(); 316 317 Introspector.checkCompliance(theClass); 318 319 final String infoClassName = getNewMBeanClassName(object); 320 321 checkMBeanPermission(infoClassName, null, name, "registerMBean"); 322 checkMBeanTrustPermission(theClass); 323 324 return registerObject(infoClassName, object, name); 325 } 326 327 private static String getNewMBeanClassName(Object mbeanToRegister) 328 throws NotCompliantMBeanException { 329 if (mbeanToRegister instanceof DynamicMBean) { 330 DynamicMBean mbean = (DynamicMBean) mbeanToRegister; 331 final String name; 332 try { 333 name = mbean.getMBeanInfo().getClassName(); 334 } catch (Exception e) { 335 // Includes case where getMBeanInfo() returns null 336 NotCompliantMBeanException ncmbe = 337 new NotCompliantMBeanException("Bad getMBeanInfo()"); 338 ncmbe.initCause(e); 339 throw ncmbe; 340 } 341 if (name == null) { 342 final String msg = "MBeanInfo has null class name"; 343 throw new NotCompliantMBeanException(msg); 344 } 345 return name; 346 } else 347 return mbeanToRegister.getClass().getName(); 348 } 349 350 private final Set<ObjectName> beingUnregistered = 351 new HashSet<ObjectName>(); 352 353 public void unregisterMBean(ObjectName name) 354 throws InstanceNotFoundException, MBeanRegistrationException { 355 356 if (name == null) { 357 final RuntimeException wrapped = 358 new IllegalArgumentException("Object name cannot be null"); 359 throw new RuntimeOperationsException(wrapped, 360 "Exception occurred trying to unregister the MBean"); 361 } 362 363 name = nonDefaultDomain(name); 364 365 /* The semantics of preDeregister are tricky. If it throws an 366 exception, then the unregisterMBean fails. This allows an 367 MBean to refuse to be unregistered. If it returns 368 successfully, then the unregisterMBean can proceed. In 369 this case the preDeregister may have cleaned up some state, 370 and will not expect to be called a second time. So if two 371 threads try to unregister the same MBean at the same time 372 then one of them must wait for the other one to either (a) 373 call preDeregister and get an exception or (b) call 374 preDeregister successfully and unregister the MBean. 375 Suppose thread T1 is unregistering an MBean and thread T2 376 is trying to unregister the same MBean, so waiting for T1. 377 Then a deadlock is possible if the preDeregister for T1 378 ends up needing a lock held by T2. Given the semantics 379 just described, there does not seem to be any way to avoid 380 this. This will not happen to code where it is clear for 381 any given MBean what thread may unregister that MBean. 382 383 On the other hand we clearly do not want a thread that is 384 unregistering MBean A to have to wait for another thread 385 that is unregistering another MBean B (see bug 6318664). A 386 deadlock in this situation could reasonably be considered 387 gratuitous. So holding a global lock across the 388 preDeregister call would be bad. 389 390 So we have a set of ObjectNames that some thread is 391 currently unregistering. When a thread wants to unregister 392 a name, it must first check if the name is in the set, and 393 if so it must wait. When a thread successfully unregisters 394 a name it removes the name from the set and notifies any 395 waiting threads that the set has changed. 396 397 This implies that we must be very careful to ensure that 398 the name is removed from the set and waiters notified, no 399 matter what code path is taken. */ 400 401 synchronized (beingUnregistered) { 402 while (beingUnregistered.contains(name)) { 403 try { 404 beingUnregistered.wait(); 405 } catch (InterruptedException e) { 406 throw new MBeanRegistrationException(e, e.toString()); 407 // pretend the exception came from preDeregister; 408 // in another execution sequence it could have 409 } 410 } 411 beingUnregistered.add(name); 412 } 413 414 try { 415 exclusiveUnregisterMBean(name); 416 } finally { 417 synchronized (beingUnregistered) { 418 beingUnregistered.remove(name); 419 beingUnregistered.notifyAll(); 420 } 421 } 422 } 423 424 private void exclusiveUnregisterMBean(ObjectName name) 425 throws InstanceNotFoundException, MBeanRegistrationException { 426 427 DynamicMBean instance = getMBean(name); 428 // may throw InstanceNotFoundException 429 430 checkMBeanPermission(instance, null, name, "unregisterMBean"); 431 432 if (instance instanceof MBeanRegistration) 433 preDeregisterInvoke((MBeanRegistration) instance); 434 435 final Object resource = getResource(instance); 436 437 // Unregisters the MBean from the repository. 438 // Returns the resource context that was used. 439 // The returned context does nothing for regular MBeans. 440 // For ClassLoader MBeans and JMXNamespace (and JMXDomain) 441 // MBeans - the context makes it possible to unregister these 442 // objects from the appropriate framework artifacts, such as 443 // the CLR or the dispatcher, from within the repository lock. 444 // In case of success, we also need to call context.done() at the 445 // end of this method. 446 // 447 final ResourceContext context = 448 unregisterFromRepository(resource, instance, name); 449 450 try { 451 if (instance instanceof MBeanRegistration) 452 postDeregisterInvoke(name,(MBeanRegistration) instance); 453 } finally { 454 context.done(); 455 } 456 } 457 458 public ObjectInstance getObjectInstance(ObjectName name) 459 throws InstanceNotFoundException { 460 461 name = nonDefaultDomain(name); 462 DynamicMBean instance = getMBean(name); 463 464 checkMBeanPermission(instance, null, name, "getObjectInstance"); 465 466 final String className = getClassName(instance); 467 468 return new ObjectInstance(name, className); 469 } 470 471 public Set<ObjectInstance> queryMBeans(ObjectName name, QueryExp query) { 472 SecurityManager sm = System.getSecurityManager(); 473 if (sm != null) { 474 // Check if the caller has the right to invoke 'queryMBeans' 475 // 476 checkMBeanPermission((String) null, null, null, "queryMBeans"); 477 478 // Perform query without "query". 479 // 480 Set<ObjectInstance> list = queryMBeansImpl(name, null); 481 482 // Check if the caller has the right to invoke 'queryMBeans' 483 // on each specific classname/objectname in the list. 484 // 485 Set<ObjectInstance> allowedList = 486 new HashSet<ObjectInstance>(list.size()); 487 for (ObjectInstance oi : list) { 488 try { 489 checkMBeanPermission(oi.getClassName(), null, 490 oi.getObjectName(), "queryMBeans"); 491 allowedList.add(oi); 492 } catch (SecurityException e) { 493 // OK: Do not add this ObjectInstance to the list 494 } 495 } 496 497 // Apply query to allowed MBeans only. 498 // 499 return filterListOfObjectInstances(allowedList, query); 500 } else { 501 // Perform query. 502 // 503 return queryMBeansImpl(name, query); 504 } 505 } 506 507 private Set<ObjectInstance> queryMBeansImpl(ObjectName name, 508 QueryExp query) { 509 // Query the MBeans on the repository 510 // 511 Set<NamedObject> list = repository.query(name, query); 512 513 return (objectInstancesFromFilteredNamedObjects(list, query)); 514 } 515 516 public Set<ObjectName> queryNames(ObjectName name, QueryExp query) { 517 Set<ObjectName> queryList; 518 SecurityManager sm = System.getSecurityManager(); 519 if (sm != null) { 520 // Check if the caller has the right to invoke 'queryNames' 521 // 522 checkMBeanPermission((String) null, null, null, "queryNames"); 523 524 // Perform query without "query". 525 // 526 Set<ObjectInstance> list = queryMBeansImpl(name, null); 527 528 // Check if the caller has the right to invoke 'queryNames' 529 // on each specific classname/objectname in the list. 530 // 531 Set<ObjectInstance> allowedList = 532 new HashSet<ObjectInstance>(list.size()); 533 for (ObjectInstance oi : list) { 534 try { 535 checkMBeanPermission(oi.getClassName(), null, 536 oi.getObjectName(), "queryNames"); 537 allowedList.add(oi); 538 } catch (SecurityException e) { 539 // OK: Do not add this ObjectInstance to the list 540 } 541 } 542 543 // Apply query to allowed MBeans only. 544 // 545 Set<ObjectInstance> queryObjectInstanceList = 546 filterListOfObjectInstances(allowedList, query); 547 queryList = new HashSet<ObjectName>(queryObjectInstanceList.size()); 548 for (ObjectInstance oi : queryObjectInstanceList) { 549 queryList.add(oi.getObjectName()); 550 } 551 } else { 552 // Perform query. 553 // 554 queryList = queryNamesImpl(name, query); 555 } 556 return queryList; 557 } 558 559 private Set<ObjectName> queryNamesImpl(ObjectName name, QueryExp query) { 560 // Query the MBeans on the repository 561 // 562 Set<NamedObject> list = repository.query(name, query); 563 564 return (objectNamesFromFilteredNamedObjects(list, query)); 565 } 566 567 public boolean isRegistered(ObjectName name) { 568 if (name == null) { 569 throw new RuntimeOperationsException( 570 new IllegalArgumentException("Object name cannot be null"), 571 "Object name cannot be null"); 572 } 573 574 name = nonDefaultDomain(name); 575 576 /* No Permission check */ 577 // isRegistered is always unchecked as per JMX spec. 578 579 return (repository.contains(name)); 580 } 581 582 public String[] getDomains() { 583 SecurityManager sm = System.getSecurityManager(); 584 if (sm != null) { 585 // Check if the caller has the right to invoke 'getDomains' 586 // 587 checkMBeanPermission((String) null, null, null, "getDomains"); 588 589 // Return domains 590 // 591 String[] domains = repository.getDomains(); 592 593 // Check if the caller has the right to invoke 'getDomains' 594 // on each specific domain in the list. 595 // 596 List<String> result = new ArrayList<String>(domains.length); 597 for (int i = 0; i < domains.length; i++) { 598 try { 599 ObjectName dom = Util.newObjectName(domains[i] + ":x=x"); 600 checkMBeanPermission((String) null, null, dom, "getDomains"); 601 result.add(domains[i]); 602 } catch (SecurityException e) { 603 // OK: Do not add this domain to the list 604 } 605 } 606 607 // Make an array from result. 608 // 609 return result.toArray(new String[result.size()]); 610 } else { 611 return repository.getDomains(); 612 } 613 } 614 615 public Integer getMBeanCount() { 616 return (repository.getCount()); 617 } 618 619 public Object getAttribute(ObjectName name, String attribute) 620 throws MBeanException, AttributeNotFoundException, 621 InstanceNotFoundException, ReflectionException { 622 623 if (name == null) { 624 throw new RuntimeOperationsException(new 625 IllegalArgumentException("Object name cannot be null"), 626 "Exception occurred trying to invoke the getter on the MBean"); 627 } 628 if (attribute == null) { 629 throw new RuntimeOperationsException(new 630 IllegalArgumentException("Attribute cannot be null"), 631 "Exception occurred trying to invoke the getter on the MBean"); 632 } 633 634 name = nonDefaultDomain(name); 635 636 if (MBEANSERVER_LOGGER.isLoggable(Level.FINER)) { 637 MBEANSERVER_LOGGER.logp(Level.FINER, 638 DefaultMBeanServerInterceptor.class.getName(), 639 "getAttribute", 640 "Attribute = " + attribute + ", ObjectName = " + name); 641 } 642 643 final DynamicMBean instance = getMBean(name); 644 checkMBeanPermission(instance, attribute, name, "getAttribute"); 645 646 try { 647 return instance.getAttribute(attribute); 648 } catch (AttributeNotFoundException e) { 649 throw e; 650 } catch (Throwable t) { 651 rethrowMaybeMBeanException(t); 652 throw new AssertionError(); // not reached 653 } 654 } 655 656 public AttributeList getAttributes(ObjectName name, String[] attributes) 657 throws InstanceNotFoundException, ReflectionException { 658 659 if (name == null) { 660 throw new RuntimeOperationsException(new 661 IllegalArgumentException("ObjectName name cannot be null"), 662 "Exception occurred trying to invoke the getter on the MBean"); 663 } 664 665 if (attributes == null) { 666 throw new RuntimeOperationsException(new 667 IllegalArgumentException("Attributes cannot be null"), 668 "Exception occurred trying to invoke the getter on the MBean"); 669 } 670 671 name = nonDefaultDomain(name); 672 673 if (MBEANSERVER_LOGGER.isLoggable(Level.FINER)) { 674 MBEANSERVER_LOGGER.logp(Level.FINER, 675 DefaultMBeanServerInterceptor.class.getName(), 676 "getAttributes", "ObjectName = " + name); 677 } 678 679 final DynamicMBean instance = getMBean(name); 680 final String[] allowedAttributes; 681 final SecurityManager sm = System.getSecurityManager(); 682 if (sm == null) 683 allowedAttributes = attributes; 684 else { 685 final String classname = getClassName(instance); 686 687 // Check if the caller has the right to invoke 'getAttribute' 688 // 689 checkMBeanPermission(classname, null, name, "getAttribute"); 690 691 // Check if the caller has the right to invoke 'getAttribute' 692 // on each specific attribute 693 // 694 List<String> allowedList = 695 new ArrayList<String>(attributes.length); 696 for (String attr : attributes) { 697 try { 698 checkMBeanPermission(classname, attr, name, "getAttribute"); 699 allowedList.add(attr); 700 } catch (SecurityException e) { 701 // OK: Do not add this attribute to the list 702 } 703 } 704 allowedAttributes = 705 allowedList.toArray(new String[allowedList.size()]); 706 } 707 708 try { 709 return instance.getAttributes(allowedAttributes); 710 } catch (Throwable t) { 711 rethrow(t); 712 throw new AssertionError(); 713 } 714 } 715 716 public void setAttribute(ObjectName name, Attribute attribute) 717 throws InstanceNotFoundException, AttributeNotFoundException, 718 InvalidAttributeValueException, MBeanException, 719 ReflectionException { 720 721 if (name == null) { 722 throw new RuntimeOperationsException(new 723 IllegalArgumentException("ObjectName name cannot be null"), 724 "Exception occurred trying to invoke the setter on the MBean"); 725 } 726 727 if (attribute == null) { 728 throw new RuntimeOperationsException(new 729 IllegalArgumentException("Attribute cannot be null"), 730 "Exception occurred trying to invoke the setter on the MBean"); 731 } 732 733 name = nonDefaultDomain(name); 734 735 if (MBEANSERVER_LOGGER.isLoggable(Level.FINER)) { 736 MBEANSERVER_LOGGER.logp(Level.FINER, 737 DefaultMBeanServerInterceptor.class.getName(), 738 "setAttribute", "ObjectName = " + name + 739 ", Attribute = " + attribute.getName()); 740 } 741 742 DynamicMBean instance = getMBean(name); 743 checkMBeanPermission(instance, attribute.getName(), name, "setAttribute"); 744 745 try { 746 instance.setAttribute(attribute); 747 } catch (AttributeNotFoundException e) { 748 throw e; 749 } catch (InvalidAttributeValueException e) { 750 throw e; 751 } catch (Throwable t) { 752 rethrowMaybeMBeanException(t); 753 throw new AssertionError(); 754 } 755 } 756 757 public AttributeList setAttributes(ObjectName name, 758 AttributeList attributes) 759 throws InstanceNotFoundException, ReflectionException { 760 761 if (name == null) { 762 throw new RuntimeOperationsException(new 763 IllegalArgumentException("ObjectName name cannot be null"), 764 "Exception occurred trying to invoke the setter on the MBean"); 765 } 766 767 if (attributes == null) { 768 throw new RuntimeOperationsException(new 769 IllegalArgumentException("AttributeList cannot be null"), 770 "Exception occurred trying to invoke the setter on the MBean"); 771 } 772 773 name = nonDefaultDomain(name); 774 775 final DynamicMBean instance = getMBean(name); 776 final AttributeList allowedAttributes; 777 final SecurityManager sm = System.getSecurityManager(); 778 if (sm == null) 779 allowedAttributes = attributes; 780 else { 781 String classname = getClassName(instance); 782 783 // Check if the caller has the right to invoke 'setAttribute' 784 // 785 checkMBeanPermission(classname, null, name, "setAttribute"); 786 787 // Check if the caller has the right to invoke 'setAttribute' 788 // on each specific attribute 789 // 790 allowedAttributes = new AttributeList(attributes.size()); 791 for (Attribute attribute : attributes.asList()) { 792 try { 793 checkMBeanPermission(classname, attribute.getName(), 794 name, "setAttribute"); 795 allowedAttributes.add(attribute); 796 } catch (SecurityException e) { 797 // OK: Do not add this attribute to the list 798 } 799 } 800 } 801 try { 802 return instance.setAttributes(allowedAttributes); 803 } catch (Throwable t) { 804 rethrow(t); 805 throw new AssertionError(); 806 } 807 } 808 809 public Object invoke(ObjectName name, String operationName, 810 Object params[], String signature[]) 811 throws InstanceNotFoundException, MBeanException, 812 ReflectionException { 813 814 name = nonDefaultDomain(name); 815 816 DynamicMBean instance = getMBean(name); 817 checkMBeanPermission(instance, operationName, name, "invoke"); 818 try { 819 return instance.invoke(operationName, params, signature); 820 } catch (Throwable t) { 821 rethrowMaybeMBeanException(t); 822 throw new AssertionError(); 823 } 824 } 825 826 /* Centralize some of the tedious exception wrapping demanded by the JMX 827 spec. */ 828 private static void rethrow(Throwable t) 829 throws ReflectionException { 830 try { 831 throw t; 832 } catch (ReflectionException e) { 833 throw e; 834 } catch (RuntimeOperationsException e) { 835 throw e; 836 } catch (RuntimeErrorException e) { 837 throw e; 838 } catch (RuntimeException e) { 839 throw new RuntimeMBeanException(e, e.toString()); 840 } catch (Error e) { 841 throw new RuntimeErrorException(e, e.toString()); 842 } catch (Throwable t2) { 843 // should not happen 844 throw new RuntimeException("Unexpected exception", t2); 845 } 846 } 847 848 private static void rethrowMaybeMBeanException(Throwable t) 849 throws ReflectionException, MBeanException { 850 if (t instanceof MBeanException) 851 throw (MBeanException) t; 852 rethrow(t); 853 } 854 855 /** 856 * Register <code>object</code> in the repository, with the 857 * given <code>name</code>. 858 * This method is called by the various createMBean() flavours 859 * and by registerMBean() after all MBean compliance tests 860 * have been performed. 861 * <p> 862 * This method does not performed any kind of test compliance, 863 * and the caller should make sure that the given <code>object</code> 864 * is MBean compliant. 865 * <p> 866 * This methods performed all the basic steps needed for object 867 * registration: 868 * <ul> 869 * <li>If the <code>object</code> implements the MBeanRegistration 870 * interface, it invokes preRegister() on the object.</li> 871 * <li>Then the object is added to the repository with the given 872 * <code>name</code>.</li> 873 * <li>Finally, if the <code>object</code> implements the 874 * MBeanRegistration interface, it invokes postRegister() 875 * on the object.</li> 876 * </ul> 877 * @param object A reference to a MBean compliant object. 878 * @param name The ObjectName of the <code>object</code> MBean. 879 * @return the actual ObjectName with which the object was registered. 880 * @exception InstanceAlreadyExistsException if an object is already 881 * registered with that name. 882 * @exception MBeanRegistrationException if an exception occurs during 883 * registration. 884 **/ 885 private ObjectInstance registerObject(String classname, 886 Object object, ObjectName name) 887 throws InstanceAlreadyExistsException, 888 MBeanRegistrationException, 889 NotCompliantMBeanException { 890 891 if (object == null) { 892 final RuntimeException wrapped = 893 new IllegalArgumentException("Cannot add null object"); 894 throw new RuntimeOperationsException(wrapped, 895 "Exception occurred trying to register the MBean"); 896 } 897 898 DynamicMBean mbean = Introspector.makeDynamicMBean(object); 899 900 return registerDynamicMBean(classname, mbean, name); 901 } 902 903 private ObjectInstance registerDynamicMBean(String classname, 904 DynamicMBean mbean, 905 ObjectName name) 906 throws InstanceAlreadyExistsException, 907 MBeanRegistrationException, 908 NotCompliantMBeanException { 909 910 911 name = nonDefaultDomain(name); 912 913 if (MBEANSERVER_LOGGER.isLoggable(Level.FINER)) { 914 MBEANSERVER_LOGGER.logp(Level.FINER, 915 DefaultMBeanServerInterceptor.class.getName(), 916 "registerMBean", "ObjectName = " + name); 917 } 918 919 ObjectName logicalName = preRegister(mbean, server, name); 920 921 // preRegister returned successfully, so from this point on we 922 // must call postRegister(false) if there is any problem. 923 boolean registered = false; 924 boolean registerFailed = false; 925 ResourceContext context = null; 926 927 try { 928 if (mbean instanceof DynamicMBean2) { 929 try { 930 ((DynamicMBean2) mbean).preRegister2(server, logicalName); 931 registerFailed = true; // until we succeed 932 } catch (Exception e) { 933 if (e instanceof RuntimeException) 934 throw (RuntimeException) e; 935 if (e instanceof InstanceAlreadyExistsException) 936 throw (InstanceAlreadyExistsException) e; 937 throw new RuntimeException(e); 938 } 939 } 940 941 if (logicalName != name && logicalName != null) { 942 logicalName = 943 ObjectName.getInstance(nonDefaultDomain(logicalName)); 944 } 945 946 checkMBeanPermission(classname, null, logicalName, "registerMBean"); 947 948 if (logicalName == null) { 949 final RuntimeException wrapped = 950 new IllegalArgumentException("No object name specified"); 951 throw new RuntimeOperationsException(wrapped, 952 "Exception occurred trying to register the MBean"); 953 } 954 955 final Object resource = getResource(mbean); 956 957 // Register the MBean with the repository. 958 // Returns the resource context that was used. 959 // The returned context does nothing for regular MBeans. 960 // For ClassLoader MBeans the context makes it possible to register these 961 // objects with the appropriate framework artifacts, such as 962 // the CLR, from within the repository lock. 963 // In case of success, we also need to call context.done() at the 964 // end of this method. 965 // 966 context = registerWithRepository(resource, mbean, logicalName); 967 968 969 registerFailed = false; 970 registered = true; 971 972 } finally { 973 try { 974 postRegister(logicalName, mbean, registered, registerFailed); 975 } finally { 976 if (registered && context!=null) context.done(); 977 } 978 } 979 return new ObjectInstance(logicalName, classname); 980 } 981 982 private static void throwMBeanRegistrationException(Throwable t, String where) 983 throws MBeanRegistrationException { 984 if (t instanceof RuntimeException) { 985 throw new RuntimeMBeanException((RuntimeException)t, 986 "RuntimeException thrown " + where); 987 } else if (t instanceof Error) { 988 throw new RuntimeErrorException((Error)t, 989 "Error thrown " + where); 990 } else if (t instanceof MBeanRegistrationException) { 991 throw (MBeanRegistrationException)t; 992 } else if (t instanceof Exception) { 993 throw new MBeanRegistrationException((Exception)t, 994 "Exception thrown " + where); 995 } else // neither Error nor Exception?? 996 throw new RuntimeException(t); 997 } 998 999 private static ObjectName preRegister( 1000 DynamicMBean mbean, MBeanServer mbs, ObjectName name) 1001 throws InstanceAlreadyExistsException, MBeanRegistrationException { 1002 1003 ObjectName newName = null; 1004 1005 try { 1006 if (mbean instanceof MBeanRegistration) 1007 newName = ((MBeanRegistration) mbean).preRegister(mbs, name); 1008 } catch (Throwable t) { 1009 throwMBeanRegistrationException(t, "in preRegister method"); 1010 } 1011 1012 if (newName != null) return newName; 1013 else return name; 1014 } 1015 1016 private static void postRegister( 1017 ObjectName logicalName, DynamicMBean mbean, 1018 boolean registrationDone, boolean registerFailed) { 1019 1020 if (registerFailed && mbean instanceof DynamicMBean2) 1021 ((DynamicMBean2) mbean).registerFailed(); 1022 try { 1023 if (mbean instanceof MBeanRegistration) 1024 ((MBeanRegistration) mbean).postRegister(registrationDone); 1025 } catch (RuntimeException e) { 1026 MBEANSERVER_LOGGER.fine("While registering MBean ["+logicalName+ 1027 "]: " + "Exception thrown by postRegister: " + 1028 "rethrowing <"+e+">, but keeping the MBean registered"); 1029 throw new RuntimeMBeanException(e, 1030 "RuntimeException thrown in postRegister method: "+ 1031 "rethrowing <"+e+">, but keeping the MBean registered"); 1032 } catch (Error er) { 1033 MBEANSERVER_LOGGER.fine("While registering MBean ["+logicalName+ 1034 "]: " + "Error thrown by postRegister: " + 1035 "rethrowing <"+er+">, but keeping the MBean registered"); 1036 throw new RuntimeErrorException(er, 1037 "Error thrown in postRegister method: "+ 1038 "rethrowing <"+er+">, but keeping the MBean registered"); 1039 } 1040 } 1041 1042 private static void preDeregisterInvoke(MBeanRegistration moi) 1043 throws MBeanRegistrationException { 1044 try { 1045 moi.preDeregister(); 1046 } catch (Throwable t) { 1047 throwMBeanRegistrationException(t, "in preDeregister method"); 1048 } 1049 } 1050 1051 private static void postDeregisterInvoke(ObjectName mbean, 1052 MBeanRegistration moi) { 1053 try { 1054 moi.postDeregister(); 1055 } catch (RuntimeException e) { 1056 MBEANSERVER_LOGGER.fine("While unregistering MBean ["+mbean+ 1057 "]: " + "Exception thrown by postDeregister: " + 1058 "rethrowing <"+e+">, although the MBean is succesfully " + 1059 "unregistered"); 1060 throw new RuntimeMBeanException(e, 1061 "RuntimeException thrown in postDeregister method: "+ 1062 "rethrowing <"+e+ 1063 ">, although the MBean is sucessfully unregistered"); 1064 } catch (Error er) { 1065 MBEANSERVER_LOGGER.fine("While unregistering MBean ["+mbean+ 1066 "]: " + "Error thrown by postDeregister: " + 1067 "rethrowing <"+er+">, although the MBean is succesfully " + 1068 "unregistered"); 1069 throw new RuntimeErrorException(er, 1070 "Error thrown in postDeregister method: "+ 1071 "rethrowing <"+er+ 1072 ">, although the MBean is sucessfully unregistered"); 1073 } 1074 } 1075 1076 /** 1077 * Gets a specific MBean controlled by the DefaultMBeanServerInterceptor. 1078 * The name must have a non-default domain. 1079 */ 1080 private DynamicMBean getMBean(ObjectName name) 1081 throws InstanceNotFoundException { 1082 1083 if (name == null) { 1084 throw new RuntimeOperationsException(new 1085 IllegalArgumentException("Object name cannot be null"), 1086 "Exception occurred trying to get an MBean"); 1087 } 1088 DynamicMBean obj = repository.retrieve(name); 1089 if (obj == null) { 1090 if (MBEANSERVER_LOGGER.isLoggable(Level.FINER)) { 1091 MBEANSERVER_LOGGER.logp(Level.FINER, 1092 DefaultMBeanServerInterceptor.class.getName(), 1093 "getMBean", name + " : Found no object"); 1094 } 1095 throw new InstanceNotFoundException(name.toString()); 1096 } 1097 return obj; 1098 } 1099 1100 private static Object getResource(DynamicMBean mbean) { 1101 if (mbean instanceof DynamicMBean2) 1102 return ((DynamicMBean2) mbean).getResource(); 1103 else 1104 return mbean; 1105 } 1106 1107 private ObjectName nonDefaultDomain(ObjectName name) { 1108 if (name == null || name.getDomain().length() > 0) 1109 return name; 1110 1111 /* The ObjectName looks like ":a=b", and that's what its 1112 toString() will return in this implementation. So 1113 we can just stick the default domain in front of it 1114 to get a non-default-domain name. We depend on the 1115 fact that toString() works like that and that it 1116 leaves wildcards in place (so we can detect an error 1117 if one is supplied where it shouldn't be). */ 1118 final String completeName = domain + name; 1119 1120 return Util.newObjectName(completeName); 1121 } 1122 1123 public String getDefaultDomain() { 1124 return domain; 1125 } 1126 1127 /* 1128 * Notification handling. 1129 * 1130 * This is not trivial, because the MBeanServer translates the 1131 * source of a received notification from a reference to an MBean 1132 * into the ObjectName of that MBean. While that does make 1133 * notification sending easier for MBean writers, it comes at a 1134 * considerable cost. We need to replace the source of a 1135 * notification, which is basically wrong if there are also 1136 * listeners registered directly with the MBean (without going 1137 * through the MBean server). We also need to wrap the listener 1138 * supplied by the client of the MBeanServer with a listener that 1139 * performs the substitution before forwarding. This is why we 1140 * strongly discourage people from putting MBean references in the 1141 * source of their notifications. Instead they should arrange to 1142 * put the ObjectName there themselves. 1143 * 1144 * However, existing code relies on the substitution, so we are 1145 * stuck with it. 1146 * 1147 * Here's how we handle it. When you add a listener, we make a 1148 * ListenerWrapper around it. We look that up in the 1149 * listenerWrappers map, and if there was already a wrapper for 1150 * that listener with the given ObjectName, we reuse it. This map 1151 * is a WeakHashMap, so a listener that is no longer registered 1152 * with any MBean can be garbage collected. 1153 * 1154 * We cannot use simpler solutions such as always creating a new 1155 * wrapper or always registering the same listener with the MBean 1156 * and using the handback to find the client's original listener. 1157 * The reason is that we need to support the removeListener 1158 * variant that removes all (listener,filter,handback) triples on 1159 * a broadcaster that have a given listener. And we do not have 1160 * any way to inspect a broadcaster's internal list of triples. 1161 * So the same client listener must always map to the same 1162 * listener registered with the broadcaster. 1163 * 1164 * Another possible solution would be to map from ObjectName to 1165 * list of listener wrappers (or IdentityHashMap of listener 1166 * wrappers), making this list the first time a listener is added 1167 * on a given MBean, and removing it when the MBean is removed. 1168 * This is probably more costly in memory, but could be useful if 1169 * some day we don't want to rely on weak references. 1170 */ 1171 public void addNotificationListener(ObjectName name, 1172 NotificationListener listener, 1173 NotificationFilter filter, 1174 Object handback) 1175 throws InstanceNotFoundException { 1176 1177 // ------------------------------ 1178 // ------------------------------ 1179 if (MBEANSERVER_LOGGER.isLoggable(Level.FINER)) { 1180 MBEANSERVER_LOGGER.logp(Level.FINER, 1181 DefaultMBeanServerInterceptor.class.getName(), 1182 "addNotificationListener", "ObjectName = " + name); 1183 } 1184 1185 DynamicMBean instance = getMBean(name); 1186 checkMBeanPermission(instance, null, name, "addNotificationListener"); 1187 1188 NotificationBroadcaster broadcaster = 1189 getNotificationBroadcaster(name, instance, 1190 NotificationBroadcaster.class); 1191 1192 // ------------------ 1193 // Check listener 1194 // ------------------ 1195 if (listener == null) { 1196 throw new RuntimeOperationsException(new 1197 IllegalArgumentException("Null listener"),"Null listener"); 1198 } 1199 1200 NotificationListener listenerWrapper = 1201 getListenerWrapper(listener, name, instance, true); 1202 broadcaster.addNotificationListener(listenerWrapper, filter, handback); 1203 } 1204 1205 public void addNotificationListener(ObjectName name, 1206 ObjectName listener, 1207 NotificationFilter filter, 1208 Object handback) 1209 throws InstanceNotFoundException { 1210 1211 // ------------------------------ 1212 // ------------------------------ 1213 1214 // ---------------- 1215 // Get listener object 1216 // ---------------- 1217 DynamicMBean instance = getMBean(listener); 1218 Object resource = getResource(instance); 1219 if (!(resource instanceof NotificationListener)) { 1220 throw new RuntimeOperationsException(new 1221 IllegalArgumentException(listener.getCanonicalName()), 1222 "The MBean " + listener.getCanonicalName() + 1223 "does not implement the NotificationListener interface") ; 1224 } 1225 1226 // ---------------- 1227 // Add a listener on an MBean 1228 // ---------------- 1229 if (MBEANSERVER_LOGGER.isLoggable(Level.FINER)) { 1230 MBEANSERVER_LOGGER.logp(Level.FINER, 1231 DefaultMBeanServerInterceptor.class.getName(), 1232 "addNotificationListener", 1233 "ObjectName = " + name + ", Listener = " + listener); 1234 } 1235 server.addNotificationListener(name,(NotificationListener) resource, 1236 filter, handback) ; 1237 } 1238 1239 public void removeNotificationListener(ObjectName name, 1240 NotificationListener listener) 1241 throws InstanceNotFoundException, ListenerNotFoundException { 1242 removeNotificationListener(name, listener, null, null, true); 1243 } 1244 1245 public void removeNotificationListener(ObjectName name, 1246 NotificationListener listener, 1247 NotificationFilter filter, 1248 Object handback) 1249 throws InstanceNotFoundException, ListenerNotFoundException { 1250 removeNotificationListener(name, listener, filter, handback, false); 1251 } 1252 1253 public void removeNotificationListener(ObjectName name, 1254 ObjectName listener) 1255 throws InstanceNotFoundException, ListenerNotFoundException { 1256 NotificationListener instance = getListener(listener); 1257 1258 if (MBEANSERVER_LOGGER.isLoggable(Level.FINER)) { 1259 MBEANSERVER_LOGGER.logp(Level.FINER, 1260 DefaultMBeanServerInterceptor.class.getName(), 1261 "removeNotificationListener", 1262 "ObjectName = " + name + ", Listener = " + listener); 1263 } 1264 server.removeNotificationListener(name, instance); 1265 } 1266 1267 public void removeNotificationListener(ObjectName name, 1268 ObjectName listener, 1269 NotificationFilter filter, 1270 Object handback) 1271 throws InstanceNotFoundException, ListenerNotFoundException { 1272 1273 NotificationListener instance = getListener(listener); 1274 1275 if (MBEANSERVER_LOGGER.isLoggable(Level.FINER)) { 1276 MBEANSERVER_LOGGER.logp(Level.FINER, 1277 DefaultMBeanServerInterceptor.class.getName(), 1278 "removeNotificationListener", 1279 "ObjectName = " + name + ", Listener = " + listener); 1280 } 1281 server.removeNotificationListener(name, instance, filter, handback); 1282 } 1283 1284 private NotificationListener getListener(ObjectName listener) 1285 throws ListenerNotFoundException { 1286 // ---------------- 1287 // Get listener object 1288 // ---------------- 1289 DynamicMBean instance; 1290 try { 1291 instance = getMBean(listener); 1292 } catch (InstanceNotFoundException e) { 1293 throw EnvHelp.initCause( 1294 new ListenerNotFoundException(e.getMessage()), e); 1295 } 1296 1297 Object resource = getResource(instance); 1298 if (!(resource instanceof NotificationListener)) { 1299 final RuntimeException exc = 1300 new IllegalArgumentException(listener.getCanonicalName()); 1301 final String msg = 1302 "MBean " + listener.getCanonicalName() + " does not " + 1303 "implement " + NotificationListener.class.getName(); 1304 throw new RuntimeOperationsException(exc, msg); 1305 } 1306 return (NotificationListener) resource; 1307 } 1308 1309 private void removeNotificationListener(ObjectName name, 1310 NotificationListener listener, 1311 NotificationFilter filter, 1312 Object handback, 1313 boolean removeAll) 1314 throws InstanceNotFoundException, ListenerNotFoundException { 1315 1316 if (MBEANSERVER_LOGGER.isLoggable(Level.FINER)) { 1317 MBEANSERVER_LOGGER.logp(Level.FINER, 1318 DefaultMBeanServerInterceptor.class.getName(), 1319 "removeNotificationListener", "ObjectName = " + name); 1320 } 1321 1322 DynamicMBean instance = getMBean(name); 1323 checkMBeanPermission(instance, null, name, "removeNotificationListener"); 1324 1325 /* We could simplify the code by assigning broadcaster after 1326 assigning listenerWrapper, but that would change the error 1327 behavior when both the broadcaster and the listener are 1328 erroneous. */ 1329 1330 Class<? extends NotificationBroadcaster> reqClass = 1331 removeAll ? NotificationBroadcaster.class : NotificationEmitter.class; 1332 NotificationBroadcaster broadcaster = 1333 getNotificationBroadcaster(name, instance, reqClass); 1334 1335 NotificationListener listenerWrapper = 1336 getListenerWrapper(listener, name, instance, false); 1337 1338 if (listenerWrapper == null) 1339 throw new ListenerNotFoundException("Unknown listener"); 1340 1341 if (removeAll) 1342 broadcaster.removeNotificationListener(listenerWrapper); 1343 else { 1344 NotificationEmitter emitter = (NotificationEmitter) broadcaster; 1345 emitter.removeNotificationListener(listenerWrapper, 1346 filter, 1347 handback); 1348 } 1349 } 1350 1351 private static <T extends NotificationBroadcaster> 1352 T getNotificationBroadcaster(ObjectName name, Object instance, 1353 Class<T> reqClass) { 1354 if (reqClass.isInstance(instance)) 1355 return reqClass.cast(instance); 1356 if (instance instanceof DynamicMBean2) 1357 instance = ((DynamicMBean2) instance).getResource(); 1358 if (reqClass.isInstance(instance)) 1359 return reqClass.cast(instance); 1360 final RuntimeException exc = 1361 new IllegalArgumentException(name.getCanonicalName()); 1362 final String msg = 1363 "MBean " + name.getCanonicalName() + " does not " + 1364 "implement " + reqClass.getName(); 1365 throw new RuntimeOperationsException(exc, msg); 1366 } 1367 1368 public MBeanInfo getMBeanInfo(ObjectName name) 1369 throws InstanceNotFoundException, IntrospectionException, 1370 ReflectionException { 1371 1372 // ------------------------------ 1373 // ------------------------------ 1374 1375 DynamicMBean moi = getMBean(name); 1376 final MBeanInfo mbi; 1377 try { 1378 mbi = moi.getMBeanInfo(); 1379 } catch (RuntimeMBeanException e) { 1380 throw e; 1381 } catch (RuntimeErrorException e) { 1382 throw e; 1383 } catch (RuntimeException e) { 1384 throw new RuntimeMBeanException(e, 1385 "getMBeanInfo threw RuntimeException"); 1386 } catch (Error e) { 1387 throw new RuntimeErrorException(e, "getMBeanInfo threw Error"); 1388 } 1389 if (mbi == null) 1390 throw new JMRuntimeException("MBean " + name + 1391 "has no MBeanInfo"); 1392 1393 checkMBeanPermission(mbi.getClassName(), null, name, "getMBeanInfo"); 1394 1395 return mbi; 1396 } 1397 1398 public boolean isInstanceOf(ObjectName name, String className) 1399 throws InstanceNotFoundException { 1400 1401 final DynamicMBean instance = getMBean(name); 1402 checkMBeanPermission(instance, null, name, "isInstanceOf"); 1403 1404 try { 1405 Object resource = getResource(instance); 1406 1407 final String resourceClassName = 1408 (resource instanceof DynamicMBean) ? 1409 getClassName((DynamicMBean) resource) : 1410 resource.getClass().getName(); 1411 1412 if (resourceClassName.equals(className)) 1413 return true; 1414 final ClassLoader cl = resource.getClass().getClassLoader(); 1415 1416 final Class<?> classNameClass = Class.forName(className, false, cl); 1417 if (classNameClass.isInstance(resource)) 1418 return true; 1419 1420 final Class<?> resourceClass = Class.forName(resourceClassName, false, cl); 1421 return classNameClass.isAssignableFrom(resourceClass); 1422 } catch (Exception x) { 1423 /* Could be SecurityException or ClassNotFoundException */ 1424 if (MBEANSERVER_LOGGER.isLoggable(Level.FINEST)) { 1425 MBEANSERVER_LOGGER.logp(Level.FINEST, 1426 DefaultMBeanServerInterceptor.class.getName(), 1427 "isInstanceOf", "Exception calling isInstanceOf", x); 1428 } 1429 return false; 1430 } 1431 1432 } 1433 1434 /** 1435 * <p>Return the {@link java.lang.ClassLoader} that was used for 1436 * loading the class of the named MBean. 1437 * @param mbeanName The ObjectName of the MBean. 1438 * @return The ClassLoader used for that MBean. 1439 * @exception InstanceNotFoundException if the named MBean is not found. 1440 */ 1441 public ClassLoader getClassLoaderFor(ObjectName mbeanName) 1442 throws InstanceNotFoundException { 1443 1444 DynamicMBean instance = getMBean(mbeanName); 1445 checkMBeanPermission(instance, null, mbeanName, "getClassLoaderFor"); 1446 return getResource(instance).getClass().getClassLoader(); 1447 } 1448 1449 /** 1450 * <p>Return the named {@link java.lang.ClassLoader}. 1451 * @param loaderName The ObjectName of the ClassLoader. 1452 * @return The named ClassLoader. 1453 * @exception InstanceNotFoundException if the named ClassLoader 1454 * is not found. 1455 */ 1456 public ClassLoader getClassLoader(ObjectName loaderName) 1457 throws InstanceNotFoundException { 1458 1459 if (loaderName == null) { 1460 checkMBeanPermission((String) null, null, null, "getClassLoader"); 1461 return server.getClass().getClassLoader(); 1462 } 1463 1464 DynamicMBean instance = getMBean(loaderName); 1465 checkMBeanPermission(instance, null, loaderName, "getClassLoader"); 1466 1467 Object resource = getResource(instance); 1468 1469 /* Check if the given MBean is a ClassLoader */ 1470 if (!(resource instanceof ClassLoader)) 1471 throw new InstanceNotFoundException(loaderName.toString() + 1472 " is not a classloader"); 1473 1474 return (ClassLoader) resource; 1475 } 1476 1477 /** 1478 * Sends an MBeanServerNotifications with the specified type for the 1479 * MBean with the specified ObjectName 1480 */ 1481 private void sendNotification(String NotifType, ObjectName name) { 1482 1483 // ------------------------------ 1484 // ------------------------------ 1485 1486 // --------------------- 1487 // Create notification 1488 // --------------------- 1489 MBeanServerNotification notif = new MBeanServerNotification( 1490 NotifType,MBeanServerDelegate.DELEGATE_NAME,0,name); 1491 1492 if (MBEANSERVER_LOGGER.isLoggable(Level.FINER)) { 1493 MBEANSERVER_LOGGER.logp(Level.FINER, 1494 DefaultMBeanServerInterceptor.class.getName(), 1495 "sendNotification", NotifType + " " + name); 1496 } 1497 1498 delegate.sendNotification(notif); 1499 } 1500 1501 /** 1502 * Applies the specified queries to the set of NamedObjects. 1503 */ 1504 private Set<ObjectName> 1505 objectNamesFromFilteredNamedObjects(Set<NamedObject> list, 1506 QueryExp query) { 1507 Set<ObjectName> result = new HashSet<ObjectName>(); 1508 // No query ... 1509 if (query == null) { 1510 for (NamedObject no : list) { 1511 result.add(no.getName()); 1512 } 1513 } else { 1514 // Access the filter 1515 final MBeanServer oldServer = QueryEval.getMBeanServer(); 1516 query.setMBeanServer(server); 1517 try { 1518 for (NamedObject no : list) { 1519 boolean res; 1520 try { 1521 res = query.apply(no.getName()); 1522 } catch (Exception e) { 1523 res = false; 1524 } 1525 if (res) { 1526 result.add(no.getName()); 1527 } 1528 } 1529 } finally { 1530 /* 1531 * query.setMBeanServer is probably 1532 * QueryEval.setMBeanServer so put back the old 1533 * value. Since that method uses a ThreadLocal 1534 * variable, this code is only needed for the 1535 * unusual case where the user creates a custom 1536 * QueryExp that calls a nested query on another 1537 * MBeanServer. 1538 */ 1539 query.setMBeanServer(oldServer); 1540 } 1541 } 1542 return result; 1543 } 1544 1545 /** 1546 * Applies the specified queries to the set of NamedObjects. 1547 */ 1548 private Set<ObjectInstance> 1549 objectInstancesFromFilteredNamedObjects(Set<NamedObject> list, 1550 QueryExp query) { 1551 Set<ObjectInstance> result = new HashSet<ObjectInstance>(); 1552 // No query ... 1553 if (query == null) { 1554 for (NamedObject no : list) { 1555 final DynamicMBean obj = no.getObject(); 1556 final String className = safeGetClassName(obj); 1557 result.add(new ObjectInstance(no.getName(), className)); 1558 } 1559 } else { 1560 // Access the filter 1561 MBeanServer oldServer = QueryEval.getMBeanServer(); 1562 query.setMBeanServer(server); 1563 try { 1564 for (NamedObject no : list) { 1565 final DynamicMBean obj = no.getObject(); 1566 boolean res; 1567 try { 1568 res = query.apply(no.getName()); 1569 } catch (Exception e) { 1570 res = false; 1571 } 1572 if (res) { 1573 String className = safeGetClassName(obj); 1574 result.add(new ObjectInstance(no.getName(), className)); 1575 } 1576 } 1577 } finally { 1578 /* 1579 * query.setMBeanServer is probably 1580 * QueryEval.setMBeanServer so put back the old 1581 * value. Since that method uses a ThreadLocal 1582 * variable, this code is only needed for the 1583 * unusual case where the user creates a custom 1584 * QueryExp that calls a nested query on another 1585 * MBeanServer. 1586 */ 1587 query.setMBeanServer(oldServer); 1588 } 1589 } 1590 return result; 1591 } 1592 1593 private static String safeGetClassName(DynamicMBean mbean) { 1594 try { 1595 return getClassName(mbean); 1596 } catch (Exception e) { 1597 if (MBEANSERVER_LOGGER.isLoggable(Level.FINEST)) { 1598 MBEANSERVER_LOGGER.logp(Level.FINEST, 1599 DefaultMBeanServerInterceptor.class.getName(), 1600 "safeGetClassName", 1601 "Exception getting MBean class name", e); 1602 } 1603 return null; 1604 } 1605 } 1606 1607 /** 1608 * Applies the specified queries to the set of ObjectInstances. 1609 */ 1610 private Set<ObjectInstance> 1611 filterListOfObjectInstances(Set<ObjectInstance> list, 1612 QueryExp query) { 1613 // Null query. 1614 // 1615 if (query == null) { 1616 return list; 1617 } else { 1618 Set<ObjectInstance> result = new HashSet<ObjectInstance>(); 1619 // Access the filter. 1620 // 1621 for (ObjectInstance oi : list) { 1622 boolean res = false; 1623 MBeanServer oldServer = QueryEval.getMBeanServer(); 1624 query.setMBeanServer(server); 1625 try { 1626 res = query.apply(oi.getObjectName()); 1627 } catch (Exception e) { 1628 res = false; 1629 } finally { 1630 /* 1631 * query.setMBeanServer is probably 1632 * QueryEval.setMBeanServer so put back the old 1633 * value. Since that method uses a ThreadLocal 1634 * variable, this code is only needed for the 1635 * unusual case where the user creates a custom 1636 * QueryExp that calls a nested query on another 1637 * MBeanServer. 1638 */ 1639 query.setMBeanServer(oldServer); 1640 } 1641 if (res) { 1642 result.add(oi); 1643 } 1644 } 1645 return result; 1646 } 1647 } 1648 1649 /* 1650 * Get the existing wrapper for this listener, name, and mbean, if 1651 * there is one. Otherwise, if "create" is true, create and 1652 * return one. Otherwise, return null. 1653 * 1654 * We use a WeakHashMap so that if the only reference to a user 1655 * listener is in listenerWrappers, it can be garbage collected. 1656 * This requires a certain amount of care, because only the key in 1657 * a WeakHashMap is weak; the value is strong. We need to recover 1658 * the existing wrapper object (not just an object that is equal 1659 * to it), so we would like listenerWrappers to map any 1660 * ListenerWrapper to the canonical ListenerWrapper for that 1661 * (listener,name,mbean) set. But we do not want this canonical 1662 * wrapper to be referenced strongly. Therefore we put it inside 1663 * a WeakReference and that is the value in the WeakHashMap. 1664 */ 1665 private NotificationListener getListenerWrapper(NotificationListener l, 1666 ObjectName name, 1667 DynamicMBean mbean, 1668 boolean create) { 1669 Object resource = getResource(mbean); 1670 ListenerWrapper wrapper = new ListenerWrapper(l, name, resource); 1671 synchronized (listenerWrappers) { 1672 WeakReference<ListenerWrapper> ref = listenerWrappers.get(wrapper); 1673 if (ref != null) { 1674 NotificationListener existing = ref.get(); 1675 if (existing != null) 1676 return existing; 1677 } 1678 if (create) { 1679 ref = new WeakReference<ListenerWrapper>(wrapper); 1680 listenerWrappers.put(wrapper, ref); 1681 return wrapper; 1682 } else 1683 return null; 1684 } 1685 } 1686 1687 public Object instantiate(String className) throws ReflectionException, 1688 MBeanException { 1689 throw new UnsupportedOperationException("Not supported yet."); 1690 } 1691 1692 public Object instantiate(String className, ObjectName loaderName) throws ReflectionException, 1693 MBeanException, 1694 InstanceNotFoundException { 1695 throw new UnsupportedOperationException("Not supported yet."); 1696 } 1697 1698 public Object instantiate(String className, Object[] params, 1699 String[] signature) throws ReflectionException, MBeanException { 1700 throw new UnsupportedOperationException("Not supported yet."); 1701 } 1702 1703 public Object instantiate(String className, ObjectName loaderName, 1704 Object[] params, String[] signature) throws ReflectionException, 1705 MBeanException, 1706 InstanceNotFoundException { 1707 throw new UnsupportedOperationException("Not supported yet."); 1708 } 1709 1710 public ObjectInputStream deserialize(ObjectName name, byte[] data) throws InstanceNotFoundException, 1711 OperationsException { 1712 throw new UnsupportedOperationException("Not supported yet."); 1713 } 1714 1715 public ObjectInputStream deserialize(String className, byte[] data) throws OperationsException, 1716 ReflectionException { 1717 throw new UnsupportedOperationException("Not supported yet."); 1718 } 1719 1720 public ObjectInputStream deserialize(String className, ObjectName loaderName, 1721 byte[] data) throws InstanceNotFoundException, OperationsException, 1722 ReflectionException { 1723 throw new UnsupportedOperationException("Not supported yet."); 1724 } 1725 1726 public ClassLoaderRepository getClassLoaderRepository() { 1727 throw new UnsupportedOperationException("Not supported yet."); 1728 } 1729 1730 private static class ListenerWrapper implements NotificationListener { 1731 ListenerWrapper(NotificationListener l, ObjectName name, 1732 Object mbean) { 1733 this.listener = l; 1734 this.name = name; 1735 this.mbean = mbean; 1736 } 1737 1738 public void handleNotification(Notification notification, 1739 Object handback) { 1740 if (notification != null) { 1741 if (notification.getSource() == mbean) 1742 notification.setSource(name); 1743 } 1744 1745 /* 1746 * Listeners are not supposed to throw exceptions. If 1747 * this one does, we could remove it from the MBean. It 1748 * might indicate that a connector has stopped working, 1749 * for instance, and there is no point in sending future 1750 * notifications over that connection. However, this 1751 * seems rather drastic, so instead we propagate the 1752 * exception and let the broadcaster handle it. 1753 */ 1754 listener.handleNotification(notification, handback); 1755 } 1756 1757 @Override 1758 public boolean equals(Object o) { 1759 if (!(o instanceof ListenerWrapper)) 1760 return false; 1761 ListenerWrapper w = (ListenerWrapper) o; 1762 return (w.listener == listener && w.mbean == mbean 1763 && w.name.equals(name)); 1764 /* 1765 * We compare all three, in case the same MBean object 1766 * gets unregistered and then reregistered under a 1767 * different name, or the same name gets assigned to two 1768 * different MBean objects at different times. We do the 1769 * comparisons in this order to avoid the slow 1770 * ObjectName.equals when possible. 1771 */ 1772 } 1773 1774 @Override 1775 public int hashCode() { 1776 return (System.identityHashCode(listener) ^ 1777 System.identityHashCode(mbean)); 1778 /* 1779 * We do not include name.hashCode() in the hash because 1780 * computing it is slow and usually we will not have two 1781 * instances of ListenerWrapper with the same mbean but 1782 * different ObjectNames. That can happen if the MBean is 1783 * unregistered from one name and reregistered with 1784 * another, and there is no garbage collection between; or 1785 * if the same object is registered under two names (which 1786 * is not recommended because MBeanRegistration will 1787 * break). But even in these unusual cases the hash code 1788 * does not have to be unique. 1789 */ 1790 } 1791 1792 private NotificationListener listener; 1793 private ObjectName name; 1794 private Object mbean; 1795 } 1796 1797 // SECURITY CHECKS 1798 //---------------- 1799 1800 private static String getClassName(DynamicMBean mbean) { 1801 if (mbean instanceof DynamicMBean2) 1802 return ((DynamicMBean2) mbean).getClassName(); 1803 else 1804 return mbean.getMBeanInfo().getClassName(); 1805 } 1806 1807 private static void checkMBeanPermission(DynamicMBean mbean, 1808 String member, 1809 ObjectName objectName, 1810 String actions) { 1811 SecurityManager sm = System.getSecurityManager(); 1812 if (sm != null) { 1813 checkMBeanPermission(safeGetClassName(mbean), 1814 member, 1815 objectName, 1816 actions); 1817 } 1818 } 1819 1820 private static void checkMBeanPermission(String classname, 1821 String member, 1822 ObjectName objectName, 1823 String actions) { 1824 SecurityManager sm = System.getSecurityManager(); 1825 if (sm != null) { 1826 Permission perm = new MBeanPermission(classname, 1827 member, 1828 objectName, 1829 actions); 1830 sm.checkPermission(perm); 1831 } 1832 } 1833 1834 private static void checkMBeanTrustPermission(final Class<?> theClass) 1835 throws SecurityException { 1836 SecurityManager sm = System.getSecurityManager(); 1837 if (sm != null) { 1838 Permission perm = new MBeanTrustPermission("register"); 1839 PrivilegedAction<ProtectionDomain> act = 1840 new PrivilegedAction<ProtectionDomain>() { 1841 public ProtectionDomain run() { 1842 return theClass.getProtectionDomain(); 1843 } 1844 }; 1845 ProtectionDomain pd = AccessController.doPrivileged(act); 1846 AccessControlContext acc = 1847 new AccessControlContext(new ProtectionDomain[] { pd }); 1848 sm.checkPermission(perm, acc); 1849 } 1850 } 1851 1852 // ------------------------------------------------------------------ 1853 // 1854 // Dealing with registration of special MBeans in the repository. 1855 // 1856 // ------------------------------------------------------------------ 1857 1858 /** 1859 * A RegistrationContext that makes it possible to perform additional 1860 * post registration actions (or post unregistration actions) outside 1861 * of the repository lock, once postRegister (or postDeregister) has 1862 * been called. 1863 * The method {@code done()} will be called in registerMBean or 1864 * unregisterMBean, at the end. 1865 */ 1866 private static interface ResourceContext extends RegistrationContext { 1867 public void done(); 1868 /** An empty ResourceContext which does nothing **/ 1869 public static final ResourceContext NONE = new ResourceContext() { 1870 public void done() {} 1871 public void registering() {} 1872 public void unregistered() {} 1873 }; 1874 } 1875 1876 /** 1877 * Adds a MBean in the repository, 1878 * sends MBeanServerNotification.REGISTRATION_NOTIFICATION, 1879 * returns ResourceContext for special resources such as ClassLoaders 1880 * or JMXNamespaces. For regular MBean this method returns 1881 * ResourceContext.NONE. 1882 * @return a ResourceContext for special resources such as ClassLoaders 1883 * or JMXNamespaces. 1884 */ 1885 private ResourceContext registerWithRepository( 1886 final Object resource, 1887 final DynamicMBean object, 1888 final ObjectName logicalName) 1889 throws InstanceAlreadyExistsException, 1890 MBeanRegistrationException { 1891 1892 // Creates a registration context, if needed. 1893 // 1894 final ResourceContext context = 1895 makeResourceContextFor(resource, logicalName); 1896 1897 1898 repository.addMBean(object, logicalName, context); 1899 // May throw InstanceAlreadyExistsException 1900 1901 // --------------------- 1902 // Send create event 1903 // --------------------- 1904 if (MBEANSERVER_LOGGER.isLoggable(Level.FINER)) { 1905 MBEANSERVER_LOGGER.logp(Level.FINER, 1906 DefaultMBeanServerInterceptor.class.getName(), 1907 "addObject", "Send create notification of object " + 1908 logicalName.getCanonicalName()); 1909 } 1910 1911 sendNotification( 1912 MBeanServerNotification.REGISTRATION_NOTIFICATION, 1913 logicalName); 1914 1915 return context; 1916 } 1917 1918 /** 1919 * Removes a MBean in the repository, 1920 * sends MBeanServerNotification.UNREGISTRATION_NOTIFICATION, 1921 * returns ResourceContext for special resources such as ClassLoaders 1922 * or JMXNamespaces, or null. For regular MBean this method returns 1923 * ResourceContext.NONE. 1924 * 1925 * @return a ResourceContext for special resources such as ClassLoaders 1926 * or JMXNamespaces. 1927 */ 1928 private ResourceContext unregisterFromRepository( 1929 final Object resource, 1930 final DynamicMBean object, 1931 final ObjectName logicalName) 1932 throws InstanceNotFoundException { 1933 1934 // Creates a registration context, if needed. 1935 // 1936 final ResourceContext context = 1937 makeResourceContextFor(resource, logicalName); 1938 1939 1940 repository.remove(logicalName, context); 1941 1942 // --------------------- 1943 // Send deletion event 1944 // --------------------- 1945 if (MBEANSERVER_LOGGER.isLoggable(Level.FINER)) { 1946 MBEANSERVER_LOGGER.logp(Level.FINER, 1947 DefaultMBeanServerInterceptor.class.getName(), 1948 "unregisterMBean", "Send delete notification of object " + 1949 logicalName.getCanonicalName()); 1950 } 1951 1952 sendNotification(MBeanServerNotification.UNREGISTRATION_NOTIFICATION, 1953 logicalName); 1954 return context; 1955 } 1956 1957 1958 /** 1959 * Registers a ClassLoader with the CLR. 1960 * This method is called by the ResourceContext from within the 1961 * repository lock. 1962 * @param loader The ClassLoader. 1963 * @param logicalName The ClassLoader MBean ObjectName. 1964 */ 1965 private void addClassLoader(ClassLoader loader, 1966 final ObjectName logicalName) { 1967 /** 1968 * Called when the newly registered MBean is a ClassLoader 1969 * If so, tell the ClassLoaderRepository (CLR) about it. We do 1970 * this even if the loader is a PrivateClassLoader. In that 1971 * case, the CLR remembers the loader for use when it is 1972 * explicitly named (e.g. as the loader in createMBean) but 1973 * does not add it to the list that is consulted by 1974 * ClassLoaderRepository.loadClass. 1975 */ 1976 final ModifiableClassLoaderRepository clr = getInstantiatorCLR(); 1977 if (clr == null) { 1978 final RuntimeException wrapped = 1979 new IllegalArgumentException( 1980 "Dynamic addition of class loaders" + 1981 " is not supported"); 1982 throw new RuntimeOperationsException(wrapped, 1983 "Exception occurred trying to register" + 1984 " the MBean as a class loader"); 1985 } 1986 clr.addClassLoader(logicalName, loader); 1987 } 1988 1989 /** 1990 * Unregisters a ClassLoader from the CLR. 1991 * This method is called by the ResourceContext from within the 1992 * repository lock. 1993 * @param loader The ClassLoader. 1994 * @param logicalName The ClassLoader MBean ObjectName. 1995 */ 1996 private void removeClassLoader(ClassLoader loader, 1997 final ObjectName logicalName) { 1998 /** 1999 * Removes the MBean from the default loader repository. 2000 */ 2001 if (loader != server.getClass().getClassLoader()) { 2002 final ModifiableClassLoaderRepository clr = getInstantiatorCLR(); 2003 if (clr != null) { 2004 clr.removeClassLoader(logicalName); 2005 } 2006 } 2007 } 2008 2009 2010 /** 2011 * Creates a ResourceContext for a ClassLoader MBean. 2012 * The resource context makes it possible to add the ClassLoader to 2013 * (ResourceContext.registering) or resp. remove the ClassLoader from 2014 * (ResourceContext.unregistered) the CLR 2015 * when the associated MBean is added to or resp. removed from the 2016 * repository. 2017 * 2018 * @param loader The ClassLoader MBean being registered or 2019 * unregistered. 2020 * @param logicalName The name of the ClassLoader MBean. 2021 * @return a ResourceContext that takes in charge the addition or removal 2022 * of the loader to or from the CLR. 2023 */ 2024 private ResourceContext createClassLoaderContext( 2025 final ClassLoader loader, 2026 final ObjectName logicalName) { 2027 return new ResourceContext() { 2028 2029 public void registering() { 2030 addClassLoader(loader, logicalName); 2031 } 2032 2033 public void unregistered() { 2034 removeClassLoader(loader, logicalName); 2035 } 2036 2037 public void done() { 2038 } 2039 }; 2040 } 2041 2042 /** 2043 * Creates a ResourceContext for the given resource. 2044 * If the resource does not need a ResourceContext, returns 2045 * ResourceContext.NONE. 2046 * At this time, only ClassLoaders need a ResourceContext. 2047 * 2048 * @param resource The resource being registered or unregistered. 2049 * @param logicalName The name of the associated MBean. 2050 * @return 2051 */ 2052 private ResourceContext makeResourceContextFor(Object resource, 2053 ObjectName logicalName) { 2054 if (resource instanceof ClassLoader) { 2055 return createClassLoaderContext((ClassLoader) resource, 2056 logicalName); 2057 } 2058 return ResourceContext.NONE; 2059 } 2060 2061 private ModifiableClassLoaderRepository getInstantiatorCLR() { 2062 return AccessController.doPrivileged(new PrivilegedAction<ModifiableClassLoaderRepository>() { 2063 @Override 2064 public ModifiableClassLoaderRepository run() { 2065 return instantiator != null ? instantiator.getClassLoaderRepository() : null; 2066 } 2067 }); 2068 } 2069 }