1. /*
  2. * @(#)DefaultMBeanServerInterceptor.java 1.64 04/03/18
  3. *
  4. * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
  5. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
  6. */
  7. package com.sun.jmx.interceptor;
  8. // java import
  9. import java.util.ArrayList;
  10. import java.util.Iterator;
  11. import java.util.Set;
  12. import java.util.HashSet;
  13. import java.util.WeakHashMap;
  14. import java.lang.ref.WeakReference;
  15. import java.lang.reflect.InvocationTargetException;
  16. import java.lang.reflect.Method;
  17. import java.lang.reflect.Constructor;
  18. import java.io.OptionalDataException;
  19. import java.io.ObjectInputStream;
  20. import java.io.ObjectOutputStream;
  21. import java.io.ByteArrayInputStream;
  22. import java.io.ByteArrayOutputStream;
  23. import java.io.PrintWriter;
  24. import java.io.StringWriter;
  25. import java.io.IOException;
  26. import java.security.AccessControlContext;
  27. import java.security.Permission;
  28. import java.security.ProtectionDomain;
  29. import java.security.AccessController;
  30. import java.security.PrivilegedAction;
  31. // JMX import
  32. import javax.management.*;
  33. import javax.management.loading.ClassLoaderRepository;
  34. // JMX RI
  35. import com.sun.jmx.mbeanserver.ModifiableClassLoaderRepository;
  36. import com.sun.jmx.mbeanserver.MetaData;
  37. import com.sun.jmx.mbeanserver.MetaDataImpl;
  38. import com.sun.jmx.mbeanserver.MBeanInstantiator;
  39. import com.sun.jmx.mbeanserver.Repository;
  40. import com.sun.jmx.mbeanserver.RepositorySupport;
  41. import com.sun.jmx.mbeanserver.NamedObject;
  42. import com.sun.jmx.defaults.ServiceName;
  43. import com.sun.jmx.trace.Trace;
  44. /**
  45. * This is the default class for MBean manipulation on the agent side. It
  46. * contains the methods necessary for the creation, registration, and
  47. * deletion of MBeans as well as the access methods for registered MBeans.
  48. * This is the core component of the JMX infrastructure.
  49. * <P>
  50. * Every MBean which is added to the MBean server becomes manageable: its attributes and operations
  51. * become remotely accessible through the connectors/adaptors connected to that MBean server.
  52. * A Java object cannot be registered in the MBean server unless it is a JMX compliant MBean.
  53. * <P>
  54. * When an MBean is registered or unregistered in the MBean server an
  55. * {@link javax.management.MBeanServerNotification MBeanServerNotification}
  56. * Notification is emitted. To register an object as listener to MBeanServerNotifications
  57. * you should call the MBean server method {@link #addNotificationListener addNotificationListener} with <CODE>ObjectName</CODE>
  58. * the <CODE>ObjectName</CODE> of the {@link javax.management.MBeanServerDelegate MBeanServerDelegate}.
  59. * This <CODE>ObjectName</CODE> is:
  60. * <BR>
  61. * <CODE>JMImplementation:type=MBeanServerDelegate</CODE>.
  62. *
  63. * @since 1.5
  64. * @since.unbundled JMX RI 1.2
  65. */
  66. public class DefaultMBeanServerInterceptor implements MBeanServerInterceptor {
  67. /** MBeanServerDelegate ObjectName shared ref */
  68. private final static ObjectName _MBSDelegateObjectName;
  69. static {
  70. try {
  71. _MBSDelegateObjectName = new ObjectName(ServiceName.DELEGATE);
  72. } catch (MalformedObjectNameException e) {
  73. throw new UnsupportedOperationException(e.getMessage());
  74. }
  75. }
  76. /** The MBeanInstantiator object used by the
  77. * DefaultMBeanServerInterceptor */
  78. private final transient MBeanInstantiator instantiator;
  79. /** The MBean server object that is associated to the
  80. * DefaultMBeanServerInterceptor */
  81. private transient MBeanServer server = null;
  82. /** The MBean server object taht associated to the
  83. * DefaultMBeanServerInterceptor */
  84. private final transient MBeanServerDelegate delegate;
  85. /** The Metadata object used by the DefaultMBeanServerInterceptor */
  86. private final transient MetaData meta;
  87. /** The Repository object used by the DefaultMBeanServerInterceptor */
  88. private final transient Repository repository;
  89. /** Wrappers for client listeners. */
  90. /* See the comment before addNotificationListener below. */
  91. private final transient WeakHashMap listenerWrappers = new WeakHashMap();
  92. /** The default domain of the object names */
  93. private final String domain;
  94. /** True if the repository perform queries, false otherwise */
  95. private boolean queryByRepo;
  96. /** The sequence number identifyng the notifications sent */
  97. // Now sequence number is handled by MBeanServerDelegate.
  98. // private int sequenceNumber=0;
  99. /** The name of this class to be used for tracing */
  100. private final static String dbgTag = "DefaultMBeanServerInterceptor";
  101. /**
  102. * Creates a DefaultMBeanServerInterceptor with the specified
  103. * default domain name.
  104. * The default domain name is used as the domain part in the ObjectName
  105. * of MBeans if no domain is specified by the user.
  106. * <p>Do not forget to call <code>initialize(outer,delegate)</code>
  107. * before using this object.
  108. * @param domain The default domain name used by this MBeanServer.
  109. * @param outer A pointer to the MBeanServer object that must be
  110. * passed to the MBeans when invoking their
  111. * {@link javax.management.MBeanRegistration} interface.
  112. * @param delegate A pointer to the MBeanServerDelegate associated
  113. * with the new MBeanServer. The new MBeanServer must register
  114. * this MBean in its MBean repository.
  115. * @param instantiator The MBeanInstantiator that will be used to
  116. * instantiate MBeans and take care of class loading issues.
  117. */
  118. public DefaultMBeanServerInterceptor(String domain,
  119. MBeanServer outer,
  120. MBeanServerDelegate delegate,
  121. MBeanInstantiator instantiator) {
  122. this(outer, delegate, instantiator, null,
  123. new RepositorySupport((domain==null?ServiceName.DOMAIN:domain)));
  124. }
  125. /**
  126. * Creates a DefaultMBeanServerInterceptor with the specified
  127. * repository instance.
  128. * <p>Do not forget to call <code>initialize(outer,delegate)</code>
  129. * before using this object.
  130. * @param outer A pointer to the MBeanServer object that must be
  131. * passed to the MBeans when invoking their
  132. * {@link javax.management.MBeanRegistration} interface.
  133. * @param delegate A pointer to the MBeanServerDelegate associated
  134. * with the new MBeanServer. The new MBeanServer must register
  135. * this MBean in its MBean repository.
  136. * @param instantiator The MBeanInstantiator that will be used to
  137. * instantiate MBeans and take care of class loading issues.
  138. * @param metadata The MetaData object that will be used by the
  139. * MBean server in order to invoke the MBean interface of
  140. * the registered MBeans.
  141. * @param repository The repository to use for this MBeanServer
  142. */
  143. public DefaultMBeanServerInterceptor(MBeanServer outer,
  144. MBeanServerDelegate delegate,
  145. MBeanInstantiator instantiator,
  146. MetaData metadata,
  147. Repository repository) {
  148. if (outer == null) throw new
  149. IllegalArgumentException("outer MBeanServer cannot be null");
  150. if (delegate == null) throw new
  151. IllegalArgumentException("MBeanServerDelegate cannot be null");
  152. if (instantiator == null) throw new
  153. IllegalArgumentException("MBeanInstantiator cannot be null");
  154. if (metadata == null)
  155. metadata = new MetaDataImpl(instantiator);
  156. if (repository == null)
  157. repository = new RepositorySupport(ServiceName.DOMAIN);
  158. this.server = outer;
  159. this.delegate = delegate;
  160. this.instantiator = instantiator;
  161. this.meta = metadata;
  162. this.repository = repository;
  163. this.domain = repository.getDefaultDomain();
  164. }
  165. public ObjectInstance createMBean(String className, ObjectName name)
  166. throws ReflectionException, InstanceAlreadyExistsException,
  167. MBeanRegistrationException, MBeanException,
  168. NotCompliantMBeanException {
  169. return createMBean(className, name, (Object[]) null, (String[]) null);
  170. }
  171. public ObjectInstance createMBean(String className, ObjectName name,
  172. ObjectName loaderName)
  173. throws ReflectionException, InstanceAlreadyExistsException,
  174. MBeanRegistrationException, MBeanException,
  175. NotCompliantMBeanException, InstanceNotFoundException {
  176. return createMBean(className, name, loaderName, (Object[]) null,
  177. (String[]) null);
  178. }
  179. public ObjectInstance createMBean(String className, ObjectName name,
  180. Object[] params, String[] signature)
  181. throws ReflectionException, InstanceAlreadyExistsException,
  182. MBeanRegistrationException, MBeanException,
  183. NotCompliantMBeanException {
  184. try {
  185. return createMBean(className, name, null, true,
  186. params, signature);
  187. } catch (InstanceNotFoundException e) {
  188. /* Can only happen if loaderName doesn't exist, but we just
  189. passed null, so we shouldn't get this exception. */
  190. throw new IllegalArgumentException("Unexpected exception: " + e);
  191. }
  192. }
  193. public ObjectInstance createMBean(String className, ObjectName name,
  194. ObjectName loaderName,
  195. Object[] params, String[] signature)
  196. throws ReflectionException, InstanceAlreadyExistsException,
  197. MBeanRegistrationException, MBeanException,
  198. NotCompliantMBeanException, InstanceNotFoundException {
  199. return createMBean(className, name, loaderName, false,
  200. params, signature);
  201. }
  202. private ObjectInstance createMBean(String className, ObjectName name,
  203. ObjectName loaderName,
  204. boolean withDefaultLoaderRepository,
  205. Object[] params, String[] signature)
  206. throws ReflectionException, InstanceAlreadyExistsException,
  207. MBeanRegistrationException, MBeanException,
  208. NotCompliantMBeanException, InstanceNotFoundException {
  209. ObjectName logicalName = name;
  210. Class theClass;
  211. if (className == null) {
  212. final RuntimeException wrapped =
  213. new IllegalArgumentException("The class name cannot be null");
  214. throw new RuntimeOperationsException(wrapped,
  215. "Exception occured during MBean creation");
  216. }
  217. if (name != null) {
  218. if (name.isPattern()) {
  219. final RuntimeException wrapped =
  220. new IllegalArgumentException("Invalid name->" +
  221. name.toString());
  222. final String msg = "Exception occurred during MBean creation";
  223. throw new RuntimeOperationsException(wrapped, msg);
  224. }
  225. name = nonDefaultDomain(name);
  226. }
  227. /* Permission check */
  228. checkMBeanPermission(className, null, null, "instantiate");
  229. checkMBeanPermission(className, null, name, "registerMBean");
  230. /* Load the appropriate class. */
  231. if (withDefaultLoaderRepository) {
  232. if (isTraceOn()) {
  233. trace(dbgTag, "createMBean", "ClassName = " + className +
  234. ",ObjectName = " + name);
  235. }
  236. theClass =
  237. instantiator.findClassWithDefaultLoaderRepository(className);
  238. } else if (loaderName == null) {
  239. if (isTraceOn()) {
  240. trace(dbgTag, "createMBean", "ClassName = " + className +
  241. ",ObjectName = " + name + " Loader name = null");
  242. }
  243. theClass = instantiator.findClass(className,
  244. server.getClass().getClassLoader());
  245. } else {
  246. loaderName = nonDefaultDomain(loaderName);
  247. if (isTraceOn()) {
  248. trace(dbgTag, "createMBean", "ClassName = " + className +
  249. ",ObjectName = " + name + ",Loader name = "+
  250. loaderName.toString());
  251. }
  252. theClass = instantiator.findClass(className, loaderName);
  253. }
  254. /* Permission check */
  255. checkMBeanTrustPermission(theClass);
  256. // Check that the MBean can be instantiated by the MBeanServer.
  257. instantiator.testCreation(theClass);
  258. // Check the JMX compliance of the class
  259. meta.testCompliance(theClass);
  260. Object moi= instantiator.instantiate(theClass, params, signature,
  261. server.getClass().getClassLoader());
  262. final String infoClassName;
  263. try {
  264. infoClassName = meta.getMBeanClassName(moi);
  265. } catch (IntrospectionException e) {
  266. throw new NotCompliantMBeanException(e.getMessage());
  267. }
  268. return registerCreatedObject(infoClassName, moi, name);
  269. }
  270. public ObjectInstance registerMBean(Object object, ObjectName name)
  271. throws InstanceAlreadyExistsException, MBeanRegistrationException,
  272. NotCompliantMBeanException {
  273. // ------------------------------
  274. // ------------------------------
  275. Class theClass = object.getClass();
  276. // Check the JMX compliance of the class
  277. meta.testCompliance(theClass);
  278. /* Permission check */
  279. final String infoClassName;
  280. try {
  281. infoClassName = meta.getMBeanClassName(object);
  282. } catch (IntrospectionException e) {
  283. throw new NotCompliantMBeanException(e.getMessage());
  284. }
  285. checkMBeanPermission(infoClassName, null, name, "registerMBean");
  286. checkMBeanTrustPermission(theClass);
  287. return registerObject(infoClassName, object, name);
  288. }
  289. public void unregisterMBean(ObjectName name)
  290. throws InstanceNotFoundException, MBeanRegistrationException {
  291. Object object;
  292. if (name == null) {
  293. final RuntimeException wrapped =
  294. new IllegalArgumentException("Object name cannot be null");
  295. throw new RuntimeOperationsException(wrapped,
  296. "Exception occured trying to unregister the MBean");
  297. }
  298. name = nonDefaultDomain(name);
  299. /* Permission check */
  300. Object instance = getMBean(name);
  301. String classname = null;
  302. try {
  303. classname = meta.getMBeanClassName(instance);
  304. } catch (IntrospectionException e) {
  305. classname = null;
  306. } catch (NotCompliantMBeanException e) {
  307. classname = null;
  308. }
  309. checkMBeanPermission(classname, null, name, "unregisterMBean");
  310. /* We synchronize here to be sure that the preDeregister
  311. method will be invoked exactly once, even if more than one
  312. thread unregisters the MBean at the same time. */
  313. synchronized(this) {
  314. object = repository.retrieve(name);
  315. if (object==null) {
  316. if (isTraceOn()) {
  317. trace("unregisterMBean", name+": Found no object");
  318. }
  319. throw new InstanceNotFoundException(name.toString());
  320. }
  321. if (object instanceof MBeanRegistration) {
  322. meta.preDeregisterInvoker(object);
  323. }
  324. // Let the repository do the work.
  325. try {
  326. repository.remove(name);
  327. }
  328. catch (InstanceNotFoundException e) {
  329. throw e;
  330. }
  331. /**
  332. * Checks if the unregistered MBean is a ClassLoader
  333. * If so, it removes the MBean from the default loader repository.
  334. */
  335. if (object instanceof ClassLoader
  336. && object != server.getClass().getClassLoader()) {
  337. final ModifiableClassLoaderRepository clr =
  338. instantiator.getClassLoaderRepository();
  339. if (clr != null) clr.removeClassLoader(name);
  340. }
  341. }
  342. // ---------------------
  343. // Send deletion event
  344. // ---------------------
  345. if (isTraceOn()) {
  346. trace("unregisterMBean", "Send delete notification of object "
  347. + name.getCanonicalName());
  348. }
  349. sendNotification(MBeanServerNotification.UNREGISTRATION_NOTIFICATION,
  350. name);
  351. if (object instanceof MBeanRegistration) {
  352. meta.postDeregisterInvoker(object);
  353. }
  354. }
  355. public ObjectInstance getObjectInstance(ObjectName name)
  356. throws InstanceNotFoundException {
  357. name = nonDefaultDomain(name);
  358. Object obj = getMBean(name);
  359. final String className;
  360. try {
  361. className = meta.getMBeanClassName(obj);
  362. } catch (IntrospectionException x) {
  363. debugX("getObjectInstance",x);
  364. throw new JMRuntimeException("Can't obtain class name for " +
  365. name + ": " + x);
  366. } catch (NotCompliantMBeanException x) {
  367. debugX("getObjectInstance",x);
  368. throw new JMRuntimeException("Can't obtain class name for " +
  369. name + ": " + x);
  370. }
  371. /* Permission check */
  372. checkMBeanPermission(className, null, name, "getObjectInstance");
  373. return new ObjectInstance(name, className);
  374. }
  375. public Set queryMBeans(ObjectName name, QueryExp query) {
  376. /* Permission check */
  377. SecurityManager sm = System.getSecurityManager();
  378. if (sm != null) {
  379. // Check if the caller has the right to invoke 'queryMBeans'
  380. //
  381. checkMBeanPermission(null, null, null, "queryMBeans");
  382. // Perform query without "query".
  383. //
  384. Set list = queryMBeansImpl(name, null);
  385. // Check if the caller has the right to invoke 'queryMBeans'
  386. // on each specific classname/objectname in the list.
  387. //
  388. Set allowedList = new HashSet(list.size());
  389. for (Iterator i = list.iterator(); i.hasNext(); ) {
  390. try {
  391. ObjectInstance oi = (ObjectInstance) i.next();
  392. checkMBeanPermission(oi.getClassName(), null,
  393. oi.getObjectName(), "queryMBeans");
  394. allowedList.add(oi);
  395. } catch (SecurityException e) {
  396. // OK: Do not add this ObjectInstance to the list
  397. }
  398. }
  399. // Apply query to allowed MBeans only.
  400. //
  401. return filterListOfObjectInstances(allowedList, query);
  402. } else {
  403. // Perform query.
  404. //
  405. return queryMBeansImpl(name, query);
  406. }
  407. }
  408. private Set queryMBeansImpl(ObjectName name, QueryExp query) {
  409. // Query the MBeans on the repository
  410. //
  411. Set list = null;
  412. synchronized(this) {
  413. list = repository.query(name, query);
  414. }
  415. // The repository performs the filtering
  416. //
  417. if (queryByRepo) {
  418. return list;
  419. } else {
  420. // The filtering will be performed by the MBeanServer
  421. //
  422. return (filterListOfObjects(list, query));
  423. }
  424. }
  425. public Set queryNames(ObjectName name, QueryExp query) {
  426. /* Permission check */
  427. SecurityManager sm = System.getSecurityManager();
  428. if (sm != null) {
  429. // Check if the caller has the right to invoke 'queryNames'
  430. //
  431. checkMBeanPermission(null, null, null, "queryNames");
  432. // Perform query without "query".
  433. //
  434. Set list = queryMBeansImpl(name, null);
  435. // Check if the caller has the right to invoke 'queryNames'
  436. // on each specific classname/objectname in the list.
  437. //
  438. Set allowedList = new HashSet(list.size());
  439. for (Iterator i = list.iterator(); i.hasNext(); ) {
  440. try {
  441. ObjectInstance oi = (ObjectInstance) i.next();
  442. checkMBeanPermission(oi.getClassName(), null,
  443. oi.getObjectName(), "queryNames");
  444. allowedList.add(oi);
  445. } catch (SecurityException e) {
  446. // OK: Do not add this ObjectInstance to the list
  447. }
  448. }
  449. // Apply query to allowed MBeans only.
  450. //
  451. Set queryList = filterListOfObjectInstances(allowedList, query);
  452. Set result = new HashSet(queryList.size());
  453. for (Iterator i = queryList.iterator(); i.hasNext(); ) {
  454. ObjectInstance oi = (ObjectInstance) i.next();
  455. result.add(oi.getObjectName());
  456. }
  457. return result;
  458. } else {
  459. // Perform query.
  460. //
  461. Set queryList = queryMBeansImpl(name, query);
  462. Set result = new HashSet(queryList.size());
  463. for (Iterator i = queryList.iterator(); i.hasNext(); ) {
  464. ObjectInstance oi = (ObjectInstance) i.next();
  465. result.add(oi.getObjectName());
  466. }
  467. return result;
  468. }
  469. }
  470. public boolean isRegistered(ObjectName name) {
  471. if (name == null) {
  472. throw new RuntimeOperationsException(
  473. new IllegalArgumentException("Object name cannot be null"),
  474. "Object name cannot be null");
  475. }
  476. name = nonDefaultDomain(name);
  477. // /* Permission check */
  478. // checkMBeanPermission(null, null, name, "isRegistered");
  479. synchronized(this) {
  480. return (repository.contains(name));
  481. }
  482. }
  483. public String[] getDomains() {
  484. /* Permission check */
  485. SecurityManager sm = System.getSecurityManager();
  486. if (sm != null) {
  487. // Check if the caller has the right to invoke 'getDomains'
  488. //
  489. checkMBeanPermission(null, null, null, "getDomains");
  490. // Return domains
  491. //
  492. String[] domains = repository.getDomains();
  493. // Check if the caller has the right to invoke 'getDomains'
  494. // on each specific domain in the list.
  495. //
  496. ArrayList result = new ArrayList(domains.length);
  497. for (int i = 0; i < domains.length; i++) {
  498. try {
  499. ObjectName domain = new ObjectName(domains[i] + ":x=x");
  500. checkMBeanPermission(null, null, domain, "getDomains");
  501. result.add(domains[i]);
  502. } catch (MalformedObjectNameException e) {
  503. // Should never occur... But let's log it just in case.
  504. error("getDomains",
  505. "Failed to check permission for domain=" +
  506. domains[i] + ". Error is: " + e);
  507. debugX("getDomains",e);
  508. } catch (SecurityException e) {
  509. // OK: Do not add this domain to the list
  510. }
  511. }
  512. // Make an array from result.
  513. //
  514. return (String[]) result.toArray(new String[result.size()]);
  515. } else {
  516. return repository.getDomains();
  517. }
  518. }
  519. public Integer getMBeanCount() {
  520. return (repository.getCount());
  521. }
  522. public Object getAttribute(ObjectName name, String attribute)
  523. throws MBeanException, AttributeNotFoundException,
  524. InstanceNotFoundException, ReflectionException {
  525. if (name == null) {
  526. throw new RuntimeOperationsException(new
  527. IllegalArgumentException("Object name cannot be null"),
  528. "Exception occured trying to invoke the getter on the MBean");
  529. }
  530. if (attribute == null) {
  531. throw new RuntimeOperationsException(new
  532. IllegalArgumentException("Attribute cannot be null"),
  533. "Exception occured trying to invoke the getter on the MBean");
  534. }
  535. name = nonDefaultDomain(name);
  536. if (isTraceOn()) {
  537. trace("getAttribute", "Attribute= " + attribute +
  538. ", obj= " + name);
  539. }
  540. /* Permission check */
  541. Object instance = getMBean(name);
  542. String classname = null;
  543. try {
  544. classname = meta.getMBeanClassName(instance);
  545. } catch (IntrospectionException e) {
  546. classname = null;
  547. } catch (NotCompliantMBeanException e) {
  548. classname = null;
  549. }
  550. checkMBeanPermission(classname, attribute, name, "getAttribute");
  551. return meta.getAttribute(instance, attribute);
  552. }
  553. public AttributeList getAttributes(ObjectName name, String[] attributes)
  554. throws InstanceNotFoundException, ReflectionException {
  555. if (name == null) {
  556. throw new RuntimeOperationsException(new
  557. IllegalArgumentException("ObjectName name cannot be null"),
  558. "Exception occured trying to invoke the getter on the MBean");
  559. }
  560. if (attributes == null) {
  561. throw new RuntimeOperationsException(new
  562. IllegalArgumentException("Attributes cannot be null"),
  563. "Exception occured trying to invoke the getter on the MBean");
  564. }
  565. name = nonDefaultDomain(name);
  566. if (isTraceOn()) {
  567. trace("getAttributes", "Object= " + name);
  568. }
  569. Object instance = getMBean(name);
  570. SecurityManager sm = System.getSecurityManager();
  571. if (sm != null) {
  572. /* Permission check */
  573. String classname = null;
  574. try {
  575. classname = meta.getMBeanClassName(instance);
  576. } catch (IntrospectionException e) {
  577. classname = null;
  578. } catch (NotCompliantMBeanException e) {
  579. classname = null;
  580. }
  581. // Check if the caller has the right to invoke 'getAttribute'
  582. //
  583. checkMBeanPermission(classname, null, name, "getAttribute");
  584. // Check if the caller has the right to invoke 'getAttribute'
  585. // on each specific attribute
  586. //
  587. ArrayList allowedList = new ArrayList(attributes.length);
  588. for (int i = 0; i < attributes.length; i++) {
  589. try {
  590. checkMBeanPermission(classname, attributes[i],
  591. name, "getAttribute");
  592. allowedList.add(attributes[i]);
  593. } catch (SecurityException e) {
  594. // OK: Do not add this attribute to the list
  595. }
  596. }
  597. String[] allowedAttributes =
  598. (String[]) allowedList.toArray(new String[0]);
  599. return meta.getAttributes(instance, allowedAttributes);
  600. } else {
  601. return meta.getAttributes(instance, attributes);
  602. }
  603. }
  604. public void setAttribute(ObjectName name, Attribute attribute)
  605. throws InstanceNotFoundException, AttributeNotFoundException,
  606. InvalidAttributeValueException, MBeanException,
  607. ReflectionException {
  608. if (name == null) {
  609. throw new RuntimeOperationsException(new
  610. IllegalArgumentException("ObjectName name cannot be null"),
  611. "Exception occured trying to invoke the setter on the MBean");
  612. }
  613. if (attribute == null) {
  614. throw new RuntimeOperationsException(new
  615. IllegalArgumentException("Attribute cannot be null"),
  616. "Exception occured trying to invoke the setter on the MBean");
  617. }
  618. name = nonDefaultDomain(name);
  619. if (isTraceOn()) {
  620. trace("setAttribute", "Object= " + name + ", attribute=" +
  621. attribute.getName());
  622. }
  623. /* Permission check */
  624. Object instance = getMBean(name);
  625. String classname = null;
  626. try {
  627. classname = meta.getMBeanClassName(instance);
  628. } catch (IntrospectionException e) {
  629. classname = null;
  630. } catch (NotCompliantMBeanException e) {
  631. classname = null;
  632. }
  633. checkMBeanPermission(classname, attribute.getName(),
  634. name, "setAttribute");
  635. final Object o = meta.setAttribute(instance, attribute);
  636. }
  637. public AttributeList setAttributes(ObjectName name,
  638. AttributeList attributes)
  639. throws InstanceNotFoundException, ReflectionException {
  640. if (name == null) {
  641. throw new RuntimeOperationsException(new
  642. IllegalArgumentException("ObjectName name cannot be null"),
  643. "Exception occured trying to invoke the setter on the MBean");
  644. }
  645. if (attributes == null) {
  646. throw new RuntimeOperationsException(new
  647. IllegalArgumentException("AttributeList cannot be null"),
  648. "Exception occured trying to invoke the setter on the MBean");
  649. }
  650. name = nonDefaultDomain(name);
  651. Object instance = getMBean(name);
  652. SecurityManager sm = System.getSecurityManager();
  653. if (sm != null) {
  654. /* Permission check */
  655. String classname = null;
  656. try {
  657. classname = meta.getMBeanClassName(instance);
  658. } catch (IntrospectionException e) {
  659. classname = null;
  660. } catch (NotCompliantMBeanException e) {
  661. classname = null;
  662. }
  663. // Check if the caller has the right to invoke 'setAttribute'
  664. //
  665. checkMBeanPermission(classname, null, name, "setAttribute");
  666. // Check if the caller has the right to invoke 'setAttribute'
  667. // on each specific attribute
  668. //
  669. AttributeList allowedAttributes =
  670. new AttributeList(attributes.size());
  671. for (Iterator i = attributes.iterator(); i.hasNext();) {
  672. try {
  673. Attribute attribute = (Attribute) i.next();
  674. checkMBeanPermission(classname, attribute.getName(),
  675. name, "setAttribute");
  676. allowedAttributes.add(attribute);
  677. } catch (SecurityException e) {
  678. // OK: Do not add this attribute to the list
  679. }
  680. }
  681. return meta.setAttributes(instance, allowedAttributes);
  682. } else {
  683. return meta.setAttributes(instance, attributes);
  684. }
  685. }
  686. public Object invoke(ObjectName name, String operationName,
  687. Object params[], String signature[])
  688. throws InstanceNotFoundException, MBeanException,
  689. ReflectionException {
  690. name = nonDefaultDomain(name);
  691. /* Permission check */
  692. Object instance = getMBean(name);
  693. String classname = null;
  694. try {
  695. classname = meta.getMBeanClassName(instance);
  696. } catch (IntrospectionException e) {
  697. classname = null;
  698. } catch (NotCompliantMBeanException e) {
  699. classname = null;
  700. }
  701. checkMBeanPermission(classname, operationName, name, "invoke");
  702. return meta.invoke(instance, operationName, params, signature);
  703. }
  704. /**
  705. * Return the MetaData service object used by this interceptor.
  706. *
  707. **/
  708. protected MetaData meta() {
  709. return meta;
  710. }
  711. /**
  712. * Builds an ObjectInstance.
  713. * <ul>
  714. * <li> If the given <code>object</code> implements DynamicMBean,
  715. * then ask its MBeanInfo for the class name.</li>
  716. * <li> Otherwise, uses the provided <code>className</code></li>
  717. * </ul>
  718. *
  719. * @return A new ObjectInstance for the given <code>object</code>.
  720. * @exception NotCompliantMBeanException if the <code>object</code>
  721. * implements DynamicMBean but the class name can't be
  722. * retrieved from its MBeanInfo.
  723. **/
  724. protected ObjectInstance makeObjectInstance(String className,
  725. Object object,
  726. ObjectName name)
  727. throws NotCompliantMBeanException {
  728. // if the MBean is a dynamic MBean ask its MBeanInfo for the
  729. // class name
  730. if (object instanceof DynamicMBean) {
  731. try {
  732. className = meta.getMBeanClassName(object);
  733. } catch (SecurityException x) {
  734. debugX("makeObjectInstance",x);
  735. throw x;
  736. } catch (IntrospectionException x) {
  737. debugX("makeObjectInstance",x);
  738. throw new NotCompliantMBeanException(
  739. "Can't obtain class name for " + name + ": " + x);
  740. } catch (JMRuntimeException x) {
  741. debugX("makeObjectInstance",x);
  742. throw new NotCompliantMBeanException(
  743. "Can't obtain class name for " + name + ": " + x);
  744. }
  745. }
  746. if (className == null) {
  747. throw new NotCompliantMBeanException(
  748. "The class Name returned is null");
  749. }
  750. return(new ObjectInstance(nonDefaultDomain(name), className));
  751. }
  752. /**
  753. * Register <code>object</code> in the repository, with the
  754. * given <code>name</code>.
  755. * This method is called by the various createMBean() flavours
  756. * and by registerMBean() after all MBean compliance tests
  757. * have been performed.
  758. * <p>
  759. * This method does not performed any kind of test compliance,
  760. * and the caller should make sure that the given <code>object</object>
  761. * is MBean compliant.
  762. * <p>
  763. * This methods performed all the basic steps needed for object
  764. * registration:
  765. * <ul>
  766. * <li>If the <code>object</code> implements the MBeanRegistration
  767. * interface, it invokes preRegister() on the object.</li>
  768. * <li>Then the object is added to the repository with the given
  769. * <code>name</code>.</li>
  770. * <li>Finally, if the <code>object</code> implements the
  771. * MBeanRegistration interface, it invokes postRegister()
  772. * on the object.</li>
  773. * </ul>
  774. * @param object A reference to a MBean compliant object.
  775. * @param name The ObjectName of the <code>object</code> MBean.
  776. * @return the actual ObjectName with which the object was registered.
  777. * @exception InstanceAlreadyExistsException if an object is already
  778. * registered with that name.
  779. * @exception MBeanRegistrationException if an exception occurs during
  780. * registration.
  781. **/
  782. protected ObjectInstance registerObject(String classname,
  783. Object object, ObjectName name)
  784. throws InstanceAlreadyExistsException,
  785. MBeanRegistrationException,
  786. NotCompliantMBeanException {
  787. if (object == null) {
  788. final RuntimeException wrapped =
  789. new IllegalArgumentException("Cannot add null object");
  790. throw new RuntimeOperationsException(wrapped,
  791. "Exception occured trying to register the MBean");
  792. }
  793. name = nonDefaultDomain(name);
  794. if (isTraceOn()) {
  795. trace(dbgTag, "registerMBean", "ObjectName = " + name);
  796. }
  797. ObjectName logicalName = name;
  798. if (object instanceof MBeanRegistration) {
  799. logicalName = meta.preRegisterInvoker(object, name, server);
  800. if (logicalName != name && logicalName != null) {
  801. logicalName =
  802. ObjectName.getInstance(nonDefaultDomain(logicalName));
  803. }
  804. }
  805. /* Permission check */
  806. checkMBeanPermission(classname, null, logicalName, "registerMBean");
  807. final ObjectInstance result;
  808. if (logicalName!=null) {
  809. result = makeObjectInstance(classname, object, logicalName);
  810. internal_addObject(object, logicalName);
  811. } else {
  812. if (object instanceof MBeanRegistration ) {
  813. meta.postRegisterInvoker(object, false);
  814. }
  815. final RuntimeException wrapped =
  816. new IllegalArgumentException("No object name specified");
  817. throw new RuntimeOperationsException(wrapped,
  818. "Exception occured trying to register the MBean");
  819. }
  820. if (object instanceof MBeanRegistration)
  821. meta.postRegisterInvoker(object, true);
  822. /**
  823. * Checks if the newly registered MBean is a ClassLoader
  824. * If so, tell the ClassLoaderRepository (CLR) about it. We do
  825. * this even if the object is a PrivateClassLoader. In that
  826. * case, the CLR remembers the loader for use when it is
  827. * explicitly named (e.g. as the loader in createMBean) but
  828. * does not add it to the list that is consulted by
  829. * ClassLoaderRepository.loadClass.
  830. */
  831. if (object instanceof ClassLoader) {
  832. final ModifiableClassLoaderRepository clr =
  833. instantiator.getClassLoaderRepository();
  834. if (clr == null) {
  835. final RuntimeException wrapped =
  836. new IllegalArgumentException(
  837. "Dynamic addition of class loaders is not supported");
  838. throw new RuntimeOperationsException(wrapped,
  839. "Exception occured trying to register the MBean as a class loader");
  840. }
  841. clr.addClassLoader(logicalName, (ClassLoader)object);
  842. }
  843. return result;
  844. }
  845. /**
  846. * Register an object from within createMBean().
  847. * This method wrapps registerObject() and is only called from within
  848. * createMBean().
  849. * It calls directly registerObject(). Its only purpose is to provide
  850. * hooks for derived classes.
  851. **/
  852. protected ObjectInstance registerCreatedObject(String classname,
  853. Object object,
  854. ObjectName name)
  855. throws InstanceAlreadyExistsException,
  856. MBeanRegistrationException,
  857. NotCompliantMBeanException {
  858. return registerObject(classname,object,name);
  859. }
  860. /**
  861. * Gets a specific MBean controlled by the DefaultMBeanServerInterceptor.
  862. * The name must have a non-default domain.
  863. */
  864. private Object getMBean(ObjectName name)
  865. throws InstanceNotFoundException {
  866. if (name == null) {
  867. throw new RuntimeOperationsException(new
  868. IllegalArgumentException("Object name cannot be null"),
  869. "Exception occured trying to get an MBean");
  870. }
  871. Object obj = null;
  872. synchronized(this) {
  873. obj = repository.retrieve(name);
  874. if (obj == null) {
  875. if (isTraceOn()) {
  876. trace("getMBean", name+": Found no object");
  877. }
  878. throw new InstanceNotFoundException(name.toString());
  879. }
  880. }
  881. return obj;
  882. }
  883. private ObjectName nonDefaultDomain(ObjectName name) {
  884. if (name == null || name.getDomain().length() > 0)
  885. return name;
  886. /* The ObjectName looks like ":a=b", and that's what its
  887. toString() will return in this implementation. So
  888. we can just stick the default domain in front of it
  889. to get a non-default-domain name. We depend on the
  890. fact that toString() works like that and that it
  891. leaves wildcards in place (so we can detect an error
  892. if one is supplied where it shouldn't be). */
  893. final String completeName = domain + name;
  894. try {
  895. return new ObjectName(completeName);
  896. } catch (MalformedObjectNameException e) {
  897. final String msg =
  898. "Unexpected default domain problem: " + completeName + ": " +
  899. e;
  900. throw new IllegalArgumentException(msg);
  901. }
  902. }
  903. public String getDefaultDomain() {
  904. return domain;
  905. }
  906. /*
  907. * Notification handling.
  908. *
  909. * This is not trivial, because the MBeanServer translates the
  910. * source of a received notification from a reference to an MBean
  911. * into the ObjectName of that MBean. While that does make
  912. * notification sending easier for MBean writers, it comes at a
  913. * considerable cost. We need to replace the source of a
  914. * notification, which is basically wrong if there are also
  915. * listeners registered directly with the MBean (without going
  916. * through the MBean server). We also need to wrap the listener
  917. * supplied by the client of the MBeanServer with a listener that
  918. * performs the substitution before forwarding. This is why we
  919. * strongly discourage people from putting MBean references in the
  920. * source of their notifications. Instead they should arrange to
  921. * put the ObjectName there themselves.
  922. *
  923. * However, existing code relies on the substitution, so we are
  924. * stuck with it.
  925. *
  926. * Here's how we handle it. When you add a listener, we make a
  927. * ListenerWrapper around it. We look that up in the
  928. * listenerWrappers map, and if there was already a wrapper for
  929. * that listener with the given ObjectName, we reuse it. This map
  930. * is a WeakHashMap, so a listener that is no longer registered
  931. * with any MBean can be garbage collected.
  932. *
  933. * We cannot use simpler solutions such as always creating a new
  934. * wrapper or always registering the same listener with the MBean
  935. * and using the handback to find the client's original listener.
  936. * The reason is that we need to support the removeListener
  937. * variant that removes all (listener,filter,handback) triples on
  938. * a broadcaster that have a given listener. And we do not have
  939. * any way to inspect a broadcaster's internal list of triples.
  940. * So the same client listener must always map to the same
  941. * listener registered with the broadcaster.
  942. *
  943. * Another possible solution would be to map from ObjectName to
  944. * list of listener wrappers (or IdentityHashMap of listener
  945. * wrappers), making this list the first time a listener is added
  946. * on a given MBean, and removing it when the MBean is removed.
  947. * This is probably more costly in memory, but could be useful if
  948. * some day we don't want to rely on weak references.
  949. */
  950. public void addNotificationListener(ObjectName name,
  951. NotificationListener listener,
  952. NotificationFilter filter,
  953. Object handback)
  954. throws InstanceNotFoundException {
  955. // ------------------------------
  956. // ------------------------------
  957. if (isTraceOn()) {
  958. trace("addNotificationListener", "obj= " + name);
  959. }
  960. /* Permission check */
  961. Object instance = getMBean(name);
  962. String classname = null;
  963. try {
  964. classname = meta.getMBeanClassName(instance);
  965. } catch (IntrospectionException e) {
  966. classname = null;
  967. } catch (NotCompliantMBeanException e) {
  968. classname = null;
  969. }
  970. checkMBeanPermission(classname, null, name, "addNotificationListener");
  971. NotificationBroadcaster broadcaster;
  972. if (!(instance instanceof NotificationBroadcaster)) {
  973. throw new RuntimeOperationsException(new
  974. IllegalArgumentException(name.getCanonicalName() ),
  975. "The MBean " + name.getCanonicalName() +
  976. " does not implement the NotificationBroadcaster interface");
  977. }
  978. broadcaster = (NotificationBroadcaster) instance;
  979. // ------------------
  980. // Check listener
  981. // ------------------
  982. if (listener == null) {
  983. throw new RuntimeOperationsException(new
  984. IllegalArgumentException("Null listener"),"Null listener");
  985. }
  986. NotificationListener listenerWrapper =
  987. getListenerWrapper(listener, name, instance, true);
  988. broadcaster.addNotificationListener(listenerWrapper, filter, handback);
  989. }
  990. public void addNotificationListener(ObjectName name,
  991. ObjectName listener,
  992. NotificationFilter filter,
  993. Object handback)
  994. throws InstanceNotFoundException {
  995. // ------------------------------
  996. // ------------------------------
  997. // ----------------
  998. // Get listener object
  999. // ----------------
  1000. Object instance = getMBean(listener);
  1001. if (!(instance instanceof NotificationListener)) {
  1002. throw new RuntimeOperationsException(new
  1003. IllegalArgumentException(listener.getCanonicalName()),
  1004. "The MBean " + listener.getCanonicalName() +
  1005. "does not implement the NotificationListener interface") ;
  1006. }
  1007. // ----------------
  1008. // Add a listener on an MBean
  1009. // ----------------
  1010. if (isTraceOn()) {
  1011. trace("addNotificationListener", "obj= " + name + " listener= " +
  1012. listener);
  1013. }
  1014. server.addNotificationListener(name,(NotificationListener) instance,
  1015. filter, handback) ;
  1016. }
  1017. public void removeNotificationListener(ObjectName name,
  1018. NotificationListener listener)
  1019. throws InstanceNotFoundException, ListenerNotFoundException {
  1020. removeNotificationListener(name, listener, null, null, true);
  1021. }
  1022. public void removeNotificationListener(ObjectName name,
  1023. NotificationListener listener,
  1024. NotificationFilter filter,
  1025. Object handback)
  1026. throws InstanceNotFoundException, ListenerNotFoundException {
  1027. removeNotificationListener(name, listener, filter, handback, false);
  1028. }
  1029. public void removeNotificationListener(ObjectName name,
  1030. ObjectName listener)
  1031. throws InstanceNotFoundException, ListenerNotFoundException {
  1032. NotificationListener instance = getListener(listener);
  1033. if (isTraceOn()) {
  1034. trace("removeNotificationListener", "obj= " + name +
  1035. " listener= " + listener);
  1036. }
  1037. server.removeNotificationListener(name, instance);
  1038. }
  1039. public void removeNotificationListener(ObjectName name,
  1040. ObjectName listener,
  1041. NotificationFilter filter,
  1042. Object handback)
  1043. throws InstanceNotFoundException, ListenerNotFoundException {
  1044. NotificationListener instance = getListener(listener);
  1045. if (isTraceOn()) {
  1046. trace("removeNotificationListener", "obj= " + name +
  1047. " listener= " + listener);
  1048. }
  1049. server.removeNotificationListener(name, instance, filter, handback);
  1050. }
  1051. private NotificationListener getListener(ObjectName listener)
  1052. throws ListenerNotFoundException {
  1053. // ----------------
  1054. // Get listener object
  1055. // ----------------
  1056. final Object instance;
  1057. try {
  1058. instance = getMBean(listener);
  1059. } catch (InstanceNotFoundException e) {
  1060. throw new ListenerNotFoundException(e.getMessage()) ;
  1061. }
  1062. if (!(instance instanceof NotificationListener)) {
  1063. final RuntimeException exc =
  1064. new IllegalArgumentException(listener.getCanonicalName());
  1065. final String msg =
  1066. "MBean " + listener.getCanonicalName() + " does not " +
  1067. "implement " + NotificationListener.class.getName();
  1068. throw new RuntimeOperationsException(exc, msg);
  1069. }
  1070. return (NotificationListener) instance;
  1071. }
  1072. private void removeNotificationListener(ObjectName name,
  1073. NotificationListener listener,
  1074. NotificationFilter filter,
  1075. Object handback,
  1076. boolean removeAll)
  1077. throws InstanceNotFoundException, ListenerNotFoundException {
  1078. if (isTraceOn()) {
  1079. trace("removeNotificationListener", "obj= " + name);
  1080. }
  1081. /* Permission check */
  1082. Object instance = getMBean(name);
  1083. String classname = null;
  1084. try {
  1085. classname = meta.getMBeanClassName(instance);
  1086. } catch (IntrospectionException e) {
  1087. classname = null;
  1088. } catch (NotCompliantMBeanException e) {
  1089. classname = null;
  1090. }
  1091. checkMBeanPermission(classname, null, name,
  1092. "removeNotificationListener");
  1093. /* We could simplify the code by assigning broadcaster after
  1094. assigning listenerWrapper, but that would change the error
  1095. behaviour when both the broadcaster and the listener are
  1096. erroneous. */
  1097. NotificationBroadcaster broadcaster = null;
  1098. NotificationEmitter emitter = null;
  1099. if (removeAll) {
  1100. if (!(instance instanceof NotificationBroadcaster)) {
  1101. final RuntimeException exc =
  1102. new IllegalArgumentException(name.getCanonicalName());
  1103. final String msg =
  1104. "MBean " + name.getCanonicalName() + " does not " +
  1105. "implement " + NotificationBroadcaster.class.getName();
  1106. throw new RuntimeOperationsException(exc, msg);
  1107. }
  1108. broadcaster = (NotificationBroadcaster) instance;
  1109. } else {
  1110. if (!(instance instanceof NotificationEmitter)) {
  1111. final RuntimeException exc =
  1112. new IllegalArgumentException(name.getCanonicalName());
  1113. final String msg =
  1114. "MBean " + name.getCanonicalName() + " does not " +
  1115. "implement " + NotificationEmitter.class.getName();
  1116. throw new RuntimeOperationsException(exc, msg);
  1117. }
  1118. emitter = (NotificationEmitter) instance;
  1119. }
  1120. NotificationListener listenerWrapper =
  1121. getListenerWrapper(listener, name, instance, false);
  1122. if (listenerWrapper == null)
  1123. throw new ListenerNotFoundException("Unknown listener");
  1124. if (removeAll)
  1125. broadcaster.removeNotificationListener(listenerWrapper);
  1126. else {
  1127. emitter.removeNotificationListener(listenerWrapper,
  1128. filter,
  1129. handback);
  1130. }
  1131. }
  1132. public MBeanInfo getMBeanInfo(ObjectName name)
  1133. throws InstanceNotFoundException, IntrospectionException,
  1134. ReflectionException {
  1135. // ------------------------------
  1136. // ------------------------------
  1137. Object moi = getMBean(name);
  1138. final MBeanInfo mbi = meta.getMBeanInfo(moi);
  1139. if (mbi == null)
  1140. throw new JMRuntimeException("MBean " + name +
  1141. "has no MBeanInfo");
  1142. /* Permission check */
  1143. checkMBeanPermission(mbi.getClassName(), null, name, "getMBeanInfo");
  1144. return mbi;
  1145. }
  1146. public boolean isInstanceOf(ObjectName name, String className)
  1147. throws InstanceNotFoundException {
  1148. /* Permission check */
  1149. Object instance = getMBean(name);
  1150. String classname = null;
  1151. try {
  1152. classname = meta.getMBeanClassName(instance);
  1153. } catch (IntrospectionException e) {
  1154. classname = null;
  1155. } catch (NotCompliantMBeanException e) {
  1156. classname = null;
  1157. }
  1158. checkMBeanPermission(classname, null, name, "isInstanceOf");
  1159. try {
  1160. return meta.isInstanceOf(instance, className);
  1161. } catch (ReflectionException e) {
  1162. debugX("isInstanceOf",e);
  1163. return false;
  1164. }
  1165. }
  1166. /**
  1167. * <p>Return the {@link java.lang.ClassLoader} that was used for
  1168. * loading the class of the named MBean.
  1169. * @param mbeanName The ObjectName of the MBean.
  1170. * @return The ClassLoader used for that MBean.
  1171. * @exception InstanceNotFoundException if the named MBean is not found.
  1172. */
  1173. public ClassLoader getClassLoaderFor(ObjectName mbeanName)
  1174. throws InstanceNotFoundException {
  1175. /* Permission check */
  1176. Object instance = getMBean(mbeanName);
  1177. String classname = null;
  1178. try {
  1179. classname = meta.getMBeanClassName(instance);
  1180. } catch (IntrospectionException e) {
  1181. classname = null;
  1182. } catch (NotCompliantMBeanException e) {
  1183. classname = null;
  1184. }
  1185. checkMBeanPermission(classname, null, mbeanName, "getClassLoaderFor");
  1186. return instance.getClass().getClassLoader();
  1187. }
  1188. /**
  1189. * <p>Return the named {@link java.lang.ClassLoader}.
  1190. * @param loaderName The ObjectName of the ClassLoader.
  1191. * @return The named ClassLoader.
  1192. * @exception InstanceNotFoundException if the named ClassLoader
  1193. * is not found.
  1194. */
  1195. public ClassLoader getClassLoader(ObjectName loaderName)
  1196. throws InstanceNotFoundException {
  1197. if (loaderName == null) {
  1198. checkMBeanPermission(null, null, null, "getClassLoader");
  1199. return server.getClass().getClassLoader();
  1200. }
  1201. Object instance = getMBean(loaderName);
  1202. String classname = null;
  1203. try {
  1204. classname = meta.getMBeanClassName(instance);
  1205. } catch (IntrospectionException e) {
  1206. classname = null;
  1207. } catch (NotCompliantMBeanException e) {
  1208. classname = null;
  1209. }
  1210. checkMBeanPermission(classname, null, loaderName, "getClassLoader");
  1211. /* Check if the given MBean is a ClassLoader */
  1212. if (!(instance instanceof ClassLoader))
  1213. throw new InstanceNotFoundException(loaderName.toString() +
  1214. " is not a classloader");
  1215. return (ClassLoader) instance;
  1216. }
  1217. /**
  1218. * Adds a MBean in the repository
  1219. */
  1220. private void internal_addObject(Object object, ObjectName logicalName)
  1221. throws InstanceAlreadyExistsException {
  1222. // ------------------------------
  1223. // ------------------------------
  1224. // Let the repository do the work.
  1225. synchronized(this) {
  1226. try {
  1227. repository.addMBean(object, logicalName);
  1228. }
  1229. catch (InstanceAlreadyExistsException e) {
  1230. if (object instanceof MBeanRegistration ) {
  1231. meta.postRegisterInvoker(object,false);
  1232. }
  1233. throw e;
  1234. }
  1235. }
  1236. // ---------------------
  1237. // Send create event
  1238. // ---------------------
  1239. if (isTraceOn()) {
  1240. trace("addObject", "Send create notification of object " +
  1241. logicalName.getCanonicalName());
  1242. }
  1243. sendNotification(MBeanServerNotification.REGISTRATION_NOTIFICATION,
  1244. logicalName ) ;
  1245. }
  1246. /**
  1247. * Sends an MBeanServerNotifications with the specified type for the
  1248. * MBean with the specified ObjectName
  1249. */
  1250. private void sendNotification(String NotifType, ObjectName name) {
  1251. // ------------------------------
  1252. // ------------------------------
  1253. // ---------------------
  1254. // Create notification
  1255. // ---------------------
  1256. MBeanServerNotification notif = new
  1257. MBeanServerNotification(NotifType,_MBSDelegateObjectName,0,name);
  1258. if (isTraceOn()) {
  1259. trace("sendNotification", NotifType + " " + name);
  1260. }
  1261. delegate.sendNotification(notif);
  1262. }
  1263. /**
  1264. * Performs the necessary initializations for the MBeanServer.
  1265. * Creates and registers the MetaData service and the MBeanServer
  1266. * identification MBean
  1267. */
  1268. private void initialize(String domain,
  1269. MBeanServer outer,
  1270. MBeanServerDelegate delegate,
  1271. MBeanInstantiator inst,
  1272. MetaData meta,
  1273. Repository repos) {
  1274. // ------------------------------
  1275. // ------------------------------
  1276. if (!this.domain.equals(repository.getDefaultDomain()))
  1277. throw new IllegalArgumentException("Domain Name Mismatch");
  1278. try {
  1279. queryByRepo = repository.isFiltering();
  1280. } catch (SecurityException e) {
  1281. throw e;
  1282. } catch (Exception e) {
  1283. queryByRepo = false;
  1284. }
  1285. }
  1286. /**
  1287. * Applies the specified queries to the set of objects
  1288. */
  1289. private Set filterListOfObjects(Set list, QueryExp query) {
  1290. Set result = new HashSet();
  1291. // No query ...
  1292. if (query == null ) {
  1293. for (final Iterator i = list.iterator(); i.hasNext(); ) {
  1294. final NamedObject no = (NamedObject) i.next();
  1295. final Object obj = no.getObject();
  1296. String className = null;
  1297. try {
  1298. className = meta.getMBeanClassName(obj);
  1299. } catch (JMException x) {
  1300. if (isDebugOn()) {
  1301. debug("filterListOfObjects",
  1302. "Can't obtain class name for " +
  1303. no.getName() + ": " + x);
  1304. debugX("filterListOfObjects",x);
  1305. }
  1306. }
  1307. result.add(new ObjectInstance(no.getName(), className));
  1308. }
  1309. } else {
  1310. // Access the filter
  1311. for (final Iterator i = list.iterator(); i.hasNext(); ) {
  1312. final NamedObject no = (NamedObject) i.next();
  1313. final Object obj = no.getObject();
  1314. boolean res = false;
  1315. MBeanServer oldServer = QueryEval.getMBeanServer();
  1316. query.setMBeanServer(server);
  1317. try {
  1318. res = query.apply(no.getName());
  1319. } catch (Exception e) {
  1320. res = false;
  1321. } finally {
  1322. /*
  1323. * query.setMBeanServer is probably
  1324. * QueryEval.setMBeanServer so put back the old
  1325. * value. Since that method uses a ThreadLocal
  1326. * variable, this code is only needed for the
  1327. * unusual case where the user creates a custom
  1328. * QueryExp that calls a nested query on another
  1329. * MBeanServer.
  1330. */
  1331. query.setMBeanServer(oldServer);
  1332. }
  1333. if (res) {
  1334. // if the MBean is a dynamic MBean ask its MBeanInfo
  1335. // for the class name
  1336. String className = null;
  1337. try {
  1338. className = meta.getMBeanClassName(obj);
  1339. } catch (JMException x) {
  1340. if (isDebugOn()) {
  1341. debug("filterListOfObjects",
  1342. "Can't obtain class name for " +
  1343. no.getName() + ": " + x);
  1344. debugX("filterListOfObjects",x);
  1345. }
  1346. }
  1347. result.add(new ObjectInstance(no.getName(), className));
  1348. }
  1349. }
  1350. }
  1351. return result;
  1352. }
  1353. /**
  1354. * Applies the specified queries to the set of ObjectInstances.
  1355. */
  1356. private Set filterListOfObjectInstances(Set list, QueryExp query) {
  1357. // Null query.
  1358. //
  1359. if (query == null) {
  1360. return list;
  1361. } else {
  1362. Set result = new HashSet();
  1363. // Access the filter.
  1364. //
  1365. for (final Iterator i = list.iterator(); i.hasNext(); ) {
  1366. final ObjectInstance oi = (ObjectInstance) i.next();
  1367. boolean res = false;
  1368. MBeanServer oldServer = QueryEval.getMBeanServer();
  1369. query.setMBeanServer(server);
  1370. try {
  1371. res = query.apply(oi.getObjectName());
  1372. } catch (Exception e) {
  1373. res = false;
  1374. } finally {
  1375. /*
  1376. * query.setMBeanServer is probably
  1377. * QueryEval.setMBeanServer so put back the old
  1378. * value. Since that method uses a ThreadLocal
  1379. * variable, this code is only needed for the
  1380. * unusual case where the user creates a custom
  1381. * QueryExp that calls a nested query on another
  1382. * MBeanServer.
  1383. */
  1384. query.setMBeanServer(oldServer);
  1385. }
  1386. if (res) {
  1387. result.add(oi);
  1388. }
  1389. }
  1390. return result;
  1391. }
  1392. }
  1393. /*
  1394. * Get the existing wrapper for this listener, name, and mbean, if
  1395. * there is one. Otherwise, if "create" is true, create and
  1396. * return one. Otherwise, return null.
  1397. *
  1398. * We use a WeakHashMap so that if the only reference to a user
  1399. * listener is in listenerWrappers, it can be garbage collected.
  1400. * This requires a certain amount of care, because only the key in
  1401. * a WeakHashMap is weak; the value is strong. We need to recover
  1402. * the existing wrapper object (not just an object that is equal
  1403. * to it), so we would like listenerWrappers to map any
  1404. * ListenerWrapper to the canonical ListenerWrapper for that
  1405. * (listener,name,mbean) set. But we do not want this canonical
  1406. * wrapper to be referenced strongly. Therefore we put it inside
  1407. * a WeakReference and that is the value in the WeakHashMap.
  1408. */
  1409. private NotificationListener getListenerWrapper(NotificationListener l,
  1410. ObjectName name,
  1411. Object mbean,
  1412. boolean create) {
  1413. NotificationListener wrapper = new ListenerWrapper(l, name, mbean);
  1414. synchronized (listenerWrappers) {
  1415. WeakReference ref = (WeakReference) listenerWrappers.get(wrapper);
  1416. if (ref != null) {
  1417. NotificationListener existing =
  1418. (NotificationListener) ref.get();
  1419. if (existing != null)
  1420. return existing;
  1421. }
  1422. if (create) {
  1423. listenerWrappers.put(wrapper, new WeakReference(wrapper));
  1424. return wrapper;
  1425. } else
  1426. return null;
  1427. }
  1428. }
  1429. private static class ListenerWrapper implements NotificationListener {
  1430. ListenerWrapper(NotificationListener l, ObjectName name,
  1431. Object mbean) {
  1432. this.listener = l;
  1433. this.name = name;
  1434. this.mbean = mbean;
  1435. }
  1436. public void handleNotification(Notification notification,
  1437. Object handback) {
  1438. if (notification != null) {
  1439. if (notification.getSource() == mbean)
  1440. notification.setSource(name);
  1441. }
  1442. /*
  1443. * Listeners are not supposed to throw exceptions. If
  1444. * this one does, we could remove it from the MBean. It
  1445. * might indicate that a connector has stopped working,
  1446. * for instance, and there is no point in sending future
  1447. * notifications over that connection. However, this
  1448. * seems rather drastic, so instead we propagate the
  1449. * exception and let the broadcaster handle it.
  1450. */
  1451. listener.handleNotification(notification, handback);
  1452. }
  1453. public boolean equals(Object o) {
  1454. if (!(o instanceof ListenerWrapper))
  1455. return false;
  1456. ListenerWrapper w = (ListenerWrapper) o;
  1457. return (w.listener == listener && w.mbean == mbean
  1458. && w.name.equals(name));
  1459. /*
  1460. * We compare all three, in case the same MBean object
  1461. * gets unregistered and then reregistered under a
  1462. * different name, or the same name gets assigned to two
  1463. * different MBean objects at different times. We do the
  1464. * comparisons in this order to avoid the slow
  1465. * ObjectName.equals when possible.
  1466. */
  1467. }
  1468. public int hashCode() {
  1469. return (System.identityHashCode(listener) ^
  1470. System.identityHashCode(mbean));
  1471. /*
  1472. * We do not include name.hashCode() in the hash because
  1473. * computing it is slow and usually we will not have two
  1474. * instances of ListenerWrapper with the same mbean but
  1475. * different ObjectNames. That can happen if the MBean is
  1476. * unregistered from one name and reregistered with
  1477. * another, and there is no garbage collection between; or
  1478. * if the same object is registered under two names (which
  1479. * is not recommended because MBeanRegistration will
  1480. * break). But even in these unusual cases the hash code
  1481. * does not have to be unique.
  1482. */
  1483. }
  1484. private NotificationListener listener;
  1485. private ObjectName name;
  1486. private Object mbean;
  1487. }
  1488. // SECURITY CHECKS
  1489. //----------------
  1490. private static void checkMBeanPermission(String classname,
  1491. String member,
  1492. ObjectName objectName,
  1493. String actions)
  1494. throws SecurityException {
  1495. SecurityManager sm = System.getSecurityManager();
  1496. if (sm != null) {
  1497. Permission perm = new MBeanPermission(classname,
  1498. member,
  1499. objectName,
  1500. actions);
  1501. sm.checkPermission(perm);
  1502. }
  1503. }
  1504. private static void checkMBeanTrustPermission(final Class theClass)
  1505. throws SecurityException {
  1506. SecurityManager sm = System.getSecurityManager();
  1507. if (sm != null) {
  1508. Permission perm = new MBeanTrustPermission("register");
  1509. ProtectionDomain pd = (ProtectionDomain)
  1510. AccessController.doPrivileged(new PrivilegedAction() {
  1511. public Object run() {
  1512. return theClass.getProtectionDomain();
  1513. }
  1514. });
  1515. AccessControlContext acc =
  1516. new AccessControlContext(new ProtectionDomain[] { pd });
  1517. sm.checkPermission(perm, acc);
  1518. }
  1519. }
  1520. // TRACES & DEBUG
  1521. //---------------
  1522. private static boolean isTraceOn() {
  1523. return Trace.isSelected(Trace.LEVEL_TRACE, Trace.INFO_MBEANSERVER);
  1524. }
  1525. private static void trace(String clz, String func, String info) {
  1526. Trace.send(Trace.LEVEL_TRACE, Trace.INFO_MBEANSERVER, clz, func, info);
  1527. }
  1528. private static void trace(String func, String info) {
  1529. trace(dbgTag, func, info);
  1530. }
  1531. private static void error(String func, String info) {
  1532. Trace.send(Trace.LEVEL_ERROR,Trace.INFO_MBEANSERVER,dbgTag,func,info);
  1533. }
  1534. private static boolean isDebugOn() {
  1535. return Trace.isSelected(Trace.LEVEL_DEBUG, Trace.INFO_MBEANSERVER);
  1536. }
  1537. private static void debug(String clz, String func, String info) {
  1538. Trace.send(Trace.LEVEL_DEBUG, Trace.INFO_MBEANSERVER, clz, func, info);
  1539. }
  1540. private static void debug(String func, String info) {
  1541. debug(dbgTag, func, info);
  1542. }
  1543. private static void debugX(String func,Throwable e) {
  1544. if (isDebugOn()) {
  1545. final StringWriter s = new StringWriter();
  1546. e.printStackTrace(new PrintWriter(s));
  1547. final String stack = s.toString();
  1548. debug(dbgTag,func,"Exception caught in "+ func+"(): "+e);
  1549. debug(dbgTag,func,stack);
  1550. // java.lang.System.err.println("**** Exception caught in "+
  1551. // func+"(): "+e);
  1552. // java.lang.System.err.println(stack);
  1553. }
  1554. }
  1555. }