1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.commons.modeler;
19
20
21 import java.lang.reflect.InvocationTargetException;
22 import java.lang.reflect.Method;
23 import java.util.HashMap;
24 import java.util.Hashtable;
25 import java.util.Iterator;
26
27 import javax.management.Attribute;
28 import javax.management.AttributeChangeNotification;
29 import javax.management.AttributeList;
30 import javax.management.AttributeNotFoundException;
31 import javax.management.Descriptor;
32 import javax.management.DynamicMBean;
33 import javax.management.InstanceNotFoundException;
34 import javax.management.InvalidAttributeValueException;
35 import javax.management.ListenerNotFoundException;
36 import javax.management.MBeanException;
37 import javax.management.MBeanInfo;
38 import javax.management.MBeanNotificationInfo;
39 import javax.management.MBeanRegistration;
40 import javax.management.MBeanServer;
41 import javax.management.Notification;
42 import javax.management.NotificationFilter;
43 import javax.management.NotificationListener;
44 import javax.management.ObjectName;
45 import javax.management.ReflectionException;
46 import javax.management.RuntimeErrorException;
47 import javax.management.RuntimeOperationsException;
48 import javax.management.ServiceNotFoundException;
49 import javax.management.modelmbean.DescriptorSupport;
50 import javax.management.modelmbean.InvalidTargetObjectTypeException;
51 import javax.management.modelmbean.ModelMBean;
52 import javax.management.modelmbean.ModelMBeanAttributeInfo;
53 import javax.management.modelmbean.ModelMBeanInfo;
54 import javax.management.modelmbean.ModelMBeanInfoSupport;
55 import javax.management.modelmbean.ModelMBeanNotificationInfo;
56 import javax.management.modelmbean.ModelMBeanOperationInfo;
57
58 import org.apache.commons.logging.Log;
59 import org.apache.commons.logging.LogFactory;
60 import org.apache.commons.modeler.modules.ModelerSource;
61
62
63
64 /***
65 * <p>Basic implementation of the <code>ModelMBean</code> interface, which
66 * supports the minimal requirements of the interface contract.</p>
67 *
68 * <p>This can be used directly to wrap an existing java bean, or inside
69 * an mlet or anywhere an MBean would be used. The String parameter
70 * passed to the constructor will be used to construct an instance of the
71 * real object that we wrap.
72 *
73 * Limitations:
74 * <ul>
75 * <li>Only managed resources of type <code>objectReference</code> are
76 * supportd.</li>
77 * <li>Caching of attribute values and operation results is not supported.
78 * All calls to <code>invoke()</code> are immediately executed.</li>
79 * <li>Logging (under control of descriptors) is not supported.</li>
80 * <li>Persistence of MBean attributes and operations is not supported.</li>
81 * <li>All classes referenced as attribute types, operation parameters, or
82 * operation return values must be one of the following:
83 * <ul>
84 * <li>One of the Java primitive types (boolean, byte, char, double,
85 * float, integer, long, short). Corresponding value will be wrapped
86 * in the appropriate wrapper class automatically.</li>
87 * <li>Operations that return no value should declare a return type of
88 * <code>void</code>.</li>
89 * </ul>
90 * <li>Attribute caching is not supported</li>
91 * </ul>
92 *
93 * @author Craig R. McClanahan
94 * @author Costin Manolache
95 * @version $Revision: 383269 $ $Date: 2006-03-04 21:22:41 -0500 (Sat, 04 Mar 2006) $
96 */
97
98 public class BaseModelMBean implements ModelMBean, MBeanRegistration {
99 private static Log log = LogFactory.getLog(BaseModelMBean.class);
100
101
102
103 /***
104 * Construct a <code>ModelMBean</code> with default
105 * <code>ModelMBeanInfo</code> information.
106 *
107 * @exception MBeanException if the initializer of an object
108 * throws an exception
109 * @exception RuntimeOperationsException if an IllegalArgumentException
110 * occurs
111 */
112 public BaseModelMBean() throws MBeanException, RuntimeOperationsException {
113
114 super();
115 if( log.isDebugEnabled()) log.debug("default constructor");
116 setModelMBeanInfo(createDefaultModelMBeanInfo());
117 }
118
119
120 /***
121 * Construct a <code>ModelMBean</code> associated with the specified
122 * <code>ModelMBeanInfo</code> information.
123 *
124 * @param info ModelMBeanInfo for this MBean
125 *
126 * @exception MBeanException if the initializer of an object
127 * throws an exception
128 * @exception RuntimeOperationsException if an IllegalArgumentException
129 * occurs
130 */
131 public BaseModelMBean(ModelMBeanInfo info)
132 throws MBeanException, RuntimeOperationsException {
133
134 super();
135 setModelMBeanInfo(info);
136 if( log.isDebugEnabled()) log.debug("ModelMBeanInfo constructor");
137 }
138
139 /*** Construct a ModelMBean of a specified type.
140 * The type can be a class name or the key used in one of the descriptors.
141 *
142 * If no descriptor is available, we'll first try to locate one in
143 * the same package with the class, then use introspection.
144 *
145 * The mbean resource will be created.
146 *
147 * @param type Class name or the type key used in the descriptor.
148 * @throws MBeanException
149 * @throws RuntimeOperationsException
150 */
151 public BaseModelMBean( String type )
152 throws MBeanException, RuntimeOperationsException
153 {
154 try {
155
156
157 setModeledType(type);
158 } catch( Throwable ex ) {
159 log.error( "Error creating mbean ", ex);
160 }
161 }
162
163 public BaseModelMBean( String type, ModelerSource source )
164 throws MBeanException, RuntimeOperationsException
165 {
166 try {
167 setModeledType(type);
168 } catch( Throwable ex ) {
169 log.error( "Error creating mbean ", ex);
170 }
171 this.source=source;
172 }
173
174
175
176
177 /***
178 * Notification broadcaster for attribute changes.
179 */
180 protected BaseNotificationBroadcaster attributeBroadcaster = null;
181
182 /*** Registry we are associated with
183 */
184 protected Registry registry=null;
185
186 /***
187 * Notification broadcaster for general notifications.
188 */
189 protected BaseNotificationBroadcaster generalBroadcaster = null;
190
191 protected ObjectName oname=null;
192
193 /***
194 * The <code>ModelMBeanInfo</code> object that controls our activity.
195 */
196 protected ModelMBeanInfo info = null;
197
198
199 /***
200 * The managed resource this MBean is associated with (if any).
201 */
202 protected Object resource = null;
203 protected String resourceType = null;
204
205 /*** Source object used to read this mbean. Can be used to
206 * persist the mbean
207 */
208 protected ModelerSource source=null;
209
210 /*** Attribute values. XXX That can be stored in the value Field
211 */
212 protected HashMap attributes=new HashMap();
213
214
215 static final Object[] NO_ARGS_PARAM=new Object[0];
216 static final Class[] NO_ARGS_PARAM_SIG=new Class[0];
217
218 private Hashtable getAttMap=new Hashtable();
219
220
221 private Hashtable setAttMap=new Hashtable();
222
223
224 private Hashtable invokeAttMap=new Hashtable();
225
226 /***
227 * Obtain and return the value of a specific attribute of this MBean.
228 *
229 * @param name Name of the requested attribute
230 *
231 * @exception AttributeNotFoundException if this attribute is not
232 * supported by this MBean
233 * @exception MBeanException if the initializer of an object
234 * throws an exception
235 * @exception ReflectionException if a Java reflection exception
236 * occurs when invoking the getter
237 */
238 public Object getAttribute(String name)
239 throws AttributeNotFoundException, MBeanException,
240 ReflectionException {
241
242 if (name == null)
243 throw new RuntimeOperationsException
244 (new IllegalArgumentException("Attribute name is null"),
245 "Attribute name is null");
246
247 if( (resource instanceof DynamicMBean) &&
248 ! ( resource instanceof BaseModelMBean )) {
249 return ((DynamicMBean)resource).getAttribute(name);
250 }
251
252
253 Method m=(Method)getAttMap.get( name );
254
255 if( m==null ) {
256
257 ModelMBeanAttributeInfo attrInfo = info.getAttribute(name);
258 if (attrInfo == null)
259 throw new AttributeNotFoundException(" Cannot find attribute " + name);
260 Descriptor attrDesc = attrInfo.getDescriptor();
261 if (attrDesc == null)
262 throw new AttributeNotFoundException("Cannot find attribute " + name + " descriptor");
263 String getMethod = (String) attrDesc.getFieldValue("getMethod");
264
265 if (getMethod == null)
266 throw new AttributeNotFoundException("Cannot find attribute " + name + " get method name");
267
268 Object object = null;
269 NoSuchMethodException exception = null;
270 try {
271 object = this;
272 m = object.getClass().getMethod(getMethod, NO_ARGS_PARAM_SIG);
273 } catch (NoSuchMethodException e) {
274 exception = e;;
275 }
276 if( m== null && resource != null ) {
277 try {
278 object = resource;
279 m = object.getClass().getMethod(getMethod, NO_ARGS_PARAM_SIG);
280 exception=null;
281 } catch (NoSuchMethodException e) {
282 exception = e;
283 }
284 }
285 if( exception != null )
286 throw new ReflectionException(exception,
287 "Cannot find getter method " + getMethod);
288 getAttMap.put( name, m );
289 }
290
291 Object result = null;
292 try {
293 Class declaring=m.getDeclaringClass();
294
295
296 if( declaring.isAssignableFrom(this.getClass()) ) {
297 result = m.invoke(this, NO_ARGS_PARAM );
298 } else {
299 result = m.invoke(resource, NO_ARGS_PARAM );
300 }
301 } catch (InvocationTargetException e) {
302 Throwable t = e.getTargetException();
303 if (t == null)
304 t = e;
305 if (t instanceof RuntimeException)
306 throw new RuntimeOperationsException
307 ((RuntimeException) t, "Exception invoking method " + name);
308 else if (t instanceof Error)
309 throw new RuntimeErrorException
310 ((Error) t, "Error invoking method " + name);
311 else
312 throw new MBeanException
313 (e, "Exception invoking method " + name);
314 } catch (Exception e) {
315 throw new MBeanException
316 (e, "Exception invoking method " + name);
317 }
318
319
320
321 return (result);
322 }
323
324
325 /***
326 * Obtain and return the values of several attributes of this MBean.
327 *
328 * @param names Names of the requested attributes
329 */
330 public AttributeList getAttributes(String names[]) {
331
332
333 if (names == null)
334 throw new RuntimeOperationsException
335 (new IllegalArgumentException("Attribute names list is null"),
336 "Attribute names list is null");
337
338
339 AttributeList response = new AttributeList();
340 for (int i = 0; i < names.length; i++) {
341 try {
342 response.add(new Attribute(names[i],getAttribute(names[i])));
343 } catch (Exception e) {
344 ;
345 ;
346 }
347 }
348 return (response);
349
350 }
351
352
353 /***
354 * Return the <code>MBeanInfo</code> object for this MBean.
355 */
356 public MBeanInfo getMBeanInfo() {
357
358 if( info== null ) return null;
359 return ((MBeanInfo) info.clone());
360 }
361
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
390
391 if (name == null)
392 throw new RuntimeOperationsException
393 (new IllegalArgumentException("Method name is null"),
394 "Method name is null");
395
396 if( log.isDebugEnabled()) log.debug("Invoke " + name);
397 MethodKey mkey = new MethodKey(name, signature);
398 Method method=(Method)invokeAttMap.get(mkey);
399 if( method==null ) {
400 if (params == null)
401 params = new Object[0];
402 if (signature == null)
403 signature = new String[0];
404 if (params.length != signature.length)
405 throw new RuntimeOperationsException
406 (new IllegalArgumentException("Inconsistent arguments and signature"),
407 "Inconsistent arguments and signature");
408
409
410
411 ModelMBeanOperationInfo opInfo = info.getOperation(name);
412 if (opInfo == null)
413 throw new MBeanException
414 (new ServiceNotFoundException("Cannot find operation " + name),
415 "Cannot find operation " + name);
416
417
418
419 Class types[] = new Class[signature.length];
420 for (int i = 0; i < signature.length; i++) {
421 types[i]=getAttributeClass( signature[i] );
422 }
423
424
425
426
427 Object object = null;
428 Exception exception = null;
429 try {
430 object = this;
431 method = object.getClass().getMethod(name, types);
432 } catch (NoSuchMethodException e) {
433 exception = e;;
434 }
435 try {
436 if ((method == null) && (resource != null)) {
437 object = resource;
438 method = object.getClass().getMethod(name, types);
439 }
440 } catch (NoSuchMethodException e) {
441 exception = e;
442 }
443 if (method == null) {
444 throw new ReflectionException(exception,
445 "Cannot find method " + name +
446 " with this signature");
447 }
448 invokeAttMap.put( mkey, method );
449 }
450
451
452 Object result = null;
453 try {
454 if( method.getDeclaringClass().isAssignableFrom( this.getClass()) ) {
455 result = method.invoke(this, params );
456 } else {
457 result = method.invoke(resource, params);
458 }
459 } catch (InvocationTargetException e) {
460 Throwable t = e.getTargetException();
461 log.error("Exception invoking method " + name , t );
462 if (t == null)
463 t = e;
464 if (t instanceof RuntimeException)
465 throw new RuntimeOperationsException
466 ((RuntimeException) t, "Exception invoking method " + name);
467 else if (t instanceof Error)
468 throw new RuntimeErrorException
469 ((Error) t, "Error invoking method " + name);
470 else
471 throw new MBeanException
472 ((Exception)t, "Exception invoking method " + name);
473 } catch (Exception e) {
474 log.error("Exception invoking method " + name , e );
475 throw new MBeanException
476 (e, "Exception invoking method " + name);
477 }
478
479
480
481 return (result);
482
483 }
484
485 private Class getAttributeClass(String signature)
486 throws ReflectionException
487 {
488 if (signature.equals(Boolean.TYPE.getName()))
489 return Boolean.TYPE;
490 else if (signature.equals(Byte.TYPE.getName()))
491 return Byte.TYPE;
492 else if (signature.equals(Character.TYPE.getName()))
493 return Character.TYPE;
494 else if (signature.equals(Double.TYPE.getName()))
495 return Double.TYPE;
496 else if (signature.equals(Float.TYPE.getName()))
497 return Float.TYPE;
498 else if (signature.equals(Integer.TYPE.getName()))
499 return Integer.TYPE;
500 else if (signature.equals(Long.TYPE.getName()))
501 return Long.TYPE;
502 else if (signature.equals(Short.TYPE.getName()))
503 return Short.TYPE;
504 else {
505 try {
506 ClassLoader cl=Thread.currentThread().getContextClassLoader();
507 if( cl!=null )
508 return cl.loadClass(signature);
509 } catch( ClassNotFoundException e ) {
510 }
511 try {
512 return Class.forName(signature);
513 } catch (ClassNotFoundException e) {
514 throw new ReflectionException
515 (e, "Cannot find Class for " + signature);
516 }
517 }
518 }
519
520 /***
521 * Set the value of a specific attribute of this MBean.
522 *
523 * @param attribute The identification of the attribute to be set
524 * and the new value
525 *
526 * @exception AttributeNotFoundException if this attribute is not
527 * supported by this MBean
528 * @exception MBeanException if the initializer of an object
529 * throws an exception
530 * @exception ReflectionException if a Java reflection exception
531 * occurs when invoking the getter
532 */
533 public void setAttribute(Attribute attribute)
534 throws AttributeNotFoundException, MBeanException,
535 ReflectionException
536 {
537 if( log.isDebugEnabled() )
538 log.debug("Setting attribute " + this + " " + attribute );
539
540 if( (resource instanceof DynamicMBean) &&
541 ! ( resource instanceof BaseModelMBean )) {
542 try {
543 ((DynamicMBean)resource).setAttribute(attribute);
544 } catch (InvalidAttributeValueException e) {
545 throw new MBeanException(e);
546 }
547 return;
548 }
549
550
551 if (attribute == null)
552 throw new RuntimeOperationsException
553 (new IllegalArgumentException("Attribute is null"),
554 "Attribute is null");
555
556 String name = attribute.getName();
557 Object value = attribute.getValue();
558
559 if (name == null)
560 throw new RuntimeOperationsException
561 (new IllegalArgumentException("Attribute name is null"),
562 "Attribute name is null");
563
564 ModelMBeanAttributeInfo attrInfo=info.getAttribute(name);
565 if (attrInfo == null)
566 throw new AttributeNotFoundException("Cannot find attribute " + name);
567
568 Descriptor attrDesc=attrInfo.getDescriptor();
569 if (attrDesc == null)
570 throw new AttributeNotFoundException("Cannot find attribute " + name + " descriptor");
571
572 Object oldValue=null;
573 if( getAttMap.get(name) != null )
574 oldValue=getAttribute( name );
575
576
577
578 Method m=(Method)setAttMap.get( name );
579
580 if( m==null ) {
581
582 String setMethod = (String) attrDesc.getFieldValue("setMethod");
583 if (setMethod == null)
584 throw new AttributeNotFoundException("Cannot find attribute " + name + " set method name");
585
586 String argType=attrInfo.getType();
587
588 Class signature[] = new Class[] { getAttributeClass( argType ) };
589
590 Object object = null;
591 NoSuchMethodException exception = null;
592 try {
593 object = this;
594 m = object.getClass().getMethod(setMethod, signature);
595 } catch (NoSuchMethodException e) {
596 exception = e;;
597 }
598 if( m== null && resource != null ) {
599 try {
600 object = resource;
601 m = object.getClass().getMethod(setMethod, signature);
602 exception=null;
603 } catch (NoSuchMethodException e) {
604 if( log.isDebugEnabled())
605 log.debug("Method not found in resource " +resource);
606 exception = e;
607 }
608 }
609 if( exception != null )
610 throw new ReflectionException(exception,
611 "Cannot find setter method " + setMethod +
612 " " + resource);
613 setAttMap.put( name, m );
614 }
615
616 Object result = null;
617 try {
618 if( m.getDeclaringClass().isAssignableFrom( this.getClass()) ) {
619 result = m.invoke(this, new Object[] { value });
620 } else {
621 result = m.invoke(resource, new Object[] { value });
622 }
623 } catch (InvocationTargetException e) {
624 Throwable t = e.getTargetException();
625 if (t == null)
626 t = e;
627 if (t instanceof RuntimeException)
628 throw new RuntimeOperationsException
629 ((RuntimeException) t, "Exception invoking method " + name);
630 else if (t instanceof Error)
631 throw new RuntimeErrorException
632 ((Error) t, "Error invoking method " + name);
633 else
634 throw new MBeanException
635 (e, "Exception invoking method " + name);
636 } catch (Exception e) {
637 log.error("Exception invoking method " + name , e );
638 throw new MBeanException
639 (e, "Exception invoking method " + name);
640 }
641 try {
642 sendAttributeChangeNotification(new Attribute( name, oldValue),
643 attribute);
644 } catch(Exception ex) {
645 log.error("Error sending notification " + name, ex);
646 }
647 attributes.put( name, value );
648 if( source != null ) {
649
650 source.updateField(oname, name, value);
651 }
652 }
653
654 public String toString() {
655 if( resource==null )
656 return "BaseModelMbean[" + resourceType + "]";
657 return resource.toString();
658 }
659
660 /***
661 * Set the values of several attributes of this MBean.
662 *
663 * @param attributes THe names and values to be set
664 *
665 * @return The list of attributes that were set and their new values
666 */
667 public AttributeList setAttributes(AttributeList attributes) {
668
669
670 if (attributes == null)
671 throw new RuntimeOperationsException
672 (new IllegalArgumentException("Attributes list is null"),
673 "Attributes list is null");
674
675
676 AttributeList response = new AttributeList();
677 String names[] = new String[attributes.size()];
678 int n = 0;
679 Iterator items = attributes.iterator();
680 while (items.hasNext()) {
681 Attribute item = (Attribute) items.next();
682 names[n++] = item.getName();
683 try {
684 setAttribute(item);
685 } catch (Exception e) {
686 ;
687 }
688 }
689
690 return (getAttributes(names));
691
692 }
693
694
695
696
697
698 /***
699 * Get the instance handle of the object against which we execute
700 * all methods in this ModelMBean management interface.
701 *
702 * @exception InstanceNotFoundException if the managed resource object
703 * cannot be found
704 * @exception MBeanException if the initializer of the object throws
705 * an exception
706 * @exception RuntimeOperationsException if the managed resource or the
707 * resource type is <code>null</code> or invalid
708 */
709 public Object getManagedResource()
710 throws InstanceNotFoundException, InvalidTargetObjectTypeException,
711 MBeanException, RuntimeOperationsException {
712
713 if (resource == null)
714 throw new RuntimeOperationsException
715 (new IllegalArgumentException("Managed resource is null"),
716 "Managed resource is null");
717
718 return resource;
719
720 }
721
722
723 /***
724 * Set the instance handle of the object against which we will execute
725 * all methods in this ModelMBean management interface.
726 *
727 * This method will detect and call "setModelMbean" method. A resource
728 * can implement this method to get a reference to the model mbean.
729 * The reference can be used to send notification and access the
730 * registry.
731 *
732 * @param resource The resource object to be managed
733 * @param type The type of reference for the managed resource
734 * ("ObjectReference", "Handle", "IOR", "EJBHandle", or
735 * "RMIReference")
736 *
737 * @exception InstanceNotFoundException if the managed resource object
738 * cannot be found
739 * @exception InvalidTargetObjectTypeException if this ModelMBean is
740 * asked to handle a reference type it cannot deal with
741 * @exception MBeanException if the initializer of the object throws
742 * an exception
743 * @exception RuntimeOperationsException if the managed resource or the
744 * resource type is <code>null</code> or invalid
745 */
746 public void setManagedResource(Object resource, String type)
747 throws InstanceNotFoundException, InvalidTargetObjectTypeException,
748 MBeanException, RuntimeOperationsException
749 {
750 if (resource == null)
751 throw new RuntimeOperationsException
752 (new IllegalArgumentException("Managed resource is null"),
753 "Managed resource is null");
754
755 if (!"objectreference".equalsIgnoreCase(type))
756 throw new InvalidTargetObjectTypeException(type);
757
758 this.resource = resource;
759 this.resourceType = resource.getClass().getName();
760
761
762 try {
763 Method m=resource.getClass().getMethod("setModelMBean",
764 new Class[] {ModelMBean.class});
765 if( m!= null ) {
766 m.invoke(resource, new Object[] {this});
767 }
768 } catch( NoSuchMethodException t ) {
769
770 } catch( Throwable t ) {
771 log.error( "Can't set model mbean ", t );
772 }
773 }
774
775
776 /***
777 * Initialize the <code>ModelMBeanInfo</code> associated with this
778 * <code>ModelMBean</code>. After the information and associated
779 * descriptors have been customized, the <code>ModelMBean</code> should
780 * be registered with the associated <code>MBeanServer</code>.
781 *
782 * Currently the model can be set after registration. This behavior is
783 * deprecated and won't be supported in future versions.
784 *
785 * @param info The ModelMBeanInfo object to be used by this ModelMBean
786 *
787 * @exception MBeanException If an exception occurs recording this
788 * ModelMBeanInfo information
789 * @exception RuntimeOperations if the specified parameter is
790 * <code>null</code> or invalid
791 */
792 public void setModelMBeanInfo(ModelMBeanInfo info)
793 throws MBeanException, RuntimeOperationsException {
794
795 if (info == null)
796 throw new RuntimeOperationsException
797 (new IllegalArgumentException("ModelMBeanInfo is null"),
798 "ModelMBeanInfo is null");
799
800 if (!isModelMBeanInfoValid(info))
801 throw new RuntimeOperationsException
802 (new IllegalArgumentException("ModelMBeanInfo is invalid"),
803 "ModelMBeanInfo is invalid");
804
805 this.info = (ModelMBeanInfo) info.clone();
806
807 }
808
809
810
811
812
813 /***
814 * Add an attribute change notification event listener to this MBean.
815 *
816 * @param listener Listener that will receive event notifications
817 * @param name Name of the attribute of interest, or <code>null</code>
818 * to indicate interest in all attributes
819 * @param handback Handback object to be sent along with event
820 * notifications
821 *
822 * @exception IllegalArgumentException if the listener parameter is null
823 */
824 public void addAttributeChangeNotificationListener
825 (NotificationListener listener, String name, Object handback)
826 throws IllegalArgumentException {
827
828 if (listener == null)
829 throw new IllegalArgumentException("Listener is null");
830 if (attributeBroadcaster == null)
831 attributeBroadcaster = new BaseNotificationBroadcaster();
832
833 if( log.isDebugEnabled() )
834 log.debug("addAttributeNotificationListener " + listener);
835
836 BaseAttributeFilter filter = new BaseAttributeFilter(name);
837 attributeBroadcaster.addNotificationListener
838 (listener, filter, handback);
839
840 }
841
842
843 /***
844 * Remove an attribute change notification event listener from
845 * this MBean.
846 *
847 * @param listener The listener to be removed
848 * @param name The attribute name for which no more events are required
849 *
850 *
851 * @exception ListenerNotFoundException if this listener is not
852 * registered in the MBean
853 */
854 public void removeAttributeChangeNotificationListener
855 (NotificationListener listener, String name)
856 throws ListenerNotFoundException {
857
858 if (listener == null)
859 throw new IllegalArgumentException("Listener is null");
860 if (attributeBroadcaster == null)
861 attributeBroadcaster = new BaseNotificationBroadcaster();
862
863
864 attributeBroadcaster.removeNotificationListener(listener);
865
866 }
867
868
869 /***
870 * Remove an attribute change notification event listener from
871 * this MBean.
872 *
873 * @param listener The listener to be removed
874 * @param attributeName The attribute name for which no more events are required
875 * @param handback Handback object to be sent along with event
876 * notifications
877 *
878 *
879 * @exception ListenerNotFoundException if this listener is not
880 * registered in the MBean
881 */
882 public void removeAttributeChangeNotificationListener
883 (NotificationListener listener, String attributeName, Object handback)
884 throws ListenerNotFoundException {
885
886 removeAttributeChangeNotificationListener(listener, attributeName);
887
888 }
889
890
891 /***
892 * Send an <code>AttributeChangeNotification</code> to all registered
893 * listeners.
894 *
895 * @param notification The <code>AttributeChangeNotification</code>
896 * that will be passed
897 *
898 * @exception MBeanException if an object initializer throws an
899 * exception
900 * @exception RuntimeOperationsException wraps IllegalArgumentException
901 * when the specified notification is <code>null</code> or invalid
902 */
903 public void sendAttributeChangeNotification
904 (AttributeChangeNotification notification)
905 throws MBeanException, RuntimeOperationsException {
906
907 if (notification == null)
908 throw new RuntimeOperationsException
909 (new IllegalArgumentException("Notification is null"),
910 "Notification is null");
911 if (attributeBroadcaster == null)
912 return;
913 if( log.isDebugEnabled() )
914 log.debug( "AttributeChangeNotification " + notification );
915 attributeBroadcaster.sendNotification(notification);
916
917 }
918
919
920 /***
921 * Send an <code>AttributeChangeNotification</code> to all registered
922 * listeners.
923 *
924 * @param oldValue The original value of the <code>Attribute</code>
925 * @param newValue The new value of the <code>Attribute</code>
926 *
927 * @exception MBeanException if an object initializer throws an
928 * exception
929 * @exception RuntimeOperationsException wraps IllegalArgumentException
930 * when the specified notification is <code>null</code> or invalid
931 */
932 public void sendAttributeChangeNotification
933 (Attribute oldValue, Attribute newValue)
934 throws MBeanException, RuntimeOperationsException {
935
936
937 String type = null;
938 if (newValue.getValue() != null)
939 type = newValue.getValue().getClass().getName();
940 else if (oldValue.getValue() != null)
941 type = oldValue.getValue().getClass().getName();
942 else
943 return;
944
945 AttributeChangeNotification notification =
946 new AttributeChangeNotification
947 (this, 1, System.currentTimeMillis(),
948 "Attribute value has changed",
949 oldValue.getName(), type,
950 oldValue.getValue(), newValue.getValue());
951 sendAttributeChangeNotification(notification);
952
953 }
954
955
956
957
958 /***
959 * Send a <code>Notification</code> to all registered listeners as a
960 * <code>jmx.modelmbean.general</code> notification.
961 *
962 * @param notification The <code>Notification</code> that will be passed
963 *
964 * @exception MBeanException if an object initializer throws an
965 * exception
966 * @exception RuntimeOperationsException wraps IllegalArgumentException
967 * when the specified notification is <code>null</code> or invalid
968 */
969 public void sendNotification(Notification notification)
970 throws MBeanException, RuntimeOperationsException {
971
972 if (notification == null)
973 throw new RuntimeOperationsException
974 (new IllegalArgumentException("Notification is null"),
975 "Notification is null");
976 if (generalBroadcaster == null)
977 return;
978 generalBroadcaster.sendNotification(notification);
979
980 }
981
982
983 /***
984 * Send a <code>Notification</code> which contains the specified string
985 * as a <code>jmx.modelmbean.generic</code> notification.
986 *
987 * @param message The message string to be passed
988 *
989 * @exception MBeanException if an object initializer throws an
990 * exception
991 * @exception RuntimeOperationsException wraps IllegalArgumentException
992 * when the specified notification is <code>null</code> or invalid
993 */
994 public void sendNotification(String message)
995 throws MBeanException, RuntimeOperationsException {
996
997 if (message == null)
998 throw new RuntimeOperationsException
999 (new IllegalArgumentException("Message is null"),
1000 "Message is null");
1001 Notification notification = new Notification
1002 ("jmx.modelmbean.generic", this, 1, message);
1003 sendNotification(notification);
1004
1005 }
1006
1007
1008
1009
1010
1011
1012
1013 /***
1014 * Add a notification event listener to this MBean.
1015 *
1016 * @param listener Listener that will receive event notifications
1017 * @param filter Filter object used to filter event notifications
1018 * actually delivered, or <code>null</code> for no filtering
1019 * @param handback Handback object to be sent along with event
1020 * notifications
1021 *
1022 * @exception IllegalArgumentException if the listener parameter is null
1023 */
1024 public void addNotificationListener(NotificationListener listener,
1025 NotificationFilter filter,
1026 Object handback)
1027 throws IllegalArgumentException {
1028
1029 if (listener == null)
1030 throw new IllegalArgumentException("Listener is null");
1031
1032 if( log.isDebugEnabled() ) log.debug("addNotificationListener " + listener);
1033
1034 if (generalBroadcaster == null)
1035 generalBroadcaster = new BaseNotificationBroadcaster();
1036 generalBroadcaster.addNotificationListener
1037 (listener, filter, handback);
1038
1039
1040
1041
1042
1043 if (attributeBroadcaster == null)
1044 attributeBroadcaster = new BaseNotificationBroadcaster();
1045
1046 if( log.isDebugEnabled() )
1047 log.debug("addAttributeNotificationListener " + listener);
1048
1049 attributeBroadcaster.addNotificationListener
1050 (listener, filter, handback);
1051 }
1052
1053
1054 /***
1055 * Return an <code>MBeanNotificationInfo</code> object describing the
1056 * notifications sent by this MBean.
1057 */
1058 public MBeanNotificationInfo[] getNotificationInfo() {
1059
1060
1061 MBeanNotificationInfo current[] = info.getNotifications();
1062 if (current == null)
1063 current = new MBeanNotificationInfo[0];
1064 MBeanNotificationInfo response[] =
1065 new MBeanNotificationInfo[current.length + 2];
1066 Descriptor descriptor = null;
1067
1068
1069 descriptor = new DescriptorSupport
1070 (new String[] { "name=GENERIC",
1071 "descriptorType=notification",
1072 "log=T",
1073 "severity=5",
1074 "displayName=jmx.modelmbean.generic" });
1075 response[0] = new ModelMBeanNotificationInfo
1076 (new String[] { "jmx.modelmbean.generic" },
1077 "GENERIC",
1078 "Text message notification from the managed resource",
1079 descriptor);
1080
1081
1082 descriptor = new DescriptorSupport
1083 (new String[] { "name=ATTRIBUTE_CHANGE",
1084 "descriptorType=notification",
1085 "log=T",
1086 "severity=5",
1087 "displayName=jmx.attribute.change" });
1088 response[1] = new ModelMBeanNotificationInfo
1089 (new String[] { "jmx.attribute.change" },
1090 "ATTRIBUTE_CHANGE",
1091 "Observed MBean attribute value has changed",
1092 descriptor);
1093
1094
1095 System.arraycopy(current, 0, response, 2, current.length);
1096 return (response);
1097
1098 }
1099
1100
1101 /***
1102 * Remove a notification event listener from this MBean.
1103 *
1104 * @param listener The listener to be removed (any and all registrations
1105 * for this listener will be eliminated)
1106 *
1107 * @exception ListenerNotFoundException if this listener is not
1108 * registered in the MBean
1109 */
1110 public void removeNotificationListener(NotificationListener listener)
1111 throws ListenerNotFoundException {
1112
1113 if (listener == null)
1114 throw new IllegalArgumentException("Listener is null");
1115 if (generalBroadcaster == null)
1116 generalBroadcaster = new BaseNotificationBroadcaster();
1117 generalBroadcaster.removeNotificationListener(listener);
1118
1119
1120 }
1121
1122
1123 /***
1124 * Remove a notification event listener from this MBean.
1125 *
1126 * @param listener The listener to be removed (any and all registrations
1127 * for this listener will be eliminated)
1128 * @param handback Handback object to be sent along with event
1129 * notifications
1130 *
1131 * @exception ListenerNotFoundException if this listener is not
1132 * registered in the MBean
1133 */
1134 public void removeNotificationListener(NotificationListener listener,
1135 Object handback)
1136 throws ListenerNotFoundException {
1137
1138 removeNotificationListener(listener);
1139
1140 }
1141
1142
1143 /***
1144 * Remove a notification event listener from this MBean.
1145 *
1146 * @param listener The listener to be removed (any and all registrations
1147 * for this listener will be eliminated)
1148 * @param filter Filter object used to filter event notifications
1149 * actually delivered, or <code>null</code> for no filtering
1150 * @param handback Handback object to be sent along with event
1151 * notifications
1152 *
1153 * @exception ListenerNotFoundException if this listener is not
1154 * registered in the MBean
1155 */
1156 public void removeNotificationListener(NotificationListener listener,
1157 NotificationFilter filter,
1158 Object handback)
1159 throws ListenerNotFoundException {
1160
1161 removeNotificationListener(listener);
1162
1163 }
1164
1165
1166
1167
1168
1169 /***
1170 * Instantiates this MBean instance from data found in the persistent
1171 * store. The data loaded could include attribute and operation values.
1172 * This method should be called during construction or initialization
1173 * of the instance, and before the MBean is registered with the
1174 * <code>MBeanServer</code>.
1175 *
1176 * <p><strong>IMPLEMENTATION NOTE</strong> - This implementation does
1177 * not support persistence.</p>
1178 *
1179 * @exception InstanceNotFoundException if the managed resource object
1180 * cannot be found
1181 * @exception MBeanException if the initializer of the object throws
1182 * an exception
1183 * @exception RuntimeOperationsException if an exception is reported
1184 * by the persistence mechanism
1185 */
1186 public void load() throws InstanceNotFoundException,
1187 MBeanException, RuntimeOperationsException {
1188
1189 throw new MBeanException
1190 (new IllegalStateException("Persistence is not supported"),
1191 "Persistence is not supported");
1192
1193 }
1194
1195
1196 /***
1197 * Capture the current state of this MBean instance and write it out
1198 * to the persistent store. The state stored could include attribute
1199 * and operation values. If one of these methods of persistence is not
1200 * supported, a "service not found" exception will be thrown.
1201 *
1202 * <p><strong>IMPLEMENTATION NOTE</strong> - This implementation does
1203 * not support persistence.</p>
1204 *
1205 * @exception InstanceNotFoundException if the managed resource object
1206 * cannot be found
1207 * @exception MBeanException if the initializer of the object throws
1208 * an exception, or persistence is not supported
1209 * @exception RuntimeOperationsException if an exception is reported
1210 * by the persistence mechanism
1211 */
1212 public void store() throws InstanceNotFoundException,
1213 MBeanException, RuntimeOperationsException {
1214
1215
1216 throw new MBeanException
1217 (new IllegalStateException("Persistence is not supported"),
1218 "Persistence is not supported");
1219
1220 }
1221
1222
1223
1224 /*** Set the type of the mbean. This is used as a key to locate
1225 * the description in the Registry.
1226 *
1227 * @param type the type of classname of the modeled object
1228 */
1229 public void setModeledType( String type ) {
1230 initModelInfo(type);
1231 createResource();
1232 }
1233 /*** Set the type of the mbean. This is used as a key to locate
1234 * the description in the Registry.
1235 *
1236 * @param type the type of classname of the modeled object
1237 */
1238 protected void initModelInfo( String type ) {
1239 try {
1240 if( log.isDebugEnabled())
1241 log.debug("setModeledType " + type);
1242
1243 log.debug( "Set model Info " + type);
1244 if(type==null) {
1245 return;
1246 }
1247 resourceType=type;
1248
1249 Class c=null;
1250 try {
1251 c=Class.forName( type);
1252 } catch( Throwable t ) {
1253 log.debug( "Error creating class " + t);
1254 }
1255
1256
1257 ManagedBean descriptor=getRegistry().findManagedBean(c, type);
1258 if( descriptor==null )
1259 return;
1260 this.setModelMBeanInfo(descriptor.createMBeanInfo());
1261 } catch( Throwable ex) {
1262 log.error( "TCL: " + Thread.currentThread().getContextClassLoader(),
1263 ex);
1264 }
1265 }
1266
1267 /*** Set the type of the mbean. This is used as a key to locate
1268 * the description in the Registry.
1269 */
1270 protected void createResource() {
1271 try {
1272
1273 Class c=null;
1274 try {
1275 c=Class.forName( resourceType );
1276 resource = c.newInstance();
1277 } catch( Throwable t ) {
1278 log.error( "Error creating class " + t);
1279 }
1280 } catch( Throwable ex) {
1281 log.error( "TCL: " + Thread.currentThread().getContextClassLoader(),
1282 ex);
1283 }
1284 }
1285
1286
1287 public String getModelerType() {
1288 return resourceType;
1289 }
1290
1291 public String getClassName() {
1292 return getModelerType();
1293 }
1294
1295 public ObjectName getJmxName() {
1296 return oname;
1297 }
1298
1299 public String getObjectName() {
1300 if (oname != null) {
1301 return oname.toString();
1302 } else {
1303 return null;
1304 }
1305 }
1306
1307 public void setRegistry(Registry registry) {
1308 this.registry = registry;
1309 }
1310
1311 public Registry getRegistry() {
1312
1313 if( registry == null )
1314 registry=Registry.getRegistry();
1315
1316 return registry;
1317 }
1318
1319
1320
1321
1322 /***
1323 * Create and return a default <code>ModelMBeanInfo</code> object.
1324 */
1325 protected ModelMBeanInfo createDefaultModelMBeanInfo() {
1326
1327 return (new ModelMBeanInfoSupport(this.getClass().getName(),
1328 "Default ModelMBean",
1329 null, null, null, null));
1330
1331 }
1332
1333 /***
1334 * Is the specified <code>ModelMBeanInfo</code> instance valid?
1335 *
1336 * <p><strong>IMPLEMENTATION NOTE</strong> - This implementation
1337 * does not check anything, but this method can be overridden
1338 * as required.</p>
1339 *
1340 * @param info The <code>ModelMBeanInfo object to check
1341 */
1342 protected boolean isModelMBeanInfoValid(ModelMBeanInfo info) {
1343 return (true);
1344 }
1345
1346
1347
1348
1349
1350 public ObjectName preRegister(MBeanServer server,
1351 ObjectName name)
1352 throws Exception
1353 {
1354 if( log.isDebugEnabled())
1355 log.debug("preRegister " + resource + " " + name );
1356 oname=name;
1357 if( resource instanceof MBeanRegistration ) {
1358 oname = ((MBeanRegistration)resource).preRegister(server, name );
1359 }
1360 return oname;
1361 }
1362
1363 public void postRegister(Boolean registrationDone) {
1364 if( resource instanceof MBeanRegistration ) {
1365 ((MBeanRegistration)resource).postRegister(registrationDone);
1366 }
1367 }
1368
1369 public void preDeregister() throws Exception {
1370 if( resource instanceof MBeanRegistration ) {
1371 ((MBeanRegistration)resource).preDeregister();
1372 }
1373 }
1374
1375 public void postDeregister() {
1376 if( resource instanceof MBeanRegistration ) {
1377 ((MBeanRegistration)resource).postDeregister();
1378 }
1379 }
1380
1381 static class MethodKey {
1382 private String name;
1383 private String[] signature;
1384
1385 MethodKey(String name, String[] signature) {
1386 this.name = name;
1387 if(signature == null) {
1388 signature = new String[0];
1389 }
1390 this.signature = signature;
1391 }
1392
1393 public boolean equals(Object other) {
1394 if(!(other instanceof MethodKey)) {
1395 return false;
1396 }
1397 MethodKey omk = (MethodKey)other;
1398 if(!name.equals(omk.name)) {
1399 return false;
1400 }
1401 if(signature.length != omk.signature.length) {
1402 return false;
1403 }
1404 for(int i=0; i < signature.length; i++) {
1405 if(!signature[i].equals(omk.signature[i])) {
1406 return false;
1407 }
1408 }
1409 return true;
1410 }
1411
1412 public int hashCode() {
1413 return name.hashCode();
1414 }
1415 }
1416 }