KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > javax > management > modelmbean > RequiredModelMBean


1 /*
2  * @(#)file RequiredModelMBean.java
3  * @(#)author Sun Microsystems, Inc.
4  * @(#)version 1.55
5  * @(#)lastedit 07/07/24
6  *
7  * Copyright IBM Corp. 1999-2000. All rights reserved.
8  *
9  * The program is provided "as is" without any warranty express or implied,
10  * including the warranty of non-infringement and the implied warranties of
11  * merchantibility and fitness for a particular purpose. IBM will not be
12  * liable for any damages suffered by you or any third party claim against
13  * you regarding the Program.
14  *
15  * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
16  * This software is the proprietary information of Sun Microsystems, Inc.
17  * Use is subject to license terms.
18  *
19  * Copyright 2005 Sun Microsystems, Inc. Tous droits reserves.
20  * Ce logiciel est propriete de Sun Microsystems, Inc.
21  * Distribue par des licences qui en restreignent l'utilisation.
22  *
23  */

24
25
26
27
28 package javax.management.modelmbean;
29
30 /* java imports */
31
32 import java.lang.reflect.Method JavaDoc;
33 import java.lang.reflect.InvocationTargetException JavaDoc;
34
35 import java.util.Date JavaDoc;
36 import java.util.HashMap JavaDoc;
37 import java.util.HashSet JavaDoc;
38 import java.util.Iterator JavaDoc;
39 import java.util.Map JavaDoc;
40 import java.util.Set JavaDoc;
41
42 import java.io.PrintStream JavaDoc;
43 import java.io.FileOutputStream JavaDoc;
44
45 import javax.management.Attribute JavaDoc;
46 import javax.management.AttributeList JavaDoc;
47 import javax.management.AttributeChangeNotification JavaDoc;
48 import javax.management.AttributeChangeNotificationFilter JavaDoc;
49 import javax.management.AttributeNotFoundException JavaDoc;
50 import javax.management.Descriptor JavaDoc;
51 import javax.management.DescriptorAccess JavaDoc;
52 import javax.management.InstanceNotFoundException JavaDoc;
53 import javax.management.InvalidAttributeValueException JavaDoc;
54 import javax.management.ListenerNotFoundException JavaDoc;
55 import javax.management.MBeanAttributeInfo JavaDoc;
56 import javax.management.MBeanConstructorInfo JavaDoc;
57 import javax.management.MBeanException JavaDoc;
58 import javax.management.MBeanInfo JavaDoc;
59 import javax.management.MBeanNotificationInfo JavaDoc;
60 import javax.management.MBeanOperationInfo JavaDoc;
61 import javax.management.MBeanRegistration JavaDoc;
62 import javax.management.MBeanRegistrationException JavaDoc;
63 import javax.management.MBeanServer JavaDoc;
64 import javax.management.MBeanServerFactory JavaDoc;
65 import javax.management.Notification JavaDoc;
66 import javax.management.NotificationBroadcasterSupport JavaDoc;
67 import javax.management.NotificationFilter JavaDoc;
68 import javax.management.NotificationListener JavaDoc;
69 import javax.management.ObjectName JavaDoc;
70 import javax.management.ReflectionException JavaDoc;
71 import javax.management.RuntimeErrorException JavaDoc;
72 import javax.management.RuntimeMBeanException JavaDoc;
73 import javax.management.RuntimeOperationsException JavaDoc;
74 import javax.management.ServiceNotFoundException JavaDoc;
75 import javax.management.NotificationEmitter JavaDoc;
76 import javax.management.loading.ClassLoaderRepository JavaDoc;
77
78 import sun.reflect.misc.MethodUtil;
79 import sun.reflect.misc.ReflectUtil;
80
81 import com.sun.jmx.trace.Trace;
82
83 /**
84  * This class is the implementation of a ModelMBean. An appropriate
85  * implementation of a ModelMBean must be shipped with every JMX Agent
86  * and the class must be named RequiredModelMBean.
87  * <P>
88  * Java resources wishing to be manageable instantiate the
89  * RequiredModelMBean using the MBeanServer's createMBean method.
90  * The resource then sets the MBeanInfo and Descriptors for the
91  * RequiredModelMBean instance. The attributes and operations exposed
92  * via the ModelMBeanInfo for the ModelMBean are accessible
93  * from MBeans, connectors/adaptors like other MBeans. Through the
94  * Descriptors, values and methods in the managed application can be
95  * defined and mapped to attributes and operations of the ModelMBean.
96  * This mapping can be defined in an XML formatted file or dynamically and
97  * programmatically at runtime.
98  * <P>
99  * Every RequiredModelMBean which is instantiated in the MBeanServer
100  * becomes manageable:<br>
101  * its attributes and operations become remotely accessible through the
102  * connectors/adaptors connected to that MBeanServer.
103  * <P>
104  * A Java object cannot be registered in the MBeanServer unless it is a
105  * JMX compliant MBean. By instantiating a RequiredModelMBean, resources
106  * are guaranteed that the MBean is valid.
107  *
108  * MBeanException and RuntimeOperationsException must be thrown on every
109  * public method. This allows for wrapping exceptions from distributed
110  * communications (RMI, EJB, etc.)
111  *
112  * @since 1.5
113  */

114
115 public class RequiredModelMBean
116     implements ModelMBean JavaDoc, MBeanRegistration JavaDoc, NotificationEmitter JavaDoc {
117
118     /*************************************/
119     /* attributes */
120     /*************************************/
121     ModelMBeanInfo JavaDoc modelMBeanInfo;
122
123     /* Notification broadcaster for any notification to be sent
124      * from the application through the RequiredModelMBean. */

125     private NotificationBroadcasterSupport JavaDoc generalBroadcaster = null;
126
127     /* Notification broadcaster for attribute change notifications */
128     private NotificationBroadcasterSupport JavaDoc attributeBroadcaster = null;
129
130     /* handle, name, or reference for instance on which the actual invoke
131      * and operations will be executed */

132     private Object JavaDoc managedResource = null;
133
134     private static final String JavaDoc currClass = "RequiredModelMBean";
135
136     /* records the registering in MBeanServer */
137     private boolean registered = false;
138     private transient MBeanServer JavaDoc server = null;
139
140     /*************************************/
141     /* constructors */
142     /*************************************/
143
144     /**
145      * Constructs an <CODE>RequiredModelMBean</CODE> with an empty
146      * ModelMBeanInfo.
147      * <P>
148      * The RequiredModelMBean's MBeanInfo and Descriptors
149      * can be customized using the {@link #setModelMBeanInfo} method.
150      * After the RequiredModelMBean's MBeanInfo and Descriptors are
151      * customized, the RequiredModelMBean can be registered with
152      * the MBeanServer.
153      *
154      * @exception MBeanException Wraps a distributed communication Exception.
155      *
156      * @exception RuntimeOperationsException Wraps a {@link
157      * RuntimeException} during the construction of the object.
158      **/

159     public RequiredModelMBean()
160     throws MBeanException JavaDoc, RuntimeOperationsException JavaDoc {
161
162     if (tracing())
163         trace("RequiredModelMBean()","Entry and Exit");
164
165     modelMBeanInfo = createDefaultModelMBeanInfo();
166     }
167
168     /**
169      * Constructs a RequiredModelMBean object using ModelMBeanInfo passed in.
170      * As long as the RequiredModelMBean is not registered
171      * with the MBeanServer yet, the RequiredModelMBean's MBeanInfo and
172      * Descriptors can be customized using the {@link #setModelMBeanInfo}
173      * method.
174      * After the RequiredModelMBean's MBeanInfo and Descriptors are
175      * customized, the RequiredModelMBean can be registered with the
176      * MBeanServer.
177      *
178      * @param mbi The ModelMBeanInfo object to be used by the
179      * RequiredModelMBean. The given ModelMBeanInfo is cloned
180      * and modified as specified by {@link #setModelMBeanInfo}
181      *
182      * @exception MBeanException Wraps a distributed communication Exception.
183      * @exception RuntimeOperationsException Wraps an
184      * {link java.lang.IllegalArgumentException}:
185      * The MBeanInfo passed in parameter is null.
186      *
187      **/

188     public RequiredModelMBean(ModelMBeanInfo JavaDoc mbi)
189     throws MBeanException JavaDoc, RuntimeOperationsException JavaDoc {
190
191     if (tracing())
192         trace("RequiredModelMBean(MBeanInfo)","Entry");
193
194     setModelMBeanInfo(mbi);
195
196     if (tracing())
197         trace("RequiredModelMBean(MBeanInfo)","Exit");
198     }
199
200
201     /*************************************/
202     /* initializers */
203     /*************************************/
204
205     /**
206      * Initializes a ModelMBean object using ModelMBeanInfo passed in.
207      * This method makes it possible to set a customized ModelMBeanInfo on
208      * the ModelMBean as long as it is not registered with the MBeanServer.
209      * <br>
210      * Once the ModelMBean's ModelMBeanInfo (with Descriptors) are
211      * customized and set on the ModelMBean, the ModelMBean be
212      * registered with the MBeanServer.
213      * <P>
214      * If the ModelMBean is currently registered, this method throws
215      * a {@link javax.management.RuntimeOperationsException} wrapping an
216      * {@link IllegalStateException}
217      * <P>
218      * If the given <var>inModelMBeanInfo</var> does not contain any
219      * {@link ModelMBeanNotificationInfo} for the <code>GENERIC</code>
220      * or <code>ATTRIBUTE_CHANGE</code> notifications, then the
221      * RequiredModelMBean will supply its own default
222      * {@link ModelMBeanNotificationInfo ModelMBeanNotificationInfo}s for
223      * those missing notifications.
224      *
225      * @param mbi The ModelMBeanInfo object to be used
226      * by the ModelMBean.
227      *
228      * @exception MBeanException Wraps a distributed communication
229      * Exception.
230      * @exception RuntimeOperationsException
231      * <ul><li>Wraps an {@link IllegalArgumentException} if
232      * the MBeanInfo passed in parameter is null.</li>
233      * <li>Wraps an {@link IllegalStateException} if the ModelMBean
234      * is currently registered in the MBeanServer.</li>
235      * </ul>
236      *
237      **/

238     public void setModelMBeanInfo(ModelMBeanInfo JavaDoc mbi)
239     throws MBeanException JavaDoc, RuntimeOperationsException JavaDoc {
240     
241     if (tracing())
242         trace("setModelMBeanInfo(ModelMBeanInfo)","Entry");
243     
244     if (mbi == null) {
245         if (tracing())
246         trace("setModelMBeanInfo(ModelMBeanInfo)",
247               "ModelMBeanInfo is null: Raising exception.");
248         final RuntimeException JavaDoc x = new
249         IllegalArgumentException JavaDoc("ModelMBeanInfo must not be null");
250         final String JavaDoc exceptionText =
251         "Exception occured trying to initialize the " +
252         "ModelMBeanInfo of the RequiredModelMBean";
253         throw new RuntimeOperationsException JavaDoc(x,exceptionText);
254     }
255
256     if (registered) {
257         if (tracing())
258         trace("setModelMBeanInfo(ModelMBeanInfo)",
259               "RequiredMBean is registered: Raising exception.");
260         final String JavaDoc exceptionText =
261         "Exception occured trying to set the " +
262         "ModelMBeanInfo of the RequiredModelMBean";
263         final RuntimeException JavaDoc x = new IllegalStateException JavaDoc(
264          "cannot call setModelMBeanInfo while ModelMBean is registered");
265         throw new RuntimeOperationsException JavaDoc(x,exceptionText);
266     }
267
268     if (tracing()) {
269         trace("setModelMBeanInfo(ModelMBeanInfo)",
270           "Setting ModelMBeanInfo to " + printModelMBeanInfo(mbi));
271         trace("setModelMBeanInfo(ModelMBeanInfo)",
272           "ModelMBeanInfo notifications has " +
273           (mbi.getNotifications()).length + " elements");
274     }
275
276     modelMBeanInfo = (ModelMBeanInfo JavaDoc)mbi.clone();
277     
278     if (tracing())
279         trace("setModelMBeanInfo(ModelMBeanInfo)","set mbeanInfo to: "+
280           printModelMBeanInfo(modelMBeanInfo));
281     
282     if (tracing())
283         trace("setModelMBeanInfo(ModelMBeanInfo)","Exit");
284     }
285
286
287     /**
288      * Sets the instance handle of the object against which to
289      * execute all methods in this ModelMBean management interface
290      * (MBeanInfo and Descriptors).
291      *
292      * @param mr Object that is the managed resource
293      * @param mr_type The type of reference for the managed resource.
294      * <br>Can be: "ObjectReference", "Handle", "IOR", "EJBHandle",
295      * or "RMIReference".
296      * <br>In this implementation only "ObjectReference" is supported.
297      *
298      * @exception MBeanException The initializer of the object has
299      * thrown an exception.
300      * @exception InstanceNotFoundException The managed resource
301      * object could not be found
302      * @exception InvalidTargetObjectTypeException The managed
303      * resource type should be "ObjectReference".
304      * @exception RuntimeOperationsException Wraps a {@link
305      * RuntimeException} when setting the resource.
306      **/

307     public void setManagedResource(Object JavaDoc mr, String JavaDoc mr_type)
308     throws MBeanException JavaDoc, RuntimeOperationsException JavaDoc,
309            InstanceNotFoundException JavaDoc, InvalidTargetObjectTypeException JavaDoc {
310     if (tracing())
311         trace("setManagedResource(Object,String)","Entry");
312
313     // check that the mr_type is supported by this JMXAgent
314
// only "objectReference" is supported
315
if ((mr_type == null) ||
316         (! mr_type.equalsIgnoreCase("objectReference"))) {
317         if (tracing())
318         trace("setManagedResource(Object,String)",
319               "Managed Resouce Type is not supported: " + mr_type);
320     
321         throw new InvalidTargetObjectTypeException JavaDoc(mr_type);
322     }
323
324     if (tracing())
325         trace("setManagedResource(Object,String)",
326           "Managed Resouce is valid");
327
328     managedResource = mr;
329         
330     if (tracing())
331         trace("setManagedResource(Object, String)", "Exit");
332     }
333
334     /**
335      * <p>Instantiates this MBean instance with the data found for
336      * the MBean in the persistent store. The data loaded could include
337      * attribute and operation values.</p>
338      *
339      * <p>This method should be called during construction or
340      * initialization of this instance, and before the MBean is
341      * registered with the MBeanServer.</p>
342      *
343      * <p>If the implementation of this class does not support
344      * persistence, an {@link MBeanException} wrapping a {@link
345      * ServiceNotFoundException} is thrown.</p>
346      *
347      * @exception MBeanException Wraps another exception, or
348      * persistence is not supported
349      * @exception RuntimeOperationsException Wraps exceptions from the
350      * persistence mechanism
351      * @exception InstanceNotFoundException Could not find or load
352      * this MBean from persistent storage
353      */

354     public void load()
355     throws MBeanException JavaDoc, RuntimeOperationsException JavaDoc,
356            InstanceNotFoundException JavaDoc {
357     final ServiceNotFoundException JavaDoc x = new ServiceNotFoundException JavaDoc(
358                     "Persistence not supported for this MBean");
359     throw new MBeanException JavaDoc(x, x.getMessage());
360     }
361
362         /**
363      * <p>Captures the current state of this MBean instance and writes
364      * it out to the persistent store. The state stored could include
365      * attribute and operation values.</p>
366      *
367      * <p>If the implementation of this class does not support
368      * persistence, an {@link MBeanException} wrapping a {@link
369      * ServiceNotFoundException} is thrown.</p>
370      *
371      * <p>Persistence policy from the MBean and attribute descriptor
372      * is used to guide execution of this method. The MBean should be
373      * stored if 'persistPolicy' field is:</p>
374      *
375      * <PRE> != "never"
376      * = "always"
377      * = "onTimer" and now > 'lastPersistTime' + 'persistPeriod'
378      * = "NoMoreOftenThan" and now > 'lastPersistTime' + 'persistPeriod'
379      * </PRE>
380      *
381      * <p>Do not store the MBean if 'persistPolicy' field is:</p>
382      * <PRE>
383      * = "never"
384      * = "onUpdate"
385      * = "onTimer" && now < 'lastPersistTime' + 'persistPeriod'
386      * </PRE>
387      *
388      * @exception MBeanException Wraps another exception, or
389      * persistence is not supported
390      * @exception RuntimeOperationsException Wraps exceptions from the
391      * persistence mechanism
392      * @exception InstanceNotFoundException Could not find/access the
393      * persistent store
394      */

395     public void store()
396     throws MBeanException JavaDoc, RuntimeOperationsException JavaDoc,
397            InstanceNotFoundException JavaDoc {
398     final ServiceNotFoundException JavaDoc x = new ServiceNotFoundException JavaDoc(
399                     "Persistence not supported for this MBean");
400     throw new MBeanException JavaDoc(x, x.getMessage());
401     }
402
403     /*************************************/
404     /* DynamicMBean Interface */
405     /*************************************/
406
407     /**
408      * The resolveForCacheValue method checks the descriptor passed in to
409      * see if there is a valid cached value in the descriptor.
410      * The valid value will be in the 'value' field if there is one.
411      * If the 'currencyTimeLimit' field in the descriptor is:
412      * <ul>
413      * <li><b>&lt;0</b> Then the value is not cached and is never valid.
414      * Null is returned. The 'value' and 'lastUpdatedTimeStamp'
415      * fields are cleared.</li>
416      * <li><b>=0</b> Then the value is always cached and always valid.
417      * The 'value' field is returned.
418      * The 'lastUpdatedTimeStamp' field is not checked.</li>
419      * <li><b>&gt;0</b> Represents the number of seconds that the
420      * 'value' field is valid.
421      * The 'value' field is no longer valid when
422      * 'lastUpdatedTimeStamp' + 'currencyTimeLimit' &gt; Now.</li>
423      * </ul>
424      * <li>When 'value' is valid, 'valid' is returned.</li>
425      * <li>When 'value' is no longer valid then null is returned and
426      * 'value' and 'lastUpdatedTimeStamp' fields are cleared.</li>
427      *
428      **/

429     private Object JavaDoc resolveForCacheValue(Descriptor JavaDoc descr)
430     throws MBeanException JavaDoc, RuntimeOperationsException JavaDoc {
431     if (tracing())
432         trace("resolveForCacheValue(Descriptor)","Entry");
433
434     Object JavaDoc response = null;
435     boolean resetValue = false, returnCachedValue = true;
436     long currencyPeriod = 0;
437
438     if (descr == null) {
439         if (tracing())
440         trace("resolveForCacheValue(Descriptor)",
441               "Input Descriptor is null");
442         return response;
443     }
444
445     if (tracing())
446         trace("resolveForCacheValue(Descriptor)","descriptor is " +
447           descr.toString());
448
449     final Descriptor JavaDoc mmbDescr = modelMBeanInfo.getMBeanDescriptor();
450     if (mmbDescr == null) {
451         if (tracing())
452         trace("resolveForCacheValue(Descriptor)",
453               "MBean Descriptor is null");
454         //return response;
455
}
456
457     Object JavaDoc objExpTime = descr.getFieldValue("currencyTimeLimit");
458
459     String JavaDoc expTime;
460     if (objExpTime != null) {
461         expTime = objExpTime.toString();
462     } else {
463         expTime = null;
464     }
465
466     if ((expTime == null) && (mmbDescr != null)) {
467         objExpTime = mmbDescr.getFieldValue("currencyTimeLimit");
468         if (objExpTime != null) {
469         expTime = objExpTime.toString();
470         } else {
471         expTime = null;
472         }
473     }
474
475     if (expTime != null) {
476         if (tracing())
477         trace("resolveForCacheValue(Descriptor)",
478               "currencyTimeLimit: " + expTime);
479
480         // convert seconds to milliseconds for time comparison
481
currencyPeriod = ((new Long JavaDoc(expTime)).longValue()) * 1000;
482         if (currencyPeriod < 0) {
483         /* if currencyTimeLimit is -1 then value is never cached */
484         returnCachedValue = false;
485         resetValue = true;
486         if (tracing())
487             trace("resolveForCacheValue(Descriptor)",
488               currencyPeriod + ": never Cached");
489         } else if (currencyPeriod == 0) {
490         /* if currencyTimeLimit is 0 then value is always cached */
491         returnCachedValue = true;
492         resetValue = false;
493         if (tracing())
494             trace("resolveForCacheValue(Descriptor)",
495               "always valid Cache");
496         } else {
497         Object JavaDoc objtStamp =
498             descr.getFieldValue("lastUpdatedTimeStamp");
499
500         String JavaDoc tStamp;
501         if (objtStamp != null) tStamp = objtStamp.toString();
502         else tStamp = null;
503         
504         if (tracing())
505             trace("resolveForCacheValue(Descriptor)",
506               "lastUpdatedTimeStamp: " + tStamp);
507
508         if (tStamp == null)
509             tStamp = "0";
510     
511         long lastTime = (new Long JavaDoc(tStamp)).longValue();
512
513         if (tracing())
514             trace("resolveForCacheValue(Descriptor)",
515               " currencyPeriod:" + currencyPeriod +
516               " lastUpdatedTimeStamp:" + lastTime);
517
518         long now = (new Date JavaDoc()).getTime();
519
520         if (now < (lastTime + currencyPeriod)) {
521             returnCachedValue = true;
522             resetValue = false;
523             if (tracing())
524             trace("resolveForCacheValue(Descriptor)",
525                   " timed valid Cache for " + now + " < " +
526                   (lastTime + currencyPeriod));
527         } else { /* value is expired */
528             returnCachedValue = false;
529             resetValue = true;
530             if (tracing())
531             trace("resolveForCacheValue(Descriptor)",
532                   "timed expired cache for " + now + " > " +
533                   (lastTime + currencyPeriod));
534         }
535         }
536
537         if (tracing())
538         trace("resolveForCacheValue(Descriptor)",
539               "returnCachedValue:" + returnCachedValue +
540               " resetValue: " + resetValue);
541
542         if (returnCachedValue == true) {
543         Object JavaDoc currValue = descr.getFieldValue("value");
544         if (currValue != null) {
545             /* error/validity check return value here */
546             response = currValue;
547             /* need to cast string cached value to type */
548             if (tracing())
549             trace("resolveForCacheValue(Descriptor)",
550                   "valid Cache value: " + currValue);
551                     
552         } else {
553             response = null;
554             if (tracing())
555             trace("resolveForCacheValue(Descriptor)",
556                   "no Cached value");
557         }
558         }
559
560         if (resetValue == true) {
561         /* value is not current, so remove it */
562         descr.removeField("lastUpdatedTimeStamp");
563         descr.removeField("value");
564         response = null;
565         modelMBeanInfo.setDescriptor(descr,null);
566         if (tracing())
567             trace("resolveForCacheValue(Descriptor)",
568               "reset cached value to null");
569         }
570     }
571
572     if (tracing())
573         trace("resolveForCache(Descriptor)","Exit");
574
575     return response;
576     }
577
578     /**
579      * Returns the attributes, operations, constructors and notifications
580      * that this RequiredModelMBean exposes for management.
581      *
582      * @return An instance of ModelMBeanInfo allowing retrieval all
583      * attributes, operations, and Notifications of this MBean.
584      *
585      **/

586     public MBeanInfo JavaDoc getMBeanInfo() {
587     
588     if (tracing())
589         trace("getMBeanInfo()","Entry and Exit");
590
591     if (modelMBeanInfo == null) {
592         if (tracing())
593         trace("getMBeanInfo()","modelMBeanInfo is null");
594         modelMBeanInfo = createDefaultModelMBeanInfo();
595         //return new ModelMBeanInfo(" ", "", null, null, null, null);
596
}
597
598     if (tracing()) {
599         trace("getMBeanInfo()","ModelMBeanInfo is " +
600           modelMBeanInfo.getClassName() + " for " +
601           modelMBeanInfo.getDescription());
602         trace("getMBeanInfo()",printModelMBeanInfo(modelMBeanInfo));
603     }
604
605     return((MBeanInfo JavaDoc) ((ModelMBeanInfo JavaDoc)modelMBeanInfo).clone());
606     }
607
608     private String JavaDoc printModelMBeanInfo(ModelMBeanInfo JavaDoc info) {
609     final StringBuffer JavaDoc retStr = new StringBuffer JavaDoc();
610     if (info == null) {
611         if (tracing())
612         trace("printModelMBeanInfo(ModelMBeanInfo)",
613               "ModelMBeanInfo to print is null, " +
614               "printing local ModelMBeanInfo");
615         info = modelMBeanInfo;
616     }
617
618     retStr.append("\nMBeanInfo for ModelMBean is:");
619     retStr.append("\nCLASSNAME: \t"+ info.getClassName());
620     retStr.append("\nDESCRIPTION: \t"+ info.getDescription());
621
622
623     try {
624         retStr.append("\nMBEAN DESCRIPTOR: \t"+
625               info.getMBeanDescriptor());
626     } catch (Exception JavaDoc e) {
627         retStr.append("\nMBEAN DESCRIPTOR: \t" + " is invalid");
628     }
629
630     retStr.append("\nATTRIBUTES");
631
632     final MBeanAttributeInfo JavaDoc[] attrInfo = info.getAttributes();
633     if ((attrInfo != null) && (attrInfo.length>0)) {
634         for (int i=0; i<attrInfo.length; i++) {
635         final ModelMBeanAttributeInfo JavaDoc attInfo =
636             (ModelMBeanAttributeInfo JavaDoc)attrInfo[i];
637         retStr.append(" ** NAME: \t"+ attInfo.getName());
638         retStr.append(" DESCR: \t"+ attInfo.getDescription());
639         retStr.append(" TYPE: \t"+ attInfo.getType() +
640                   " READ: \t"+ attInfo.isReadable() +
641                   " WRITE: \t"+ attInfo.isWritable());
642         retStr.append(" DESCRIPTOR: " +
643                   attInfo.getDescriptor().toString());
644         }
645     } else {
646         retStr.append(" ** No attributes **");
647     }
648
649     retStr.append("\nCONSTRUCTORS");
650     final MBeanConstructorInfo JavaDoc[] constrInfo = info.getConstructors();
651     if ((constrInfo != null) && (constrInfo.length > 0 )) {
652         for (int i=0; i<constrInfo.length; i++) {
653         final ModelMBeanConstructorInfo JavaDoc ctorInfo =
654             (ModelMBeanConstructorInfo JavaDoc)constrInfo[i];
655         retStr.append(" ** NAME: \t"+ ctorInfo.getName());
656         retStr.append(" DESCR: \t"+
657                   ctorInfo.getDescription());
658         retStr.append(" PARAM: \t"+
659                   ctorInfo.getSignature().length +
660                   " parameter(s)");
661         retStr.append(" DESCRIPTOR: " +
662                   ctorInfo.getDescriptor().toString());
663         }
664     } else {
665         retStr.append(" ** No Constructors **");
666     }
667         
668     retStr.append("\nOPERATIONS");
669     final MBeanOperationInfo JavaDoc[] opsInfo = info.getOperations();
670     if ((opsInfo != null) && (opsInfo.length>0)) {
671         for (int i=0; i<opsInfo.length; i++) {
672         final ModelMBeanOperationInfo JavaDoc operInfo =
673             (ModelMBeanOperationInfo JavaDoc)opsInfo[i];
674         retStr.append(" ** NAME: \t"+ operInfo.getName());
675         retStr.append(" DESCR: \t"+ operInfo.getDescription());
676         retStr.append(" PARAM: \t"+
677                   operInfo.getSignature().length +
678                   " parameter(s)");
679         retStr.append(" DESCRIPTOR: " +
680                   operInfo.getDescriptor().toString());
681         }
682     } else {
683         retStr.append(" ** No operations ** ");
684     }
685
686     retStr.append("\nNOTIFICATIONS");
687
688     MBeanNotificationInfo JavaDoc[] notifInfo = info.getNotifications();
689     if ((notifInfo != null) && (notifInfo.length>0)) {
690         for (int i=0; i<notifInfo.length; i++) {
691         final ModelMBeanNotificationInfo JavaDoc nInfo =
692             (ModelMBeanNotificationInfo JavaDoc)notifInfo[i];
693         retStr.append(" ** NAME: \t"+ nInfo.getName());
694         retStr.append(" DESCR: \t"+ nInfo.getDescription());
695         retStr.append(" DESCRIPTOR: " +
696                   nInfo.getDescriptor().toString());
697         }
698     } else {
699         retStr.append(" ** No notifications **");
700     }
701
702     retStr.append(" ** ModelMBean: End of MBeanInfo ** ");
703
704     return retStr.toString();
705     }
706
707     private void echo(String JavaDoc txt) {
708     trace("echo(txt)",txt);
709     }
710
711
712     /**
713      * Invokes a method on or through a RequiredModelMBean and returns
714      * the result of the method execution.
715      * <P>
716      * If the given method to be invoked, together with the provided
717      * signature, matches one of RequiredModelMbean
718      * accessible methods, this one will be call. Otherwise the call to
719      * the given method will be tried on the managed resource.
720      * <P>
721      * The last value returned by an operation may be cached in
722      * the operation's descriptor which
723      * is in the ModelMBeanOperationInfo's descriptor.
724      * The valid value will be in the 'value' field if there is one.
725      * If the 'currencyTimeLimit' field in the descriptor is:
726      * <UL>
727      * <LI><b>&lt;0</b> Then the value is not cached and is never valid.
728      * The operation method is invoked.
729      * The 'value' and 'lastUpdatedTimeStamp' fields are cleared.</LI>
730      * <LI><b>=0</b> Then the value is always cached and always valid.
731      * The 'value' field is returned. If there is no 'value' field
732      * then the operation method is invoked for the attribute.
733      * The 'lastUpdatedTimeStamp' field and `value' fields are set to
734      * the operation's return value and the current time stamp.</LI>
735      * <LI><b>&gt;0</b> Represents the number of seconds that the 'value'
736      * field is valid.
737      * The 'value' field is no longer valid when
738      * 'lastUpdatedTimeStamp' + 'currencyTimeLimit' &gt; Now.
739      * <UL>
740      * <LI>When 'value' is valid, 'value' is returned.</LI>
741      * <LI>When 'value' is no longer valid then the operation
742      * method is invoked. The 'lastUpdatedTimeStamp' field
743      * and `value' fields are updated.</lI>
744      * </UL>
745      * </LI>
746      * </UL>
747      *
748      * <p><b>Note:</b> because of inconsistencies in previous versions of
749      * this specification, it is recommended not to use negative or zero
750      * values for <code>currencyTimeLimit</code>. To indicate that a
751      * cached value is never valid, omit the
752      * <code>currencyTimeLimit</code> field. To indicate that it is
753      * always valid, use a very large number for this field.</p>
754      *
755      * @param opName The name of the method to be invoked. The
756      * name can be the fully qualified method name including the
757      * classname, or just the method name if the classname is
758      * defined in the 'class' field of the operation descriptor.
759      * @param opArgs An array containing the parameters to be set
760      * when the operation is invoked
761      * @param sig An array containing the signature of the
762      * operation. The class objects will be loaded using the same
763      * class loader as the one used for loading the MBean on which
764      * the operation was invoked.
765      *
766      * @return The object returned by the method, which represents the
767      * result of invoking the method on the specified managed resource.
768      *
769      * @exception MBeanException Wraps one of the following Exceptions:
770      * <UL>
771      * <LI> An Exception thrown by the managed object's invoked method.</LI>
772      * <LI> {@link ServiceNotFoundException}: No ModelMBeanOperationInfo or
773      * no descriptor defined for the specified operation or the managed
774      * resource is null.</LI>
775      * <LI> {@link InvalidTargetObjectTypeException}: The 'targetType'
776      * field value is not 'objectReference'.</LI>
777      * </UL>
778      * @exception ReflectionException Wraps an {@link java.lang.Exception}
779      * thrown while trying to invoke the method.
780      * @exception RuntimeOperationsException Wraps an
781      * {@link IllegalArgumentException} Method name is null.
782      *
783      **/

784     /*
785       The requirement to be able to invoke methods on the
786       RequiredModelMBean class itself makes this method considerably
787       more complicated than it might otherwise be. Note that, unlike
788       earlier versions, we do not allow you to invoke such methods if
789       they are not explicitly mentioned in the ModelMBeanInfo. Doing
790       so was potentially a security problem, and certainly very
791       surprising.
792
793       We do not look for the method in the RequiredModelMBean class
794       itself if:
795       (a) there is a "targetObject" field in the Descriptor for the
796       operation; or
797       (b) there is a "class" field in the Descriptor for the operation
798       and the named class is not RequiredModelMBean or one of its
799       superinterfaces; or
800       (c) the name of the operation is not the name of a method in
801       RequiredModelMBean (this is just an optimization).
802
803       In cases (a) and (b), if you have gone to the trouble of adding
804       those fields specifically for this operation then presumably you
805       do not want RequiredModelMBean's methods to be called.
806
807       We have to pay attention to class loading issues. If the
808       "class" field is present, the named class has to be resolved
809       relative to RequiredModelMBean's class loader to test the
810       condition (b) above, and relative to the managed resource's
811       class loader to ensure that the managed resource is in fact of
812       the named class (or a subclass). The class names in the sig
813       array likewise have to be resolved, first against
814       RequiredModelMBean's class loader, then against the managed
815       resource's class loader. There is no point in using any other
816       loader because when we call Method.invoke we must call it on
817       a Method that is implemented by the target object.
818      */

819     public Object JavaDoc invoke(String JavaDoc opName, Object JavaDoc[] opArgs, String JavaDoc[] sig)
820         throws MBeanException JavaDoc, ReflectionException JavaDoc {
821     final boolean tracing = tracing();
822
823     if (tracing)
824         trace("invoke(String, Object[], String[])","Entry");
825
826     if (opName == null) {
827         final RuntimeException JavaDoc x =
828         new IllegalArgumentException JavaDoc("Method name must not be null");
829         throw new RuntimeOperationsException JavaDoc(x,
830                       "An exception occured while trying to " +
831               "invoke a method on a RequiredModelMBean");
832     }
833
834     String JavaDoc opClassName = null;
835     String JavaDoc opMethodName;
836
837     // Parse for class name and method
838
int opSplitter = opName.lastIndexOf(".");
839     if (opSplitter > 0) {
840         opClassName = opName.substring(0,opSplitter);
841         opMethodNam