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