1. /*
  2. * @(#)file RequiredModelMBean.java
  3. * @(#)author Sun Microsystems, Inc.
  4. * @(#)version 1.50
  5. * @(#)lastedit 04/02/11
  6. *
  7. * Copyright IBM Corp. 1999-2000. All rights reserved.
  8. *
  9. * The program is provided "as is" without any warranty express or implied,
  10. * including the warranty of non-infringement and the implied warranties of
  11. * merchantibility and fitness for a particular purpose. IBM will not be
  12. * liable for any damages suffered by you or any third party claim against
  13. * you regarding the Program.
  14. *
  15. * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
  16. * This software is the proprietary information of Sun Microsystems, Inc.
  17. * Use is subject to license terms.
  18. *
  19. * Copyright 2004 Sun Microsystems, Inc. Tous droits reserves.
  20. * Ce logiciel est propriete de Sun Microsystems, Inc.
  21. * Distribue par des licences qui en restreignent l'utilisation.
  22. *
  23. */
  24. package javax.management.modelmbean;
  25. /* java imports */
  26. import java.lang.reflect.Method;
  27. import java.lang.reflect.InvocationTargetException;
  28. import java.util.Date;
  29. import java.util.HashMap;
  30. import java.util.HashSet;
  31. import java.util.Iterator;
  32. import java.util.Map;
  33. import java.util.Set;
  34. import java.io.PrintStream;
  35. import java.io.FileOutputStream;
  36. import javax.management.Attribute;
  37. import javax.management.AttributeList;
  38. import javax.management.AttributeChangeNotification;
  39. import javax.management.AttributeChangeNotificationFilter;
  40. import javax.management.AttributeNotFoundException;
  41. import javax.management.Descriptor;
  42. import javax.management.DescriptorAccess;
  43. import javax.management.InstanceNotFoundException;
  44. import javax.management.InvalidAttributeValueException;
  45. import javax.management.ListenerNotFoundException;
  46. import javax.management.MBeanAttributeInfo;
  47. import javax.management.MBeanConstructorInfo;
  48. import javax.management.MBeanException;
  49. import javax.management.MBeanInfo;
  50. import javax.management.MBeanNotificationInfo;
  51. import javax.management.MBeanOperationInfo;
  52. import javax.management.MBeanRegistration;
  53. import javax.management.MBeanRegistrationException;
  54. import javax.management.MBeanServer;
  55. import javax.management.MBeanServerFactory;
  56. import javax.management.Notification;
  57. import javax.management.NotificationBroadcasterSupport;
  58. import javax.management.NotificationFilter;
  59. import javax.management.NotificationListener;
  60. import javax.management.ObjectName;
  61. import javax.management.ReflectionException;
  62. import javax.management.RuntimeErrorException;
  63. import javax.management.RuntimeMBeanException;
  64. import javax.management.RuntimeOperationsException;
  65. import javax.management.ServiceNotFoundException;
  66. import javax.management.NotificationEmitter;
  67. import javax.management.loading.ClassLoaderRepository;
  68. import com.sun.jmx.trace.Trace;
  69. /**
  70. * This class is the implementation of a ModelMBean. An appropriate
  71. * implementation of a ModelMBean must be shipped with every JMX Agent
  72. * and the class must be named RequiredModelMBean.
  73. * <P>
  74. * Java resources wishing to be manageable instantiate the
  75. * RequiredModelMBean using the MBeanServer's createMBean method.
  76. * The resource then sets the MBeanInfo and Descriptors for the
  77. * RequiredModelMBean instance. The attributes and operations exposed
  78. * via the ModelMBeanInfo for the ModelMBean are accessible
  79. * from MBeans, connectors/adaptors like other MBeans. Through the
  80. * Descriptors, values and methods in the managed application can be
  81. * defined and mapped to attributes and operations of the ModelMBean.
  82. * This mapping can be defined in an XML formatted file or dynamically and
  83. * programmatically at runtime.
  84. * <P>
  85. * Every RequiredModelMBean which is instantiated in the MBeanServer
  86. * becomes manageable:<br>
  87. * its attributes and operations become remotely accessible through the
  88. * connectors/adaptors connected to that MBeanServer.
  89. * <P>
  90. * A Java object cannot be registered in the MBeanServer unless it is a
  91. * JMX compliant MBean. By instantiating a RequiredModelMBean, resources
  92. * are guaranteed that the MBean is valid.
  93. *
  94. * MBeanException and RuntimeOperationsException must be thrown on every
  95. * public method. This allows for wrapping exceptions from distributed
  96. * communications (RMI, EJB, etc.)
  97. *
  98. * @since 1.5
  99. */
  100. public class RequiredModelMBean
  101. implements ModelMBean, MBeanRegistration, NotificationEmitter {
  102. /*************************************/
  103. /* attributes */
  104. /*************************************/
  105. ModelMBeanInfo modelMBeanInfo;
  106. /* Notification broadcaster for any notification to be sent
  107. * from the application through the RequiredModelMBean. */
  108. private NotificationBroadcasterSupport generalBroadcaster = null;
  109. /* Notification broadcaster for attribute change notifications */
  110. private NotificationBroadcasterSupport attributeBroadcaster = null;
  111. /* handle, name, or reference for instance on which the actual invoke
  112. * and operations will be executed */
  113. private Object managedResource = null;
  114. private static final String currClass = "RequiredModelMBean";
  115. /* records the registering in MBeanServer */
  116. private boolean registered = false;
  117. private transient MBeanServer server = null;
  118. /*************************************/
  119. /* constructors */
  120. /*************************************/
  121. /**
  122. * Constructs an <CODE>RequiredModelMBean</CODE> with an empty
  123. * ModelMBeanInfo.
  124. * <P>
  125. * The RequiredModelMBean's MBeanInfo and Descriptors
  126. * can be customized using the {@link #setModelMBeanInfo} method.
  127. * After the RequiredModelMBean's MBeanInfo and Descriptors are
  128. * customized, the RequiredModelMBean can be registered with
  129. * the MBeanServer.
  130. *
  131. * @exception MBeanException Wraps a distributed communication Exception.
  132. *
  133. * @exception RuntimeOperationsException Wraps a {@link
  134. * RuntimeException} during the construction of the object.
  135. **/
  136. public RequiredModelMBean()
  137. throws MBeanException, RuntimeOperationsException {
  138. if (tracing())
  139. trace("RequiredModelMBean()","Entry and Exit");
  140. modelMBeanInfo = createDefaultModelMBeanInfo();
  141. }
  142. /**
  143. * Constructs a RequiredModelMBean object using ModelMBeanInfo passed in.
  144. * As long as the RequiredModelMBean is not registered
  145. * with the MBeanServer yet, the RequiredModelMBean's MBeanInfo and
  146. * Descriptors can be customized using the {@link #setModelMBeanInfo}
  147. * method.
  148. * After the RequiredModelMBean's MBeanInfo and Descriptors are
  149. * customized, the RequiredModelMBean can be registered with the
  150. * MBeanServer.
  151. *
  152. * @param mbi The ModelMBeanInfo object to be used by the
  153. * RequiredModelMBean. The given ModelMBeanInfo is cloned
  154. * and modified as specified by {@link #setModelMBeanInfo}
  155. *
  156. * @exception MBeanException Wraps a distributed communication Exception.
  157. * @exception RuntimeOperationsException Wraps an
  158. * {link java.lang.IllegalArgumentException}:
  159. * The MBeanInfo passed in parameter is null.
  160. *
  161. **/
  162. public RequiredModelMBean(ModelMBeanInfo mbi)
  163. throws MBeanException, RuntimeOperationsException {
  164. if (tracing())
  165. trace("RequiredModelMBean(MBeanInfo)","Entry");
  166. setModelMBeanInfo(mbi);
  167. if (tracing())
  168. trace("RequiredModelMBean(MBeanInfo)","Exit");
  169. }
  170. /*************************************/
  171. /* initializers */
  172. /*************************************/
  173. /**
  174. * Initializes a ModelMBean object using ModelMBeanInfo passed in.
  175. * This method makes it possible to set a customized ModelMBeanInfo on
  176. * the ModelMBean as long as it is not registered with the MBeanServer.
  177. * <br>
  178. * Once the ModelMBean's ModelMBeanInfo (with Descriptors) are
  179. * customized and set on the ModelMBean, the ModelMBean be
  180. * registered with the MBeanServer.
  181. * <P>
  182. * If the ModelMBean is currently registered, this method throws
  183. * a {@link javax.management.RuntimeOperationsException} wrapping an
  184. * {@link IllegalStateException}
  185. * <P>
  186. * If the given <var>inModelMBeanInfo</var> does not contain any
  187. * {@link ModelMBeanNotificationInfo} for the <code>GENERIC</code>
  188. * or <code>ATTRIBUTE_CHANGE</code> notifications, then the
  189. * RequiredModelMBean will supply its own default
  190. * {@link ModelMBeanNotificationInfo ModelMBeanNotificationInfo}s for
  191. * those missing notifications.
  192. *
  193. * @param mbi The ModelMBeanInfo object to be used
  194. * by the ModelMBean.
  195. *
  196. * @exception MBeanException Wraps a distributed communication
  197. * Exception.
  198. * @exception RuntimeOperationsException
  199. * <ul><li>Wraps an {@link IllegalArgumentException} if
  200. * the MBeanInfo passed in parameter is null.</li>
  201. * <li>Wraps an {@link IllegalStateException} if the ModelMBean
  202. * is currently registered in the MBeanServer.</li>
  203. * </ul>
  204. *
  205. **/
  206. public void setModelMBeanInfo(ModelMBeanInfo mbi)
  207. throws MBeanException, RuntimeOperationsException {
  208. if (tracing())
  209. trace("setModelMBeanInfo(ModelMBeanInfo)","Entry");
  210. if (mbi == null) {
  211. if (tracing())
  212. trace("setModelMBeanInfo(ModelMBeanInfo)",
  213. "ModelMBeanInfo is null: Raising exception.");
  214. final RuntimeException x = new
  215. IllegalArgumentException("ModelMBeanInfo must not be null");
  216. final String exceptionText =
  217. "Exception occured trying to initialize the " +
  218. "ModelMBeanInfo of the RequiredModelMBean";
  219. throw new RuntimeOperationsException(x,exceptionText);
  220. }
  221. if (registered) {
  222. if (tracing())
  223. trace("setModelMBeanInfo(ModelMBeanInfo)",
  224. "RequiredMBean is registered: Raising exception.");
  225. final String exceptionText =
  226. "Exception occured trying to set the " +
  227. "ModelMBeanInfo of the RequiredModelMBean";
  228. final RuntimeException x = new IllegalStateException(
  229. "cannot call setModelMBeanInfo while ModelMBean is registered");
  230. throw new RuntimeOperationsException(x,exceptionText);
  231. }
  232. if (tracing()) {
  233. trace("setModelMBeanInfo(ModelMBeanInfo)",
  234. "Setting ModelMBeanInfo to " + printModelMBeanInfo(mbi));
  235. trace("setModelMBeanInfo(ModelMBeanInfo)",
  236. "ModelMBeanInfo notifications has " +
  237. (mbi.getNotifications()).length + " elements");
  238. }
  239. modelMBeanInfo = (ModelMBeanInfo)mbi.clone();
  240. if (tracing())
  241. trace("setModelMBeanInfo(ModelMBeanInfo)","set mbeanInfo to: "+
  242. printModelMBeanInfo(modelMBeanInfo));
  243. if (tracing())
  244. trace("setModelMBeanInfo(ModelMBeanInfo)","Exit");
  245. }
  246. /**
  247. * Sets the instance handle of the object against which to
  248. * execute all methods in this ModelMBean management interface
  249. * (MBeanInfo and Descriptors).
  250. *
  251. * @param mr Object that is the managed resource
  252. * @param mr_type The type of reference for the managed resource.
  253. * <br>Can be: "ObjectReference", "Handle", "IOR", "EJBHandle",
  254. * or "RMIReference".
  255. * <br>In this implementation only "ObjectReference" is supported.
  256. *
  257. * @exception MBeanException The initializer of the object has
  258. * thrown an exception.
  259. * @exception InstanceNotFoundException The managed resource
  260. * object could not be found
  261. * @exception InvalidTargetObjectTypeException The managed
  262. * resource type should be "ObjectReference".
  263. * @exception RuntimeOperationsException Wraps a {@link
  264. * RuntimeException} when setting the resource.
  265. **/
  266. public void setManagedResource(Object mr, String mr_type)
  267. throws MBeanException, RuntimeOperationsException,
  268. InstanceNotFoundException, InvalidTargetObjectTypeException {
  269. if (tracing())
  270. trace("setManagedResource(Object,String)","Entry");
  271. // check that the mr_type is supported by this JMXAgent
  272. // only "objectReference" is supported
  273. if ((mr_type == null) ||
  274. (! mr_type.equalsIgnoreCase("objectReference"))) {
  275. if (tracing())
  276. trace("setManagedResource(Object,String)",
  277. "Managed Resouce Type is not supported: " + mr_type);
  278. throw new InvalidTargetObjectTypeException(mr_type);
  279. }
  280. if (tracing())
  281. trace("setManagedResource(Object,String)",
  282. "Managed Resouce is valid");
  283. managedResource = mr;
  284. if (tracing())
  285. trace("setManagedResource(Object, String)", "Exit");
  286. }
  287. /**
  288. * <p>Instantiates this MBean instance with the data found for
  289. * the MBean in the persistent store. The data loaded could include
  290. * attribute and operation values.</p>
  291. *
  292. * <p>This method should be called during construction or
  293. * initialization of this instance, and before the MBean is
  294. * registered with the MBeanServer.</p>
  295. *
  296. * <p>If the implementation of this class does not support
  297. * persistence, an {@link MBeanException} wrapping a {@link
  298. * ServiceNotFoundException} is thrown.</p>
  299. *
  300. * @exception MBeanException Wraps another exception, or
  301. * persistence is not supported
  302. * @exception RuntimeOperationsException Wraps exceptions from the
  303. * persistence mechanism
  304. * @exception InstanceNotFoundException Could not find or load
  305. * this MBean from persistent storage
  306. */
  307. public void load()
  308. throws MBeanException, RuntimeOperationsException,
  309. InstanceNotFoundException {
  310. final ServiceNotFoundException x = new ServiceNotFoundException(
  311. "Persistence not supported for this MBean");
  312. throw new MBeanException(x, x.getMessage());
  313. }
  314. /**
  315. * <p>Captures the current state of this MBean instance and writes
  316. * it out to the persistent store. The state stored could include
  317. * attribute and operation values.</p>
  318. *
  319. * <p>If the implementation of this class does not support
  320. * persistence, an {@link MBeanException} wrapping a {@link
  321. * ServiceNotFoundException} is thrown.</p>
  322. *
  323. * <p>Persistence policy from the MBean and attribute descriptor
  324. * is used to guide execution of this method. The MBean should be
  325. * stored if 'persistPolicy' field is:</p>
  326. *
  327. * <PRE> != "never"
  328. * = "always"
  329. * = "onTimer" and now > 'lastPersistTime' + 'persistPeriod'
  330. * = "NoMoreOftenThan" and now > 'lastPersistTime' + 'persistPeriod'
  331. * </PRE>
  332. *
  333. * <p>Do not store the MBean if 'persistPolicy' field is:</p>
  334. * <PRE>
  335. * = "never"
  336. * = "onUpdate"
  337. * = "onTimer" && now < 'lastPersistTime' + 'persistPeriod'
  338. * </PRE>
  339. *
  340. * @exception MBeanException Wraps another exception, or
  341. * persistence is not supported
  342. * @exception RuntimeOperationsException Wraps exceptions from the
  343. * persistence mechanism
  344. * @exception InstanceNotFoundException Could not find/access the
  345. * persistent store
  346. */
  347. public void store()
  348. throws MBeanException, RuntimeOperationsException,
  349. InstanceNotFoundException {
  350. final ServiceNotFoundException x = new ServiceNotFoundException(
  351. "Persistence not supported for this MBean");
  352. throw new MBeanException(x, x.getMessage());
  353. }
  354. /*************************************/
  355. /* DynamicMBean Interface */
  356. /*************************************/
  357. /**
  358. * The resolveForCacheValue method checks the descriptor passed in to
  359. * see if there is a valid cached value in the descriptor.
  360. * The valid value will be in the 'value' field if there is one.
  361. * If the 'currencyTimeLimit' field in the descriptor is:
  362. * <ul>
  363. * <li><b><0</b> Then the value is not cached and is never valid.
  364. * Null is returned. The 'value' and 'lastUpdatedTimeStamp'
  365. * fields are cleared.</li>
  366. * <li><b>=0</b> Then the value is always cached and always valid.
  367. * The 'value' field is returned.
  368. * The 'lastUpdatedTimeStamp' field is not checked.</li>
  369. * <li><b>>0</b> Represents the number of seconds that the
  370. * 'value' field is valid.
  371. * The 'value' field is no longer valid when
  372. * 'lastUpdatedTimeStamp' + 'currencyTimeLimit' > Now.</li>
  373. * </ul>
  374. * <li>When 'value' is valid, 'valid' is returned.</li>
  375. * <li>When 'value' is no longer valid then null is returned and
  376. * 'value' and 'lastUpdatedTimeStamp' fields are cleared.</li>
  377. *
  378. **/
  379. private Object resolveForCacheValue(Descriptor descr)
  380. throws MBeanException, RuntimeOperationsException {
  381. if (tracing())
  382. trace("resolveForCacheValue(Descriptor)","Entry");
  383. Object response = null;
  384. boolean resetValue = false, returnCachedValue = true;
  385. long currencyPeriod = 0;
  386. if (descr == null) {
  387. if (tracing())
  388. trace("resolveForCacheValue(Descriptor)",
  389. "Input Descriptor is null");
  390. return response;
  391. }
  392. if (tracing())
  393. trace("resolveForCacheValue(Descriptor)","descriptor is " +
  394. descr.toString());
  395. final Descriptor mmbDescr = modelMBeanInfo.getMBeanDescriptor();
  396. if (mmbDescr == null) {
  397. if (tracing())
  398. trace("resolveForCacheValue(Descriptor)",
  399. "MBean Descriptor is null");
  400. //return response;
  401. }
  402. Object objExpTime = descr.getFieldValue("currencyTimeLimit");
  403. String expTime;
  404. if (objExpTime != null) {
  405. expTime = objExpTime.toString();
  406. } else {
  407. expTime = null;
  408. }
  409. if ((expTime == null) && (mmbDescr != null)) {
  410. objExpTime = mmbDescr.getFieldValue("currencyTimeLimit");
  411. if (objExpTime != null) {
  412. expTime = objExpTime.toString();
  413. } else {
  414. expTime = null;
  415. }
  416. }
  417. if (expTime != null) {
  418. if (tracing())
  419. trace("resolveForCacheValue(Descriptor)",
  420. "currencyTimeLimit: " + expTime);
  421. // convert seconds to milliseconds for time comparison
  422. currencyPeriod = ((new Long(expTime)).longValue()) * 1000;
  423. if (currencyPeriod < 0) {
  424. /* if currencyTimeLimit is -1 then value is never cached */
  425. returnCachedValue = false;
  426. resetValue = true;
  427. if (tracing())
  428. trace("resolveForCacheValue(Descriptor)",
  429. currencyPeriod + ": never Cached");
  430. } else if (currencyPeriod == 0) {
  431. /* if currencyTimeLimit is 0 then value is always cached */
  432. returnCachedValue = true;
  433. resetValue = false;
  434. if (tracing())
  435. trace("resolveForCacheValue(Descriptor)",
  436. "always valid Cache");
  437. } else {
  438. Object objtStamp =
  439. descr.getFieldValue("lastUpdatedTimeStamp");
  440. String tStamp;
  441. if (objtStamp != null) tStamp = objtStamp.toString();
  442. else tStamp = null;
  443. if (tracing())
  444. trace("resolveForCacheValue(Descriptor)",
  445. "lastUpdatedTimeStamp: " + tStamp);
  446. if (tStamp == null)
  447. tStamp = "0";
  448. long lastTime = (new Long(tStamp)).longValue();
  449. if (tracing())
  450. trace("resolveForCacheValue(Descriptor)",
  451. " currencyPeriod:" + currencyPeriod +
  452. " lastUpdatedTimeStamp:" + lastTime);
  453. long now = (new Date()).getTime();
  454. if (now < (lastTime + currencyPeriod)) {
  455. returnCachedValue = true;
  456. resetValue = false;
  457. if (tracing())
  458. trace("resolveForCacheValue(Descriptor)",
  459. " timed valid Cache for " + now + " < " +
  460. (lastTime + currencyPeriod));
  461. } else { /* value is expired */
  462. returnCachedValue = false;
  463. resetValue = true;
  464. if (tracing())
  465. trace("resolveForCacheValue(Descriptor)",
  466. "timed expired cache for " + now + " > " +
  467. (lastTime + currencyPeriod));
  468. }
  469. }
  470. if (tracing())
  471. trace("resolveForCacheValue(Descriptor)",
  472. "returnCachedValue:" + returnCachedValue +
  473. " resetValue: " + resetValue);
  474. if (returnCachedValue == true) {
  475. Object currValue = descr.getFieldValue("value");
  476. if (currValue != null) {
  477. /* error/validity check return value here */
  478. response = currValue;
  479. /* need to cast string cached value to type */
  480. if (tracing())
  481. trace("resolveForCacheValue(Descriptor)",
  482. "valid Cache value: " + currValue);
  483. } else {
  484. response = null;
  485. if (tracing())
  486. trace("resolveForCacheValue(Descriptor)",
  487. "no Cached value");
  488. }
  489. }
  490. if (resetValue == true) {
  491. /* value is not current, so remove it */
  492. descr.removeField("lastUpdatedTimeStamp");
  493. descr.removeField("value");
  494. response = null;
  495. modelMBeanInfo.setDescriptor(descr,null);
  496. if (tracing())
  497. trace("resolveForCacheValue(Descriptor)",
  498. "reset cached value to null");
  499. }
  500. }
  501. if (tracing())
  502. trace("resolveForCache(Descriptor)","Exit");
  503. return response;
  504. }
  505. /**
  506. * Returns the attributes, operations, constructors and notifications
  507. * that this RequiredModelMBean exposes for management.
  508. *
  509. * @return An instance of ModelMBeanInfo allowing retrieval all
  510. * attributes, operations, and Notifications of this MBean.
  511. *
  512. **/
  513. public MBeanInfo getMBeanInfo() {
  514. if (tracing())
  515. trace("getMBeanInfo()","Entry and Exit");
  516. if (modelMBeanInfo == null) {
  517. if (tracing())
  518. trace("getMBeanInfo()","modelMBeanInfo is null");
  519. modelMBeanInfo = createDefaultModelMBeanInfo();
  520. //return new ModelMBeanInfo(" ", "", null, null, null, null);
  521. }
  522. if (tracing()) {
  523. trace("getMBeanInfo()","ModelMBeanInfo is " +
  524. modelMBeanInfo.getClassName() + " for " +
  525. modelMBeanInfo.getDescription());
  526. trace("getMBeanInfo()",printModelMBeanInfo(modelMBeanInfo));
  527. }
  528. return((MBeanInfo) ((ModelMBeanInfo)modelMBeanInfo).clone());
  529. }
  530. private String printModelMBeanInfo(ModelMBeanInfo info) {
  531. final StringBuffer retStr = new StringBuffer();
  532. if (info == null) {
  533. if (tracing())
  534. trace("printModelMBeanInfo(ModelMBeanInfo)",
  535. "ModelMBeanInfo to print is null, " +
  536. "printing local ModelMBeanInfo");
  537. info = modelMBeanInfo;
  538. }
  539. retStr.append("\nMBeanInfo for ModelMBean is:");
  540. retStr.append("\nCLASSNAME: \t"+ info.getClassName());
  541. retStr.append("\nDESCRIPTION: \t"+ info.getDescription());
  542. try {
  543. retStr.append("\nMBEAN DESCRIPTOR: \t"+
  544. info.getMBeanDescriptor());
  545. } catch (Exception e) {
  546. retStr.append("\nMBEAN DESCRIPTOR: \t" + " is invalid");
  547. }
  548. retStr.append("\nATTRIBUTES");
  549. final MBeanAttributeInfo[] attrInfo = info.getAttributes();
  550. if ((attrInfo != null) && (attrInfo.length>0)) {
  551. for (int i=0; i<attrInfo.length; i++) {
  552. final ModelMBeanAttributeInfo attInfo =
  553. (ModelMBeanAttributeInfo)attrInfo[i];
  554. retStr.append(" ** NAME: \t"+ attInfo.getName());
  555. retStr.append(" DESCR: \t"+ attInfo.getDescription());
  556. retStr.append(" TYPE: \t"+ attInfo.getType() +
  557. " READ: \t"+ attInfo.isReadable() +
  558. " WRITE: \t"+ attInfo.isWritable());
  559. retStr.append(" DESCRIPTOR: " +
  560. attInfo.getDescriptor().toString());
  561. }
  562. } else {
  563. retStr.append(" ** No attributes **");
  564. }
  565. retStr.append("\nCONSTRUCTORS");
  566. final MBeanConstructorInfo[] constrInfo = info.getConstructors();
  567. if ((constrInfo != null) && (constrInfo.length > 0 )) {
  568. for (int i=0; i<constrInfo.length; i++) {
  569. final ModelMBeanConstructorInfo ctorInfo =
  570. (ModelMBeanConstructorInfo)constrInfo[i];
  571. retStr.append(" ** NAME: \t"+ ctorInfo.getName());
  572. retStr.append(" DESCR: \t"+
  573. ctorInfo.getDescription());
  574. retStr.append(" PARAM: \t"+
  575. ctorInfo.getSignature().length +
  576. " parameter(s)");
  577. retStr.append(" DESCRIPTOR: " +
  578. ctorInfo.getDescriptor().toString());
  579. }
  580. } else {
  581. retStr.append(" ** No Constructors **");
  582. }
  583. retStr.append("\nOPERATIONS");
  584. final MBeanOperationInfo[] opsInfo = info.getOperations();
  585. if ((opsInfo != null) && (opsInfo.length>0)) {
  586. for (int i=0; i<opsInfo.length; i++) {
  587. final ModelMBeanOperationInfo operInfo =
  588. (ModelMBeanOperationInfo)opsInfo[i];
  589. retStr.append(" ** NAME: \t"+ operInfo.getName());
  590. retStr.append(" DESCR: \t"+ operInfo.getDescription());
  591. retStr.append(" PARAM: \t"+
  592. operInfo.getSignature().length +
  593. " parameter(s)");
  594. retStr.append(" DESCRIPTOR: " +
  595. operInfo.getDescriptor().toString());
  596. }
  597. } else {
  598. retStr.append(" ** No operations ** ");
  599. }
  600. retStr.append("\nNOTIFICATIONS");
  601. MBeanNotificationInfo[] notifInfo = info.getNotifications();
  602. if ((notifInfo != null) && (notifInfo.length>0)) {
  603. for (int i=0; i<notifInfo.length; i++) {
  604. final ModelMBeanNotificationInfo nInfo =
  605. (ModelMBeanNotificationInfo)notifInfo[i];
  606. retStr.append(" ** NAME: \t"+ nInfo.getName());
  607. retStr.append(" DESCR: \t"+ nInfo.getDescription());
  608. retStr.append(" DESCRIPTOR: " +
  609. nInfo.getDescriptor().toString());
  610. }
  611. } else {
  612. retStr.append(" ** No notifications **");
  613. }
  614. retStr.append(" ** ModelMBean: End of MBeanInfo ** ");
  615. return retStr.toString();
  616. }
  617. private void echo(String txt) {
  618. trace("echo(txt)",txt);
  619. }
  620. /**
  621. * Invokes a method on or through a RequiredModelMBean and returns
  622. * the result of the method execution.
  623. * <P>
  624. * If the given method to be invoked, together with the provided
  625. * signature, matches one of RequiredModelMbean
  626. * accessible methods, this one will be call. Otherwise the call to
  627. * the given method will be tried on the managed resource.
  628. * <P>
  629. * The last value returned by an operation may be cached in
  630. * the operation's descriptor which
  631. * is in the ModelMBeanOperationInfo's descriptor.
  632. * The valid value will be in the 'value' field if there is one.
  633. * If the 'currencyTimeLimit' field in the descriptor is:
  634. * <UL>
  635. * <LI><b><0</b> Then the value is not cached and is never valid.
  636. * The operation method is invoked.
  637. * The 'value' and 'lastUpdatedTimeStamp' fields are cleared.</LI>
  638. * <LI><b>=0</b> Then the value is always cached and always valid.
  639. * The 'value' field is returned. If there is no 'value' field
  640. * then the operation method is invoked for the attribute.
  641. * The 'lastUpdatedTimeStamp' field and `value' fields are set to
  642. * the operation's return value and the current time stamp.</LI>
  643. * <LI><b>>0</b> Represents the number of seconds that the 'value'
  644. * field is valid.
  645. * The 'value' field is no longer valid when
  646. * 'lastUpdatedTimeStamp' + 'currencyTimeLimit' > Now.
  647. * <UL>
  648. * <LI>When 'value' is valid, 'value' is returned.</LI>
  649. * <LI>When 'value' is no longer valid then the operation
  650. * method is invoked. The 'lastUpdatedTimeStamp' field
  651. * and `value' fields are updated.</lI>
  652. * </UL>
  653. * </LI>
  654. * </UL>
  655. *
  656. * <p><b>Note:</b> because of inconsistencies in previous versions of
  657. * this specification, it is recommended not to use negative or zero
  658. * values for <code>currencyTimeLimit</code>. To indicate that a
  659. * cached value is never valid, omit the
  660. * <code>currencyTimeLimit</code> field. To indicate that it is
  661. * always valid, use a very large number for this field.</p>
  662. *
  663. * @param opName The name of the method to be invoked. The
  664. * name can be the fully qualified method name including the
  665. * classname, or just the method name if the classname is
  666. * defined in the 'class' field of the operation descriptor.
  667. * @param opArgs An array containing the parameters to be set
  668. * when the operation is invoked
  669. * @param sig An array containing the signature of the
  670. * operation. The class objects will be loaded using the same
  671. * class loader as the one used for loading the MBean on which
  672. * the operation was invoked.
  673. *
  674. * @return The object returned by the method, which represents the
  675. * result of invoking the method on the specified managed resource.
  676. *
  677. * @exception MBeanException Wraps one of the following Exceptions:
  678. * <UL>
  679. * <LI> An Exception thrown by the managed object's invoked method.</LI>
  680. * <LI> {@link ServiceNotFoundException}: No ModelMBeanOperationInfo or
  681. * no descriptor defined for the specified operation or the managed
  682. * resource is null.</LI>
  683. * <LI> {@link InvalidTargetObjectTypeException}: The 'targetType'
  684. * field value is not 'objectReference'.</LI>
  685. * </UL>
  686. * @exception ReflectionException Wraps an {@link java.lang.Exception}
  687. * thrown while trying to invoke the method.
  688. * @exception RuntimeOperationsException Wraps an
  689. * {@link IllegalArgumentException} Method name is null.
  690. *
  691. **/
  692. /*
  693. The requirement to be able to invoke methods on the
  694. RequiredModelMBean class itself makes this method considerably
  695. more complicated than it might otherwise be. Note that, unlike
  696. earlier versions, we do not allow you to invoke such methods if
  697. they are not explicitly mentioned in the ModelMBeanInfo. Doing
  698. so was potentially a security problem, and certainly very
  699. surprising.
  700. We do not look for the method in the RequiredModelMBean class
  701. itself if:
  702. (a) there is a "targetObject" field in the Descriptor for the
  703. operation; or
  704. (b) there is a "class" field in the Descriptor for the operation
  705. and the named class is not RequiredModelMBean or one of its
  706. superinterfaces; or
  707. (c) the name of the operation is not the name of a method in
  708. RequiredModelMBean (this is just an optimization).
  709. In cases (a) and (b), if you have gone to the trouble of adding
  710. those fields specifically for this operation then presumably you
  711. do not want RequiredModelMBean's methods to be called.
  712. We have to pay attention to class loading issues. If the
  713. "class" field is present, the named class has to be resolved
  714. relative to RequiredModelMBean's class loader to test the
  715. condition (b) above, and relative to the managed resource's
  716. class loader to ensure that the managed resource is in fact of
  717. the named class (or a subclass). The class names in the sig
  718. array likewise have to be resolved, first against
  719. RequiredModelMBean's class loader, then against the managed
  720. resource's class loader. There is no point in using any other
  721. loader because when we call Method.invoke we must call it on
  722. a Method that is implemented by the target object.
  723. */
  724. public Object invoke(String opName, Object[] opArgs, String[] sig)
  725. throws MBeanException, ReflectionException {
  726. final boolean tracing = tracing();
  727. if (tracing)
  728. trace("invoke(String, Object[], String[])","Entry");
  729. if (opName == null) {
  730. final RuntimeException x =
  731. new IllegalArgumentException("Method name must not be null");
  732. throw new RuntimeOperationsException(x,
  733. "An exception occured while trying to " +
  734. "invoke a method on a RequiredModelMBean");
  735. }
  736. String opClassName = null;
  737. String opMethodName;
  738. // Parse for class name and method
  739. int opSplitter = opName.lastIndexOf(".");
  740. if (opSplitter > 0) {
  741. opClassName = opName.substring(0,opSplitter);
  742. opMethodName = opName.substring(opSplitter+1);
  743. } else
  744. opMethodName = opName;
  745. /* Ignore anything after a left paren. We keep this for
  746. compatibility but it isn't specified. */
  747. opSplitter = opMethodName.indexOf("(");
  748. if (opSplitter > 0)
  749. opMethodName = opMethodName.substring(0,opSplitter);
  750. if (tracing)
  751. trace("invoke(String, Object[], String[])",
  752. "Finding operation " + opName + " as " + opMethodName);
  753. ModelMBeanOperationInfo opInfo =
  754. modelMBeanInfo.getOperation(opMethodName);
  755. if (opInfo == null) {
  756. final String msg =
  757. "Operation " + opName + " not in ModelMBeanInfo";
  758. throw new MBeanException(new ServiceNotFoundException(msg), msg);
  759. }
  760. final Descriptor opDescr = opInfo.getDescriptor();
  761. if (opDescr == null) {
  762. final String msg = "Operation descriptor null";
  763. throw new MBeanException(new ServiceNotFoundException(msg), msg);
  764. }
  765. final Object cached = resolveForCacheValue(opDescr);
  766. if (cached != null) {
  767. if (tracing)
  768. trace("invoke(String, Object[], String[])",
  769. "Returning cached value");
  770. return cached;
  771. }
  772. if (opClassName == null)
  773. opClassName = (String) opDescr.getFieldValue("class");
  774. // may still be null now
  775. opMethodName = (String) opDescr.getFieldValue("name");
  776. if (opMethodName == null) {
  777. final String msg =
  778. "Method descriptor must include `name' field";
  779. throw new MBeanException(new ServiceNotFoundException(msg), msg);
  780. }
  781. final String targetTypeField = (String)
  782. opDescr.getFieldValue("targetType");
  783. if (targetTypeField != null
  784. && !targetTypeField.equalsIgnoreCase("objectReference")) {
  785. final String msg =
  786. "Target type must be objectReference: " + targetTypeField;
  787. throw new MBeanException(new InvalidTargetObjectTypeException(msg),
  788. msg);
  789. }
  790. final Object targetObjectField = opDescr.getFieldValue("targetObject");
  791. if (tracing && targetObjectField != null)
  792. trace("invoke(String, Object[], String[])",
  793. "Found target object in descriptor");
  794. /* Now look for the method, either in RequiredModelMBean itself
  795. or in the target object. Set "method" and "targetObject"
  796. appropriately. */
  797. Method method;
  798. Object targetObject;
  799. method = findRMMBMethod(opMethodName, targetObjectField,
  800. opClassName, sig);
  801. if (method != null)
  802. targetObject = this;
  803. else {
  804. if (tracing)
  805. trace("invoke(String, Object[], String[])",
  806. "looking for method in managedResource class");
  807. if (targetObjectField != null)
  808. targetObject = targetObjectField;
  809. else {
  810. targetObject = managedResource;
  811. if (targetObject == null) {
  812. final String msg =
  813. "managedResource for invoke " + opName +
  814. " is null";
  815. Exception snfe = new ServiceNotFoundException(msg);
  816. throw new MBeanException(snfe);
  817. }
  818. }
  819. final Class targetClass;
  820. if (opClassName != null) {
  821. try {
  822. final ClassLoader targetClassLoader =
  823. targetObject.getClass().getClassLoader();
  824. targetClass = Class.forName(opClassName, false,
  825. targetClassLoader);
  826. } catch (ClassNotFoundException e) {
  827. final String msg =
  828. "class for invoke " + opName + " not found";
  829. throw new ReflectionException(e, msg);
  830. }
  831. } else
  832. targetClass = targetObject.getClass();
  833. method = resolveMethod(targetClass, opMethodName, sig);
  834. }
  835. if (tracing)
  836. trace("invoke(String, Object[], String[])",
  837. "found " + opMethodName + ", now invoking");
  838. final Object result =
  839. invokeMethod(opName, method, targetObject, opArgs);
  840. if (tracing)
  841. trace("invoke(String, Object[], String[])",
  842. "successfully invoked method");
  843. if (result != null)
  844. cacheResult(opInfo, opDescr, result);
  845. return result;
  846. }
  847. private static Method resolveMethod(Class targetClass,
  848. String opMethodName,
  849. String[] sig)
  850. throws ReflectionException {
  851. final boolean tracing = tracing();
  852. if (tracing)
  853. trace("resolveMethod",
  854. "resolving " + targetClass + "." + opMethodName);
  855. final Class[] argClasses;
  856. if (sig == null)
  857. argClasses = null;
  858. else {
  859. final ClassLoader targetClassLoader = targetClass.getClassLoader();
  860. argClasses = new Class[sig.length];
  861. for (int i = 0; i < sig.length; i++) {
  862. if (tracing)
  863. trace("resolveMethod", "resolve type " + sig[i]);
  864. argClasses[i] = (Class) primitiveClassMap.get(sig[i]);
  865. if (argClasses[i] == null) {
  866. try {
  867. argClasses[i] =
  868. Class.forName(sig[i], false, targetClassLoader);
  869. } catch (ClassNotFoundException e) {
  870. if (tracing)
  871. trace("resolveMethod", "class not found");
  872. final String msg = "Parameter class not found";
  873. throw new ReflectionException(e, msg);
  874. }
  875. }
  876. }
  877. }
  878. try {
  879. return targetClass.getMethod(opMethodName, argClasses);
  880. } catch (NoSuchMethodException e) {
  881. final String msg =
  882. "Target method not found: " + targetClass.getName() + "." +
  883. opMethodName;
  884. throw new ReflectionException(e, msg);
  885. }
  886. }
  887. /* Map e.g. "int" to int.class. Goodness knows how many time this
  888. particular wheel has been reinvented. */
  889. private static final Class[] primitiveClasses = {
  890. int.class, long.class, boolean.class, double.class,
  891. float.class, short.class, byte.class, char.class,
  892. };
  893. private static final Map/*<String,Class>*/ primitiveClassMap =
  894. new HashMap();
  895. static {
  896. for (int i = 0; i < primitiveClasses.length; i++) {
  897. final Class c = primitiveClasses[i];
  898. primitiveClassMap.put(c.getName(), c);
  899. }
  900. }
  901. /* Find a method in RequiredModelMBean as determined by the given
  902. parameters. Return null if there is none, or if the parameters
  903. exclude using it. Called from invoke. */
  904. private static Method findRMMBMethod(String opMethodName,
  905. Object targetObjectField,
  906. String opClassName,
  907. String[] sig) {
  908. if (tracing())
  909. trace("invoke(String, Object[], String[])",
  910. "looking for method in RequiredModelMBean class");
  911. if (!isRMMBMethodName(opMethodName))
  912. return null;
  913. if (targetObjectField != null)
  914. return null;
  915. final Class rmmbClass = RequiredModelMBean.class;
  916. final Class targetClass;
  917. if (opClassName == null)
  918. targetClass = rmmbClass;
  919. else {
  920. try {
  921. final ClassLoader targetClassLoader =
  922. rmmbClass.getClassLoader();
  923. targetClass = Class.forName(opClassName, false,
  924. targetClassLoader);
  925. if (!rmmbClass.isAssignableFrom(targetClass))
  926. return null;
  927. } catch (ClassNotFoundException e) {
  928. return null;
  929. }
  930. }
  931. try {
  932. return resolveMethod(targetClass, opMethodName, sig);
  933. } catch (ReflectionException e) {
  934. return null;
  935. }
  936. }
  937. /*
  938. * Invoke the given method, and throw the somewhat unpredictable
  939. * appropriate exception if the method itself gets an exception.
  940. */
  941. private Object invokeMethod(String opName, Method method,
  942. Object targetObject, Object[] opArgs)
  943. throws MBeanException, ReflectionException {
  944. try {
  945. return method.invoke(targetObject, opArgs);
  946. } catch (RuntimeErrorException ree) {
  947. throw new RuntimeOperationsException(ree,
  948. "RuntimeException occured in RequiredModelMBean "+
  949. "while trying to invoke operation " + opName);
  950. } catch (RuntimeException re) {
  951. throw new RuntimeOperationsException(re,
  952. "RuntimeException occured in RequiredModelMBean "+
  953. "while trying to invoke operation " + opName);
  954. } catch (IllegalAccessException iae) {
  955. throw new ReflectionException(iae,
  956. "IllegalAccessException occured in " +
  957. "RequiredModelMBean while trying to " +
  958. "invoke operation " + opName);
  959. } catch (InvocationTargetException ite) {
  960. Throwable mmbTargEx = ite.getTargetException();
  961. if (mmbTargEx instanceof RuntimeException) {
  962. throw new MBeanException ((RuntimeException)mmbTargEx,
  963. "RuntimeException thrown in RequiredModelMBean "+
  964. "while trying to invoke operation " + opName);
  965. } else if (mmbTargEx instanceof Error) {
  966. throw new RuntimeErrorException((Error)mmbTargEx,
  967. "Error occured in RequiredModelMBean while trying "+
  968. "to invoke operation " + opName);
  969. } else if (mmbTargEx instanceof ReflectionException) {
  970. throw (ReflectionException) mmbTargEx;
  971. } else {
  972. throw new MBeanException ((Exception)mmbTargEx,
  973. "Exception thrown in RequiredModelMBean "+
  974. "while trying to invoke operation " + opName);
  975. }
  976. } catch (Error err) {
  977. throw new RuntimeErrorException(err,
  978. "Error occured in RequiredModelMBean while trying "+
  979. "to invoke operation " + opName);
  980. } catch (Exception e) {
  981. throw new ReflectionException(e,
  982. "Exception occured in RequiredModelMBean while " +
  983. "trying to invoke operation " + opName);
  984. }
  985. }
  986. /*
  987. * Cache the result of an operation in the descriptor, if that is
  988. * called for by the descriptor's configuration. Note that we
  989. * don't remember operation parameters when caching the result, so
  990. * this is unlikely to be useful if there are any.
  991. */
  992. private void cacheResult(ModelMBeanOperationInfo opInfo,
  993. Descriptor opDescr, Object result)
  994. throws MBeanException {
  995. Descriptor mmbDesc =
  996. modelMBeanInfo.getMBeanDescriptor();
  997. Object objctl =
  998. opDescr.getFieldValue("currencyTimeLimit");
  999. String ctl;
  1000. if (objctl != null) {
  1001. ctl = objctl.toString();
  1002. } else {
  1003. ctl = null;
  1004. }
  1005. if ((ctl == null) && (mmbDesc != null)) {
  1006. objctl =
  1007. mmbDesc.getFieldValue("currencyTimeLimit");
  1008. if (objctl != null) {
  1009. ctl = objctl.toString();
  1010. } else {
  1011. ctl = null;
  1012. }
  1013. }
  1014. if ((ctl != null) && !(ctl.equals("-1"))) {
  1015. opDescr.setField("value", result);
  1016. opDescr.setField("lastUpdatedTimeStamp",
  1017. (new Long((new Date()).getTime())).toString());
  1018. modelMBeanInfo.setDescriptor(opDescr,
  1019. "operation");
  1020. if (tracing()) {
  1021. trace("invoke(String,Object[],Object[])",
  1022. "new descriptor is " +
  1023. opDescr.toString());
  1024. }
  1025. }
  1026. }
  1027. /*
  1028. * Determine whether the given name is the name of a public method
  1029. * in this class. This is only an optimization: it prevents us
  1030. * from trying to do argument type lookups and reflection on a
  1031. * method that will obviously fail because it has the wrong name.
  1032. *
  1033. * The first time this method is called we do the reflection, and
  1034. * every other time we reuse the remembered values.
  1035. *
  1036. * It's conceivable that the (possibly malicious) first caller
  1037. * doesn't have the required permissions to do reflection, in
  1038. * which case we don't touch anything so as not to interfere
  1039. * with a later permissionful caller.
  1040. */
  1041. private static Set/*<String>*/ rmmbMethodNames;
  1042. private static synchronized boolean isRMMBMethodName(String name) {
  1043. if (rmmbMethodNames == null) {
  1044. try {
  1045. Set names = new HashSet();
  1046. Method[] methods = RequiredModelMBean.class.getMethods();
  1047. for (int i = 0; i < methods.length; i++)
  1048. names.add(methods[i].getName());
  1049. rmmbMethodNames = names;
  1050. } catch (Exception e) {
  1051. return true;
  1052. // This is only an optimization so we'll go on to discover
  1053. // whether the name really is an RMMB method.
  1054. }
  1055. }
  1056. return rmmbMethodNames.contains(name);
  1057. }
  1058. /**
  1059. * Returns the value of a specific attribute defined for this
  1060. * ModelMBean.
  1061. * The last value returned by an attribute may be cached in the
  1062. * attribute's descriptor.
  1063. * The valid value will be in the 'value' field if there is one.
  1064. * If the 'currencyTimeLimit' field in the descriptor is:
  1065. * <UL>
  1066. * <LI> <b><0</b> Then the value is not cached and is never valid.
  1067. * The getter method is invoked for the attribute.
  1068. * The 'value' and 'lastUpdatedTimeStamp' fields are cleared.</LI>
  1069. * <LI> <b>=0</b> Then the value is always cached and always valid.
  1070. * The 'value' field is returned. If there is no'value' field
  1071. * then the getter method is invoked for the attribute.
  1072. * The 'lastUpdatedTimeStamp' field and `value' fields are set
  1073. * to the attribute's value and the current time stamp.</LI>
  1074. * <LI> <b>>0</b> Represents the number of seconds that the 'value'
  1075. * field is valid.
  1076. * The 'value' field is no longer valid when
  1077. * 'lastUpdatedTimeStamp' + 'currencyTimeLimit' > Now.
  1078. * <UL>
  1079. * <LI>When 'value' is valid, 'value' is returned.</LI>
  1080. * <LI>When 'value' is no longer valid then the getter
  1081. * method is invoked for the attribute.
  1082. * The 'lastUpdatedTimeStamp' field and `value' fields
  1083. * are updated.</LI>
  1084. * </UL></LI>
  1085. * </UL>
  1086. *
  1087. * <p><b>Note:</b> because of inconsistencies in previous versions of
  1088. * this specification, it is recommended not to use negative or zero
  1089. * values for <code>currencyTimeLimit</code>. To indicate that a
  1090. * cached value is never valid, omit the
  1091. * <code>currencyTimeLimit</code> field. To indicate that it is
  1092. * always valid, use a very large number for this field.</p>
  1093. *
  1094. * <p>If the 'getMethod' field contains the name of a valid
  1095. * operation descriptor, then the method described by the
  1096. * operation descriptor is executed. The response from the
  1097. * method is returned as the value of the attribute. If the
  1098. * operation fails or the returned value is not of the same
  1099. * type as the attribute, an exception will be thrown. If no
  1100. * 'getMethod' field is defined then the default value of the
  1101. * attribute is returned. In this implementation, in every
  1102. * case where the getMethod needs to be called, because the
  1103. * method is invoked through the standard "invoke" method and
  1104. * thus needs operationInfo, an operation must be specified
  1105. * for that getMethod so that the invocation works correctly.</p>
  1106. *
  1107. * @param attrName A String specifying the name of the
  1108. * attribute to be retrieved. It must match the name of a
  1109. * ModelMBeanAttributeInfo.
  1110. *
  1111. * @return The value of the retrieved attribute from the
  1112. * descriptor 'value' field or from the invocation of the
  1113. * operation in the 'getMethod' field of the descriptor.
  1114. *
  1115. * @exception AttributeNotFoundException The specified attribute is
  1116. * not accessible in the MBean.
  1117. * The following cases may result in an AttributeNotFoundException:
  1118. * <UL>
  1119. * <LI> No ModelMBeanInfo was found for the Model MBean.</LI>
  1120. * <LI> No ModelMBeanAttributeInfo was found for the specified
  1121. * attribute name.</LI>
  1122. * <LI> The ModelMBeanAttributeInfo isReadable method returns
  1123. * 'false'.</LI>
  1124. * </UL>
  1125. * @exception MBeanException Wraps one of the following Exceptions:
  1126. * <UL>
  1127. * <LI> {@link InvalidAttributeValueException}: A wrong value type
  1128. * was received from the attribute's getter method or
  1129. * no 'getMethod' field defined in the descriptor for
  1130. * the attribute and no default value exists.</LI>
  1131. * <LI> {@link ServiceNotFoundException}: No
  1132. * ModelMBeanOperationInfo defined for the attribute's
  1133. * getter method or no descriptor associated with the
  1134. * ModelMBeanOperationInfo or the managed resource is
  1135. * null.</LI>
  1136. * <LI> {@link InvalidTargetObjectTypeException} The 'targetType'
  1137. * field value is not 'objectReference'.</LI>
  1138. * <LI> An Exception thrown by the managed object's getter.</LI>
  1139. * </UL>
  1140. * @exception ReflectionException Wraps an {@link java.lang.Exception}
  1141. * thrown while trying to invoke the getter.
  1142. * @exception RuntimeOperationsException Wraps an
  1143. * {@link IllegalArgumentException}: The attribute name in
  1144. * parameter is null.
  1145. *
  1146. * @see #setAttribute(javax.management.Attribute)
  1147. **/
  1148. public Object getAttribute(String attrName)
  1149. throws AttributeNotFoundException, MBeanException,
  1150. ReflectionException {
  1151. if (attrName == null)
  1152. throw new RuntimeOperationsException(new
  1153. IllegalArgumentException("attributeName must not be null"),
  1154. "Exception occured trying to get attribute of a " +
  1155. "RequiredModelMBean");
  1156. if (tracing())
  1157. trace("getAttribute(String)","Entry with" + attrName);
  1158. /* Check attributeDescriptor for getMethod */
  1159. ModelMBeanAttributeInfo attrInfo=null;
  1160. Descriptor attrDescr=null;
  1161. Object response = null;
  1162. try {
  1163. if (modelMBeanInfo == null)
  1164. throw new AttributeNotFoundException(
  1165. "getAttribute failed: ModelMBeanInfo not found for "+
  1166. attrName);
  1167. attrInfo = modelMBeanInfo.getAttribute(attrName);
  1168. Descriptor mmbDesc = modelMBeanInfo.getMBeanDescriptor();
  1169. if (attrInfo == null)
  1170. throw new AttributeNotFoundException("getAttribute failed:"+
  1171. " ModelMBeanAttributeInfo not found for " + attrName);
  1172. attrDescr = attrInfo.getDescriptor();
  1173. if (attrDescr != null) {
  1174. if (!attrInfo.isReadable())
  1175. throw new AttributeNotFoundException(
  1176. "getAttribute failed: " + attrName +
  1177. " is not readable ");
  1178. response = resolveForCacheValue(attrDescr);
  1179. /* return current cached value */
  1180. if (tracing())
  1181. trace("getAttribute(String)","*** cached value is " +
  1182. response);
  1183. if (response == null) {
  1184. /* no cached value, run getMethod */
  1185. if (tracing())
  1186. trace("getAttribute(String)",
  1187. "**** cached value is null" +
  1188. " - " + "getting getMethod");
  1189. String attrGetMethod =
  1190. (String)(attrDescr.getFieldValue("getMethod"));
  1191. if (attrGetMethod != null) {
  1192. /* run method from operations descriptor */
  1193. if (tracing())
  1194. trace("getAttribute(String)",
  1195. "invoking a getMethod for " + attrName);
  1196. Object getResponse =
  1197. invoke(attrGetMethod, new Object[] {},
  1198. new String[] {});
  1199. if (getResponse != null) {
  1200. // error/validity check return value here
  1201. if (tracing())
  1202. trace("getAttribute(String)",
  1203. "got a non-null response from getMethod\n");
  1204. response = getResponse;
  1205. // change cached value in attribute descriptor
  1206. Object objctl =
  1207. attrDescr.getFieldValue("currencyTimeLimit");
  1208. String ctl;
  1209. if (objctl != null) ctl = objctl.toString();
  1210. else ctl = null;
  1211. if ((ctl == null) && (mmbDesc != null)) {
  1212. objctl = mmbDesc.
  1213. getFieldValue("currencyTimeLimit");
  1214. if (objctl != null) ctl = objctl.toString();
  1215. else ctl = null;
  1216. }
  1217. if ((ctl != null) && !(ctl.equals("-1"))) {
  1218. if (tracing())
  1219. trace("getAttribute(String)",
  1220. "setting cached value and "+
  1221. "lastUpdatedTime in descriptor");
  1222. attrDescr.setField("value", response);
  1223. final String stamp =
  1224. (new Long((new Date()).getTime())).
  1225. toString();
  1226. attrDescr.setField("lastUpdatedTimeStamp",
  1227. stamp);
  1228. attrInfo.setDescriptor(attrDescr);
  1229. modelMBeanInfo.setDescriptor(attrDescr,
  1230. "attribute");
  1231. if (tracing()) {
  1232. trace("getAttribute(String)",
  1233. "new descriptor is " +
  1234. attrDescr.toString());
  1235. trace("getAttribute(String)","local: "+
  1236. "AttributeInfo descriptor is "+
  1237. attrInfo.getDescriptor().
  1238. toString());
  1239. final String attStr = modelMBeanInfo.
  1240. getDescriptor(attrName,"attribute").
  1241. toString();
  1242. trace("getAttribute(String)",
  1243. "modelMBeanInfo: " +
  1244. "AttributeInfo descriptor is " +
  1245. attStr);
  1246. }
  1247. }
  1248. } else {
  1249. // response was invalid or really returned null
  1250. if (tracing())
  1251. trace("getAttribute(String)",
  1252. "got a null response from getMethod\n");
  1253. response = null;
  1254. }
  1255. } else {
  1256. // not getMethod so return descriptor (default) value
  1257. String qualifier="";
  1258. response = attrDescr.getFieldValue("value");
  1259. if (response == null) {
  1260. qualifier="default ";
  1261. response = attrDescr.getFieldValue("default");
  1262. }
  1263. if (tracing())
  1264. trace("getAttribute(String)",
  1265. "could not find getMethod for " +
  1266. attrName + ", returning descriptor " +
  1267. qualifier + "value");
  1268. // !! cast response to right class
  1269. }
  1270. }
  1271. // make sure response class matches type field
  1272. String respType = attrInfo.getType();
  1273. if (response != null) {
  1274. String responseClass = response.getClass().getName();
  1275. if (! respType.equals(responseClass)) {
  1276. // Revisit !! : this should be stacically initialized !
  1277. final String[] primitiveTypes = new String[] {
  1278. Boolean.TYPE.getName(),
  1279. Byte.TYPE.getName(),
  1280. Character.TYPE.getName(),
  1281. Short.TYPE.getName(),
  1282. Integer.TYPE.getName(),
  1283. Long.TYPE.getName(),
  1284. Float.TYPE.getName(),
  1285. Double.TYPE.getName(),
  1286. Void.TYPE.getName()};
  1287. final String[] primitiveWrappers = new String[] {
  1288. Boolean.class.getName(),
  1289. Byte.class.getName(),
  1290. Character.class.getName(),
  1291. Short.class.getName(),
  1292. Integer.class.getName(),
  1293. Long.class.getName(),
  1294. Float.class.getName(),
  1295. Double.class.getName(),
  1296. Void.class.getName()};
  1297. // unequality may come from primitive/wrapper class specs
  1298. boolean correspondingTypes = false;
  1299. for (int i = 0; i <= 8; i++) {
  1300. if ((respType.equals(primitiveTypes[i]))&&
  1301. (responseClass.equals(primitiveWrappers[i]))) {
  1302. correspondingTypes = true;
  1303. break;
  1304. }
  1305. }
  1306. // did we really get the expected response type ?
  1307. if (! correspondingTypes) {
  1308. if (tracing())
  1309. trace("getAttribute(String)",
  1310. "wrong response type '" + respType + "'" );
  1311. // throw exception, didn't get back right attribute type
  1312. throw new MBeanException(new
  1313. InvalidAttributeValueException("Wrong value type received for get attribute"),
  1314. "An exception occured while trying to get an "+
  1315. "attribute value through a RequiredModelMBean");
  1316. }
  1317. }
  1318. }
  1319. } else {
  1320. if (tracing())
  1321. trace("getAttribute(String)","getMethod failed " +
  1322. attrName + " not in attributeDescriptor\n");
  1323. throw new MBeanException(new
  1324. InvalidAttributeValueException(
  1325. "Unable to resolve attribute value, " +
  1326. "no getMethod defined in descriptor for attribute"),
  1327. "An exception occured while trying to get an "+
  1328. "attribute value through a RequiredModelMBean");
  1329. }
  1330. } catch (MBeanException mbe) {
  1331. throw mbe;
  1332. } catch (AttributeNotFoundException t) {
  1333. throw t;
  1334. } catch (Exception e) {
  1335. if (tracing())
  1336. trace("getAttribute(String)","getMethod failed with " +
  1337. e.getMessage() + " exception type " +
  1338. (e.getClass()).toString());
  1339. throw new MBeanException(e,"An exception occured while trying "+
  1340. "to get an attribute value: " + e.getMessage());
  1341. }
  1342. if (tracing())
  1343. trace("getAttribute(String)","Exit");
  1344. return response;
  1345. }
  1346. /**
  1347. * Returns the values of several attributes in the ModelMBean.
  1348. * Executes a getAttribute for each attribute name in the
  1349. * attrNames array passed in.
  1350. *
  1351. * @param attrNames A String array of names of the attributes
  1352. * to be retrieved.
  1353. *
  1354. * @return The array of the retrieved attributes.
  1355. *
  1356. * @exception RuntimeOperationsException Wraps an
  1357. * {@link IllegalArgumentException}: The object name in parameter is
  1358. * null or attributes in parameter is null.
  1359. *
  1360. * @see #setAttributes(javax.management.AttributeList)
  1361. */
  1362. public AttributeList getAttributes(String[] attrNames) {
  1363. if (tracing())
  1364. trace("getAttributes(String[])","Entry");
  1365. AttributeList responseList = null;
  1366. if (attrNames == null)
  1367. throw new RuntimeOperationsException(new
  1368. IllegalArgumentException("attributeNames must not be null"),
  1369. "Exception occured trying to get attributes of a "+
  1370. "RequiredModelMBean");
  1371. responseList = new AttributeList();
  1372. for (int i = 0; i < attrNames.length; i++) {
  1373. try {
  1374. responseList.add(new Attribute(attrNames[i],
  1375. getAttribute(attrNames[i])));
  1376. } catch (Exception e) {
  1377. // eat exceptions because interface doesn't have an
  1378. // exception on it
  1379. error("getAttributes(String[])","Failed to get \"" +
  1380. attrNames[i] + "\": " + e);
  1381. traceX("getAttributes(String[])",e);
  1382. }
  1383. }
  1384. if (tracing())
  1385. trace("getAttributes(String[])","Exit");
  1386. return responseList;
  1387. }
  1388. /**
  1389. * Sets the value of a specific attribute of a named ModelMBean.
  1390. *
  1391. * If the 'setMethod' field of the attribute's descriptor
  1392. * contains the name of a valid operation descriptor, then the
  1393. * method described by the operation descriptor is executed.
  1394. * In this implementation, the operation descriptor must be specified
  1395. * correctly and assigned to the modelMBeanInfo so that the 'setMethod'
  1396. * works correctly.
  1397. * The response from the method is set as the value of the attribute
  1398. * in the descriptor.
  1399. *
  1400. * <p>If currencyTimeLimit is > 0, then the new value for the
  1401. * attribute is cached in the attribute descriptor's
  1402. * 'value' field and the 'lastUpdatedTimeStamp' field is set to
  1403. * the current time stamp.
  1404. *
  1405. * <p>If the persist field of the attribute's descriptor is not null
  1406. * then Persistence policy from the attribute descriptor is used to
  1407. * guide storing the attribute in a persistent store.
  1408. * <br>Store the MBean if 'persistPolicy' field is:
  1409. * <UL>
  1410. * <Li> != "never"</Li>
  1411. * <Li> = "always"</Li>
  1412. * <Li> = "onUpdate"</Li>
  1413. * <Li> = "onTimer" and now > 'lastPersistTime' + 'persistPeriod'</Li>
  1414. * <Li> = "NoMoreOftenThan" and now > 'lastPersistTime' +
  1415. * 'persistPeriod'</Li>
  1416. * </UL>
  1417. * Do not store the MBean if 'persistPolicy' field is:
  1418. * <UL>
  1419. * <Li> = "never"</Li>
  1420. * <Li> = "onTimer" && now < 'lastPersistTime' + 'persistPeriod'</Li>
  1421. * <Li> = "NoMoreOftenThan" and now < 'lastPersistTime' +
  1422. * 'persistPeriod'</Li>
  1423. * </UL>
  1424. *
  1425. * <p>The ModelMBeanInfo of the Model MBean is stored in a file.
  1426. *
  1427. * @param attribute The Attribute instance containing the name of
  1428. * the attribute to be set and the value it is to be set to.
  1429. *
  1430. *
  1431. * @exception AttributeNotFoundException The specified attribute is
  1432. * not accessible in the MBean.
  1433. * <br>The following cases may result in an AttributeNotFoundException:
  1434. * <UL>
  1435. * <LI> No ModelMBeanAttributeInfo is found for the specified
  1436. * attribute.</LI>
  1437. * <LI> The ModelMBeanAttributeInfo's isWritable method returns
  1438. * 'false'.</LI>
  1439. * </UL>
  1440. * @exception InvalidAttributeValueException No descriptor is defined
  1441. * for the specified attribute.
  1442. * @exception MBeanException Wraps one of the following Exceptions:
  1443. * <UL>
  1444. * <LI> An Exception thrown by the managed object's setter.</LI>
  1445. * <LI> A {@link ServiceNotFoundException} if no `setMethod` field
  1446. * is defined in the descriptor for the attribute or the
  1447. * managed resource is null.</LI>
  1448. * <LI> {@link InvalidTargetObjectTypeException} The 'targetType'
  1449. * field value is not 'objectReference'.</LI>
  1450. * <LI> An Exception thrown by the managed object's getter.</LI>
  1451. * </UL>
  1452. * @exception ReflectionException Wraps an {@link java.lang.Exception}
  1453. * thrown while trying to invoke the setter.
  1454. * @exception RuntimeOperationsException Wraps an
  1455. * {@link IllegalArgumentException}: The attribute in parameter is
  1456. * null.
  1457. *
  1458. * @see #getAttribute(java.lang.String)
  1459. **/
  1460. public void setAttribute(Attribute attribute)
  1461. throws AttributeNotFoundException, InvalidAttributeValueException,
  1462. MBeanException, ReflectionException {
  1463. if (tracing())
  1464. trace("setAttribute()","Entry");
  1465. if (attribute == null)
  1466. throw new RuntimeOperationsException(new
  1467. IllegalArgumentException("attribute must not be null"),
  1468. "Exception occured trying to set an attribute of a "+
  1469. "RequiredModelMBean");
  1470. /* run setMethod if there is one */
  1471. /* return cached value if its current */
  1472. /* set cached value in descriptor and set date/time */
  1473. /* send attribute change Notification */
  1474. /* check persistence policy and persist if need be */
  1475. String attrName = attribute.getName();
  1476. Object attrValue = attribute.getValue();
  1477. boolean updateDescriptor = false;
  1478. ModelMBeanAttributeInfo attrInfo =
  1479. modelMBeanInfo.getAttribute(attrName);
  1480. if (attrInfo == null)
  1481. throw new AttributeNotFoundException("setAttribute failed: " +
  1482. attrName + " is not found ");
  1483. Descriptor mmbDesc = modelMBeanInfo.getMBeanDescriptor();
  1484. Descriptor attrDescr = attrInfo.getDescriptor();
  1485. if (attrDescr != null) {
  1486. if (!attrInfo.isWritable())
  1487. throw new AttributeNotFoundException("setAttribute failed: "
  1488. + attrName + " is not writable ");
  1489. Object setResponse = null;
  1490. String attrSetMethod = (String)
  1491. (attrDescr.getFieldValue("setMethod"));
  1492. String attrType = (String)(attrInfo.getType());
  1493. Object currValue = "Unknown";
  1494. try {
  1495. currValue = this.getAttribute(attrName);
  1496. } catch (Throwable t) {
  1497. // OK: Default "Unknown" value used for unknown attribute
  1498. }
  1499. Attribute oldAttr = new Attribute(attrName, currValue);
  1500. /* run method from operations descriptor */
  1501. if (attrSetMethod == null) {
  1502. if (attrValue != null) {
  1503. try {
  1504. final Class clazz = loadClass(attrType);
  1505. if (! clazz.isInstance(attrValue)) throw new
  1506. InvalidAttributeValueException(clazz.getName() +
  1507. " expected, " +
  1508. attrValue.getClass().getName() +
  1509. " received.");
  1510. } catch (ClassNotFoundException x) {
  1511. error("setAttribute","Class " + attrType +
  1512. " for attribute " + attrName + " not found: " +
  1513. x);
  1514. debug("setAttribute",x);
  1515. }
  1516. }
  1517. updateDescriptor = true;
  1518. } else {
  1519. setResponse = invoke(attrSetMethod,
  1520. (new Object[] {attrValue}),
  1521. (new String[] {attrType}) );
  1522. }
  1523. /* change cached value */
  1524. Object objctl = attrDescr.getFieldValue("currencyTimeLimit");
  1525. String ctl;
  1526. if (objctl != null) ctl = objctl.toString();
  1527. else ctl = null;
  1528. if ((ctl == null) && (mmbDesc != null)) {
  1529. objctl = mmbDesc.getFieldValue("currencyTimeLimit");
  1530. if (objctl != null) ctl = objctl.toString();
  1531. else ctl = null;
  1532. }
  1533. final boolean updateCache = ((ctl != null) && !(ctl.equals("-1")));
  1534. if (updateCache || updateDescriptor) {
  1535. if (tracing())
  1536. trace("setAttribute()","setting cached value of " +
  1537. attrName + " to " + attrValue);
  1538. attrDescr.setField("value", attrValue);
  1539. if (updateCache) {
  1540. final String currtime =
  1541. (new Long((new Date()).getTime())).toString();
  1542. attrDescr.setField("lastUpdatedTimeStamp", currtime);
  1543. }
  1544. attrInfo.setDescriptor(attrDescr);
  1545. modelMBeanInfo.setDescriptor(attrDescr,"attribute");
  1546. if (tracing()) {
  1547. trace("setAttribute()","new descriptor is " +
  1548. attrDescr.toString());
  1549. trace("setAttribute()","AttributeInfo descriptor is " +
  1550. attrInfo.getDescriptor().toString());
  1551. trace("setAttribute()","AttributeInfo descriptor is " +
  1552. modelMBeanInfo.getDescriptor(attrName,"attribute")
  1553. .toString());
  1554. }
  1555. }
  1556. if (tracing())
  1557. trace("setAttribute()","sending sendAttributeNotification");
  1558. sendAttributeChangeNotification(oldAttr,attribute);
  1559. } else { // if descriptor ... else no descriptor
  1560. if (tracing())
  1561. trace("setAttribute(String)","setMethod failed "+attrName+
  1562. " not in attributeDescriptor\n");
  1563. throw new InvalidAttributeValueException(
  1564. "Unable to resolve attribute value, "+
  1565. "no defined in descriptor for attribute");
  1566. } // else no descriptor
  1567. if (tracing())
  1568. trace("setAttribute(Attribute)","Exit");
  1569. }
  1570. /**
  1571. * Sets the values of an array of attributes of this ModelMBean.
  1572. * Executes the setAttribute() method for each attribute in the list.
  1573. *
  1574. * @param attributes A list of attributes: The identification of the
  1575. * attributes to be set and the values they are to be set to.
  1576. *
  1577. * @return The array of attributes that were set, with their new
  1578. * values in Attribute instances.
  1579. *
  1580. * @exception RuntimeOperationsException Wraps an
  1581. * {@link IllegalArgumentException}: The object name in parameter
  1582. * is null or attributes in parameter is null.
  1583. *
  1584. * @see #getAttributes
  1585. **/
  1586. public AttributeList setAttributes(AttributeList attributes) {
  1587. if (tracing())
  1588. trace("setAttributes(AttributeList)","Entry");
  1589. if (attributes == null)
  1590. throw new RuntimeOperationsException(new
  1591. IllegalArgumentException("attributes must not be null"),
  1592. "Exception occured trying to set attributes of a "+
  1593. "RequiredModelMBean");
  1594. final AttributeList responseList = new AttributeList();
  1595. // Go through the list of attributes
  1596. for (Iterator i = attributes.iterator(); i.hasNext();) {
  1597. final Attribute attr = (Attribute) i.next();
  1598. try {
  1599. setAttribute(attr);
  1600. responseList.add(attr);
  1601. } catch (Exception excep) {
  1602. responseList.remove(attr);
  1603. }
  1604. }
  1605. return responseList;
  1606. }
  1607. private ModelMBeanInfo createDefaultModelMBeanInfo() {
  1608. return(new ModelMBeanInfoSupport((this.getClass().getName()),
  1609. "Default ModelMBean", null, null, null, null));
  1610. }
  1611. /*************************************/
  1612. /* NotificationBroadcaster Interface */
  1613. /*************************************/
  1614. private synchronized void writeToLog(String logFileName,
  1615. String logEntry) throws Exception {
  1616. PrintStream logOut = null;
  1617. FileOutputStream fos = null;
  1618. if (tracing()) trace("writeToLog()","Notification Logging to " +
  1619. logFileName + ": " + logEntry);
  1620. if ((logFileName == null) || (logEntry == null)) {
  1621. if (tracing()) trace("writeToLog()","Bad input parameters");
  1622. return;
  1623. }
  1624. try {
  1625. fos = new FileOutputStream(logFileName, true);
  1626. logOut = new PrintStream(fos);
  1627. logOut.println(logEntry);
  1628. logOut.close();
  1629. if (tracing()) trace("writeToLog()",
  1630. "Successfully opened log " + logFileName);
  1631. } catch (Exception e) {
  1632. if (tracing())
  1633. trace("writeToLog","Exception " + e.toString() +
  1634. " trying to write to the Notification log file " +
  1635. logFileName);
  1636. throw e;
  1637. }
  1638. }
  1639. /**
  1640. * Registers an object which implements the NotificationListener
  1641. * interface as a listener. This
  1642. * object's 'handleNotification()' method will be invoked when any
  1643. * notification is issued through or by the ModelMBean. This does
  1644. * not include attributeChangeNotifications. They must be registered
  1645. * for independently.
  1646. *
  1647. * @param listener The listener object which will handles
  1648. * notifications emitted by the registered MBean.
  1649. * @param filter The filter object. If null, no filtering will be
  1650. * performed before handling notifications.
  1651. * @param handback The context to be sent to the listener with
  1652. * the notification when a notification is emitted.
  1653. *
  1654. * @exception IllegalArgumentException The listener cannot be null.
  1655. *
  1656. * @see #removeNotificationListener
  1657. */
  1658. public void addNotificationListener(NotificationListener listener,
  1659. NotificationFilter filter,
  1660. Object handback)
  1661. throws java.lang.IllegalArgumentException {
  1662. final String ftag = "addNotificationListener(NotificationListener, NotificationFilter, Object)";
  1663. if (tracing())
  1664. trace(ftag,"Entry");
  1665. if (listener == null)
  1666. throw new IllegalArgumentException(
  1667. "notification listener must not be null");
  1668. if (generalBroadcaster == null)
  1669. generalBroadcaster = new NotificationBroadcasterSupport();
  1670. generalBroadcaster.addNotificationListener(listener, filter,
  1671. handback);
  1672. if (tracing()) {
  1673. trace(ftag,"NotificationListener added");
  1674. trace(ftag,"Exit");
  1675. }
  1676. }
  1677. /**
  1678. * Removes a listener for Notifications from the RequiredModelMBean.
  1679. *
  1680. * @param listener The listener name which was handling notifications
  1681. * emitted by the registered MBean.
  1682. * This method will remove all information related to this listener.
  1683. *
  1684. * @exception ListenerNotFoundException The listener is not registered
  1685. * in the MBean or is null.
  1686. *
  1687. * @see #addNotificationListener
  1688. **/
  1689. public void removeNotificationListener(NotificationListener listener)
  1690. throws ListenerNotFoundException {
  1691. if (listener == null)
  1692. throw new ListenerNotFoundException(
  1693. "Notification listener is null");
  1694. final String ftag="removeNotificationListener(NotificationListener)";
  1695. if (tracing()) trace(ftag,"Entry");
  1696. if (generalBroadcaster == null)
  1697. throw new ListenerNotFoundException(
  1698. "No notification listeners registered");
  1699. generalBroadcaster.removeNotificationListener(listener);
  1700. if (tracing()) trace(ftag,"Exit");
  1701. }
  1702. public void removeNotificationListener(NotificationListener listener,
  1703. NotificationFilter filter,
  1704. Object handback)
  1705. throws ListenerNotFoundException {
  1706. if (listener == null)
  1707. throw new ListenerNotFoundException(
  1708. "Notification listener is null");
  1709. final String ftag="removeNotificationListener(NotificationListener, NotificationFilter, Object)";
  1710. if (tracing()) trace(ftag,"Entry");
  1711. if (generalBroadcaster == null)
  1712. throw new ListenerNotFoundException(
  1713. "No notification listeners registered");
  1714. generalBroadcaster.removeNotificationListener(listener,filter,
  1715. handback);
  1716. if (tracing()) trace(ftag,"Exit");
  1717. }
  1718. public void sendNotification(Notification ntfyObj)
  1719. throws MBeanException, RuntimeOperationsException {
  1720. if (tracing())
  1721. trace("sendNotification(Notification)","Entry");
  1722. if (ntfyObj == null)
  1723. throw new RuntimeOperationsException(new
  1724. IllegalArgumentException("notification object must not be "+
  1725. "null"),
  1726. "Exception occured trying to send a notification from a "+
  1727. "RequiredModelMBean");
  1728. // log notification if specified in descriptor
  1729. Descriptor ntfyDesc =
  1730. modelMBeanInfo.getDescriptor(ntfyObj.getType(),"notification");
  1731. Descriptor mmbDesc = modelMBeanInfo.getMBeanDescriptor();
  1732. if (ntfyDesc != null) {
  1733. String logging = (String) ntfyDesc.getFieldValue("log");
  1734. if (logging == null) {
  1735. if (mmbDesc != null)
  1736. logging = (String) mmbDesc.getFieldValue("log");
  1737. }
  1738. if ((logging != null) &&
  1739. (logging.equalsIgnoreCase("t") ||
  1740. logging.equalsIgnoreCase("true"))) {
  1741. String logfile = (String) ntfyDesc.getFieldValue("logfile");
  1742. if (logfile == null) {
  1743. if (mmbDesc != null)
  1744. logfile = (String)mmbDesc.getFieldValue("logfile");
  1745. }
  1746. if (logfile != null) {
  1747. try {
  1748. writeToLog(logfile,"LogMsg: " +
  1749. ((new Date(ntfyObj.getTimeStamp())).toString())+
  1750. " " + ntfyObj.getType() + " " +
  1751. ntfyObj.getMessage() + " Severity = " +
  1752. (String)ntfyDesc.getFieldValue("severity"));
  1753. } catch (Exception e) {
  1754. error("sendNotification(Notification)",
  1755. "Failed to log " + ntfyObj.getType() +
  1756. " notification: " + e);
  1757. traceX("sendNotification(Notification)",e);
  1758. }
  1759. }
  1760. }
  1761. }
  1762. if (generalBroadcaster != null) {
  1763. generalBroadcaster.sendNotification(ntfyObj);
  1764. }
  1765. if (tracing()) trace("sendNotification(Notification)",
  1766. "sendNotification sent provided notification object");
  1767. if (tracing())
  1768. trace("sendNotification(Notification)","Exit");
  1769. }
  1770. public void sendNotification(String ntfyText)
  1771. throws MBeanException, RuntimeOperationsException {
  1772. if (tracing())
  1773. trace("sendNotification(String)","Entry");
  1774. if (ntfyText == null)
  1775. throw new RuntimeOperationsException(new
  1776. IllegalArgumentException("notification message must not "+
  1777. "be null"),
  1778. "Exception occured trying to send a text notification "+
  1779. "from a ModelMBean");
  1780. Notification myNtfyObj = new Notification("jmx.modelmbean.generic",
  1781. this, 1, ntfyText);
  1782. sendNotification(myNtfyObj);
  1783. if (tracing()) trace("sendNotification(string)",
  1784. "Notification sent");
  1785. if (tracing())
  1786. trace("sendNotification(String)","Exit");
  1787. }
  1788. /**
  1789. * Returns `true' if the notification `notifName' is found
  1790. * in `info'. (bug 4744667)
  1791. **/
  1792. private static final
  1793. boolean hasNotification(final ModelMBeanInfo info,
  1794. final String notifName) {
  1795. try {
  1796. if (info == null) return false;
  1797. else return (info.getNotification(notifName)!=null);
  1798. } catch (MBeanException x) {
  1799. return false;
  1800. } catch (RuntimeOperationsException r) {
  1801. return false;
  1802. }
  1803. }
  1804. /**
  1805. * Creates a default ModelMBeanNotificationInfo for GENERIC
  1806. * notification. (bug 4744667)
  1807. **/
  1808. private static final ModelMBeanNotificationInfo makeGenericInfo() {
  1809. final Descriptor genericDescriptor = new DescriptorSupport( new
  1810. String[] {
  1811. "name=GENERIC",
  1812. "descriptorType=notification",
  1813. "log=T",
  1814. "severity=6",
  1815. "displayName=jmx.modelmbean.generic"} );
  1816. return new ModelMBeanNotificationInfo(new
  1817. String[] {"jmx.modelmbean.generic"},
  1818. "GENERIC",
  1819. "A text notification has been issued by the managed resource",
  1820. genericDescriptor);
  1821. }
  1822. /**
  1823. * Creates a default ModelMBeanNotificationInfo for ATTRIBUTE_CHANGE
  1824. * notification. (bug 4744667)
  1825. **/
  1826. private static final
  1827. ModelMBeanNotificationInfo makeAttributeChangeInfo() {
  1828. final Descriptor attributeDescriptor = new DescriptorSupport(new
  1829. String[] {
  1830. "name=ATTRIBUTE_CHANGE",
  1831. "descriptorType=notification",
  1832. "log=T",
  1833. "severity=6",
  1834. "displayName=jmx.attribute.change"});
  1835. return new ModelMBeanNotificationInfo(new
  1836. String[] {"jmx.attribute.change"},
  1837. "ATTRIBUTE_CHANGE",
  1838. "Signifies that an observed MBean attribute value has changed",
  1839. attributeDescriptor );
  1840. }
  1841. /**
  1842. * Returns the array of Notifications always generated by the
  1843. * RequiredModelMBean.
  1844. * <P>
  1845. *
  1846. * RequiredModelMBean may always send also two additional notifications:
  1847. * <UL>
  1848. * <LI> One with descriptor <code>"name=GENERIC,descriptorType=notification,log=T,severity=6,displayName=jmx.modelmbean.generic"</code></LI>
  1849. * <LI> Second is a standard attribute change notification
  1850. * with descriptor <code>"name=ATTRIBUTE_CHANGE,descriptorType=notification,log=T,severity=6,displayName=jmx.attribute.change"</code></LI>
  1851. * </UL>
  1852. * Thus these two notifications are always added to those specified
  1853. * by the application.
  1854. *
  1855. * @return MBeanNotificationInfo[]
  1856. *
  1857. **/
  1858. public MBeanNotificationInfo[] getNotificationInfo() {
  1859. if (tracing())
  1860. trace("getNotificationInfo()","Entry");
  1861. // Using hasNotification() is not optimal, but shouldn't really
  1862. // matter in this context...
  1863. // hasGeneric==true if GENERIC notification is present.
  1864. // (bug 4744667)
  1865. final boolean hasGeneric = hasNotification(modelMBeanInfo,"GENERIC");
  1866. // hasAttributeChange==true if ATTRIBUTE_CHANGE notification is
  1867. // present.
  1868. // (bug 4744667)
  1869. final boolean hasAttributeChange =
  1870. hasNotification(modelMBeanInfo,"ATTRIBUTE_CHANGE");
  1871. // User supplied list of notification infos.
  1872. //
  1873. final ModelMBeanNotificationInfo[] currInfo =
  1874. (ModelMBeanNotificationInfo[])modelMBeanInfo.getNotifications();
  1875. // Length of the returned list of notification infos:
  1876. // length of user suplied list + possibly 1 for GENERIC, +
  1877. // possibly 1 for ATTRIBUTE_CHANGE
  1878. // (bug 4744667)
  1879. final int len = ((currInfo==null?0:currInfo.length) +
  1880. (hasGeneric?0:1) + (hasAttributeChange?0:1));
  1881. // Returned list of notification infos:
  1882. //
  1883. final ModelMBeanNotificationInfo[] respInfo =
  1884. new ModelMBeanNotificationInfo[len];
  1885. // Preserve previous ordering (JMX 1.1)
  1886. //
  1887. // Counter of "standard" notification inserted before user
  1888. // supplied notifications.
  1889. //
  1890. int inserted=0;
  1891. if (!hasGeneric)
  1892. // We need to add description for GENERIC notification
  1893. // (bug 4744667)
  1894. respInfo[inserted++] = makeGenericInfo();
  1895. if (!hasAttributeChange)
  1896. // We need to add description for ATTRIBUTE_CHANGE notification
  1897. // (bug 4744667)
  1898. respInfo[inserted++] = makeAttributeChangeInfo();
  1899. // Now copy user supplied list in returned list.
  1900. //
  1901. final int count = currInfo.length;
  1902. final int offset = inserted;
  1903. for (int j=0; j < count; j++) {
  1904. respInfo[offset+j] = (ModelMBeanNotificationInfo)(currInfo[j]);
  1905. }
  1906. if (tracing())
  1907. trace("getNotificationInfo()","Exit");
  1908. return respInfo;
  1909. }
  1910. public void addAttributeChangeNotificationListener(NotificationListener
  1911. inlistener,
  1912. String
  1913. inAttributeName,
  1914. Object inhandback)
  1915. throws MBeanException, RuntimeOperationsException,
  1916. IllegalArgumentException {
  1917. final String ftag="addAttributeChangeNotificationListener(NotificationListener, String, Object)";
  1918. if (tracing()) trace(ftag,"Entry");
  1919. if (inlistener == null)
  1920. throw new IllegalArgumentException(
  1921. "Listener to be registered must not be null");
  1922. if (attributeBroadcaster == null)
  1923. attributeBroadcaster = new NotificationBroadcasterSupport();
  1924. AttributeChangeNotificationFilter currFilter =
  1925. new AttributeChangeNotificationFilter();
  1926. MBeanAttributeInfo[] attrInfo = modelMBeanInfo.getAttributes();
  1927. boolean found = false;
  1928. if (inAttributeName == null) {
  1929. if ((attrInfo != null) && (attrInfo.length>0)) {
  1930. for (int i=0; i<attrInfo.length; i++) {
  1931. currFilter.enableAttribute(attrInfo[i].getName());
  1932. }
  1933. }
  1934. } else {
  1935. if ((attrInfo != null) && (attrInfo.length>0)) {
  1936. for (int i=0; i<attrInfo.length; i++) {
  1937. if (inAttributeName.equals(attrInfo[i].getName())) {
  1938. found = true;
  1939. currFilter.enableAttribute(inAttributeName);
  1940. break;
  1941. }
  1942. }
  1943. if (!found) {
  1944. throw new RuntimeOperationsException(new
  1945. IllegalArgumentException(
  1946. "The attribute name does not exist"),
  1947. "Exception occured trying to add an "+
  1948. "AttributeChangeNotification listener");
  1949. }
  1950. }
  1951. }
  1952. if (tracing())
  1953. trace(ftag, "Set attribute change filter to " +
  1954. ((currFilter.getEnabledAttributes()).firstElement()).toString());
  1955. attributeBroadcaster.addNotificationListener(inlistener,currFilter,
  1956. inhandback);
  1957. if (tracing()) trace("addAttributeChangeNotificationListener",
  1958. "added for " + inAttributeName);
  1959. if (tracing()) trace(ftag,"Exit");
  1960. }
  1961. public void removeAttributeChangeNotificationListener(NotificationListener inlistener, String inAttributeName)
  1962. throws MBeanException, RuntimeOperationsException,
  1963. ListenerNotFoundException {
  1964. if (inlistener == null) throw new
  1965. ListenerNotFoundException("Notification listener is null");
  1966. final String ftag = "removeAttributeChangeNotificationListener(NotificationListener, String)";
  1967. if (tracing()) trace(ftag,"Entry");
  1968. if (attributeBroadcaster == null)
  1969. throw new ListenerNotFoundException(
  1970. "No attribute change notification listeners registered");
  1971. MBeanAttributeInfo[] attrInfo = modelMBeanInfo.getAttributes();
  1972. boolean found = false;
  1973. if ((attrInfo != null) && (attrInfo.length>0)) {
  1974. for (int i=0; i<attrInfo.length; i++) {
  1975. if (attrInfo[i].getName().equals(inAttributeName)) {
  1976. found = true;
  1977. break;
  1978. }
  1979. }
  1980. }
  1981. if ((!found) && (inAttributeName != null)) {
  1982. throw new RuntimeOperationsException(new
  1983. IllegalArgumentException("Invalid attribute name"),
  1984. "Exception occured trying to remove "+
  1985. "attribute change notification listener");
  1986. }
  1987. /* note: */
  1988. /* this may be a problem if the same listener is registered for
  1989. multiple attributes with multiple filters and/or handback
  1990. objects. It may remove all of them */
  1991. attributeBroadcaster.removeNotificationListener(inlistener);
  1992. if (tracing()) trace(ftag,"Exit");
  1993. }
  1994. public void sendAttributeChangeNotification(AttributeChangeNotification
  1995. ntfyObj)
  1996. throws MBeanException, RuntimeOperationsException {
  1997. final String ftag =
  1998. "sendAttributeChangeNotification(AttributeChangeNotification)";
  1999. if (tracing()) trace(ftag,"Entry");
  2000. if (ntfyObj == null)
  2001. throw new RuntimeOperationsException(new
  2002. IllegalArgumentException(
  2003. "attribute change notification object must not be null"),
  2004. "Exception occured trying to send "+
  2005. "attribute change notification of a ModelMBean");
  2006. Object oldv = ntfyObj.getOldValue();
  2007. Object newv = ntfyObj.getNewValue();
  2008. if (oldv == null) oldv = "null";
  2009. if (newv == null) newv = "null";
  2010. if (tracing())
  2011. trace(ftag,"Sending AttributeChangeNotification " +
  2012. " with " + ntfyObj.getAttributeName() +
  2013. ntfyObj.getAttributeType() +
  2014. ntfyObj.getNewValue() +
  2015. ntfyObj.getOldValue());
  2016. // log notification if specified in descriptor
  2017. Descriptor ntfyDesc =
  2018. modelMBeanInfo.getDescriptor(ntfyObj.getType(),"notification");
  2019. Descriptor mmbDesc = modelMBeanInfo.getMBeanDescriptor();
  2020. String logging, logfile;
  2021. if (ntfyDesc != null) {
  2022. logging =(String) ntfyDesc.getFieldValue("log");
  2023. if (logging == null) {
  2024. if (mmbDesc != null)
  2025. logging = (String) mmbDesc.getFieldValue("log");
  2026. }
  2027. if ((logging != null) &&
  2028. ( logging.equalsIgnoreCase("t") ||
  2029. logging.equalsIgnoreCase("true"))) {
  2030. logfile = (String) ntfyDesc.getFieldValue("logfile");
  2031. if (logfile == null) {
  2032. if (mmbDesc != null)
  2033. logfile = (String)mmbDesc.getFieldValue("logfile");
  2034. }
  2035. if (logfile != null) {
  2036. try {
  2037. writeToLog(logfile,"LogMsg: " +
  2038. ((new Date(ntfyObj.getTimeStamp())).toString())+
  2039. " " + ntfyObj.getType() + " " +
  2040. ntfyObj.getMessage() +
  2041. " Name = " + ntfyObj.getAttributeName() +
  2042. " Old value = " + oldv +
  2043. " New value = " + newv);
  2044. } catch (Exception e) {
  2045. error(ftag,"Failed to log " + ntfyObj.getType() +
  2046. " notification: " + e);
  2047. traceX(ftag,e);
  2048. }
  2049. }
  2050. }
  2051. } else if (mmbDesc != null) {
  2052. logging = (String) mmbDesc.getFieldValue("log");
  2053. if ((logging != null) &&
  2054. ( logging.equalsIgnoreCase("t") ||
  2055. logging.equalsIgnoreCase("true") )) {
  2056. logfile = (String) mmbDesc.getFieldValue("logfile");
  2057. if (logfile != null) {
  2058. try {
  2059. writeToLog(logfile,"LogMsg: " +
  2060. ((new Date(ntfyObj.getTimeStamp())).toString())+
  2061. " " + ntfyObj.getType() + " " +
  2062. ntfyObj.getMessage() +
  2063. " Name = " + ntfyObj.getAttributeName() +
  2064. " Old value = " + oldv +
  2065. " New value = " + newv);
  2066. } catch (Exception e) {
  2067. error(ftag,"Failed to log " + ntfyObj.getType() +
  2068. " notification: " + e);
  2069. traceX(ftag,e);
  2070. }
  2071. }
  2072. }
  2073. }
  2074. if (attributeBroadcaster != null) {
  2075. attributeBroadcaster.sendNotification(ntfyObj);
  2076. }
  2077. // XXX Revisit: This is a quickfix: it would be better to have a
  2078. // single broadcaster. However, it is not so simple because
  2079. // removeAttributeChangeNotificationListener() should
  2080. // remove only listeners whose filter is an instanceof
  2081. // AttributeChangeNotificationFilter.
  2082. //
  2083. if (generalBroadcaster != null) {
  2084. generalBroadcaster.sendNotification(ntfyObj);
  2085. }
  2086. if (tracing()) trace(ftag,"sent notification");
  2087. if (tracing()) trace(ftag,"Exit");
  2088. }
  2089. public void sendAttributeChangeNotification(Attribute inOldVal,
  2090. Attribute inNewVal)
  2091. throws MBeanException, RuntimeOperationsException {
  2092. final String ftag =
  2093. "sendAttributeChangeNotification(Attribute, Attribute)";
  2094. if (tracing()) trace(ftag,"Entry");
  2095. // do we really want to do this?
  2096. if ((inOldVal == null) || (inNewVal == null))
  2097. throw new RuntimeOperationsException(new
  2098. IllegalArgumentException("Attribute object must not be null"),
  2099. "Exception occured trying to send " +
  2100. "attribute change notification of a ModelMBean");
  2101. if (!(inOldVal.getName().equals(inNewVal.getName())))
  2102. throw new RuntimeOperationsException(new
  2103. IllegalArgumentException("Attribute names are not the same"),
  2104. "Exception occured trying to send " +
  2105. "attribute change notification of a ModelMBean");
  2106. Object newVal = inNewVal.getValue();
  2107. Object oldVal = inOldVal.getValue();
  2108. String className = "unknown";
  2109. if (newVal != null)
  2110. className = newVal.getClass().getName();
  2111. if (oldVal != null)
  2112. className = oldVal.getClass().getName();
  2113. AttributeChangeNotification myNtfyObj = new
  2114. AttributeChangeNotification(this,
  2115. 1,
  2116. ((new Date()).getTime()),
  2117. "AttributeChangeDetected",
  2118. inOldVal.getName(),
  2119. className,
  2120. inOldVal.getValue(),
  2121. inNewVal.getValue());
  2122. sendAttributeChangeNotification(myNtfyObj);
  2123. if (tracing()) trace(ftag,"Exit");
  2124. }
  2125. /**
  2126. * Return the Class Loader Repository used to perform class loading.
  2127. * Subclasses may wish to redefine this method in order to return
  2128. * the appropriate {@link javax.management.loading.ClassLoaderRepository}
  2129. * that should be used in this object.
  2130. *
  2131. * @return the Class Loader Repository.
  2132. *
  2133. * @since.unbundled JMX 1.1
  2134. */
  2135. protected ClassLoaderRepository getClassLoaderRepository() {
  2136. return MBeanServerFactory.getClassLoaderRepository(server);
  2137. }
  2138. private Class loadClass(String className)
  2139. throws ClassNotFoundException {
  2140. try {
  2141. return Class.forName(className);
  2142. } catch (ClassNotFoundException e) {
  2143. final ClassLoaderRepository clr =
  2144. getClassLoaderRepository();
  2145. if (clr == null) throw new ClassNotFoundException(className);
  2146. return clr.loadClass(className);
  2147. }
  2148. }
  2149. /*************************************/
  2150. /* MBeanRegistration Interface */
  2151. /*************************************/
  2152. /**
  2153. * Allows the MBean to perform any operations it needs before
  2154. * being registered in the MBean server. If the name of the MBean
  2155. * is not specified, the MBean can provide a name for its
  2156. * registration. If any exception is raised, the MBean will not be
  2157. * registered in the MBean server.
  2158. * <P>
  2159. * In order to ensure proper run-time semantics of RequireModelMBean,
  2160. * Any subclass of RequiredModelMBean overloading or overriding this
  2161. * method should call <code>super.preRegister(server, name)</code>
  2162. * in its own <code>preRegister</code> implementation.
  2163. *
  2164. * @param server The MBean server in which the MBean will be registered.
  2165. *
  2166. * @param name The object name of the MBean. This name is null if
  2167. * the name parameter to one of the <code>createMBean</code> or
  2168. * <code>registerMBean</code> methods in the {@link MBeanServer}
  2169. * interface is null. In that case, this method must return a
  2170. * non-null ObjectName for the new MBean.
  2171. *
  2172. * @return The name under which the MBean is to be registered.
  2173. * This value must not be null. If the <code>name</code>
  2174. * parameter is not null, it will usually but not necessarily be
  2175. * the returned value.
  2176. *
  2177. * @exception java.lang.Exception This exception will be caught by
  2178. * the MBean server and re-thrown as an
  2179. * {@link javax.management.MBeanRegistrationException
  2180. * MBeanRegistrationException}.
  2181. */
  2182. public ObjectName preRegister(MBeanServer server,
  2183. ObjectName name)
  2184. throws java.lang.Exception {
  2185. // Since ModelMbeanInfo cannot be null (otherwise exception
  2186. // thrown at creation)
  2187. // no exception thrown on ModelMBeanInfo not set.
  2188. if (name == null) throw new NullPointerException(
  2189. "name of RequiredModelMBean to registered is null");
  2190. this.server = server;
  2191. return name;
  2192. }
  2193. /**
  2194. * Allows the MBean to perform any operations needed after having been
  2195. * registered in the MBean server or after the registration has failed.
  2196. * <P>
  2197. * In order to ensure proper run-time semantics of RequireModelMBean,
  2198. * Any subclass of RequiredModelMBean overloading or overriding this
  2199. * method should call <code>super.postRegister(registrationDone)</code>
  2200. * in its own <code>postRegister</code> implementation.
  2201. *
  2202. * @param registrationDone Indicates whether or not the MBean has
  2203. * been successfully registered in the MBean server. The value
  2204. * false means that the registration phase has failed.
  2205. */
  2206. public void postRegister(Boolean registrationDone) {
  2207. registered = registrationDone.booleanValue();
  2208. }
  2209. /**
  2210. * Allows the MBean to perform any operations it needs before
  2211. * being unregistered by the MBean server.
  2212. * <P>
  2213. * In order to ensure proper run-time semantics of RequireModelMBean,
  2214. * Any subclass of RequiredModelMBean overloading or overriding this
  2215. * method should call <code>super.preDeregister()</code> in its own
  2216. * <code>preDeregister</code> implementation.
  2217. *
  2218. * @exception java.lang.Exception This exception will be caught by
  2219. * the MBean server and re-thrown as an
  2220. * {@link javax.management.MBeanRegistrationException
  2221. * MBeanRegistrationException}.
  2222. */
  2223. public void preDeregister() throws java.lang.Exception {
  2224. }
  2225. /**
  2226. * Allows the MBean to perform any operations needed after having been
  2227. * unregistered in the MBean server.
  2228. * <P>
  2229. * In order to ensure proper run-time semantics of RequireModelMBean,
  2230. * Any subclass of RequiredModelMBean overloading or overriding this
  2231. * method should call <code>super.postDeregister()</code> in its own
  2232. * <code>postDeregister</code> implementation.
  2233. */
  2234. public void postDeregister() {
  2235. registered = false;
  2236. this.server=null;
  2237. }
  2238. // SUN Trace and debug functions
  2239. private final static boolean tracing() {
  2240. return Trace.isSelected(Trace.LEVEL_TRACE, Trace.INFO_MODELMBEAN);
  2241. }
  2242. private static void trace(String inClass, String inMethod, String inText) {
  2243. Trace.send(Trace.LEVEL_TRACE, Trace.INFO_MODELMBEAN, inClass,
  2244. inMethod, inText);
  2245. }
  2246. private static void traceX(String inMethod, Throwable x) {
  2247. Trace.send(Trace.LEVEL_TRACE, Trace.INFO_MODELMBEAN, currClass,
  2248. inMethod, x);
  2249. }
  2250. private static void trace(String inMethod, String inText) {
  2251. trace(currClass, inMethod, inText);
  2252. }
  2253. private static void error(String inMethod, String inText) {
  2254. Trace.send(Trace.LEVEL_ERROR, Trace.INFO_MODELMBEAN, currClass,
  2255. inMethod, inText);
  2256. }
  2257. private static boolean debugging() {
  2258. return Trace.isSelected(Trace.LEVEL_DEBUG, Trace.INFO_MODELMBEAN);
  2259. }
  2260. private static void debug(String inClass, String inMethod, String inText) {
  2261. Trace.send(Trace.LEVEL_DEBUG, Trace.INFO_MODELMBEAN, inClass,
  2262. inMethod, inText);
  2263. }
  2264. private static void debug(String inMethod, String inText) {
  2265. debug(currClass, inMethod, inText);
  2266. }
  2267. private static void debug(String inMethod, Throwable x) {
  2268. Trace.send(Trace.LEVEL_DEBUG, Trace.INFO_MODELMBEAN, currClass,
  2269. inMethod, x);
  2270. }
  2271. }