1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18
19 package org.apache.tomcat.util.modeler;
20
21
22 import java.lang.reflect.InvocationTargetException;
23 import java.lang.reflect.Method;
24 import java.util.Iterator;
25
26 import javax.management.Attribute;
27 import javax.management.AttributeChangeNotification;
28 import javax.management.AttributeList;
29 import javax.management.AttributeNotFoundException;
30 import javax.management.DynamicMBean;
31 import javax.management.InstanceNotFoundException;
32 import javax.management.InvalidAttributeValueException;
33 import javax.management.ListenerNotFoundException;
34 import javax.management.MBeanException;
35 import javax.management.MBeanInfo;
36 import javax.management.MBeanNotificationInfo;
37 import javax.management.MBeanRegistration;
38 import javax.management.MBeanServer;
39 import javax.management.Notification;
40 import javax.management.NotificationFilter;
41 import javax.management.NotificationListener;
42 import javax.management.ObjectName;
43 import javax.management.ReflectionException;
44 import javax.management.RuntimeErrorException;
45 import javax.management.RuntimeOperationsException;
46 import javax.management.modelmbean.InvalidTargetObjectTypeException;
47 import javax.management.modelmbean.ModelMBeanNotificationBroadcaster;
48
49 import org.apache.juli.logging.Log;
50 import org.apache.juli.logging.LogFactory;
51 import org.apache.tomcat.util.res.StringManager;
52
53 /*
54 * Changes from commons.modeler:
55 *
56 * - use DynamicMBean
57 * - remove methods not used in tomcat and redundant/not very generic
58 * - must be created from the ManagedBean - I don't think there were any direct
59 * uses, but now it is required.
60 * - some of the gratuitous flexibility removed - instead this is more predictive and
61 * strict with the use cases.
62 * - all Method and metadata is stored in ManagedBean. BaseModelBMean and ManagedBean act
63 * like Object and Class.
64 * - setModelMBean is no longer called on resources ( not used in tomcat )
65 * - no caching of Methods for now - operations and setters are not called repeatedly in most
66 * management use cases. Getters shouldn't be called very frequently either - and even if they
67 * are, the overhead of getting the method should be small compared with other JMX costs ( RMI, etc ).
68 * We can add getter cache if needed.
69 * - removed unused constructor, fields
70 *
71 * TODO:
72 * - clean up catalina.mbeans, stop using weird inheritance
73 */
74
75 /**
76 * <p>Basic implementation of the <code>DynamicMBean</code> interface, which
77 * supports the minimal requirements of the interface contract.</p>
78 *
79 * <p>This can be used directly to wrap an existing java bean, or inside
80 * an mlet or anywhere an MBean would be used.
81 *
82 * Limitations:
83 * <ul>
84 * <li>Only managed resources of type <code>objectReference</code> are
85 * supported.</li>
86 * <li>Caching of attribute values and operation results is not supported.
87 * All calls to <code>invoke()</code> are immediately executed.</li>
88 * <li>Persistence of MBean attributes and operations is not supported.</li>
89 * <li>All classes referenced as attribute types, operation parameters, or
90 * operation return values must be one of the following:
91 * <ul>
92 * <li>One of the Java primitive types (boolean, byte, char, double,
93 * float, integer, long, short). Corresponding value will be wrapped
94 * in the appropriate wrapper class automatically.</li>
95 * <li>Operations that return no value should declare a return type of
96 * <code>void</code>.</li>
97 * </ul>
98 * <li>Attribute caching is not supported</li>
99 * </ul>
100 *
101 * @author Craig R. McClanahan
102 * @author Costin Manolache
103 */
104 public class BaseModelMBean implements DynamicMBean, MBeanRegistration,
105 ModelMBeanNotificationBroadcaster {
106
107 private static final Log log = LogFactory.getLog(BaseModelMBean.class);
108 private static final StringManager sm = StringManager.getManager(BaseModelMBean.class);
109
110 // ----------------------------------------------------- Instance Variables
111
112 protected ObjectName oname=null;
113
114 /**
115 * Notification broadcaster for attribute changes.
116 */
117 protected BaseNotificationBroadcaster attributeBroadcaster = null;
118
119 /**
120 * Notification broadcaster for general notifications.
121 */
122 protected BaseNotificationBroadcaster generalBroadcaster = null;
123
124 /** Metadata for the mbean instance.
125 */
126 protected ManagedBean managedBean = null;
127
128 /**
129 * The managed resource this MBean is associated with (if any).
130 */
131 protected Object resource = null;
132
133 // --------------------------------------------------- DynamicMBean Methods
134 // TODO: move to ManagedBean
135 static final Object[] NO_ARGS_PARAM = new Object[0];
136
137 protected String resourceType = null;
138
139 // key: operation val: invoke method
140 //private Hashtable invokeAttMap=new Hashtable();
141
142 /**
143 * Obtain and return the value of a specific attribute of this MBean.
144 *
145 * @param name Name of the requested attribute
146 *
147 * @exception AttributeNotFoundException if this attribute is not
148 * supported by this MBean
149 * @exception MBeanException if the initializer of an object
150 * throws an exception
151 * @exception ReflectionException if a Java reflection exception
152 * occurs when invoking the getter
153 */
154 @Override
155 public Object getAttribute(String name)
156 throws AttributeNotFoundException, MBeanException,
157 ReflectionException {
158 // Validate the input parameters
159 if (name == null)
160 throw new RuntimeOperationsException
161 (new IllegalArgumentException(sm.getString("baseModelMBean.nullAttributeName")),
162 sm.getString("baseModelMBean.nullAttributeName"));
163
164 if( (resource instanceof DynamicMBean) &&
165 ! ( resource instanceof BaseModelMBean )) {
166 return ((DynamicMBean)resource).getAttribute(name);
167 }
168
169 Method m=managedBean.getGetter(name, this, resource);
170 Object result = null;
171 try {
172 Class<?> declaring = m.getDeclaringClass();
173 // workaround for catalina weird mbeans - the declaring class is BaseModelMBean.
174 // but this is the catalina class.
175 if( declaring.isAssignableFrom(this.getClass()) ) {
176 result = m.invoke(this, NO_ARGS_PARAM );
177 } else {
178 result = m.invoke(resource, NO_ARGS_PARAM );
179 }
180 } catch (InvocationTargetException e) {
181 Throwable t = e.getTargetException();
182 if (t == null)
183 t = e;
184 if (t instanceof RuntimeException)
185 throw new RuntimeOperationsException
186 ((RuntimeException) t, sm.getString("baseModelMBean.invokeError", name));
187 else if (t instanceof Error)
188 throw new RuntimeErrorException
189 ((Error) t, sm.getString("baseModelMBean.invokeError", name));
190 else
191 throw new MBeanException
192 (e, sm.getString("baseModelMBean.invokeError", name));
193 } catch (Exception e) {
194 throw new MBeanException
195 (e, sm.getString("baseModelMBean.invokeError", name));
196 }
197
198 // Return the results of this method invocation
199 // FIXME - should we validate the return type?
200 return result;
201 }
202
203
204 /**
205 * Obtain and return the values of several attributes of this MBean.
206 *
207 * @param names Names of the requested attributes
208 */
209 @Override
210 public AttributeList getAttributes(String names[]) {
211
212 // Validate the input parameters
213 if (names == null)
214 throw new RuntimeOperationsException
215 (new IllegalArgumentException(sm.getString("baseModelMBean.nullAttributeNameList")),
216 sm.getString("baseModelMBean.nullAttributeNameList"));
217
218 // Prepare our response, eating all exceptions
219 AttributeList response = new AttributeList();
220 for (int i = 0; i < names.length; i++) {
221 try {
222 response.add(new Attribute(names[i],getAttribute(names[i])));
223 } catch (Exception e) {
224 // Not having a particular attribute in the response
225 // is the indication of a getter problem
226 }
227 }
228 return response;
229
230 }
231
232 public void setManagedBean(ManagedBean managedBean) {
233 this.managedBean = managedBean;
234 }
235
236 /**
237 * Return the <code>MBeanInfo</code> object for this MBean.
238 */
239 @Override
240 public MBeanInfo getMBeanInfo() {
241 return managedBean.getMBeanInfo();
242 }
243
244
245 /**
246 * Invoke a particular method on this MBean, and return any returned
247 * value.
248 *
249 * <p><strong>IMPLEMENTATION NOTE</strong> - This implementation will
250 * attempt to invoke this method on the MBean itself, or (if not
251 * available) on the managed resource object associated with this
252 * MBean.</p>
253 *
254 * @param name Name of the operation to be invoked
255 * @param params Array containing the method parameters of this operation
256 * @param signature Array containing the class names representing
257 * the signature of this operation
258 *
259 * @exception MBeanException if the initializer of an object
260 * throws an exception
261 * @exception ReflectionException if a Java reflection exception
262 * occurs when invoking a method
263 */
264 @Override
265 public Object invoke(String name, Object params[], String signature[])
266 throws MBeanException, ReflectionException
267 {
268 if( (resource instanceof DynamicMBean) &&
269 ! ( resource instanceof BaseModelMBean )) {
270 return ((DynamicMBean)resource).invoke(name, params, signature);
271 }
272
273 // Validate the input parameters
274 if (name == null)
275 throw new RuntimeOperationsException
276 (new IllegalArgumentException(sm.getString("baseModelMBean.nullMethodName")),
277 sm.getString("baseModelMBean.nullMethodName"));
278
279 if( log.isDebugEnabled()) log.debug("Invoke " + name);
280
281 Method method= managedBean.getInvoke(name, params, signature, this, resource);
282
283 // Invoke the selected method on the appropriate object
284 Object result = null;
285 try {
286 if( method.getDeclaringClass().isAssignableFrom( this.getClass()) ) {
287 result = method.invoke(this, params );
288 } else {
289 result = method.invoke(resource, params);
290 }
291 } catch (InvocationTargetException e) {
292 Throwable t = e.getTargetException();
293 log.error(sm.getString("baseModelMBean.invokeError", name), t );
294 if (t == null)
295 t = e;
296 if (t instanceof RuntimeException)
297 throw new RuntimeOperationsException
298 ((RuntimeException) t, sm.getString("baseModelMBean.invokeError", name));
299 else if (t instanceof Error)
300 throw new RuntimeErrorException
301 ((Error) t, sm.getString("baseModelMBean.invokeError", name));
302 else
303 throw new MBeanException
304 ((Exception)t, sm.getString("baseModelMBean.invokeError", name));
305 } catch (Exception e) {
306 log.error(sm.getString("baseModelMBean.invokeError", name), e );
307 throw new MBeanException
308 (e, sm.getString("baseModelMBean.invokeError", name));
309 }
310
311 // Return the results of this method invocation
312 // FIXME - should we validate the return type?
313 return result;
314
315 }
316
317 static Class<?> getAttributeClass(String signature)
318 throws ReflectionException
319 {
320 if (signature.equals(Boolean.TYPE.getName()))
321 return Boolean.TYPE;
322 else if (signature.equals(Byte.TYPE.getName()))
323 return Byte.TYPE;
324 else if (signature.equals(Character.TYPE.getName()))
325 return Character.TYPE;
326 else if (signature.equals(Double.TYPE.getName()))
327 return Double.TYPE;
328 else if (signature.equals(Float.TYPE.getName()))
329 return Float.TYPE;
330 else if (signature.equals(Integer.TYPE.getName()))
331 return Integer.TYPE;
332 else if (signature.equals(Long.TYPE.getName()))
333 return Long.TYPE;
334 else if (signature.equals(Short.TYPE.getName()))
335 return Short.TYPE;
336 else {
337 try {
338 ClassLoader cl=Thread.currentThread().getContextClassLoader();
339 if( cl!=null )
340 return cl.loadClass(signature);
341 } catch( ClassNotFoundException e ) {
342 }
343 try {
344 return Class.forName(signature);
345 } catch (ClassNotFoundException e) {
346 throw new ReflectionException(e, sm.getString("baseModelMBean.cnfeForSignature", signature));
347 }
348 }
349 }
350
351 /**
352 * Set the value of a specific attribute of this MBean.
353 *
354 * @param attribute The identification of the attribute to be set
355 * and the new value
356 *
357 * @exception AttributeNotFoundException if this attribute is not
358 * supported by this MBean
359 * @exception MBeanException if the initializer of an object
360 * throws an exception
361 * @exception ReflectionException if a Java reflection exception
362 * occurs when invoking the getter
363 */
364 @Override
365 public void setAttribute(Attribute attribute)
366 throws AttributeNotFoundException, MBeanException,
367 ReflectionException
368 {
369 if( log.isDebugEnabled() )
370 log.debug("Setting attribute " + this + " " + attribute );
371
372 if( (resource instanceof DynamicMBean) &&
373 ! ( resource instanceof BaseModelMBean )) {
374 try {
375 ((DynamicMBean)resource).setAttribute(attribute);
376 } catch (InvalidAttributeValueException e) {
377 throw new MBeanException(e);
378 }
379 return;
380 }
381
382 // Validate the input parameters
383 if (attribute == null)
384 throw new RuntimeOperationsException
385 (new IllegalArgumentException(sm.getString("baseModelMBean.nullAttribute")),
386 sm.getString("baseModelMBean.nullAttribute"));
387
388 String name = attribute.getName();
389 Object value = attribute.getValue();
390
391 if (name == null)
392 throw new RuntimeOperationsException
393 (new IllegalArgumentException(sm.getString("baseModelMBean.nullAttributeName")),
394 sm.getString("baseModelMBean.nullAttributeName"));
395
396 Object oldValue=null;
397 //if( getAttMap.get(name) != null )
398 // oldValue=getAttribute( name );
399
400 Method m=managedBean.getSetter(name,this,resource);
401
402 try {
403 if( m.getDeclaringClass().isAssignableFrom( this.getClass()) ) {
404 m.invoke(this, new Object[] { value });
405 } else {
406 m.invoke(resource, new Object[] { value });
407 }
408 } catch (InvocationTargetException e) {
409 Throwable t = e.getTargetException();
410 if (t == null)
411 t = e;
412 if (t instanceof RuntimeException)
413 throw new RuntimeOperationsException
414 ((RuntimeException) t, sm.getString("baseModelMBean.invokeError", name));
415 else if (t instanceof Error)
416 throw new RuntimeErrorException
417 ((Error) t, sm.getString("baseModelMBean.invokeError", name));
418 else
419 throw new MBeanException
420 (e, sm.getString("baseModelMBean.invokeError", name));
421 } catch (Exception e) {
422 log.error(sm.getString("baseModelMBean.invokeError", name) , e );
423 throw new MBeanException
424 (e, sm.getString("baseModelMBean.invokeError", name));
425 }
426 try {
427 sendAttributeChangeNotification(new Attribute( name, oldValue),
428 attribute);
429 } catch(Exception ex) {
430 log.error(sm.getString("baseModelMBean.notificationError", name), ex);
431 }
432 //attributes.put( name, value );
433 // if( source != null ) {
434 // // this mbean is associated with a source - maybe we want to persist
435 // source.updateField(oname, name, value);
436 // }
437 }
438
439 @Override
440 public String toString() {
441 if( resource==null )
442 return "BaseModelMbean[" + resourceType + "]";
443 return resource.toString();
444 }
445
446 /**
447 * Set the values of several attributes of this MBean.
448 *
449 * @param attributes THe names and values to be set
450 *
451 * @return The list of attributes that were set and their new values
452 */
453 @Override
454 public AttributeList setAttributes(AttributeList attributes) {
455 AttributeList response = new AttributeList();
456
457 // Validate the input parameters
458 if (attributes == null)
459 return response;
460
461 // Prepare and return our response, eating all exceptions
462 String names[] = new String[attributes.size()];
463 int n = 0;
464 Iterator<?> items = attributes.iterator();
465 while (items.hasNext()) {
466 Attribute item = (Attribute) items.next();
467 names[n++] = item.getName();
468 try {
469 setAttribute(item);
470 } catch (Exception e) {
471 // Ignore all exceptions
472 }
473 }
474
475 return getAttributes(names);
476
477 }
478
479
480 // ----------------------------------------------------- ModelMBean Methods
481
482
483 /**
484 * Get the instance handle of the object against which we execute
485 * all methods in this ModelMBean management interface.
486 *
487 * @return the backend managed object
488 * @exception InstanceNotFoundException if the managed resource object
489 * cannot be found
490 * @exception InvalidTargetObjectTypeException if the managed resource
491 * object is of the wrong type
492 * @exception MBeanException if the initializer of the object throws
493 * an exception
494 * @exception RuntimeOperationsException if the managed resource or the
495 * resource type is <code>null</code> or invalid
496 */
497 public Object getManagedResource()
498 throws InstanceNotFoundException, InvalidTargetObjectTypeException,
499 MBeanException, RuntimeOperationsException {
500
501 if (resource == null)
502 throw new RuntimeOperationsException
503 (new IllegalArgumentException(sm.getString("baseModelMBean.nullResource")),
504 sm.getString("baseModelMBean.nullResource"));
505
506 return resource;
507
508 }
509
510
511 /**
512 * Set the instance handle of the object against which we will execute
513 * all methods in this ModelMBean management interface.
514 *
515 * The caller can provide the mbean instance or the object name to
516 * the resource, if needed.
517 *
518 * @param resource The resource object to be managed
519 * @param type The type of reference for the managed resource
520 * ("ObjectReference", "Handle", "IOR", "EJBHandle", or
521 * "RMIReference")
522 *
523 * @exception InstanceNotFoundException if the managed resource object
524 * cannot be found
525 * @exception MBeanException if the initializer of the object throws
526 * an exception
527 * @exception RuntimeOperationsException if the managed resource or the
528 * resource type is <code>null</code> or invalid
529 */
530 public void setManagedResource(Object resource, String type)
531 throws InstanceNotFoundException,
532 MBeanException, RuntimeOperationsException
533 {
534 if (resource == null)
535 throw new RuntimeOperationsException
536 (new IllegalArgumentException(sm.getString("baseModelMBean.nullResource")),
537 sm.getString("baseModelMBean.nullResource"));
538
539 // if (!"objectreference".equalsIgnoreCase(type))
540 // throw new InvalidTargetObjectTypeException(type);
541
542 this.resource = resource;
543 this.resourceType = resource.getClass().getName();
544
545 // // Make the resource aware of the model mbean.
546 // try {
547 // Method m=resource.getClass().getMethod("setModelMBean",
548 // new Class[] {ModelMBean.class});
549 // if( m!= null ) {
550 // m.invoke(resource, new Object[] {this});
551 // }
552 // } catch( NoSuchMethodException t ) {
553 // // ignore
554 // } catch( Throwable t ) {
555 // log.error( "Can't set model mbean ", t );
556 // }
557 }
558
559
560 // ------------------------------ ModelMBeanNotificationBroadcaster Methods
561
562
563 /**
564 * Add an attribute change notification event listener to this MBean.
565 *
566 * @param listener Listener that will receive event notifications
567 * @param name Name of the attribute of interest, or <code>null</code>
568 * to indicate interest in all attributes
569 * @param handback Handback object to be sent along with event
570 * notifications
571 *
572 * @exception IllegalArgumentException if the listener parameter is null
573 */
574 @Override
575 public void addAttributeChangeNotificationListener
576 (NotificationListener listener, String name, Object handback)
577 throws IllegalArgumentException {
578
579 if (listener == null)
580 throw new IllegalArgumentException(sm.getString("baseModelMBean.nullListener"));
581 if (attributeBroadcaster == null)
582 attributeBroadcaster = new BaseNotificationBroadcaster();
583
584 if( log.isDebugEnabled() )
585 log.debug("addAttributeNotificationListener " + listener);
586
587 BaseAttributeFilter filter = new BaseAttributeFilter(name);
588 attributeBroadcaster.addNotificationListener
589 (listener, filter, handback);
590
591 }
592
593
594 /**
595 * Remove an attribute change notification event listener from
596 * this MBean.
597 *
598 * @param listener The listener to be removed
599 * @param name The attribute name for which no more events are required
600 *
601 *
602 * @exception ListenerNotFoundException if this listener is not
603 * registered in the MBean
604 */
605 @Override
606 public void removeAttributeChangeNotificationListener
607 (NotificationListener listener, String name)
608 throws ListenerNotFoundException {
609
610 if (listener == null)
611 throw new IllegalArgumentException(sm.getString("baseModelMBean.nullListener"));
612
613 // FIXME - currently this removes *all* notifications for this listener
614 if (attributeBroadcaster != null) {
615 attributeBroadcaster.removeNotificationListener(listener);
616 }
617
618 }
619
620
621 /**
622 * Send an <code>AttributeChangeNotification</code> to all registered
623 * listeners.
624 *
625 * @param notification The <code>AttributeChangeNotification</code>
626 * that will be passed
627 *
628 * @exception MBeanException if an object initializer throws an
629 * exception
630 * @exception RuntimeOperationsException wraps IllegalArgumentException
631 * when the specified notification is <code>null</code> or invalid
632 */
633 @Override
634 public void sendAttributeChangeNotification
635 (AttributeChangeNotification notification)
636 throws MBeanException, RuntimeOperationsException {
637
638 if (notification == null)
639 throw new RuntimeOperationsException
640 (new IllegalArgumentException(sm.getString("baseModelMBean.nullNotification")),
641 sm.getString("baseModelMBean.nullNotification"));
642 if (attributeBroadcaster == null)
643 return; // This means there are no registered listeners
644 if( log.isDebugEnabled() )
645 log.debug( "AttributeChangeNotification " + notification );
646 attributeBroadcaster.sendNotification(notification);
647
648 }
649
650
651 /**
652 * Send an <code>AttributeChangeNotification</code> to all registered
653 * listeners.
654 *
655 * @param oldValue The original value of the <code>Attribute</code>
656 * @param newValue The new value of the <code>Attribute</code>
657 *
658 * @exception MBeanException if an object initializer throws an
659 * exception
660 * @exception RuntimeOperationsException wraps IllegalArgumentException
661 * when the specified notification is <code>null</code> or invalid
662 */
663 @Override
664 public void sendAttributeChangeNotification
665 (Attribute oldValue, Attribute newValue)
666 throws MBeanException, RuntimeOperationsException {
667
668 // Calculate the class name for the change notification
669 String type = null;
670 if (newValue.getValue() != null)
671 type = newValue.getValue().getClass().getName();
672 else if (oldValue.getValue() != null)
673 type = oldValue.getValue().getClass().getName();
674 else
675 return; // Old and new are both null == no change
676
677 AttributeChangeNotification notification =
678 new AttributeChangeNotification
679 (this, 1, System.currentTimeMillis(),
680 "Attribute value has changed",
681 oldValue.getName(), type,
682 oldValue.getValue(), newValue.getValue());
683 sendAttributeChangeNotification(notification);
684
685 }
686
687
688 /**
689 * Send a <code>Notification</code> to all registered listeners as a
690 * <code>jmx.modelmbean.general</code> notification.
691 *
692 * @param notification The <code>Notification</code> that will be passed
693 *
694 * @exception MBeanException if an object initializer throws an
695 * exception
696 * @exception RuntimeOperationsException wraps IllegalArgumentException
697 * when the specified notification is <code>null</code> or invalid
698 */
699 @Override
700 public void sendNotification(Notification notification)
701 throws MBeanException, RuntimeOperationsException {
702
703 if (notification == null)
704 throw new RuntimeOperationsException
705 (new IllegalArgumentException(sm.getString("baseModelMBean.nullNotification")),
706 sm.getString("baseModelMBean.nullNotification"));
707 if (generalBroadcaster == null)
708 return; // This means there are no registered listeners
709 generalBroadcaster.sendNotification(notification);
710
711 }
712
713
714 /**
715 * Send a <code>Notification</code> which contains the specified string
716 * as a <code>jmx.modelmbean.generic</code> notification.
717 *
718 * @param message The message string to be passed
719 *
720 * @exception MBeanException if an object initializer throws an
721 * exception
722 * @exception RuntimeOperationsException wraps IllegalArgumentException
723 * when the specified notification is <code>null</code> or invalid
724 */
725 @Override
726 public void sendNotification(String message)
727 throws MBeanException, RuntimeOperationsException {
728
729 if (message == null)
730 throw new RuntimeOperationsException
731 (new IllegalArgumentException(sm.getString("baseModelMBean.nullMessage")),
732 sm.getString("baseModelMBean.nullMessage"));
733 Notification notification = new Notification
734 ("jmx.modelmbean.generic", this, 1, message);
735 sendNotification(notification);
736
737 }
738
739
740 // ---------------------------------------- NotificationBroadcaster Methods
741
742
743 /**
744 * Add a notification event listener to this MBean.
745 *
746 * @param listener Listener that will receive event notifications
747 * @param filter Filter object used to filter event notifications
748 * actually delivered, or <code>null</code> for no filtering
749 * @param handback Handback object to be sent along with event
750 * notifications
751 *
752 * @exception IllegalArgumentException if the listener parameter is null
753 */
754 @Override
755 public void addNotificationListener(NotificationListener listener,
756 NotificationFilter filter,
757 Object handback)
758 throws IllegalArgumentException {
759
760 if (listener == null)
761 throw new IllegalArgumentException(sm.getString("baseModelMBean.nullListener"));
762
763 if( log.isDebugEnabled() ) log.debug("addNotificationListener " + listener);
764
765 if (generalBroadcaster == null)
766 generalBroadcaster = new BaseNotificationBroadcaster();
767 generalBroadcaster.addNotificationListener
768 (listener, filter, handback);
769
770 // We'll send the attribute change notifications to all listeners ( who care )
771 // The normal filtering can be used.
772 // The problem is that there is no other way to add attribute change listeners
773 // to a model mbean ( AFAIK ). I suppose the spec should be fixed.
774 if (attributeBroadcaster == null)
775 attributeBroadcaster = new BaseNotificationBroadcaster();
776
777 if( log.isDebugEnabled() )
778 log.debug("addAttributeNotificationListener " + listener);
779
780 attributeBroadcaster.addNotificationListener
781 (listener, filter, handback);
782 }
783
784
785 /**
786 * Return an <code>MBeanNotificationInfo</code> object describing the
787 * notifications sent by this MBean.
788 */
789 @Override
790 public MBeanNotificationInfo[] getNotificationInfo() {
791
792 // Acquire the set of application notifications
793 MBeanNotificationInfo current[] = getMBeanInfo().getNotifications();
794 MBeanNotificationInfo response[] =
795 new MBeanNotificationInfo[current.length + 2];
796 // Descriptor descriptor = null;
797
798 // Fill in entry for general notifications
799 // descriptor = new DescriptorSupport
800 // (new String[] { "name=GENERIC",
801 // "descriptorType=notification",
802 // "log=T",
803 // "severity=5",
804 // "displayName=jmx.modelmbean.generic" });
805 response[0] = new MBeanNotificationInfo
806 (new String[] { "jmx.modelmbean.generic" },
807 "GENERIC",
808 "Text message notification from the managed resource");
809 //descriptor);
810
811 // Fill in entry for attribute change notifications
812 // descriptor = new DescriptorSupport
813 // (new String[] { "name=ATTRIBUTE_CHANGE",
814 // "descriptorType=notification",
815 // "log=T",
816 // "severity=5",
817 // "displayName=jmx.attribute.change" });
818 response[1] = new MBeanNotificationInfo
819 (new String[] { "jmx.attribute.change" },
820 "ATTRIBUTE_CHANGE",
821 "Observed MBean attribute value has changed");
822 //descriptor);
823
824 // Copy remaining notifications as reported by the application
825 System.arraycopy(current, 0, response, 2, current.length);
826 return response;
827
828 }
829
830
831 /**
832 * Remove a notification event listener from this MBean.
833 *
834 * @param listener The listener to be removed (any and all registrations
835 * for this listener will be eliminated)
836 *
837 * @exception ListenerNotFoundException if this listener is not
838 * registered in the MBean
839 */
840 @Override
841 public void removeNotificationListener(NotificationListener listener)
842 throws ListenerNotFoundException {
843
844 if (listener == null)
845 throw new IllegalArgumentException(sm.getString("baseModelMBean.nullListener"));
846
847 if (generalBroadcaster != null) {
848 generalBroadcaster.removeNotificationListener(listener);
849 }
850
851 if (attributeBroadcaster != null) {
852 attributeBroadcaster.removeNotificationListener(listener);
853 }
854 }
855
856
857 public String getModelerType() {
858 return resourceType;
859 }
860
861 public String getClassName() {
862 return getModelerType();
863 }
864
865 public ObjectName getJmxName() {
866 return oname;
867 }
868
869 public String getObjectName() {
870 if (oname != null) {
871 return oname.toString();
872 } else {
873 return null;
874 }
875 }
876
877
878 // -------------------- Registration --------------------
879 // XXX We can add some method patterns here- like setName() and
880 // setDomain() for code that doesn't implement the Registration
881
882 @Override
883 public ObjectName preRegister(MBeanServer server,
884 ObjectName name)
885 throws Exception
886 {
887 if( log.isDebugEnabled())
888 log.debug("preRegister " + resource + " " + name );
889 oname=name;
890 if( resource instanceof MBeanRegistration ) {
891 oname = ((MBeanRegistration)resource).preRegister(server, name );
892 }
893 return oname;
894 }
895
896 @Override
897 public void postRegister(Boolean registrationDone) {
898 if( resource instanceof MBeanRegistration ) {
899 ((MBeanRegistration)resource).postRegister(registrationDone);
900 }
901 }
902
903 @Override
904 public void preDeregister() throws Exception {
905 if( resource instanceof MBeanRegistration ) {
906 ((MBeanRegistration)resource).preDeregister();
907 }
908 }
909
910 @Override
911 public void postDeregister() {
912 if( resource instanceof MBeanRegistration ) {
913 ((MBeanRegistration)resource).postDeregister();
914 }
915 }
916 }
917