1. /*
  2. * @(#)StandardMetaDataImpl.java 1.22 04/05/03
  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.mbeanserver;
  8. // java import
  9. import java.lang.reflect.Method;
  10. import java.lang.reflect.Constructor;
  11. import java.lang.reflect.InvocationTargetException;
  12. import java.lang.ref.WeakReference;
  13. import java.security.AccessController;
  14. import java.security.PrivilegedAction;
  15. import java.util.Hashtable;
  16. import java.util.Iterator;
  17. import java.io.PrintWriter;
  18. import java.io.StringWriter;
  19. // RI import
  20. import javax.management.* ;
  21. import com.sun.jmx.trace.Trace;
  22. import com.sun.jmx.mbeanserver.GetPropertyAction;
  23. /**
  24. * The MetaData class provides local access to the metadata service in
  25. * an agent.
  26. *
  27. * @since 1.5
  28. * @since.unbundled JMX RI 1.2
  29. */
  30. public class StandardMetaDataImpl extends BaseMetaDataImpl {
  31. /** The name of this class to be used for tracing */
  32. private final static String dbgTag = "StandardMetaDataImpl";
  33. /**
  34. * Cache of MBeanInfo objects.
  35. */
  36. private static java.util.Map mbeanInfoCache =
  37. new java.util.WeakHashMap();
  38. /**
  39. * Cache of MBean Interface objects.
  40. */
  41. private static java.util.Map mbeanInterfaceCache =
  42. new java.util.WeakHashMap();
  43. /**
  44. * True if RuntimeExceptions from getters, setters, and operations
  45. * should be wrapped in RuntimeMBeanException. We do not have
  46. * similar logic for Errors because DynamicMetaDataImpl does not
  47. * re-wrap RuntimeErrorException as it would
  48. * RuntimeMBeanException.
  49. */
  50. private final boolean wrapRuntimeExceptions;
  51. /**
  52. * objects maps from primitive classes to primitive object classes.
  53. */
  54. // private static Hashtable primitiveobjects = new Hashtable();
  55. // {
  56. // primitiveobjects.put(Boolean.TYPE, getClass("java.lang.Boolean"));
  57. // primitiveobjects.put(Character.TYPE, getClass("java.lang.Character"));
  58. // primitiveobjects.put(Byte.TYPE, getClass("java.lang.Byte"));
  59. // primitiveobjects.put(Short.TYPE, getClass("java.lang.Short"));
  60. // primitiveobjects.put(Integer.TYPE, getClass("java.lang.Integer"));
  61. // primitiveobjects.put(Long.TYPE, getClass("java.lang.Long"));
  62. // primitiveobjects.put(Float.TYPE, getClass("java.lang.Float"));
  63. // primitiveobjects.put(Double.TYPE, getClass("java.lang.Double"));
  64. // }
  65. private final static Hashtable primitiveClasses = new Hashtable(8);
  66. {
  67. primitiveClasses.put(Boolean.TYPE.toString(), Boolean.TYPE);
  68. primitiveClasses.put(Character.TYPE.toString(), Character.TYPE);
  69. primitiveClasses.put(Byte.TYPE.toString(), Byte.TYPE);
  70. primitiveClasses.put(Short.TYPE.toString(), Short.TYPE);
  71. primitiveClasses.put(Integer.TYPE.toString(), Integer.TYPE);
  72. primitiveClasses.put(Long.TYPE.toString(), Long.TYPE);
  73. primitiveClasses.put(Float.TYPE.toString(), Float.TYPE);
  74. primitiveClasses.put(Double.TYPE.toString(), Double.TYPE);
  75. }
  76. /**
  77. * Creates a Metadata Service.
  78. */
  79. public StandardMetaDataImpl() {
  80. this(true);
  81. }
  82. protected StandardMetaDataImpl(boolean wrapRuntimeExceptions) {
  83. this.wrapRuntimeExceptions = wrapRuntimeExceptions;
  84. }
  85. /**
  86. * Builds the MBeanInfo from the given concrete MBean class.
  87. * @param c The concrete MBean class from which the MBeanInfo
  88. * must be built.
  89. *
  90. * @exception NotCompliantMBeanException if the given class
  91. * is not MBean compliant.
  92. * @return the MBeanInfo built from class <var>c</var>, or null
  93. * if class <var>c</var> implements
  94. * {@link javax.management.DynamicMBean}
  95. */
  96. public synchronized MBeanInfo buildMBeanInfo(Class c)
  97. throws NotCompliantMBeanException {
  98. return Introspector.testCompliance(c);
  99. }
  100. /**
  101. * Builds the MBeanInfo from the given concrete MBean class,
  102. * using the given <var>mbeanInterface</var> as Management Interface.
  103. *
  104. * @param c The concrete MBean class from which the MBeanInfo
  105. * must be built.
  106. * @param mbeanInterface The management interface of the MBean.
  107. * If <code>null</code>, will use the regular design pattern
  108. * to determine the management interface.
  109. * @exception NotCompliantMBeanException if the given class and interface
  110. * are not MBean compliant. Does not enforce that if class <var>c</var>
  111. * is "X", then interface <var>mbeanInterface</var> is "XMBean".
  112. * @return the MBeanInfo built from class <var>c</var>, according
  113. * to interface <var>mbeanInterface</var>. Does not check whether
  114. * class <var>c</var> implements {@link javax.management.DynamicMBean}.
  115. **/
  116. public synchronized
  117. MBeanInfo buildMBeanInfo(Class c, Class mbeanInterface)
  118. throws NotCompliantMBeanException {
  119. return Introspector.testCompliance(c,mbeanInterface);
  120. }
  121. /**
  122. * This methods tests if the MBean is JMX compliant
  123. */
  124. public synchronized void testCompliance(Class c)
  125. throws NotCompliantMBeanException {
  126. // ------------------------------
  127. // ------------------------------
  128. final MBeanInfo mbeanInfo = buildMBeanInfo(c);
  129. final Class mbeanInterface = Introspector.getMBeanInterface(c);
  130. cacheMBeanInfo(c,mbeanInterface,mbeanInfo);
  131. }
  132. /**
  133. * This methods tests if the MBean is JMX compliant.
  134. * <li>It does not enforce that if c="X", mbeanInterface="XMBean".</li>
  135. * <li>It does not check whether c is a DynamicMBean</li>
  136. */
  137. public synchronized void testCompliance(Class c, Class mbeanInterface)
  138. throws NotCompliantMBeanException {
  139. // ------------------------------
  140. // ------------------------------
  141. final MBeanInfo mbeanInfo =
  142. buildMBeanInfo(c,mbeanInterface);
  143. if (mbeanInterface == null)
  144. mbeanInterface = Introspector.getStandardMBeanInterface(c);
  145. cacheMBeanInfo(c,mbeanInterface,mbeanInfo);
  146. }
  147. /**
  148. * This methods returns the MBean interface of an MBean
  149. */
  150. public Class getMBeanInterfaceFromClass(Class c) {
  151. final Class itf = getCachedMBeanInterface(c);
  152. if (itf != null) return itf;
  153. synchronized (this) {
  154. return Introspector.getMBeanInterface(c);
  155. }
  156. }
  157. /**
  158. * This methods analizes the passed MBean class and
  159. * returns the default MBean interface according to JMX patterns.
  160. */
  161. public Class getStandardMBeanInterface(Class c) {
  162. synchronized (this) {
  163. return Introspector.getStandardMBeanInterface(c);
  164. }
  165. }
  166. /**
  167. * This method discovers the attributes and operations that an MBean
  168. * exposes for management.
  169. *
  170. * @param beanClass The class to be analyzed.
  171. *
  172. * @return An instance of MBeanInfo allowing to retrieve all methods
  173. * and operations of this class.
  174. *
  175. * @exception IntrospectionException if an exception occurs during
  176. * introspection.
  177. * @exception NotCompliantMBeanException if the MBean class is not
  178. * MBean compliant.
  179. *
  180. */
  181. public MBeanInfo getMBeanInfoFromClass(Class beanClass)
  182. throws IntrospectionException, NotCompliantMBeanException {
  183. // Check the mbean information cache.
  184. MBeanInfo bi = getCachedMBeanInfo(beanClass);
  185. // Make an independent copy of the MBeanInfo.
  186. if (bi != null) return (MBeanInfo) bi.clone() ;
  187. // We don't have have any MBeanInfo for that class yet.
  188. // => test compliance.
  189. testCompliance(beanClass);
  190. bi = getCachedMBeanInfo(beanClass);;
  191. // Make an independent copy of the MBeanInfo.
  192. if (bi != null) return (MBeanInfo) bi.clone() ;
  193. return bi;
  194. }
  195. //---------------------------------------------------------------------
  196. //
  197. // From the MetaData interface
  198. //
  199. //---------------------------------------------------------------------
  200. public String getMBeanClassName(Object moi)
  201. throws IntrospectionException, NotCompliantMBeanException {
  202. return moi.getClass().getName();
  203. }
  204. public MBeanInfo getMBeanInfo(Object moi)
  205. throws IntrospectionException {
  206. try {
  207. final MBeanInfo mbi = getMBeanInfoFromClass(moi.getClass());
  208. return new MBeanInfo(mbi.getClassName(), mbi.getDescription(),
  209. mbi.getAttributes(),
  210. mbi.getConstructors(),
  211. mbi.getOperations(),
  212. findNotifications(moi));
  213. } catch (NotCompliantMBeanException x) {
  214. debugX("getMBeanInfo",x);
  215. throw new IntrospectionException("Can't build MBeanInfo for "+
  216. moi.getClass().getName());
  217. }
  218. }
  219. public Object getAttribute(Object instance, String attribute)
  220. throws MBeanException, AttributeNotFoundException,
  221. ReflectionException {
  222. Class mbeanClass = getMBeanInterfaceFromInstance(instance);
  223. if (isDebugOn()) {
  224. debug("getAttribute","MBean Class is " + instance.getClass());
  225. debug("getAttribute","MBean Interface is " + mbeanClass);
  226. }
  227. return getAttribute(instance, attribute, mbeanClass);
  228. }
  229. public AttributeList getAttributes(Object instance, String[] attributes)
  230. throws ReflectionException {
  231. final Class mbeanClass =
  232. getMBeanInterfaceFromInstance(instance);
  233. if (isDebugOn()) {
  234. debug("getAttributes","MBean Class is " + instance.getClass());
  235. debug("getAttributes","MBean Interface is " + mbeanClass);
  236. }
  237. if (attributes == null) {
  238. throw new RuntimeOperationsException(new
  239. IllegalArgumentException("Attributes cannot be null"),
  240. "Exception occured trying to invoke the getter on the MBean");
  241. }
  242. // Go through the list of attributes
  243. //
  244. final int maxLimit = attributes.length;
  245. final AttributeList result = new AttributeList(maxLimit);
  246. for (int i=0;i<maxLimit;i++) {
  247. final String elmt = (String)attributes[i];
  248. try {
  249. final Object value =
  250. getAttribute(instance, elmt, mbeanClass);
  251. result.add(new Attribute(elmt, value));
  252. } catch (Exception excep) {
  253. if (isDebugOn()) {
  254. debug("getAttributes", "Object= " + instance +
  255. ", Attribute=" + elmt + " failed: " + excep);
  256. }
  257. }
  258. }
  259. return result;
  260. }
  261. public AttributeList setAttributes(Object instance,
  262. AttributeList attributes)
  263. throws ReflectionException {
  264. final Class objClass = instance.getClass();
  265. final Class mbeanClass = getMBeanInterfaceFromInstance(instance);
  266. final ClassLoader aLoader = objClass.getClassLoader();
  267. if (isDebugOn()) {
  268. debug("setAttributes","MBean Class is " + instance.getClass());
  269. debug("setAttributes","MBean Interface is " + mbeanClass);
  270. }
  271. if (attributes == null) return new AttributeList();
  272. final AttributeList result = new AttributeList(attributes.size());
  273. // Go through the list of attributes
  274. for (final Iterator i = attributes.iterator(); i.hasNext();) {
  275. final Attribute attr = (Attribute) i.next();
  276. final String id = attr.getName();
  277. final Object value = attr.getValue();
  278. try {
  279. final Object newValue =
  280. setAttribute(instance, attr, mbeanClass);
  281. if (isTraceOn()) {
  282. trace("setAttributes", "Updating the list\n");
  283. }
  284. result.add(new Attribute(id, newValue));
  285. } catch (Exception excep) {
  286. if (isDebugOn()) {
  287. debug("setAttributes", "Unexpected exception occured: " +
  288. excep.getClass().getName());
  289. }
  290. }
  291. }
  292. return result;
  293. }
  294. public Object setAttribute(Object instance, Attribute attribute)
  295. throws AttributeNotFoundException, InvalidAttributeValueException,
  296. MBeanException, ReflectionException {
  297. final Class mbeanClass =
  298. getMBeanInterfaceFromInstance(instance);
  299. if (isDebugOn()) {
  300. debug("setAttribute","MBean Class is " + instance.getClass());
  301. debug("setAttribute","MBean Interface is " + mbeanClass);
  302. }
  303. return setAttribute(instance,attribute,mbeanClass);
  304. }
  305. public Object invoke(Object instance, String operationName,
  306. Object params[], String signature[])
  307. throws MBeanException, ReflectionException {
  308. if (operationName == null) {
  309. final RuntimeException r =
  310. new IllegalArgumentException("Operation name cannot be null");
  311. throw new RuntimeOperationsException(r,
  312. "Exception occured trying to invoke the operation on the MBean");
  313. }
  314. final Class objClass = instance.getClass();
  315. final Class mbeanClass = getMBeanInterfaceFromInstance(instance);
  316. final ClassLoader aLoader = objClass.getClassLoader();
  317. if (isDebugOn()) {
  318. debug("invoke","MBean Class is " + instance.getClass());
  319. debug("invoke","MBean Interface is " + mbeanClass);
  320. }
  321. // Build the signature of the method
  322. //
  323. final Class[] tab =
  324. ((signature == null)?null:
  325. findSignatureClasses(signature,aLoader));
  326. // Query the metadata service to get the right method
  327. //
  328. Method mth= findMethod(mbeanClass, operationName, tab);
  329. if (mth == null) {
  330. if (isTraceOn()) {
  331. trace("invoke", operationName + " not found in class " +
  332. mbeanClass.getName());
  333. }
  334. throw new ReflectionException(
  335. new NoSuchMethodException(operationName),
  336. "The operation with name " + operationName +
  337. " could not be found");
  338. }
  339. // Make it impossible to call getters and setters through invoke()
  340. //
  341. forbidInvokeGetterSetter(mth, operationName);
  342. // invoke the method
  343. if (isTraceOn()) {
  344. trace("invoke", "Invoking " + operationName);
  345. }
  346. Object result=null;
  347. try {
  348. result= mth.invoke(instance, params);
  349. } catch (IllegalAccessException e) {
  350. debugX("invoke",e);
  351. throw new ReflectionException(e, "IllegalAccessException" +
  352. " occured trying to invoke operation " + operationName);
  353. } catch (RuntimeException e) {
  354. debugX("invoke",e);
  355. throw new RuntimeOperationsException(e, "RuntimeException" +
  356. " occured trying to invoke operation " + operationName);
  357. } catch (InvocationTargetException e) {
  358. // Wrap the exception.
  359. Throwable t = e.getTargetException();
  360. debugX("invoke",t);
  361. if (t instanceof RuntimeException) {
  362. final String msg = "RuntimeException thrown in operation " +
  363. operationName;
  364. throw wrapRuntimeException((RuntimeException) t, msg);
  365. } else if (t instanceof Error) {
  366. throw new RuntimeErrorException((Error) t,
  367. "Error thrown in operation " + operationName);
  368. } else {
  369. throw new MBeanException((Exception) t,
  370. "Exception thrown in operation " + operationName);
  371. }
  372. }
  373. if (isTraceOn()) {
  374. trace("invoke", "Send the result");
  375. }
  376. return (result);
  377. }
  378. private static boolean startsWithAndHasMore(String s, String prefix) {
  379. return (s.startsWith(prefix) && s.length() > prefix.length());
  380. }
  381. private static void forbidInvokeGetterSetter(Method mth,
  382. String operationName)
  383. throws ReflectionException {
  384. final Class argTypes[] = mth.getParameterTypes();
  385. final Class resultType = mth.getReturnType();
  386. final int argCount = argTypes.length;
  387. boolean isInvokeGetterSetter = false;
  388. switch (argCount) {
  389. case 0: // might be a getter
  390. if ((startsWithAndHasMore(operationName, "get") &&
  391. resultType != Void.TYPE) ||
  392. (startsWithAndHasMore(operationName, "is") &&
  393. resultType == Boolean.TYPE)) {
  394. // Operation is a getter
  395. isInvokeGetterSetter = true;
  396. }
  397. break;
  398. case 1: // might be a setter
  399. if (startsWithAndHasMore(operationName, "set") &&
  400. resultType == Void.TYPE) {
  401. // Operation is a setter
  402. isInvokeGetterSetter = true;
  403. }
  404. break;
  405. }
  406. if (isInvokeGetterSetter) {
  407. boolean allow;
  408. try {
  409. GetPropertyAction getProp =
  410. new GetPropertyAction("jmx.invoke.getters");
  411. allow = (AccessController.doPrivileged(getProp) != null);
  412. } catch (SecurityException e) {
  413. // too bad, don't allow it
  414. allow = false;
  415. }
  416. if (!allow) {
  417. final String msg =
  418. "Cannot invoke getter or setter (" + operationName +
  419. ") as operation unless jmx.invoke.getters property is set";
  420. final Exception nested =
  421. new NoSuchMethodException(operationName);
  422. throw new ReflectionException(nested, msg);
  423. }
  424. }
  425. }
  426. public boolean isInstanceOf(Object instance, String className)
  427. throws ReflectionException {
  428. final Class c =
  429. findClass(className, instance.getClass().getClassLoader());
  430. return c.isInstance(instance);
  431. }
  432. /**
  433. * This methods returns the MBean interface of the given MBean
  434. * instance.
  435. * <p>It does so by calling
  436. * <code>getMBeanInterfaceFromClass(instance.getClass());</code>
  437. * @param instance the MBean instance.
  438. */
  439. protected Class getMBeanInterfaceFromInstance(Object instance) {
  440. if (instance == null) return null;
  441. return getMBeanInterfaceFromClass(instance.getClass());
  442. }
  443. /**
  444. * Cache the MBeanInfo and MBean interface obtained for class
  445. * <var>c</var>.
  446. * <p>This method is called by <code>testCompliance(...)</code>
  447. * after compliance is successfully verified. It uses two
  448. * {@link java.util.WeakHashMap WeakHashMaps} - one for the
  449. * MBeanInfo, one for the MBeanInterface, with calss <var>c</var>
  450. * as the key.
  451. *
  452. * @param c The concrete MBean class from which the MBeanInfo
  453. * was be built.
  454. *
  455. * @param mbeanInterface The management interface of the MBean.
  456. * Note that caching will not work if two MBeans of the same
  457. * class can have different mbeanInterface's. If you want
  458. * to use caching nonetheless, you will have to
  459. * to do it by redefining the method
  460. * {@link #getMBeanInterfaceFromInstance(java.lang.Object)
  461. * getMBeanInterfaceFromInstance()}.
  462. * @param info The MBeanInfo obtained from class <var>c</var> using
  463. * interface <var>mbeanInterface</var>.
  464. *
  465. **/
  466. protected void cacheMBeanInfo(Class c, Class mbeanInterface,
  467. MBeanInfo info)
  468. throws NotCompliantMBeanException {
  469. if (info != null) {
  470. synchronized (mbeanInfoCache) {
  471. if (mbeanInfoCache.get(c) == null) {
  472. mbeanInfoCache.put(c, info);
  473. }
  474. }
  475. }
  476. if (mbeanInterface != null) {
  477. synchronized (mbeanInterfaceCache) {
  478. if ((mbeanInterfaceCache.get(c) == null) || (((WeakReference)mbeanInterfaceCache.get(c)).get() == null)) {
  479. mbeanInterfaceCache.put(c, new WeakReference(mbeanInterface));
  480. }
  481. }
  482. }
  483. }
  484. /**
  485. * Returns the MBean interface that was cached for class <var>c</var>.
  486. * @param c The concrete MBean class.
  487. * @return The cached MBean interface if found, null otherwise.
  488. **/
  489. protected Class getCachedMBeanInterface(Class c) {
  490. synchronized (mbeanInterfaceCache) {
  491. return (Class)(((WeakReference)mbeanInterfaceCache.get(c)).get());
  492. }
  493. }
  494. /**
  495. * Returns the MBeanInfo that was cached for class <var>c</var>.
  496. * @param c The concrete MBean class.
  497. * @return The cached MBeanInfo if found, null otherwise.
  498. **/
  499. protected MBeanInfo getCachedMBeanInfo(Class c) {
  500. synchronized (mbeanInfoCache) {
  501. return (MBeanInfo)mbeanInfoCache.get(c);
  502. }
  503. }
  504. /**
  505. * Find a class using the specified ClassLoader.
  506. **/
  507. protected Class findClass(String className, ClassLoader loader)
  508. throws ReflectionException {
  509. return MBeanInstantiatorImpl.loadClass(className,
  510. loader);
  511. }
  512. /**
  513. * Find the classes from a signature using the specified ClassLoader.
  514. **/
  515. protected Class[] findSignatureClasses(String[] signature,
  516. ClassLoader loader)
  517. throws ReflectionException {
  518. return ((signature == null)?null:
  519. MBeanInstantiatorImpl.loadSignatureClasses(signature,loader));
  520. }
  521. /**
  522. * Invoke getAttribute through reflection on a standard MBean instance.
  523. **/
  524. protected Object getAttribute(Object instance, String attribute,
  525. Class mbeanClass)
  526. throws MBeanException, AttributeNotFoundException,
  527. ReflectionException {
  528. if (attribute == null) {
  529. final RuntimeException r =
  530. new IllegalArgumentException("Attribute name cannot be null");
  531. throw new RuntimeOperationsException(r,
  532. "Exception occured trying to invoke the getter on the MBean");
  533. }
  534. // Standard MBean: need to reflect...
  535. Method meth = null;
  536. meth = findGetter(mbeanClass, attribute);
  537. if (meth == null) {
  538. if (isTraceOn()) {
  539. trace("getAttribute", "Cannot find getter for "+attribute+
  540. " in class " + mbeanClass.getName());
  541. }
  542. throw new AttributeNotFoundException(attribute +
  543. " not accessible");
  544. }
  545. // Invoke the getter
  546. if (isTraceOn()) {
  547. trace("getAttribute", "Invoke callback");
  548. }
  549. Object result= null;
  550. try {
  551. result = meth.invoke(instance,null);
  552. } catch (InvocationTargetException e) {
  553. Throwable t = e.getTargetException();
  554. if (t instanceof RuntimeException) {
  555. debugX("getAttribute",t);
  556. final String msg =
  557. "RuntimeException thrown in the getter for the attribute "
  558. + attribute;
  559. throw wrapRuntimeException((RuntimeException) t, msg);
  560. } else if (t instanceof Error) {
  561. debugX("getAttribute",t);
  562. throw new RuntimeErrorException((Error) t ,
  563. "Error thrown in the getter for the attribute " +
  564. attribute);
  565. } else {
  566. debugX("getAttribute",t);
  567. throw new MBeanException((Exception) t,
  568. "Exception thrown in the getter for the attribute " +
  569. attribute);
  570. }
  571. } catch (RuntimeException e) {
  572. debugX("getAttribute",e);
  573. throw new RuntimeOperationsException(e,
  574. "RuntimeException thrown trying to invoke the getter" +
  575. " for the attribute " + attribute);
  576. } catch (IllegalAccessException e) {
  577. debugX("getAttribute",e);
  578. throw new ReflectionException(e, "Exception thrown trying to" +
  579. " invoke the getter for the attribute " + attribute);
  580. } catch (Error e) {
  581. debugX("getAttribute",e);
  582. throw new RuntimeErrorException((Error)e,
  583. "Error thrown trying to invoke the getter " +
  584. " for the attribute " + attribute);
  585. }
  586. if (isTraceOn()) {
  587. trace("getAttribute", attribute + "= " + result + "\n");
  588. }
  589. return result;
  590. }
  591. /**
  592. * Invoke setAttribute through reflection on a standard MBean instance.
  593. **/
  594. protected Object setAttribute(Object instance, Attribute attribute,
  595. Class mbeanClass)
  596. throws AttributeNotFoundException, InvalidAttributeValueException,
  597. MBeanException, ReflectionException {
  598. if (attribute == null) {
  599. final RuntimeException r =
  600. new IllegalArgumentException("Attribute name cannot be null");
  601. throw new RuntimeOperationsException(r,
  602. "Exception occured trying to invoke the setter on the MBean");
  603. }
  604. final Class objClass = instance.getClass();
  605. final ClassLoader aLoader = objClass.getClassLoader();
  606. Object result = null;
  607. final Object value = attribute.getValue();
  608. final String attname = attribute.getName();
  609. // Query the metadata service to get the appropriate setter
  610. // of the object.
  611. Method meth = null;
  612. if (value == null) {
  613. meth = findSetter(mbeanClass, attname);
  614. } else {
  615. meth = findSetter(mbeanClass, attname, value.getClass());
  616. }
  617. if (meth == null) {
  618. // Check whether the type is a primitive one
  619. Class primClass = findPrimForClass(value);
  620. if (primClass != null) {
  621. meth = findSetter(mbeanClass, attname, primClass);
  622. }
  623. }
  624. if (meth == null) {
  625. // Try to check if the attribute name does correspond to a
  626. // valid property
  627. meth= findSetter(mbeanClass, attname);
  628. if (meth == null) {
  629. if (isTraceOn()) {
  630. trace("setAttribute", "Cannot find setter for "+attribute+
  631. " in class " + mbeanClass.getName());
  632. }
  633. throw new AttributeNotFoundException( attname +
  634. " not accessible");
  635. } else {
  636. final Object v = attribute.getValue();
  637. if (v == null) {
  638. throw new InvalidAttributeValueException("attribute= " +
  639. attname + " value = null");
  640. } else {
  641. throw new InvalidAttributeValueException("attribute= " +
  642. attname + " value = " + v);
  643. }
  644. }
  645. }
  646. // Invoke the setter
  647. if (isTraceOn()) {
  648. trace("setAttribute", "Invoking the set method for " +
  649. attname);
  650. }
  651. final Object[] values = new Object[1];
  652. values[0] = value;
  653. try {
  654. result = meth.invoke(instance,values);
  655. } catch (IllegalAccessException e) {
  656. debugX("setAttribute",e);
  657. // Wrap the exception.
  658. throw new ReflectionException(e, "IllegalAccessException" +
  659. " occured trying to invoke the setter on the MBean");
  660. } catch (InvocationTargetException e) {
  661. Throwable t = e.getTargetException();
  662. debugX("setAttribute",t);
  663. if (t instanceof RuntimeException) {
  664. final String msg =
  665. "RuntimeException thrown in the setter for the attribute "
  666. + attribute;
  667. throw wrapRuntimeException((RuntimeException) t, msg);
  668. } else if (t instanceof Error) {
  669. throw new RuntimeErrorException((Error) t,
  670. "Error thrown in the MBean's setter");
  671. } else {
  672. throw new MBeanException((Exception) t,
  673. "Exception thrown in the MBean's setter");
  674. }
  675. }
  676. if (isTraceOn()) {
  677. trace("setAttribute", attname + "= " + value);
  678. }
  679. return value;
  680. }
  681. /**
  682. * Returns the MBeanNotificationInfo of the MBeans that implement
  683. * the NotificationBroadcaster interface.
  684. */
  685. protected MBeanNotificationInfo[] findNotifications(Object moi) {
  686. if (moi instanceof javax.management.NotificationBroadcaster) {
  687. MBeanNotificationInfo[] mbn =
  688. ((NotificationBroadcaster)moi).getNotificationInfo();
  689. if (mbn == null) {
  690. return new MBeanNotificationInfo[0];
  691. }
  692. MBeanNotificationInfo[] result =
  693. new MBeanNotificationInfo[mbn.length];
  694. for (int i = 0; i < mbn.length; i++) {
  695. result[i] = (MBeanNotificationInfo) mbn[i].clone();
  696. }
  697. return result;
  698. }
  699. return new MBeanNotificationInfo[0];
  700. }
  701. /**
  702. * Finds a specific method of an object.
  703. * Returns the method or null if not found
  704. */
  705. public static Method findMethod(Class classObj, String name,
  706. Class parameterTypes[]) {
  707. Method method=null;
  708. try {
  709. method= classObj.getMethod(name, parameterTypes);
  710. } catch(Exception e) {
  711. // OK: will return null.
  712. }
  713. return method;
  714. }
  715. /**
  716. * Finds a specific method of an object without knowing the parameter
  717. * types.
  718. * Returns the method or null if not found
  719. */
  720. public static Method findMethod(Class classObj, String name) {
  721. Method method = null ;
  722. try {
  723. Method[] methods=classObj.getMethods();
  724. int i = 0;
  725. while ((i < methods.length) &&
  726. !methods[i].getName().equals(name)) {
  727. i++;
  728. }
  729. if (i < methods.length) {
  730. method = methods[i];
  731. }
  732. } catch(Exception e) {
  733. // OK: will return null.
  734. }
  735. return method;
  736. }
  737. /**
  738. * Finds a specific method of an object given the number of parameters.
  739. * Returns the method or null if not found
  740. */
  741. public static Method findMethod(Class classObj, String name,
  742. int paramCount) {
  743. Method method = null;
  744. try {
  745. Method[] methods=classObj.getMethods();
  746. int i = 0;
  747. boolean found = false;
  748. while ((i < methods.length) && !found) {
  749. found = methods[i].getName().equals(name);
  750. if (found) { // Now check if the number of parameters
  751. found = (methods[i].getParameterTypes().length ==
  752. paramCount);
  753. }
  754. i++;
  755. }
  756. if (found) {
  757. method = methods[i-1] ; // Note i-1 !
  758. }
  759. } catch(Exception e) {
  760. // OK: will return null;
  761. }
  762. return method;
  763. }
  764. /**
  765. * Finds the getter of a specific attribute in an object.
  766. * Returns the method for accessing the attributes, null otherwise
  767. */
  768. public static Method findGetter(Class classObj, String attribute) {
  769. // Methods called "is" or "get" tout court are not getters
  770. if (attribute.length() == 0)
  771. return null;
  772. // Look for a method T getX(), where T is not void
  773. Method m = findMethod(classObj, "get" + attribute, null);
  774. if (m != null && m.getReturnType() != void.class)
  775. return m;
  776. // Look for a method boolean isX()
  777. // must not be any other type than "boolean", including not "Boolean"
  778. m = findMethod(classObj, "is" + attribute, null);
  779. if (m != null && m.getReturnType() == boolean.class)
  780. return m;
  781. return null;
  782. }
  783. /**
  784. * Finds the setter of a specific attribute in an object.
  785. * Returns the method for accessing the attribute, null otherwise
  786. */
  787. public static Method findSetter(Class classObj, String attribute,
  788. Class type) {
  789. Method mth= findMethod(classObj, "set" + attribute, 1);
  790. if (mth != null) {
  791. Class[] pars = mth.getParameterTypes();
  792. if (pars[0].isAssignableFrom(type)) {
  793. return mth;
  794. }
  795. }
  796. return null;
  797. }
  798. /**
  799. * Finds the setter of a specific attribute without knowing its type.
  800. * Returns the method for accessing the attribute, null otherwise
  801. */
  802. public static Method findSetter(Class classObj, String attribute) {
  803. return findMethod(classObj, "set" + attribute, 1) ;
  804. }
  805. /**
  806. * Finds a specific constructor of a class
  807. * Returns the requested constructor or null if not found
  808. */
  809. public static Constructor findConstructor(Class theClass,
  810. Class parameterTypes[]) {
  811. // Get the list of methods
  812. Constructor mth = null;
  813. try {
  814. mth = theClass.getConstructor(parameterTypes);
  815. } catch(Exception e) {
  816. return null;
  817. }
  818. return mth;
  819. }
  820. /**
  821. * Get the class of the constructed type
  822. * corresponding to the given primitive type
  823. */
  824. public static Class findClassForPrim(String primName) {
  825. return (Class) primitiveClasses.get(primName);
  826. }
  827. /**
  828. * Get the class of the primitive type
  829. * corresponding to the given constructed object.
  830. */
  831. public static Class findPrimForClass(Object value) {
  832. if (value instanceof Boolean)
  833. return Boolean.TYPE;
  834. else if (value instanceof Character)
  835. return Character.TYPE;
  836. else if (value instanceof Byte)
  837. return Byte.TYPE;
  838. else if (value instanceof Short)
  839. return Short.TYPE;
  840. else if (value instanceof Integer)
  841. return Integer.TYPE;
  842. else if (value instanceof Long)
  843. return Long.TYPE;
  844. else if (value instanceof Float)
  845. return Float.TYPE;
  846. else if (value instanceof Double)
  847. return Double.TYPE;
  848. return null;
  849. }
  850. /**
  851. * Converts the array of classes to an array of class signatures.
  852. */
  853. static String[] findSignatures(Class[] clz) {
  854. String signers[] = new String[clz.length];
  855. for (int i = 0; i < clz.length; i++) {
  856. signers[i] = findSignature(clz[i]);
  857. }
  858. return signers;
  859. }
  860. /**
  861. * Converts the class to a class signature.
  862. */
  863. static String findSignature(Class clz) {
  864. return clz.getName();
  865. }
  866. private RuntimeException wrapRuntimeException(RuntimeException re,
  867. String msg) {
  868. if (wrapRuntimeExceptions)
  869. return new RuntimeMBeanException(re, msg);
  870. else
  871. return re;
  872. }
  873. // TRACES & DEBUG
  874. //---------------
  875. private static boolean isTraceOn() {
  876. return Trace.isSelected(Trace.LEVEL_TRACE, Trace.INFO_MBEANSERVER);
  877. }
  878. private static void trace(String clz, String func, String info) {
  879. Trace.send(Trace.LEVEL_TRACE, Trace.INFO_MBEANSERVER, clz, func, info);
  880. }
  881. private static void trace(String func, String info) {
  882. trace(dbgTag, func, info);
  883. }
  884. private static boolean isDebugOn() {
  885. return Trace.isSelected(Trace.LEVEL_DEBUG, Trace.INFO_MBEANSERVER);
  886. }
  887. private static void debug(String clz, String func, String info) {
  888. Trace.send(Trace.LEVEL_DEBUG, Trace.INFO_MBEANSERVER, clz, func, info);
  889. }
  890. private static void debug(String func, String info) {
  891. debug(dbgTag, func, info);
  892. }
  893. private static void debugX(String func,Throwable e) {
  894. if (isDebugOn()) {
  895. final StringWriter s = new StringWriter();
  896. e.printStackTrace(new PrintWriter(s));
  897. final String stack = s.toString();
  898. debug(dbgTag,func,"Exception caught in "+ func+"(): "+e);
  899. debug(dbgTag,func,stack);
  900. // java.lang.System.err.println("**** Exception caught in "+
  901. // func+"(): "+e);
  902. // java.lang.System.err.println(stack);
  903. }
  904. }
  905. }