1. /*
  2. * $Header: /home/cvspublic/jakarta-commons/modeler/src/java/org/apache/commons/modeler/BaseModelMBean.java,v 1.24 2003/07/21 04:43:16 craigmcc Exp $
  3. * $Revision: 1.24 $
  4. * $Date: 2003/07/21 04:43:16 $
  5. *
  6. * ====================================================================
  7. *
  8. * The Apache Software License, Version 1.1
  9. *
  10. * Copyright (c) 1999-2003 The Apache Software Foundation. All rights
  11. * reserved.
  12. *
  13. * Redistribution and use in source and binary forms, with or without
  14. * modification, are permitted provided that the following conditions
  15. * are met:
  16. *
  17. * 1. Redistributions of source code must retain the above copyright
  18. * notice, this list of conditions and the following disclaimer.
  19. *
  20. * 2. Redistributions in binary form must reproduce the above copyright
  21. * notice, this list of conditions and the following disclaimer in
  22. * the documentation and/or other materials provided with the
  23. * distribution.
  24. *
  25. * 3. The end-user documentation included with the redistribution, if
  26. * any, must include the following acknowlegement:
  27. * "This product includes software developed by the
  28. * Apache Software Foundation (http://www.apache.org/)."
  29. * Alternately, this acknowlegement may appear in the software itself,
  30. * if and wherever such third-party acknowlegements normally appear.
  31. *
  32. * 4. The names "The Jakarta Project", "Commons", and "Apache Software
  33. * Foundation" must not be used to endorse or promote products derived
  34. * from this software without prior written permission. For written
  35. * permission, please contact apache@apache.org.
  36. *
  37. * 5. Products derived from this software may not be called "Apache"
  38. * nor may "Apache" appear in their names without prior written
  39. * permission of the Apache Group.
  40. *
  41. * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
  42. * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  43. * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  44. * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
  45. * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  46. * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  47. * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
  48. * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  49. * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  50. * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
  51. * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  52. * SUCH DAMAGE.
  53. * ====================================================================
  54. *
  55. * This software consists of voluntary contributions made by many
  56. * individuals on behalf of the Apache Software Foundation. For more
  57. * information on the Apache Software Foundation, please see
  58. * <http://www.apache.org/>.
  59. *
  60. * [Additional notices, if required by prior licensing conditions]
  61. *
  62. */
  63. package org.apache.commons.modeler;
  64. import java.lang.reflect.InvocationTargetException;
  65. import java.lang.reflect.Method;
  66. import java.util.HashMap;
  67. import java.util.Hashtable;
  68. import java.util.Iterator;
  69. import javax.management.Attribute;
  70. import javax.management.AttributeChangeNotification;
  71. import javax.management.AttributeList;
  72. import javax.management.AttributeNotFoundException;
  73. import javax.management.Descriptor;
  74. import javax.management.DynamicMBean;
  75. import javax.management.InstanceNotFoundException;
  76. import javax.management.InvalidAttributeValueException;
  77. import javax.management.ListenerNotFoundException;
  78. import javax.management.MBeanException;
  79. import javax.management.MBeanInfo;
  80. import javax.management.MBeanNotificationInfo;
  81. import javax.management.MBeanRegistration;
  82. import javax.management.MBeanServer;
  83. import javax.management.Notification;
  84. import javax.management.NotificationFilter;
  85. import javax.management.NotificationListener;
  86. import javax.management.ObjectName;
  87. import javax.management.ReflectionException;
  88. import javax.management.RuntimeErrorException;
  89. import javax.management.RuntimeOperationsException;
  90. import javax.management.ServiceNotFoundException;
  91. import javax.management.modelmbean.DescriptorSupport;
  92. import javax.management.modelmbean.InvalidTargetObjectTypeException;
  93. import javax.management.modelmbean.ModelMBean;
  94. import javax.management.modelmbean.ModelMBeanAttributeInfo;
  95. import javax.management.modelmbean.ModelMBeanInfo;
  96. import javax.management.modelmbean.ModelMBeanInfoSupport;
  97. import javax.management.modelmbean.ModelMBeanNotificationInfo;
  98. import javax.management.modelmbean.ModelMBeanOperationInfo;
  99. import org.apache.commons.logging.Log;
  100. import org.apache.commons.logging.LogFactory;
  101. import org.apache.commons.modeler.modules.ModelerSource;
  102. // TODO: enable ant-like substitutions ? ( or at least discuss it )
  103. /**
  104. * <p>Basic implementation of the <code>ModelMBean</code> interface, which
  105. * supports the minimal requirements of the interface contract.</p>
  106. *
  107. * <p>This can be used directly to wrap an existing java bean, or inside
  108. * an mlet or anywhere an MBean would be used. The String parameter
  109. * passed to the constructor will be used to construct an instance of the
  110. * real object that we wrap.
  111. *
  112. * Limitations:
  113. * <ul>
  114. * <li>Only managed resources of type <code>objectReference</code> are
  115. * supportd.</li>
  116. * <li>Caching of attribute values and operation results is not supported.
  117. * All calls to <code>invoke()</code> are immediately executed.</li>
  118. * <li>Logging (under control of descriptors) is not supported.</li>
  119. * <li>Persistence of MBean attributes and operations is not supported.</li>
  120. * <li>All classes referenced as attribute types, operation parameters, or
  121. * operation return values must be one of the following:
  122. * <ul>
  123. * <li>One of the Java primitive types (boolean, byte, char, double,
  124. * float, integer, long, short). Corresponding value will be wrapped
  125. * in the appropriate wrapper class automatically.</li>
  126. * <li>Operations that return no value should declare a return type of
  127. * <code>void</code>.</li>
  128. * </ul>
  129. * <li>Attribute caching is not supported</li>
  130. * </ul>
  131. *
  132. * @author Craig R. McClanahan
  133. * @author Costin Manolache
  134. * @version $Revision: 1.24 $ $Date: 2003/07/21 04:43:16 $
  135. */
  136. public class BaseModelMBean implements ModelMBean, MBeanRegistration {
  137. private static Log log = LogFactory.getLog(BaseModelMBean.class);
  138. // ----------------------------------------------------------- Constructors
  139. /**
  140. * Construct a <code>ModelMBean</code> with default
  141. * <code>ModelMBeanInfo</code> information.
  142. *
  143. * @exception MBeanException if the initializer of an object
  144. * throws an exception
  145. * @exception RuntimeOperationsException if an IllegalArgumentException
  146. * occurs
  147. */
  148. public BaseModelMBean() throws MBeanException, RuntimeOperationsException {
  149. super();
  150. if( log.isDebugEnabled()) log.debug("default constructor");
  151. setModelMBeanInfo(createDefaultModelMBeanInfo());
  152. }
  153. /**
  154. * Construct a <code>ModelMBean</code> associated with the specified
  155. * <code>ModelMBeanInfo</code> information.
  156. *
  157. * @param info ModelMBeanInfo for this MBean
  158. *
  159. * @exception MBeanException if the initializer of an object
  160. * throws an exception
  161. * @exception RuntimeOperationsException if an IllegalArgumentException
  162. * occurs
  163. */
  164. public BaseModelMBean(ModelMBeanInfo info)
  165. throws MBeanException, RuntimeOperationsException {
  166. // XXX should be deprecated - just call setInfo
  167. super();
  168. setModelMBeanInfo(info);
  169. if( log.isDebugEnabled()) log.debug("ModelMBeanInfo constructor");
  170. }
  171. /** Construct a ModelMBean of a specified type.
  172. * The type can be a class name or the key used in one of the descriptors.
  173. *
  174. * If no descriptor is available, we'll first try to locate one in
  175. * the same package with the class, then use introspection.
  176. *
  177. * The mbean resource will be created.
  178. *
  179. * @param type Class name or the type key used in the descriptor.
  180. * @throws MBeanException
  181. * @throws RuntimeOperationsException
  182. */
  183. public BaseModelMBean( String type )
  184. throws MBeanException, RuntimeOperationsException
  185. {
  186. try {
  187. // This constructor is used from <mlet>, it should create
  188. // the resource
  189. setModeledType(type);
  190. } catch( Throwable ex ) {
  191. log.error( "Error creating mbean ", ex);
  192. }
  193. }
  194. public BaseModelMBean( String type, ModelerSource source )
  195. throws MBeanException, RuntimeOperationsException
  196. {
  197. try {
  198. setModeledType(type);
  199. } catch( Throwable ex ) {
  200. log.error( "Error creating mbean ", ex);
  201. }
  202. this.source=source;
  203. }
  204. // ----------------------------------------------------- Instance Variables
  205. /**
  206. * Notification broadcaster for attribute changes.
  207. */
  208. protected BaseNotificationBroadcaster attributeBroadcaster = null;
  209. /** Registry we are associated with
  210. */
  211. protected Registry registry=null;
  212. /**
  213. * Notification broadcaster for general notifications.
  214. */
  215. protected BaseNotificationBroadcaster generalBroadcaster = null;
  216. protected ObjectName oname=null;
  217. /**
  218. * The <code>ModelMBeanInfo</code> object that controls our activity.
  219. */
  220. protected ModelMBeanInfo info = null;
  221. /**
  222. * The managed resource this MBean is associated with (if any).
  223. */
  224. protected Object resource = null;
  225. protected String resourceType = null;
  226. /** Source object used to read this mbean. Can be used to
  227. * persist the mbean
  228. */
  229. protected ModelerSource source=null;
  230. /** Attribute values. XXX That can be stored in the value Field
  231. */
  232. protected HashMap attributes=new HashMap();
  233. // --------------------------------------------------- DynamicMBean Methods
  234. static final Object[] NO_ARGS_PARAM=new Object[0];
  235. static final Class[] NO_ARGS_PARAM_SIG=new Class[0];
  236. // key: attribute val: getter method
  237. private Hashtable getAttMap=new Hashtable();
  238. // key: attribute val: setter method
  239. private Hashtable setAttMap=new Hashtable();
  240. // key: operation val: invoke method
  241. private Hashtable invokeAttMap=new Hashtable();
  242. /**
  243. * Obtain and return the value of a specific attribute of this MBean.
  244. *
  245. * @param name Name of the requested attribute
  246. *
  247. * @exception AttributeNotFoundException if this attribute is not
  248. * supported by this MBean
  249. * @exception MBeanException if the initializer of an object
  250. * throws an exception
  251. * @exception ReflectionException if a Java reflection exception
  252. * occurs when invoking the getter
  253. */
  254. public Object getAttribute(String name)
  255. throws AttributeNotFoundException, MBeanException,
  256. ReflectionException {
  257. // Validate the input parameters
  258. if (name == null)
  259. throw new RuntimeOperationsException
  260. (new IllegalArgumentException("Attribute name is null"),
  261. "Attribute name is null");
  262. if( (resource instanceof DynamicMBean) &&
  263. ! ( resource instanceof BaseModelMBean )) {
  264. return ((DynamicMBean)resource).getAttribute(name);
  265. }
  266. // Extract the method from cache
  267. Method m=(Method)getAttMap.get( name );
  268. if( m==null ) {
  269. // Look up the actual operation to be used
  270. ModelMBeanAttributeInfo attrInfo = info.getAttribute(name);
  271. if (attrInfo == null)
  272. throw new AttributeNotFoundException(" Cannot find attribute " + name);
  273. Descriptor attrDesc = attrInfo.getDescriptor();
  274. if (attrDesc == null)
  275. throw new AttributeNotFoundException("Cannot find attribute " + name + " descriptor");
  276. String getMethod = (String) attrDesc.getFieldValue("getMethod");
  277. if (getMethod == null)
  278. throw new AttributeNotFoundException("Cannot find attribute " + name + " get method name");
  279. Object object = null;
  280. NoSuchMethodException exception = null;
  281. try {
  282. object = this;
  283. m = object.getClass().getMethod(getMethod, NO_ARGS_PARAM_SIG);
  284. } catch (NoSuchMethodException e) {
  285. exception = e;;
  286. }
  287. if( m== null && resource != null ) {
  288. try {
  289. object = resource;
  290. m = object.getClass().getMethod(getMethod, NO_ARGS_PARAM_SIG);
  291. exception=null;
  292. } catch (NoSuchMethodException e) {
  293. exception = e;
  294. }
  295. }
  296. if( exception != null )
  297. throw new ReflectionException(exception,
  298. "Cannot find getter method " + getMethod);
  299. getAttMap.put( name, m );
  300. }
  301. Object result = null;
  302. try {
  303. Class declaring=m.getDeclaringClass();
  304. // workaround for catalina weird mbeans - the declaring class is BaseModelMBean.
  305. // but this is the catalina class.
  306. if( declaring.isAssignableFrom(this.getClass()) ) {
  307. result = m.invoke(this, NO_ARGS_PARAM );
  308. } else {
  309. result = m.invoke(resource, NO_ARGS_PARAM );
  310. }
  311. } catch (InvocationTargetException e) {
  312. Throwable t = e.getTargetException();
  313. if (t == null)
  314. t = e;
  315. if (t instanceof RuntimeException)
  316. throw new RuntimeOperationsException
  317. ((RuntimeException) t, "Exception invoking method " + name);
  318. else if (t instanceof Error)
  319. throw new RuntimeErrorException
  320. ((Error) t, "Error invoking method " + name);
  321. else
  322. throw new MBeanException
  323. (e, "Exception invoking method " + name);
  324. } catch (Exception e) {
  325. throw new MBeanException
  326. (e, "Exception invoking method " + name);
  327. }
  328. // Return the results of this method invocation
  329. // FIXME - should we validate the return type?
  330. return (result);
  331. }
  332. /**
  333. * Obtain and return the values of several attributes of this MBean.
  334. *
  335. * @param names Names of the requested attributes
  336. */
  337. public AttributeList getAttributes(String names[]) {
  338. // Validate the input parameters
  339. if (names == null)
  340. throw new RuntimeOperationsException
  341. (new IllegalArgumentException("Attribute names list is null"),
  342. "Attribute names list is null");
  343. // Prepare our response, eating all exceptions
  344. AttributeList response = new AttributeList();
  345. for (int i = 0; i < names.length; i++) {
  346. try {
  347. response.add(new Attribute(names[i],getAttribute(names[i])));
  348. } catch (Exception e) {
  349. ; // Not having a particular attribute in the response
  350. ; // is the indication of a getter problem
  351. }
  352. }
  353. return (response);
  354. }
  355. /**
  356. * Return the <code>MBeanInfo</code> object for this MBean.
  357. */
  358. public MBeanInfo getMBeanInfo() {
  359. // XXX Why do we have to clone ?
  360. if( info== null ) return null;
  361. return ((MBeanInfo) info.clone());
  362. }
  363. /**
  364. * Invoke a particular method on this MBean, and return any returned
  365. * value.
  366. *
  367. * <p><strong>IMPLEMENTATION NOTE</strong> - This implementation will
  368. * attempt to invoke this method on the MBean itself, or (if not
  369. * available) on the managed resource object associated with this
  370. * MBean.</p>
  371. *
  372. * @param name Name of the operation to be invoked
  373. * @param params Array containing the method parameters of this operation
  374. * @param signature Array containing the class names representing
  375. * the signature of this operation
  376. *
  377. * @exception MBeanException if the initializer of an object
  378. * throws an exception
  379. * @exception ReflectioNException if a Java reflection exception
  380. * occurs when invoking a method
  381. */
  382. public Object invoke(String name, Object params[], String signature[])
  383. throws MBeanException, ReflectionException
  384. {
  385. if( (resource instanceof DynamicMBean) &&
  386. ! ( resource instanceof BaseModelMBean )) {
  387. return ((DynamicMBean)resource).invoke(name, params, signature);
  388. }
  389. // Validate the input parameters
  390. if (name == null)
  391. throw new RuntimeOperationsException
  392. (new IllegalArgumentException("Method name is null"),
  393. "Method name is null");
  394. if( log.isDebugEnabled()) log.debug("Invoke " + name);
  395. Method method=(Method)invokeAttMap.get(name);
  396. if( method==null ) {
  397. if (params == null)
  398. params = new Object[0];
  399. if (signature == null)
  400. signature = new String[0];
  401. if (params.length != signature.length)
  402. throw new RuntimeOperationsException
  403. (new IllegalArgumentException("Inconsistent arguments and signature"),
  404. "Inconsistent arguments and signature");
  405. // Acquire the ModelMBeanOperationInfo information for
  406. // the requested operation
  407. ModelMBeanOperationInfo opInfo = info.getOperation(name);
  408. if (opInfo == null)
  409. throw new MBeanException
  410. (new ServiceNotFoundException("Cannot find operation " + name),
  411. "Cannot find operation " + name);
  412. // Prepare the signature required by Java reflection APIs
  413. // FIXME - should we use the signature from opInfo?
  414. Class types[] = new Class[signature.length];
  415. for (int i = 0; i < signature.length; i++) {
  416. types[i]=getAttributeClass( signature[i] );
  417. }
  418. // Locate the method to be invoked, either in this MBean itself
  419. // or in the corresponding managed resource
  420. // FIXME - Accessible methods in superinterfaces?
  421. Object object = null;
  422. Exception exception = null;
  423. try {
  424. object = this;
  425. method = object.getClass().getMethod(name, types);
  426. } catch (NoSuchMethodException e) {
  427. exception = e;;
  428. }
  429. try {
  430. if ((method == null) && (resource != null)) {
  431. object = resource;
  432. method = object.getClass().getMethod(name, types);
  433. }
  434. } catch (NoSuchMethodException e) {
  435. exception = e;
  436. }
  437. if (method == null) {
  438. throw new ReflectionException(exception,
  439. "Cannot find method " + name +
  440. " with this signature");
  441. }
  442. invokeAttMap.put( name, method );
  443. }
  444. // Invoke the selected method on the appropriate object
  445. Object result = null;
  446. try {
  447. if( method.getDeclaringClass().isAssignableFrom( this.getClass()) ) {
  448. result = method.invoke(this, params );
  449. } else {
  450. result = method.invoke(resource, params);
  451. }
  452. } catch (InvocationTargetException e) {
  453. Throwable t = e.getTargetException();
  454. log.error("Exception invoking method " + name , t );
  455. if (t == null)
  456. t = e;
  457. if (t instanceof RuntimeException)
  458. throw new RuntimeOperationsException
  459. ((RuntimeException) t, "Exception invoking method " + name);
  460. else if (t instanceof Error)
  461. throw new RuntimeErrorException
  462. ((Error) t, "Error invoking method " + name);
  463. else
  464. throw new MBeanException
  465. ((Exception)t, "Exception invoking method " + name);
  466. } catch (Exception e) {
  467. log.error("Exception invoking method " + name , e );
  468. throw new MBeanException
  469. (e, "Exception invoking method " + name);
  470. }
  471. // Return the results of this method invocation
  472. // FIXME - should we validate the return type?
  473. return (result);
  474. }
  475. private Class getAttributeClass(String signature)
  476. throws ReflectionException
  477. {
  478. if (signature.equals(Boolean.TYPE.getName()))
  479. return Boolean.TYPE;
  480. else if (signature.equals(Byte.TYPE.getName()))
  481. return Byte.TYPE;
  482. else if (signature.equals(Character.TYPE.getName()))
  483. return Character.TYPE;
  484. else if (signature.equals(Double.TYPE.getName()))
  485. return Double.TYPE;
  486. else if (signature.equals(Float.TYPE.getName()))
  487. return Float.TYPE;
  488. else if (signature.equals(Integer.TYPE.getName()))
  489. return Integer.TYPE;
  490. else if (signature.equals(Long.TYPE.getName()))
  491. return Long.TYPE;
  492. else if (signature.equals(Short.TYPE.getName()))
  493. return Short.TYPE;
  494. else {
  495. try {
  496. ClassLoader cl=Thread.currentThread().getContextClassLoader();
  497. if( cl!=null )
  498. return cl.loadClass(signature);
  499. } catch( ClassNotFoundException e ) {
  500. }
  501. try {
  502. return Class.forName(signature);
  503. } catch (ClassNotFoundException e) {
  504. throw new ReflectionException
  505. (e, "Cannot find Class for " + signature);
  506. }
  507. }
  508. }
  509. /**
  510. * Set the value of a specific attribute of this MBean.
  511. *
  512. * @param attribute The identification of the attribute to be set
  513. * and the new value
  514. *
  515. * @exception AttributeNotFoundException if this attribute is not
  516. * supported by this MBean
  517. * @exception MBeanException if the initializer of an object
  518. * throws an exception
  519. * @exception ReflectionException if a Java reflection exception
  520. * occurs when invoking the getter
  521. */
  522. public void setAttribute(Attribute attribute)
  523. throws AttributeNotFoundException, MBeanException,
  524. ReflectionException
  525. {
  526. if( log.isDebugEnabled() )
  527. log.debug("Setting attribute " + this + " " + attribute );
  528. if( (resource instanceof DynamicMBean) &&
  529. ! ( resource instanceof BaseModelMBean )) {
  530. try {
  531. ((DynamicMBean)resource).setAttribute(attribute);
  532. } catch (InvalidAttributeValueException e) {
  533. throw new MBeanException(e);
  534. }
  535. return;
  536. }
  537. // Validate the input parameters
  538. if (attribute == null)
  539. throw new RuntimeOperationsException
  540. (new IllegalArgumentException("Attribute is null"),
  541. "Attribute is null");
  542. String name = attribute.getName();
  543. Object value = attribute.getValue();
  544. if (name == null)
  545. throw new RuntimeOperationsException
  546. (new IllegalArgumentException("Attribute name is null"),
  547. "Attribute name is null");
  548. ModelMBeanAttributeInfo attrInfo=info.getAttribute(name);
  549. if (attrInfo == null)
  550. throw new AttributeNotFoundException("Cannot find attribute " + name);
  551. Descriptor attrDesc=attrInfo.getDescriptor();
  552. if (attrDesc == null)
  553. throw new AttributeNotFoundException("Cannot find attribute " + name + " descriptor");
  554. try {
  555. // XXX Is it before or after ?
  556. Object oldValue=null;
  557. if( getAttMap.get(name) != null )
  558. oldValue=getAttribute( name );
  559. sendAttributeChangeNotification(new Attribute( name, oldValue),
  560. attribute);
  561. } catch( Exception ex ) {
  562. log.error( "Error sending notification " + name, ex );
  563. }
  564. // Extract the method from cache
  565. Method m=(Method)setAttMap.get( name );
  566. if( m==null ) {
  567. // Look up the actual operation to be used
  568. String setMethod = (String) attrDesc.getFieldValue("setMethod");
  569. if (setMethod == null)
  570. throw new AttributeNotFoundException("Cannot find attribute " + name + " set method name");
  571. String argType=attrInfo.getType();
  572. Class signature[] = new Class[] { getAttributeClass( argType ) };
  573. Object object = null;
  574. NoSuchMethodException exception = null;
  575. try {
  576. object = this;
  577. m = object.getClass().getMethod(setMethod, signature);
  578. } catch (NoSuchMethodException e) {
  579. exception = e;;
  580. }
  581. if( m== null && resource != null ) {
  582. try {
  583. object = resource;
  584. m = object.getClass().getMethod(setMethod, signature);
  585. exception=null;
  586. } catch (NoSuchMethodException e) {
  587. if( log.isDebugEnabled())
  588. log.debug("Method not found in resource " +resource);
  589. exception = e;
  590. }
  591. }
  592. if( exception != null )
  593. throw new ReflectionException(exception,
  594. "Cannot find setter method " + setMethod +
  595. " " + resource);
  596. setAttMap.put( name, m );
  597. }
  598. Object result = null;
  599. try {
  600. if( m.getDeclaringClass().isAssignableFrom( this.getClass()) ) {
  601. result = m.invoke(this, new Object[] { value });
  602. } else {
  603. result = m.invoke(resource, new Object[] { value });
  604. }
  605. } catch (InvocationTargetException e) {
  606. Throwable t = e.getTargetException();
  607. if (t == null)
  608. t = e;
  609. if (t instanceof RuntimeException)
  610. throw new RuntimeOperationsException
  611. ((RuntimeException) t, "Exception invoking method " + name);
  612. else if (t instanceof Error)
  613. throw new RuntimeErrorException
  614. ((Error) t, "Error invoking method " + name);
  615. else
  616. throw new MBeanException
  617. (e, "Exception invoking method " + name);
  618. } catch (Exception e) {
  619. log.error("Exception invoking method " + name , e );
  620. throw new MBeanException
  621. (e, "Exception invoking method " + name);
  622. }
  623. attributes.put( name, value );
  624. if( source != null ) {
  625. // this mbean is asscoiated with a source - maybe we want to persist
  626. source.updateField(oname, name, value);
  627. }
  628. }
  629. public String toString() {
  630. if( resource==null )
  631. return "BaseModelMbean[" + resourceType + "]";
  632. return resource.toString();
  633. }
  634. /**
  635. * Set the values of several attributes of this MBean.
  636. *
  637. * @param attributes THe names and values to be set
  638. *
  639. * @return The list of attributes that were set and their new values
  640. */
  641. public AttributeList setAttributes(AttributeList attributes) {
  642. // Validate the input parameters
  643. if (attributes == null)
  644. throw new RuntimeOperationsException
  645. (new IllegalArgumentException("Attributes list is null"),
  646. "Attributes list is null");
  647. // Prepare and return our response, eating all exceptions
  648. AttributeList response = new AttributeList();
  649. String names[] = new String[attributes.size()];
  650. int n = 0;
  651. Iterator items = attributes.iterator();
  652. while (items.hasNext()) {
  653. Attribute item = (Attribute) items.next();
  654. names[n++] = item.getName();
  655. try {
  656. setAttribute(item);
  657. } catch (Exception e) {
  658. ; // Ignore all exceptions
  659. }
  660. }
  661. return (getAttributes(names));
  662. }
  663. // ----------------------------------------------------- ModelMBean Methods
  664. /**
  665. * Get the instance handle of the object against which we execute
  666. * all methods in this ModelMBean management interface.
  667. *
  668. * @exception InstanceNotFoundException if the managed resource object
  669. * cannot be found
  670. * @exception MBeanException if the initializer of the object throws
  671. * an exception
  672. * @exception RuntimeOperationsException if the managed resource or the
  673. * resource type is <code>null</code> or invalid
  674. */
  675. public Object getManagedResource()
  676. throws InstanceNotFoundException, InvalidTargetObjectTypeException,
  677. MBeanException, RuntimeOperationsException {
  678. if (resource == null)
  679. throw new RuntimeOperationsException
  680. (new IllegalArgumentException("Managed resource is null"),
  681. "Managed resource is null");
  682. return resource;
  683. }
  684. /**
  685. * Set the instance handle of the object against which we will execute
  686. * all methods in this ModelMBean management interface.
  687. *
  688. * This method will detect and call "setModelMbean" method. A resource
  689. * can implement this method to get a reference to the model mbean.
  690. * The reference can be used to send notification and access the
  691. * registry.
  692. *
  693. * @param resource The resource object to be managed
  694. * @param type The type of reference for the managed resource
  695. * ("ObjectReference", "Handle", "IOR", "EJBHandle", or
  696. * "RMIReference")
  697. *
  698. * @exception InstanceNotFoundException if the managed resource object
  699. * cannot be found
  700. * @exception InvalidTargetObjectTypeException if this ModelMBean is
  701. * asked to handle a reference type it cannot deal with
  702. * @exception MBeanException if the initializer of the object throws
  703. * an exception
  704. * @exception RuntimeOperationsException if the managed resource or the
  705. * resource type is <code>null</code> or invalid
  706. */
  707. public void setManagedResource(Object resource, String type)
  708. throws InstanceNotFoundException, InvalidTargetObjectTypeException,
  709. MBeanException, RuntimeOperationsException
  710. {
  711. if (resource == null)
  712. throw new RuntimeOperationsException
  713. (new IllegalArgumentException("Managed resource is null"),
  714. "Managed resource is null");
  715. if (!"objectreference".equalsIgnoreCase(type))
  716. throw new InvalidTargetObjectTypeException(type);
  717. this.resource = resource;
  718. this.resourceType = resource.getClass().getName();
  719. // Make the resource aware of the model mbean.
  720. try {
  721. Method m=resource.getClass().getMethod("setModelMBean",
  722. new Class[] {ModelMBean.class});
  723. if( m!= null ) {
  724. m.invoke(resource, new Object[] {this});
  725. }
  726. } catch( NoSuchMethodException t ) {
  727. // ignore
  728. } catch( Throwable t ) {
  729. log.error( "Can't set model mbean ", t );
  730. }
  731. }
  732. /**
  733. * Initialize the <code>ModelMBeanInfo</code> associated with this
  734. * <code>ModelMBean</code>. After the information and associated
  735. * descriptors have been customized, the <code>ModelMBean</code> should
  736. * be registered with the associated <code>MBeanServer</code>.
  737. *
  738. * Currently the model can be set after registration. This behavior is
  739. * deprecated and won't be supported in future versions.
  740. *
  741. * @param info The ModelMBeanInfo object to be used by this ModelMBean
  742. *
  743. * @exception MBeanException If an exception occurs recording this
  744. * ModelMBeanInfo information
  745. * @exception RuntimeOperations if the specified parameter is
  746. * <code>null</code> or invalid
  747. */
  748. public void setModelMBeanInfo(ModelMBeanInfo info)
  749. throws MBeanException, RuntimeOperationsException {
  750. if (info == null)
  751. throw new RuntimeOperationsException
  752. (new IllegalArgumentException("ModelMBeanInfo is null"),
  753. "ModelMBeanInfo is null");
  754. if (!isModelMBeanInfoValid(info))
  755. throw new RuntimeOperationsException
  756. (new IllegalArgumentException("ModelMBeanInfo is invalid"),
  757. "ModelMBeanInfo is invalid");
  758. this.info = (ModelMBeanInfo) info.clone();
  759. }
  760. // ------------------------------ ModelMBeanNotificationBroadcaster Methods
  761. /**
  762. * Add an attribute change notification event listener to this MBean.
  763. *
  764. * @param listener Listener that will receive event notifications
  765. * @param name Name of the attribute of interest, or <code>null</code>
  766. * to indicate interest in all attributes
  767. * @param handback Handback object to be sent along with event
  768. * notifications
  769. *
  770. * @exception IllegalArgumentException if the listener parameter is null
  771. */
  772. public void addAttributeChangeNotificationListener
  773. (NotificationListener listener, String name, Object handback)
  774. throws IllegalArgumentException {
  775. if (listener == null)
  776. throw new IllegalArgumentException("Listener is null");
  777. if (attributeBroadcaster == null)
  778. attributeBroadcaster = new BaseNotificationBroadcaster();
  779. if( log.isDebugEnabled() )
  780. log.debug("addAttributeNotificationListener " + listener);
  781. BaseAttributeFilter filter = new BaseAttributeFilter(name);
  782. attributeBroadcaster.addNotificationListener
  783. (listener, filter, handback);
  784. }
  785. /**
  786. * Remove an attribute change notification event listener from
  787. * this MBean.
  788. *
  789. * @param listener The listener to be removed
  790. * @param name The attribute name for which no more events are required
  791. *
  792. *
  793. * @exception ListenerNotFoundException if this listener is not
  794. * registered in the MBean
  795. */
  796. public void removeAttributeChangeNotificationListener
  797. (NotificationListener listener, String name)
  798. throws ListenerNotFoundException {
  799. if (listener == null)
  800. throw new IllegalArgumentException("Listener is null");
  801. if (attributeBroadcaster == null)
  802. attributeBroadcaster = new BaseNotificationBroadcaster();
  803. // FIXME - currently this removes *all* notifications for this listener
  804. attributeBroadcaster.removeNotificationListener(listener);
  805. }
  806. /**
  807. * Remove an attribute change notification event listener from
  808. * this MBean.
  809. *
  810. * @param listener The listener to be removed
  811. * @param attributeName The attribute name for which no more events are required
  812. * @param handback Handback object to be sent along with event
  813. * notifications
  814. *
  815. *
  816. * @exception ListenerNotFoundException if this listener is not
  817. * registered in the MBean
  818. */
  819. public void removeAttributeChangeNotificationListener
  820. (NotificationListener listener, String attributeName, Object handback)
  821. throws ListenerNotFoundException {
  822. removeAttributeChangeNotificationListener(listener, attributeName);
  823. }
  824. /**
  825. * Send an <code>AttributeChangeNotification</code> to all registered
  826. * listeners.
  827. *
  828. * @param notification The <code>AttributeChangeNotification</code>
  829. * that will be passed
  830. *
  831. * @exception MBeanException if an object initializer throws an
  832. * exception
  833. * @exception RuntimeOperationsException wraps IllegalArgumentException
  834. * when the specified notification is <code>null</code> or invalid
  835. */
  836. public void sendAttributeChangeNotification
  837. (AttributeChangeNotification notification)
  838. throws MBeanException, RuntimeOperationsException {
  839. if (notification == null)
  840. throw new RuntimeOperationsException
  841. (new IllegalArgumentException("Notification is null"),
  842. "Notification is null");
  843. if (attributeBroadcaster == null)
  844. return; // This means there are no registered listeners
  845. if( log.isDebugEnabled() )
  846. log.debug( "AttributeChangeNotification " + notification );
  847. attributeBroadcaster.sendNotification(notification);
  848. }
  849. /**
  850. * Send an <code>AttributeChangeNotification</code> to all registered
  851. * listeners.
  852. *
  853. * @param oldValue The original value of the <code>Attribute</code>
  854. * @param newValue The new value of the <code>Attribute</code>
  855. *
  856. * @exception MBeanException if an object initializer throws an
  857. * exception
  858. * @exception RuntimeOperationsException wraps IllegalArgumentException
  859. * when the specified notification is <code>null</code> or invalid
  860. */
  861. public void sendAttributeChangeNotification
  862. (Attribute oldValue, Attribute newValue)
  863. throws MBeanException, RuntimeOperationsException {
  864. // Calculate the class name for the change notification
  865. String type = null;
  866. if (newValue.getValue() != null)
  867. type = newValue.getValue().getClass().getName();
  868. else if (oldValue.getValue() != null)
  869. type = oldValue.getValue().getClass().getName();
  870. else
  871. return; // Old and new are both null == no change
  872. AttributeChangeNotification notification =
  873. new AttributeChangeNotification
  874. (this, 1, System.currentTimeMillis(),
  875. "Attribute value has changed",
  876. oldValue.getName(), type,
  877. oldValue.getValue(), newValue.getValue());
  878. sendAttributeChangeNotification(notification);
  879. }
  880. /**
  881. * Send a <code>Notification</code> to all registered listeners as a
  882. * <code>jmx.modelmbean.general</code> notification.
  883. *
  884. * @param notification The <code>Notification</code> that will be passed
  885. *
  886. * @exception MBeanException if an object initializer throws an
  887. * exception
  888. * @exception RuntimeOperationsException wraps IllegalArgumentException
  889. * when the specified notification is <code>null</code> or invalid
  890. */
  891. public void sendNotification(Notification notification)
  892. throws MBeanException, RuntimeOperationsException {
  893. if (notification == null)
  894. throw new RuntimeOperationsException
  895. (new IllegalArgumentException("Notification is null"),
  896. "Notification is null");
  897. if (generalBroadcaster == null)
  898. return; // This means there are no registered listeners
  899. generalBroadcaster.sendNotification(notification);
  900. }
  901. /**
  902. * Send a <code>Notification</code> which contains the specified string
  903. * as a <code>jmx.modelmbean.generic</code> notification.
  904. *
  905. * @param message The message string to be passed
  906. *
  907. * @exception MBeanException if an object initializer throws an
  908. * exception
  909. * @exception RuntimeOperationsException wraps IllegalArgumentException
  910. * when the specified notification is <code>null</code> or invalid
  911. */
  912. public void sendNotification(String message)
  913. throws MBeanException, RuntimeOperationsException {
  914. if (message == null)
  915. throw new RuntimeOperationsException
  916. (new IllegalArgumentException("Message is null"),
  917. "Message is null");
  918. Notification notification = new Notification
  919. ("jmx.modelmbean.generic", this, 1, message);
  920. sendNotification(notification);
  921. }
  922. // ---------------------------------------- NotificationBroadcaster Methods
  923. /**
  924. * Add a notification event listener to this MBean.
  925. *
  926. * @param listener Listener that will receive event notifications
  927. * @param filter Filter object used to filter event notifications
  928. * actually delivered, or <code>null</code> for no filtering
  929. * @param handback Handback object to be sent along with event
  930. * notifications
  931. *
  932. * @exception IllegalArgumentException if the listener parameter is null
  933. */
  934. public void addNotificationListener(NotificationListener listener,
  935. NotificationFilter filter,
  936. Object handback)
  937. throws IllegalArgumentException {
  938. if (listener == null)
  939. throw new IllegalArgumentException("Listener is null");
  940. if( log.isDebugEnabled() ) log.debug("addNotificationListener " + listener);
  941. if (generalBroadcaster == null)
  942. generalBroadcaster = new BaseNotificationBroadcaster();
  943. generalBroadcaster.addNotificationListener
  944. (listener, filter, handback);
  945. // We'll send the attribute change notifications to all listeners ( who care )
  946. // The normal filtering can be used.
  947. // The problem is that there is no other way to add attribute change listeners
  948. // to a model mbean ( AFAIK ). I suppose the spec should be fixed.
  949. if (attributeBroadcaster == null)
  950. attributeBroadcaster = new BaseNotificationBroadcaster();
  951. if( log.isDebugEnabled() )
  952. log.debug("addAttributeNotificationListener " + listener);
  953. attributeBroadcaster.addNotificationListener
  954. (listener, filter, handback);
  955. }
  956. /**
  957. * Return an <code>MBeanNotificationInfo</code> object describing the
  958. * notifications sent by this MBean.
  959. */
  960. public MBeanNotificationInfo[] getNotificationInfo() {
  961. // Acquire the set of application notifications
  962. MBeanNotificationInfo current[] = info.getNotifications();
  963. if (current == null)
  964. current = new MBeanNotificationInfo[0];
  965. MBeanNotificationInfo response[] =
  966. new MBeanNotificationInfo[current.length + 2];
  967. Descriptor descriptor = null;
  968. // Fill in entry for general notifications
  969. descriptor = new DescriptorSupport
  970. (new String[] { "name=GENERIC",
  971. "descriptorType=notification",
  972. "log=T",
  973. "severity=5",
  974. "displayName=jmx.modelmbean.generic" });
  975. response[0] = new ModelMBeanNotificationInfo
  976. (new String[] { "jmx.modelmbean.generic" },
  977. "GENERIC",
  978. "Text message notification from the managed resource",
  979. descriptor);
  980. // Fill in entry for attribute change notifications
  981. descriptor = new DescriptorSupport
  982. (new String[] { "name=ATTRIBUTE_CHANGE",
  983. "descriptorType=notification",
  984. "log=T",
  985. "severity=5",
  986. "displayName=jmx.attribute.change" });
  987. response[1] = new ModelMBeanNotificationInfo
  988. (new String[] { "jmx.attribute.change" },
  989. "ATTRIBUTE_CHANGE",
  990. "Observed MBean attribute value has changed",
  991. descriptor);
  992. // Copy remaining notifications as reported by the application
  993. System.arraycopy(current, 0, response, 2, current.length);
  994. return (response);
  995. }
  996. /**
  997. * Remove a notification event listener from this MBean.
  998. *
  999. * @param listener The listener to be removed (any and all registrations
  1000. * for this listener will be eliminated)
  1001. *
  1002. * @exception ListenerNotFoundException if this listener is not
  1003. * registered in the MBean
  1004. */
  1005. public void removeNotificationListener(NotificationListener listener)
  1006. throws ListenerNotFoundException {
  1007. if (listener == null)
  1008. throw new IllegalArgumentException("Listener is null");
  1009. if (generalBroadcaster == null)
  1010. generalBroadcaster = new BaseNotificationBroadcaster();
  1011. generalBroadcaster.removeNotificationListener(listener);
  1012. }
  1013. /**
  1014. * Remove a notification event listener from this MBean.
  1015. *
  1016. * @param listener The listener to be removed (any and all registrations
  1017. * for this listener will be eliminated)
  1018. * @param handback Handback object to be sent along with event
  1019. * notifications
  1020. *
  1021. * @exception ListenerNotFoundException if this listener is not
  1022. * registered in the MBean
  1023. */
  1024. public void removeNotificationListener(NotificationListener listener,
  1025. Object handback)
  1026. throws ListenerNotFoundException {
  1027. removeNotificationListener(listener);
  1028. }
  1029. /**
  1030. * Remove a notification event listener from this MBean.
  1031. *
  1032. * @param listener The listener to be removed (any and all registrations
  1033. * for this listener will be eliminated)
  1034. * @param filter Filter object used to filter event notifications
  1035. * actually delivered, or <code>null</code> for no filtering
  1036. * @param handback Handback object to be sent along with event
  1037. * notifications
  1038. *
  1039. * @exception ListenerNotFoundException if this listener is not
  1040. * registered in the MBean
  1041. */
  1042. public void removeNotificationListener(NotificationListener listener,
  1043. NotificationFilter filter,
  1044. Object handback)
  1045. throws ListenerNotFoundException {
  1046. removeNotificationListener(listener);
  1047. }
  1048. // ------------------------------------------------ PersistentMBean Methods
  1049. /**
  1050. * Instantiates this MBean instance from data found in the persistent
  1051. * store. The data loaded could include attribute and operation values.
  1052. * This method should be called during construction or initialization
  1053. * of the instance, and before the MBean is registered with the
  1054. * <code>MBeanServer</code>.
  1055. *
  1056. * <p><strong>IMPLEMENTATION NOTE</strong> - This implementation does
  1057. * not support persistence.</p>
  1058. *
  1059. * @exception InstanceNotFoundException if the managed resource object
  1060. * cannot be found
  1061. * @exception MBeanException if the initializer of the object throws
  1062. * an exception
  1063. * @exception RuntimeOperationsException if an exception is reported
  1064. * by the persistence mechanism
  1065. */
  1066. public void load() throws InstanceNotFoundException,
  1067. MBeanException, RuntimeOperationsException {
  1068. // XXX If a context was set, use it to load the data
  1069. throw new MBeanException
  1070. (new IllegalStateException("Persistence is not supported"),
  1071. "Persistence is not supported");
  1072. }
  1073. /**
  1074. * Capture the current state of this MBean instance and write it out
  1075. * to the persistent store. The state stored could include attribute
  1076. * and operation values. If one of these methods of persistence is not
  1077. * supported, a "service not found" exception will be thrown.
  1078. *
  1079. * <p><strong>IMPLEMENTATION NOTE</strong> - This implementation does
  1080. * not support persistence.</p>
  1081. *
  1082. * @exception InstanceNotFoundException if the managed resource object
  1083. * cannot be found
  1084. * @exception MBeanException if the initializer of the object throws
  1085. * an exception, or persistence is not supported
  1086. * @exception RuntimeOperationsException if an exception is reported
  1087. * by the persistence mechanism
  1088. */
  1089. public void store() throws InstanceNotFoundException,
  1090. MBeanException, RuntimeOperationsException {
  1091. // XXX if a context was set, use it to store the data
  1092. throw new MBeanException
  1093. (new IllegalStateException("Persistence is not supported"),
  1094. "Persistence is not supported");
  1095. }
  1096. // -------------------- BaseModelMBean methods --------------------
  1097. /** Set the type of the mbean. This is used as a key to locate
  1098. * the description in the Registry.
  1099. *
  1100. * @param type the type of classname of the modeled object
  1101. */
  1102. public void setModeledType( String type ) {
  1103. initModelInfo(type);
  1104. createResource();
  1105. }
  1106. /** Set the type of the mbean. This is used as a key to locate
  1107. * the description in the Registry.
  1108. *
  1109. * @param type the type of classname of the modeled object
  1110. */
  1111. protected void initModelInfo( String type ) {
  1112. try {
  1113. if( log.isDebugEnabled())
  1114. log.debug("setModeledType " + type);
  1115. log.debug( "Set model Info " + type);
  1116. if(type==null) {
  1117. return;
  1118. }
  1119. resourceType=type;
  1120. //Thread.currentThread().setContextClassLoader(BaseModelMBean.class.getClassLoader());
  1121. Class c=null;
  1122. try {
  1123. c=Class.forName( type);
  1124. } catch( Throwable t ) {
  1125. log.debug( "Error creating class " + t);
  1126. }
  1127. // The class c doesn't need to exist
  1128. ManagedBean descriptor=getRegistry().findManagedBean(c, type);
  1129. if( descriptor==null )
  1130. return;
  1131. this.setModelMBeanInfo(descriptor.createMBeanInfo());
  1132. } catch( Throwable ex) {
  1133. log.error( "TCL: " + Thread.currentThread().getContextClassLoader(),
  1134. ex);
  1135. }
  1136. }
  1137. /** Set the type of the mbean. This is used as a key to locate
  1138. * the description in the Registry.
  1139. */
  1140. protected void createResource() {
  1141. try {
  1142. //Thread.currentThread().setContextClassLoader(BaseModelMBean.class.getClassLoader());
  1143. Class c=null;
  1144. try {
  1145. c=Class.forName( resourceType );
  1146. resource = c.newInstance();
  1147. } catch( Throwable t ) {
  1148. log.error( "Error creating class " + t);
  1149. }
  1150. } catch( Throwable ex) {
  1151. log.error( "TCL: " + Thread.currentThread().getContextClassLoader(),
  1152. ex);
  1153. }
  1154. }
  1155. public String getModelerType() {
  1156. return resourceType;
  1157. }
  1158. public String getClassName() {
  1159. return getModelerType();
  1160. }
  1161. public ObjectName getObjectName() {
  1162. return oname;
  1163. }
  1164. public void setRegistry(Registry registry) {
  1165. this.registry = registry;
  1166. }
  1167. public Registry getRegistry() {
  1168. // XXX Need a better solution - to avoid the static
  1169. if( registry == null )
  1170. registry=Registry.getRegistry();
  1171. return registry;
  1172. }
  1173. // ------------------------------------------------------ Protected Methods
  1174. /**
  1175. * Create and return a default <code>ModelMBeanInfo</code> object.
  1176. */
  1177. protected ModelMBeanInfo createDefaultModelMBeanInfo() {
  1178. return (new ModelMBeanInfoSupport(this.getClass().getName(),
  1179. "Default ModelMBean",
  1180. null, null, null, null));
  1181. }
  1182. /**
  1183. * Is the specified <code>ModelMBeanInfo</code> instance valid?
  1184. *
  1185. * <p><strong>IMPLEMENTATION NOTE</strong> - This implementation
  1186. * does not check anything, but this method can be overridden
  1187. * as required.</p>
  1188. *
  1189. * @param info The <code>ModelMBeanInfo object to check
  1190. */
  1191. protected boolean isModelMBeanInfoValid(ModelMBeanInfo info) {
  1192. return (true);
  1193. }
  1194. // -------------------- Registration --------------------
  1195. // XXX We can add some method patterns here- like setName() and
  1196. // setDomain() for code that doesn't implement the Registration
  1197. public ObjectName preRegister(MBeanServer server,
  1198. ObjectName name)
  1199. throws Exception
  1200. {
  1201. if( log.isDebugEnabled())
  1202. log.debug("preRegister " + resource + " " + name );
  1203. oname=name;
  1204. if( resource instanceof MBeanRegistration ) {
  1205. oname = ((MBeanRegistration)resource).preRegister(server, name );
  1206. }
  1207. return oname;
  1208. }
  1209. public void postRegister(Boolean registrationDone) {
  1210. if( resource instanceof MBeanRegistration ) {
  1211. ((MBeanRegistration)resource).postRegister(registrationDone);
  1212. }
  1213. }
  1214. public void preDeregister() throws Exception {
  1215. if( resource instanceof MBeanRegistration ) {
  1216. ((MBeanRegistration)resource).preDeregister();
  1217. }
  1218. }
  1219. public void postDeregister() {
  1220. if( resource instanceof MBeanRegistration ) {
  1221. ((MBeanRegistration)resource).postDeregister();
  1222. }
  1223. }
  1224. }