1 /*
2 * Portions Copyright 2000-2007 Sun Microsystems, Inc. All Rights Reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any questions.
24 */
25 /*
26 * @author IBM Corp.
27 *
28 * Copyright IBM Corp. 1999-2000. All rights reserved.
29 */
30
31
32 package javax.management.modelmbean;
33
34 /* java imports */
35
36 import static com.sun.jmx.defaults.JmxProperties.MODELMBEAN_LOGGER;
37 import java.io.FileOutputStream;
38 import java.io.PrintStream;
39 import java.lang.reflect.InvocationTargetException;
40
41 import java.lang.reflect.Method;
42
43 import java.util.Date;
44 import java.util.HashMap;
45 import java.util.HashSet;
46 import java.util.Iterator;
47 import java.util.logging.Level;
48 import java.util.Map;
49 import java.util.Set;
50
51 import java.util.Vector;
52 import javax.management.Attribute;
53 import javax.management.AttributeChangeNotification;
54 import javax.management.AttributeChangeNotificationFilter;
55 import javax.management.AttributeList;
56 import javax.management.AttributeNotFoundException;
57 import javax.management.Descriptor;
58 import javax.management.InstanceNotFoundException;
59 import javax.management.InvalidAttributeValueException;
60 import javax.management.ListenerNotFoundException;
61 import javax.management.MBeanAttributeInfo;
62 import javax.management.MBeanConstructorInfo;
63 import javax.management.MBeanException;
64 import javax.management.MBeanInfo;
65 import javax.management.MBeanNotificationInfo;
66 import javax.management.MBeanOperationInfo;
67 import javax.management.MBeanRegistration;
68 import javax.management.MBeanServer;
69 import javax.management.MBeanServerFactory;
70 import javax.management.Notification;
71 import javax.management.NotificationBroadcasterSupport;
72 import javax.management.NotificationEmitter;
73 import javax.management.NotificationFilter;
74 import javax.management.NotificationListener;
75 import javax.management.ObjectName;
76 import javax.management.ReflectionException;
77 import javax.management.RuntimeErrorException;
78 import javax.management.RuntimeOperationsException;
79 import javax.management.ServiceNotFoundException;
80 import javax.management.loading.ClassLoaderRepository;
81
82 import sun.reflect.misc.MethodUtil;
83 import sun.reflect.misc.ReflectUtil;
84
85 /**
86 * This class is the implementation of a ModelMBean. An appropriate
87 * implementation of a ModelMBean must be shipped with every JMX Agent
88 * and the class must be named RequiredModelMBean.
89 * <P>
90 * Java resources wishing to be manageable instantiate the
91 * RequiredModelMBean using the MBeanServer's createMBean method.
92 * The resource then sets the MBeanInfo and Descriptors for the
93 * RequiredModelMBean instance. The attributes and operations exposed
94 * via the ModelMBeanInfo for the ModelMBean are accessible
95 * from MBeans, connectors/adaptors like other MBeans. Through the
96 * Descriptors, values and methods in the managed application can be
97 * defined and mapped to attributes and operations of the ModelMBean.
98 * This mapping can be defined in an XML formatted file or dynamically and
99 * programmatically at runtime.
100 * <P>
101 * Every RequiredModelMBean which is instantiated in the MBeanServer
102 * becomes manageable:<br>
103 * its attributes and operations become remotely accessible through the
104 * connectors/adaptors connected to that MBeanServer.
105 * <P>
106 * A Java object cannot be registered in the MBeanServer unless it is a
107 * JMX compliant MBean. By instantiating a RequiredModelMBean, resources
108 * are guaranteed that the MBean is valid.
109 *
110 * MBeanException and RuntimeOperationsException must be thrown on every
111 * public method. This allows for wrapping exceptions from distributed
112 * communications (RMI, EJB, etc.)
113 *
114 * @since 1.5
115 */
116
117 public class RequiredModelMBean
118 implements ModelMBean, MBeanRegistration, NotificationEmitter {
119
120 /*************************************/
121 /* attributes */
122 /*************************************/
123 ModelMBeanInfo modelMBeanInfo;
124
125 /* Notification broadcaster for any notification to be sent
126 * from the application through the RequiredModelMBean. */
127 private NotificationBroadcasterSupport generalBroadcaster = null;
128
129 /* Notification broadcaster for attribute change notifications */
130 private NotificationBroadcasterSupport attributeBroadcaster = null;
131
132 /* handle, name, or reference for instance on which the actual invoke
133 * and operations will be executed */
134 private Object managedResource = null;
135
136 /* records the registering in MBeanServer */
137 private boolean registered = false;
138 private transient MBeanServer 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, RuntimeOperationsException {
161 if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) {
162 MODELMBEAN_LOGGER.logp(Level.FINER,
163 RequiredModelMBean.class.getName(),
164 "RequiredModelMBean()", "Entry");
165 }
166 modelMBeanInfo = createDefaultModelMBeanInfo();
167 if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) {
168 MODELMBEAN_LOGGER.logp(Level.FINER,
169 RequiredModelMBean.class.getName(),
170 "RequiredModelMBean()", "Exit");
171 }
172 }
173
174 /**
175 * Constructs a RequiredModelMBean object using ModelMBeanInfo passed in.
176 * As long as the RequiredModelMBean is not registered
177 * with the MBeanServer yet, the RequiredModelMBean's MBeanInfo and
178 * Descriptors can be customized using the {@link #setModelMBeanInfo}
179 * method.
180 * After the RequiredModelMBean's MBeanInfo and Descriptors are
181 * customized, the RequiredModelMBean can be registered with the
182 * MBeanServer.
183 *
184 * @param mbi The ModelMBeanInfo object to be used by the
185 * RequiredModelMBean. The given ModelMBeanInfo is cloned
186 * and modified as specified by {@link #setModelMBeanInfo}
187 *
188 * @exception MBeanException Wraps a distributed communication Exception.
189 * @exception RuntimeOperationsException Wraps an
190 * {link java.lang.IllegalArgumentException}:
191 * The MBeanInfo passed in parameter is null.
192 *
193 **/
194 public RequiredModelMBean(ModelMBeanInfo mbi)
195 throws MBeanException, RuntimeOperationsException {
196
197 if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) {
198 MODELMBEAN_LOGGER.logp(Level.FINER,
199 RequiredModelMBean.class.getName(),
200 "RequiredModelMBean(MBeanInfo)", "Entry");
201 }
202 setModelMBeanInfo(mbi);
203
204 if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) {
205 MODELMBEAN_LOGGER.logp(Level.FINER,
206 RequiredModelMBean.class.getName(),
207 "RequiredModelMBean(MBeanInfo)", "Exit");
208 }
209 }
210
211
212 /*************************************/
213 /* initializers */
214 /*************************************/
215
216 /**
217 * Initializes a ModelMBean object using ModelMBeanInfo passed in.
218 * This method makes it possible to set a customized ModelMBeanInfo on
219 * the ModelMBean as long as it is not registered with the MBeanServer.
220 * <br>
221 * Once the ModelMBean's ModelMBeanInfo (with Descriptors) are
222 * customized and set on the ModelMBean, the ModelMBean be
223 * registered with the MBeanServer.
224 * <P>
225 * If the ModelMBean is currently registered, this method throws
226 * a {@link javax.management.RuntimeOperationsException} wrapping an
227 * {@link IllegalStateException}
228 * <P>
229 * If the given <var>inModelMBeanInfo</var> does not contain any
230 * {@link ModelMBeanNotificationInfo} for the <code>GENERIC</code>
231 * or <code>ATTRIBUTE_CHANGE</code> notifications, then the
232 * RequiredModelMBean will supply its own default
233 * {@link ModelMBeanNotificationInfo ModelMBeanNotificationInfo}s for
234 * those missing notifications.
235 *
236 * @param mbi The ModelMBeanInfo object to be used
237 * by the ModelMBean.
238 *
239 * @exception MBeanException Wraps a distributed communication
240 * Exception.
241 * @exception RuntimeOperationsException
242 * <ul><li>Wraps an {@link IllegalArgumentException} if
243 * the MBeanInfo passed in parameter is null.</li>
244 * <li>Wraps an {@link IllegalStateException} if the ModelMBean
245 * is currently registered in the MBeanServer.</li>
246 * </ul>
247 *
248 **/
249 public void setModelMBeanInfo(ModelMBeanInfo mbi)
250 throws MBeanException, RuntimeOperationsException {
251
252 if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) {
253 MODELMBEAN_LOGGER.logp(Level.FINER,
254 RequiredModelMBean.class.getName(),
255 "setModelMBeanInfo(ModelMBeanInfo)","Entry");
256 }
257
258 if (mbi == null) {
259 if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) {
260 MODELMBEAN_LOGGER.logp(Level.FINER,
261 RequiredModelMBean.class.getName(),
262 "setModelMBeanInfo(ModelMBeanInfo)",
263 "ModelMBeanInfo is null: Raising exception.");
264 }
265 final RuntimeException x = new
266 IllegalArgumentException("ModelMBeanInfo must not be null");
267 final String exceptionText =
268 "Exception occurred trying to initialize the " +
269 "ModelMBeanInfo of the RequiredModelMBean";
270 throw new RuntimeOperationsException(x,exceptionText);
271 }
272
273 if (registered) {
274 if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) {
275 MODELMBEAN_LOGGER.logp(Level.FINER,
276 RequiredModelMBean.class.getName(),
277 "setModelMBeanInfo(ModelMBeanInfo)",
278 "RequiredMBean is registered: Raising exception.");
279 }
280 final String exceptionText =
281 "Exception occurred trying to set the " +
282 "ModelMBeanInfo of the RequiredModelMBean";
283 final RuntimeException x = new IllegalStateException(
284 "cannot call setModelMBeanInfo while ModelMBean is registered");
285 throw new RuntimeOperationsException(x,exceptionText);
286 }
287
288 if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) {
289 MODELMBEAN_LOGGER.logp(Level.FINER,
290 RequiredModelMBean.class.getName(),
291 "setModelMBeanInfo(ModelMBeanInfo)",
292 "Setting ModelMBeanInfo to " + printModelMBeanInfo(mbi));
293 MODELMBEAN_LOGGER.logp(Level.FINER,
294 RequiredModelMBean.class.getName(),
295 "setModelMBeanInfo(ModelMBeanInfo)",
296 "ModelMBeanInfo notifications has " +
297 (mbi.getNotifications()).length + " elements");
298 }
299
300 modelMBeanInfo = (ModelMBeanInfo)mbi.clone();
301
302 if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) {
303 MODELMBEAN_LOGGER.logp(Level.FINER,
304 RequiredModelMBean.class.getName(),
305 "setModelMBeanInfo(ModelMBeanInfo)","set mbeanInfo to: "+
306 printModelMBeanInfo(modelMBeanInfo));
307 MODELMBEAN_LOGGER.logp(Level.FINER,
308 RequiredModelMBean.class.getName(),
309 "setModelMBeanInfo(ModelMBeanInfo)","Exit");
310 }
311 }
312
313
314 /**
315 * Sets the instance handle of the object against which to
316 * execute all methods in this ModelMBean management interface
317 * (MBeanInfo and Descriptors).
318 *
319 * @param mr Object that is the managed resource
320 * @param mr_type The type of reference for the managed resource.
321 * <br>Can be: "ObjectReference", "Handle", "IOR", "EJBHandle",
322 * or "RMIReference".
323 * <br>In this implementation only "ObjectReference" is supported.
324 *
325 * @exception MBeanException The initializer of the object has
326 * thrown an exception.
327 * @exception InstanceNotFoundException The managed resource
328 * object could not be found
329 * @exception InvalidTargetObjectTypeException The managed
330 * resource type should be "ObjectReference".
331 * @exception RuntimeOperationsException Wraps a {@link
332 * RuntimeException} when setting the resource.
333 **/
334 public void setManagedResource(Object mr, String mr_type)
335 throws MBeanException, RuntimeOperationsException,
336 InstanceNotFoundException, InvalidTargetObjectTypeException {
337 if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) {
338 MODELMBEAN_LOGGER.logp(Level.FINER,
339 RequiredModelMBean.class.getName(),
340 "setManagedResource(Object,String)","Entry");
341 }
342
343 // check that the mr_type is supported by this JMXAgent
344 // only "objectReference" is supported
345 if ((mr_type == null) ||
346 (! mr_type.equalsIgnoreCase("objectReference"))) {
347 if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) {
348 MODELMBEAN_LOGGER.logp(Level.FINER,
349 RequiredModelMBean.class.getName(),
350 "setManagedResource(Object,String)",
351 "Managed Resouce Type is not supported: " + mr_type);
352 }
353 throw new InvalidTargetObjectTypeException(mr_type);
354 }
355
356 if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) {
357 MODELMBEAN_LOGGER.logp(Level.FINER,
358 RequiredModelMBean.class.getName(),
359 "setManagedResource(Object,String)",
360 "Managed Resouce is valid");
361 }
362 managedResource = mr;
363
364 if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) {
365 MODELMBEAN_LOGGER.logp(Level.FINER,
366 RequiredModelMBean.class.getName(),
367 "setManagedResource(Object, String)", "Exit");
368 }
369 }
370
371 /**
372 * <p>Instantiates this MBean instance with the data found for
373 * the MBean in the persistent store. The data loaded could include
374 * attribute and operation values.</p>
375 *
376 * <p>This method should be called during construction or
377 * initialization of this instance, and before the MBean is
378 * registered with the MBeanServer.</p>
379 *
380 * <p>If the implementation of this class does not support
381 * persistence, an {@link MBeanException} wrapping a {@link
382 * ServiceNotFoundException} is thrown.</p>
383 *
384 * @exception MBeanException Wraps another exception, or
385 * persistence is not supported
386 * @exception RuntimeOperationsException Wraps exceptions from the
387 * persistence mechanism
388 * @exception InstanceNotFoundException Could not find or load
389 * this MBean from persistent storage
390 */
391 public void load()
392 throws MBeanException, RuntimeOperationsException,
393 InstanceNotFoundException {
394 final ServiceNotFoundException x = new ServiceNotFoundException(
395 "Persistence not supported for this MBean");
396 throw new MBeanException(x, x.getMessage());
397 }
398
399 /**
400 * <p>Captures the current state of this MBean instance and writes
401 * it out to the persistent store. The state stored could include
402 * attribute and operation values.</p>
403 *
404 * <p>If the implementation of this class does not support
405 * persistence, an {@link MBeanException} wrapping a {@link
406 * ServiceNotFoundException} is thrown.</p>
407 *
408 * <p>Persistence policy from the MBean and attribute descriptor
409 * is used to guide execution of this method. The MBean should be
410 * stored if 'persistPolicy' field is:</p>
411 *
412 * <PRE> != "never"
413 * = "always"
414 * = "onTimer" and now > 'lastPersistTime' + 'persistPeriod'
415 * = "NoMoreOftenThan" and now > 'lastPersistTime' + 'persistPeriod'
416 * = "onUnregister"
417 * </PRE>
418 *
419 * <p>Do not store the MBean if 'persistPolicy' field is:</p>
420 * <PRE>
421 * = "never"
422 * = "onUpdate"
423 * = "onTimer" && now < 'lastPersistTime' + 'persistPeriod'
424 * </PRE>
425 *
426 * @exception MBeanException Wraps another exception, or
427 * persistence is not supported
428 * @exception RuntimeOperationsException Wraps exceptions from the
429 * persistence mechanism
430 * @exception InstanceNotFoundException Could not find/access the
431 * persistent store
432 */
433 public void store()
434 throws MBeanException, RuntimeOperationsException,
435 InstanceNotFoundException {
436 final ServiceNotFoundException x = new ServiceNotFoundException(
437 "Persistence not supported for this MBean");
438 throw new MBeanException(x, x.getMessage());
439 }
440
441 /*************************************/
442 /* DynamicMBean Interface */
443 /*************************************/
444
445 /**
446 * The resolveForCacheValue method checks the descriptor passed in to
447 * see if there is a valid cached value in the descriptor.
448 * The valid value will be in the 'value' field if there is one.
449 * If the 'currencyTimeLimit' field in the descriptor is:
450 * <ul>
451 * <li><b><0</b> Then the value is not cached and is never valid.
452 * Null is returned. The 'value' and 'lastUpdatedTimeStamp'
453 * fields are cleared.</li>
454 * <li><b>=0</b> Then the value is always cached and always valid.
455 * The 'value' field is returned.
456 * The 'lastUpdatedTimeStamp' field is not checked.</li>
457 * <li><b>>0</b> Represents the number of seconds that the
458 * 'value' field is valid.
459 * The 'value' field is no longer valid when
460 * 'lastUpdatedTimeStamp' + 'currencyTimeLimit' > Now.</li>
461 * </ul>
462 * <li>When 'value' is valid, 'valid' is returned.</li>
463 * <li>When 'value' is no longer valid then null is returned and
464 * 'value' and 'lastUpdatedTimeStamp' fields are cleared.</li>
465 *
466 **/
467 private Object resolveForCacheValue(Descriptor descr)
468 throws MBeanException, RuntimeOperationsException {
469
470 final boolean tracing = MODELMBEAN_LOGGER.isLoggable(Level.FINER);
471 final String mth = "resolveForCacheValue(Descriptor)";
472 if (tracing) {
473 MODELMBEAN_LOGGER.logp(Level.FINER,
474 RequiredModelMBean.class.getName(),mth,"Entry");
475 }
476
477 Object response = null;
478 boolean resetValue = false, returnCachedValue = true;
479 long currencyPeriod = 0;
480
481 if (descr == null) {
482 if (tracing) {
483 MODELMBEAN_LOGGER.logp(Level.FINER,
484 RequiredModelMBean.class.getName(),mth,
485 "Input Descriptor is null");
486 }
487 return response;
488 }
489
490 if (tracing) {
491 MODELMBEAN_LOGGER.logp(Level.FINER,
492 RequiredModelMBean.class.getName(),
493 mth, "descriptor is " + descr);
494 }
495
496 final Descriptor mmbDescr = modelMBeanInfo.getMBeanDescriptor();
497 if (mmbDescr == null) {
498 if (tracing) {
499 MODELMBEAN_LOGGER.logp(Level.FINER,
500 RequiredModelMBean.class.getName(),
501 mth,"MBean Descriptor is null");
502 }
503 //return response;
504 }
505
506 Object objExpTime = descr.getFieldValue("currencyTimeLimit");
507
508 String expTime;
509 if (objExpTime != null) {
510 expTime = objExpTime.toString();
511 } else {
512 expTime = null;
513 }
514
515 if ((expTime == null) && (mmbDescr != null)) {
516 objExpTime = mmbDescr.getFieldValue("currencyTimeLimit");
517 if (objExpTime != null) {
518 expTime = objExpTime.toString();
519 } else {
520 expTime = null;
521 }
522 }
523
524 if (expTime != null) {
525 if (tracing) {
526 MODELMBEAN_LOGGER.logp(Level.FINER,
527 RequiredModelMBean.class.getName(),
528 mth,"currencyTimeLimit: " + expTime);
529 }
530
531 // convert seconds to milliseconds for time comparison
532 currencyPeriod = ((new Long(expTime)).longValue()) * 1000;
533 if (currencyPeriod < 0) {
534 /* if currencyTimeLimit is -1 then value is never cached */
535 returnCachedValue = false;
536 resetValue = true;
537 if (tracing) {
538 MODELMBEAN_LOGGER.logp(Level.FINER,
539 RequiredModelMBean.class.getName(),mth,
540 currencyPeriod + ": never Cached");
541 }
542 } else if (currencyPeriod == 0) {
543 /* if currencyTimeLimit is 0 then value is always cached */
544 returnCachedValue = true;
545 resetValue = false;
546 if (tracing) {
547 MODELMBEAN_LOGGER.logp(Level.FINER,
548 RequiredModelMBean.class.getName(),mth,
549 "always valid Cache");
550 }
551 } else {
552 Object objtStamp =
553 descr.getFieldValue("lastUpdatedTimeStamp");
554
555 String tStamp;
556 if (objtStamp != null) tStamp = objtStamp.toString();
557 else tStamp = null;
558
559 if (tracing) {
560 MODELMBEAN_LOGGER.logp(Level.FINER,
561 RequiredModelMBean.class.getName(),mth,
562 "lastUpdatedTimeStamp: " + tStamp);
563 }
564
565 if (tStamp == null)
566 tStamp = "0";
567
568 long lastTime = (new Long(tStamp)).longValue();
569
570 if (tracing) {
571 MODELMBEAN_LOGGER.logp(Level.FINER,
572 RequiredModelMBean.class.getName(),mth,
573 "currencyPeriod:" + currencyPeriod +
574 " lastUpdatedTimeStamp:" + lastTime);
575 }
576
577 long now = (new Date()).getTime();
578
579 if (now < (lastTime + currencyPeriod)) {
580 returnCachedValue = true;
581 resetValue = false;
582 if (tracing) {
583 MODELMBEAN_LOGGER.logp(Level.FINER,
584 RequiredModelMBean.class.getName(),mth,
585 " timed valid Cache for " + now + " < " +
586 (lastTime + currencyPeriod));
587 }
588 } else { /* value is expired */
589 returnCachedValue = false;
590 resetValue = true;
591 if (tracing) {
592 MODELMBEAN_LOGGER.logp(Level.FINER,
593 RequiredModelMBean.class.getName(),mth,
594 "timed expired cache for " + now + " > " +
595 (lastTime + currencyPeriod));
596 }
597 }
598 }
599 if (tracing) {
600 MODELMBEAN_LOGGER.logp(Level.FINER,
601 RequiredModelMBean.class.getName(),mth,
602 "returnCachedValue:" + returnCachedValue +
603 " resetValue: " + resetValue);
604 }
605
606 if (returnCachedValue == true) {
607 Object currValue = descr.getFieldValue("value");
608 if (currValue != null) {
609 /* error/validity check return value here */
610 response = currValue;
611 /* need to cast string cached value to type */
612 if (tracing) {
613 MODELMBEAN_LOGGER.logp(Level.FINER,
614 RequiredModelMBean.class.getName(),mth,
615 "valid Cache value: " + currValue);
616 }
617
618 } else {
619 response = null;
620 if (tracing) {
621 MODELMBEAN_LOGGER.logp(Level.FINER,
622 RequiredModelMBean.class.getName(),
623 mth,"no Cached value");
624 }
625 }
626 }
627
628 if (resetValue == true) {
629 /* value is not current, so remove it */
630 descr.removeField("lastUpdatedTimeStamp");
631 descr.removeField("value");
632 response = null;
633 modelMBeanInfo.setDescriptor(descr,null);
634 if (tracing) {
635 MODELMBEAN_LOGGER.logp(Level.FINER,
636 RequiredModelMBean.class.getName(),
637 mth,"reset cached value to null");
638 }
639 }
640 }
641
642 if (tracing) {
643 MODELMBEAN_LOGGER.logp(Level.FINER,
644 RequiredModelMBean.class.getName(),mth,"Exit");
645 }
646
647 return response;
648 }
649
650 /**
651 * Returns the attributes, operations, constructors and notifications
652 * that this RequiredModelMBean exposes for management.
653 *
654 * @return An instance of ModelMBeanInfo allowing retrieval all
655 * attributes, operations, and Notifications of this MBean.
656 *
657 **/
658 public MBeanInfo getMBeanInfo() {
659
660 if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) {
661 MODELMBEAN_LOGGER.logp(Level.FINER,
662 RequiredModelMBean.class.getName(),
663 "getMBeanInfo()","Entry");
664 }
665
666 if (modelMBeanInfo == null) {
667 if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) {
668 MODELMBEAN_LOGGER.logp(Level.FINER,
669 RequiredModelMBean.class.getName(),
670 "getMBeanInfo()","modelMBeanInfo is null");
671 }
672 modelMBeanInfo = createDefaultModelMBeanInfo();
673 //return new ModelMBeanInfo(" ", "", null, null, null, null);
674 }
675
676 if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) {
677 MODELMBEAN_LOGGER.logp(Level.FINER,
678 RequiredModelMBean.class.getName(),
679 "getMBeanInfo()","ModelMBeanInfo is " +
680 modelMBeanInfo.getClassName() + " for " +
681 modelMBeanInfo.getDescription());
682 MODELMBEAN_LOGGER.logp(Level.FINER,
683 RequiredModelMBean.class.getName(),
684 "getMBeanInfo()",printModelMBeanInfo(modelMBeanInfo));
685 }
686
687 return((MBeanInfo) modelMBeanInfo.clone());
688 }
689
690 private String printModelMBeanInfo(ModelMBeanInfo info) {
691 final StringBuilder retStr = new StringBuilder();
692 if (info == null) {
693 if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) {
694 MODELMBEAN_LOGGER.logp(Level.FINER,
695 RequiredModelMBean.class.getName(),
696 "printModelMBeanInfo(ModelMBeanInfo)",
697 "ModelMBeanInfo to print is null, " +
698 "printing local ModelMBeanInfo");
699 }
700 info = modelMBeanInfo;
701 }
702
703 retStr.append("\nMBeanInfo for ModelMBean is:");
704 retStr.append("\nCLASSNAME: \t"+ info.getClassName());
705 retStr.append("\nDESCRIPTION: \t"+ info.getDescription());
706
707
708 try {
709 retStr.append("\nMBEAN DESCRIPTOR: \t"+
710 info.getMBeanDescriptor());
711 } catch (Exception e) {
712 retStr.append("\nMBEAN DESCRIPTOR: \t" + " is invalid");
713 }
714
715 retStr.append("\nATTRIBUTES");
716
717 final MBeanAttributeInfo[] attrInfo = info.getAttributes();
718 if ((attrInfo != null) && (attrInfo.length>0)) {
719 for (int i=0; i<attrInfo.length; i++) {
720 final ModelMBeanAttributeInfo attInfo =
721 (ModelMBeanAttributeInfo)attrInfo[i];
722 retStr.append(" ** NAME: \t"+ attInfo.getName());
723 retStr.append(" DESCR: \t"+ attInfo.getDescription());
724 retStr.append(" TYPE: \t"+ attInfo.getType() +
725 " READ: \t"+ attInfo.isReadable() +
726 " WRITE: \t"+ attInfo.isWritable());
727 retStr.append(" DESCRIPTOR: " +
728 attInfo.getDescriptor().toString());
729 }
730 } else {
731 retStr.append(" ** No attributes **");
732 }
733
734 retStr.append("\nCONSTRUCTORS");
735 final MBeanConstructorInfo[] constrInfo = info.getConstructors();
736 if ((constrInfo != null) && (constrInfo.length > 0 )) {
737 for (int i=0; i<constrInfo.length; i++) {
738 final ModelMBeanConstructorInfo ctorInfo =
739 (ModelMBeanConstructorInfo)constrInfo[i];
740 retStr.append(" ** NAME: \t"+ ctorInfo.getName());
741 retStr.append(" DESCR: \t"+
742 ctorInfo.getDescription());
743 retStr.append(" PARAM: \t"+
744 ctorInfo.getSignature().length +
745 " parameter(s)");
746 retStr.append(" DESCRIPTOR: " +
747 ctorInfo.getDescriptor().toString());
748 }
749 } else {
750 retStr.append(" ** No Constructors **");
751 }
752
753 retStr.append("\nOPERATIONS");
754 final MBeanOperationInfo[] opsInfo = info.getOperations();
755 if ((opsInfo != null) && (opsInfo.length>0)) {
756 for (int i=0; i<opsInfo.length; i++) {
757 final ModelMBeanOperationInfo operInfo =
758 (ModelMBeanOperationInfo)opsInfo[i];
759 retStr.append(" ** NAME: \t"+ operInfo.getName());
760 retStr.append(" DESCR: \t"+ operInfo.getDescription());
761 retStr.append(" PARAM: \t"+
762 operInfo.getSignature().length +
763 " parameter(s)");
764 retStr.append(" DESCRIPTOR: " +
765 operInfo.getDescriptor().toString());
766 }
767 } else {
768 retStr.append(" ** No operations ** ");
769 }
770
771 retStr.append("\nNOTIFICATIONS");
772
773 MBeanNotificationInfo[] notifInfo = info.getNotifications();
774 if ((notifInfo != null) && (notifInfo.length>0)) {
775 for (int i=0; i<notifInfo.length; i++) {
776 final ModelMBeanNotificationInfo nInfo =
777 (ModelMBeanNotificationInfo)notifInfo[i];
778 retStr.append(" ** NAME: \t"+ nInfo.getName());
779 retStr.append(" DESCR: \t"+ nInfo.getDescription());
780 retStr.append(" DESCRIPTOR: " +
781 nInfo.getDescriptor().toString());
782 }
783 } else {
784 retStr.append(" ** No notifications **");
785 }
786
787 retStr.append(" ** ModelMBean: End of MBeanInfo ** ");
788
789 return retStr.toString();
790 }
791
792 /**
793 * Invokes a method on or through a RequiredModelMBean and returns
794 * the result of the method execution.
795 * <P>
796 * If the given method to be invoked, together with the provided
797 * signature, matches one of RequiredModelMbean
798 * accessible methods, this one will be call. Otherwise the call to
799 * the given method will be tried on the managed resource.
800 * <P>
801 * The last value returned by an operation may be cached in
802 * the operation's descriptor which
803 * is in the ModelMBeanOperationInfo's descriptor.
804 * The valid value will be in the 'value' field if there is one.
805 * If the 'currencyTimeLimit' field in the descriptor is:
806 * <UL>
807 * <LI><b><0</b> Then the value is not cached and is never valid.
808 * The operation method is invoked.
809 * The 'value' and 'lastUpdatedTimeStamp' fields are cleared.</LI>
810 * <LI><b>=0</b> Then the value is always cached and always valid.
811 * The 'value' field is returned. If there is no 'value' field
812 * then the operation method is invoked for the attribute.
813 * The 'lastUpdatedTimeStamp' field and `value' fields are set to
814 * the operation's return value and the current time stamp.</LI>
815 * <LI><b>>0</b> Represents the number of seconds that the 'value'
816 * field is valid.
817 * The 'value' field is no longer valid when
818 * 'lastUpdatedTimeStamp' + 'currencyTimeLimit' > Now.
819 * <UL>
820 * <LI>When 'value' is valid, 'value' is returned.</LI>
821 * <LI>When 'value' is no longer valid then the operation
822 * method is invoked. The 'lastUpdatedTimeStamp' field
823 * and `value' fields are updated.</lI>
824 * </UL>
825 * </LI>
826 * </UL>
827 *
828 * <p><b>Note:</b> because of inconsistencies in previous versions of
829 * this specification, it is recommended not to use negative or zero
830 * values for <code>currencyTimeLimit</code>. To indicate that a
831 * cached value is never valid, omit the
832 * <code>currencyTimeLimit</code> field. To indicate that it is
833 * always valid, use a very large number for this field.</p>
834 *
835 * @param opName The name of the method to be invoked. The
836 * name can be the fully qualified method name including the
837 * classname, or just the method name if the classname is
838 * defined in the 'class' field of the operation descriptor.
839 * @param opArgs An array containing the parameters to be set
840 * when the operation is invoked
841 * @param sig An array containing the signature of the
842 * operation. The class objects will be loaded using the same
843 * class loader as the one used for loading the MBean on which
844 * the operation was invoked.
845 *
846 * @return The object returned by the method, which represents the
847 * result of invoking the method on the specified managed resource.
848 *
849 * @exception MBeanException Wraps one of the following Exceptions:
850 * <UL>
851 * <LI> An Exception thrown by the managed object's invoked method.</LI>
852 * <LI> {@link ServiceNotFoundException}: No ModelMBeanOperationInfo or
853 * no descriptor defined for the specified operation or the managed
854 * resource is null.</LI>
855 * <LI> {@link InvalidTargetObjectTypeException}: The 'targetType'
856 * field value is not 'objectReference'.</LI>
857 * </UL>
858 * @exception ReflectionException Wraps an {@link java.lang.Exception}
859 * thrown while trying to invoke the method.
860 * @exception RuntimeOperationsException Wraps an
861 * {@link IllegalArgumentException} Method name is null.
862 *
863 **/
864 /*
865 The requirement to be able to invoke methods on the
866 RequiredModelMBean class itself makes this method considerably
867 more complicated than it might otherwise be. Note that, unlike
868 earlier versions, we do not allow you to invoke such methods if
869 they are not explicitly mentioned in the ModelMBeanInfo. Doing
870 so was potentially a security problem, and certainly very
871 surprising.
872
873 We do not look for the method in the RequiredModelMBean class
874 itself if:
875 (a) there is a "targetObject" field in the Descriptor for the
876 operation; or
877 (b) there is a "class" field in the Descriptor for the operation
878 and the named class is not RequiredModelMBean or one of its
879 superinterfaces; or
880 (c) the name of the operation is not the name of a method in
881 RequiredModelMBean (this is just an optimization).
882
883 In cases (a) and (b), if you have gone to the trouble of adding
884 those fields specifically for this operation then presumably you
885 do not want RequiredModelMBean's methods to be called.
886
887 We have to pay attention to class loading issues. If the
888 "class" field is present, the named class has to be resolved
889 relative to RequiredModelMBean's class loader to test the
890 condition (b) above, and relative to the managed resource's
891 class loader to ensure that the managed resource is in fact of
892 the named class (or a subclass). The class names in the sig
893 array likewise have to be resolved, first against
894 RequiredModelMBean's class loader, then against the managed
895 resource's class loader. There is no point in using any other
896 loader because when we call Method.invoke we must call it on
897 a Method that is implemented by the target object.
898 */
899 public Object invoke(String opName, Object[] opArgs, String[] sig)
900 throws MBeanException, ReflectionException {
901
902 final boolean tracing = MODELMBEAN_LOGGER.isLoggable(Level.FINER);
903 final String mth = "invoke(String, Object[], String[])";
904
905 if (tracing) {
906 MODELMBEAN_LOGGER.logp(Level.FINER,
907 RequiredModelMBean.class.getName(), mth, "Entry");
908 }
909
910 if (opName == null) {
911 final RuntimeException x =
912 new IllegalArgumentException("Method name must not be null");
913 throw new RuntimeOperationsException(x,
914 "An exception occurred while trying to " +
915 "invoke a method on a RequiredModelMBean");
916 }
917
918 String opClassName = null;
919 String opMethodName;
920
921 // Parse for class name and method
922 int opSplitter = opName.lastIndexOf(".");
923 if (opSplitter > 0) {
924 opClassName = opName.substring(0,opSplitter);
925 opMethodName = opName.substring(opSplitter+1);
926 } else
927 opMethodName = opName;
928
929 /* Ignore anything after a left paren. We keep this for
930 compatibility but it isn't specified. */
931 opSplitter = opMethodName.indexOf("(");
932 if (opSplitter > 0)
933 opMethodName = opMethodName.substring(0,opSplitter);
934
935 if (tracing) {
936 MODELMBEAN_LOGGER.logp(Level.FINER,
937 RequiredModelMBean.class.getName(),
938 mth, "Finding operation " + opName + " as " + opMethodName);
939 }
940
941 ModelMBeanOperationInfo opInfo =
942 modelMBeanInfo.getOperation(opMethodName);
943 if (opInfo == null) {
944 final String msg =
945 "Operation " + opName + " not in ModelMBeanInfo";
946 throw new MBeanException(new ServiceNotFoundException(msg), msg);
947 }
948
949 final Descriptor opDescr = opInfo.getDescriptor();
950 if (opDescr == null) {
951 final String msg = "Operation descriptor null";
952 throw new MBeanException(new ServiceNotFoundException(msg), msg);
953 }
954
955 final Object cached = resolveForCacheValue(opDescr);
956 if (cached != null) {
957 if (tracing) {
958 MODELMBEAN_LOGGER.logp(Level.FINER,
959 RequiredModelMBean.class.getName(),
960 mth,
961 "Returning cached value");
962 }
963 return cached;
964 }
965
966 if (opClassName == null)
967 opClassName = (String) opDescr.getFieldValue("class");
968 // may still be null now
969
970 opMethodName = (String) opDescr.getFieldValue("name");
971 if (opMethodName == null) {
972 final String msg =
973 "Method descriptor must include `name' field";
974 throw new MBeanException(new ServiceNotFoundException(msg), msg);
975 }
976
977 final String targetTypeField = (String)
978 opDescr.getFieldValue("targetType");
979 if (targetTypeField != null
980 && !targetTypeField.equalsIgnoreCase("objectReference")) {
981 final String msg =
982 "Target type must be objectReference: " + targetTypeField;
983 throw new MBeanException(new InvalidTargetObjectTypeException(msg),
984 msg);
985 }
986
987 final Object targetObjectField = opDescr.getFieldValue("targetObject");
988 if (tracing && targetObjectField != null)
989 MODELMBEAN_LOGGER.logp(Level.FINER,
990 RequiredModelMBean.class.getName(),
991 mth, "Found target object in descriptor");
992
993 /* Now look for the method, either in RequiredModelMBean itself
994 or in the target object. Set "method" and "targetObject"
995 appropriately. */
996 Method method;
997 Object targetObject;
998
999 method = findRMMBMethod(opMethodName, targetObjectField,
1000 opClassName, sig);
1001
1002 if (method != null)
1003 targetObject = this;
1004 else {
1005 if (tracing) {
1006 MODELMBEAN_LOGGER.logp(Level.FINER,
1007 RequiredModelMBean.class.getName(),
1008 mth, "looking for method in managedResource class");
1009 }
1010 if (targetObjectField != null)
1011 targetObject = targetObjectField;
1012 else {
1013 targetObject = managedResource;
1014 if (targetObject == null) {
1015 final String msg =
1016 "managedResource for invoke " + opName +
1017 " is null";
1018 Exception snfe = new ServiceNotFoundException(msg);
1019 throw new MBeanException(snfe);
1020 }
1021 }
1022
1023 final Class targetClass;
1024
1025 if (opClassName != null) {
1026 try {
1027 final ClassLoader targetClassLoader =
1028 targetObject.getClass().getClassLoader();
1029 targetClass = Class.forName(opClassName, false,
1030 targetClassLoader);
1031 } catch (ClassNotFoundException e) {
1032 final String msg =
1033 "class for invoke " + opName + " not found";
1034 throw new ReflectionException(e, msg);
1035 }
1036 } else
1037 targetClass = targetObject.getClass();
1038
1039 method = resolveMethod(targetClass, opMethodName, sig);
1040 }
1041
1042 if (tracing) {
1043 MODELMBEAN_LOGGER.logp(Level.FINER,
1044 RequiredModelMBean.class.getName(),
1045 mth, "found " + opMethodName + ", now invoking");
1046 }
1047
1048 final Object result =
1049 invokeMethod(opName, method, targetObject, opArgs);
1050
1051 if (tracing) {
1052 MODELMBEAN_LOGGER.logp(Level.FINER,
1053 RequiredModelMBean.class.getName(),
1054 mth, "successfully invoked method");
1055 }
1056
1057 if (result != null)
1058 cacheResult(opInfo, opDescr, result);
1059
1060 return result;
1061 }
1062
1063 private static Method resolveMethod(Class<?> targetClass,
1064 String opMethodName,
1065 String[] sig)
1066 throws ReflectionException {
1067 final boolean tracing = MODELMBEAN_LOGGER.isLoggable(Level.FINER);
1068
1069 if (tracing) {
1070 MODELMBEAN_LOGGER.logp(Level.FINER,
1071 RequiredModelMBean.class.getName(),"resolveMethod",
1072 "resolving " + targetClass + "." + opMethodName);
1073 }
1074
1075 final Class[] argClasses;
1076
1077 if (sig == null)
1078 argClasses = null;
1079 else {
1080 final ClassLoader targetClassLoader = targetClass.getClassLoader();
1081 argClasses = new Class[sig.length];
1082 for (int i = 0; i < sig.length; i++) {
1083 if (tracing) {
1084 MODELMBEAN_LOGGER.logp(Level.FINER,
1085 RequiredModelMBean.class.getName(),"resolveMethod",
1086 "resolve type " + sig[i]);
1087 }
1088 argClasses[i] = (Class) primitiveClassMap.get(sig[i]);
1089 if (argClasses[i] == null) {
1090 try {
1091 argClasses[i] =
1092 Class.forName(sig[i], false, targetClassLoader);
1093 } catch (ClassNotFoundException e) {
1094 if (tracing) {
1095 MODELMBEAN_LOGGER.logp(Level.FINER,
1096 RequiredModelMBean.class.getName(),
1097 "resolveMethod",
1098 "class not found");
1099 }
1100 final String msg = "Parameter class not found";
1101 throw new ReflectionException(e, msg);
1102 }
1103 }
1104 }
1105 }
1106
1107 try {
1108 return targetClass.getMethod(opMethodName, argClasses);
1109 } catch (NoSuchMethodException e) {
1110 final String msg =
1111 "Target method not found: " + targetClass.getName() + "." +
1112 opMethodName;
1113 throw new ReflectionException(e, msg);
1114 }
1115 }
1116
1117 /* Map e.g. "int" to int.class. Goodness knows how many time this
1118 particular wheel has been reinvented. */
1119 private static final Class[] primitiveClasses = {
1120 int.class, long.class, boolean.class, double.class,
1121 float.class, short.class, byte.class, char.class,
1122 };
1123 private static final Map<String,Class<?>> primitiveClassMap =
1124 new HashMap<String,Class<?>>();
1125 static {
1126 for (int i = 0; i < primitiveClasses.length; i++) {
1127 final Class c = primitiveClasses[i];
1128 primitiveClassMap.put(c.getName(), c);
1129 }
1130 }
1131
1132 /* Find a method in RequiredModelMBean as determined by the given
1133 parameters. Return null if there is none, or if the parameters
1134 exclude using it. Called from invoke. */
1135 private static Method findRMMBMethod(String opMethodName,
1136 Object targetObjectField,
1137 String opClassName,
1138 String[] sig) {
1139 final boolean tracing = MODELMBEAN_LOGGER.isLoggable(Level.FINER);
1140
1141 if (tracing) {
1142 MODELMBEAN_LOGGER.logp(Level.FINER,
1143 RequiredModelMBean.class.getName(),
1144 "invoke(String, Object[], String[])",
1145 "looking for method in RequiredModelMBean class");
1146 }
1147
1148 if (!isRMMBMethodName(opMethodName))
1149 return null;
1150 if (targetObjectField != null)
1151 return null;
1152 final Class<RequiredModelMBean> rmmbClass = RequiredModelMBean.class;
1153 final Class<?> targetClass;
1154 if (opClassName == null)
1155 targetClass = rmmbClass;
1156 else {
1157 try {
1158 final ClassLoader targetClassLoader =
1159 rmmbClass.getClassLoader();
1160 targetClass = Class.forName(opClassName, false,
1161 targetClassLoader);
1162 if (!rmmbClass.isAssignableFrom(targetClass))
1163 return null;
1164 } catch (ClassNotFoundException e) {
1165 return null;
1166 }
1167 }
1168 try {
1169 return resolveMethod(targetClass, opMethodName, sig);
1170 } catch (ReflectionException e) {
1171 return null;
1172 }
1173 }
1174
1175 /*
1176 * Invoke the given method, and throw the somewhat unpredictable
1177 * appropriate exception if the method itself gets an exception.
1178 */
1179 private Object invokeMethod(String opName, Method method,
1180 Object targetObject, Object[] opArgs)
1181 throws MBeanException, ReflectionException {
1182 try {
1183 ReflectUtil.checkPackageAccess(method.getDeclaringClass());
1184 return MethodUtil.invoke(method, targetObject, opArgs);
1185 } catch (RuntimeErrorException ree) {
1186 throw new RuntimeOperationsException(ree,
1187 "RuntimeException occurred in RequiredModelMBean "+
1188 "while trying to invoke operation " + opName);
1189 } catch (RuntimeException re) {
1190 throw new RuntimeOperationsException(re,
1191 "RuntimeException occurred in RequiredModelMBean "+
1192 "while trying to invoke operation " + opName);
1193 } catch (IllegalAccessException iae) {
1194 throw new ReflectionException(iae,
1195 "IllegalAccessException occurred in " +
1196 "RequiredModelMBean while trying to " +
1197 "invoke operation " + opName);
1198 } catch (InvocationTargetException ite) {
1199 Throwable mmbTargEx = ite.getTargetException();
1200 if (mmbTargEx instanceof RuntimeException) {
1201 throw new MBeanException ((RuntimeException)mmbTargEx,
1202 "RuntimeException thrown in RequiredModelMBean "+
1203 "while trying to invoke operation " + opName);
1204 } else if (mmbTargEx instanceof Error) {
1205 throw new RuntimeErrorException((Error)mmbTargEx,
1206 "Error occurred in RequiredModelMBean while trying "+
1207 "to invoke operation " + opName);
1208 } else if (mmbTargEx instanceof ReflectionException) {
1209 throw (ReflectionException) mmbTargEx;
1210 } else {
1211 throw new MBeanException ((Exception)mmbTargEx,
1212 "Exception thrown in RequiredModelMBean "+
1213 "while trying to invoke operation " + opName);
1214 }
1215 } catch (Error err) {
1216 throw new RuntimeErrorException(err,
1217 "Error occurred in RequiredModelMBean while trying "+
1218 "to invoke operation " + opName);
1219 } catch (Exception e) {
1220 throw new ReflectionException(e,
1221 "Exception occurred in RequiredModelMBean while " +
1222 "trying to invoke operation " + opName);
1223 }
1224 }
1225
1226 /*
1227 * Cache the result of an operation in the descriptor, if that is
1228 * called for by the descriptor's configuration. Note that we
1229 * don't remember operation parameters when caching the result, so
1230 * this is unlikely to be useful if there are any.
1231 */
1232 private void cacheResult(ModelMBeanOperationInfo opInfo,
1233 Descriptor opDescr, Object result)
1234 throws MBeanException {
1235
1236 Descriptor mmbDesc =
1237 modelMBeanInfo.getMBeanDescriptor();
1238
1239 Object objctl =
1240 opDescr.getFieldValue("currencyTimeLimit");
1241 String ctl;
1242 if (objctl != null) {
1243 ctl = objctl.toString();
1244 } else {
1245 ctl = null;
1246 }
1247 if ((ctl == null) && (mmbDesc != null)) {
1248 objctl =
1249 mmbDesc.getFieldValue("currencyTimeLimit");
1250 if (objctl != null) {
1251 ctl = objctl.toString();
1252 } else {
1253 ctl = null;
1254 }
1255 }
1256 if ((ctl != null) && !(ctl.equals("-1"))) {
1257 opDescr.setField("value", result);
1258 opDescr.setField("lastUpdatedTimeStamp",
1259 String.valueOf((new Date()).getTime()));
1260
1261
1262 modelMBeanInfo.setDescriptor(opDescr,
1263 "operation");
1264 if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) {
1265 MODELMBEAN_LOGGER.logp(Level.FINER,
1266 RequiredModelMBean.class.getName(),
1267 "invoke(String,Object[],Object[])",
1268 "new descriptor is " + opDescr);
1269 }
1270 }
1271 }
1272
1273 /*
1274 * Determine whether the given name is the name of a public method
1275 * in this class. This is only an optimization: it prevents us
1276 * from trying to do argument type lookups and reflection on a
1277 * method that will obviously fail because it has the wrong name.
1278 *
1279 * The first time this method is called we do the reflection, and
1280 * every other time we reuse the remembered values.
1281 *
1282 * It's conceivable that the (possibly malicious) first caller
1283 * doesn't have the required permissions to do reflection, in
1284 * which case we don't touch anything so as not to interfere
1285 * with a later permissionful caller.
1286 */
1287 private static Set<String> rmmbMethodNames;
1288 private static synchronized boolean isRMMBMethodName(String name) {
1289 if (rmmbMethodNames == null) {
1290 try {
1291 Set<String> names = new HashSet<String>();
1292 Method[] methods = RequiredModelMBean.class.getMethods();
1293 for (int i = 0; i < methods.length; i++)
1294 names.add(methods[i].getName());
1295 rmmbMethodNames = names;
1296 } catch (Exception e) {
1297 return true;
1298 // This is only an optimization so we'll go on to discover
1299 // whether the name really is an RMMB method.
1300 }
1301 }
1302 return rmmbMethodNames.contains(name);
1303 }
1304
1305 /**
1306 * Returns the value of a specific attribute defined for this
1307 * ModelMBean.
1308 * The last value returned by an attribute may be cached in the
1309 * attribute's descriptor.
1310 * The valid value will be in the 'value' field if there is one.
1311 * If the 'currencyTimeLimit' field in the descriptor is:
1312 * <UL>
1313 * <LI> <b><0</b> Then the value is not cached and is never valid.
1314 * The getter method is invoked for the attribute.
1315 * The 'value' and 'lastUpdatedTimeStamp' fields are cleared.</LI>
1316 * <LI> <b>=0</b> Then the value is always cached and always valid.
1317 * The 'value' field is returned. If there is no'value' field
1318 * then the getter method is invoked for the attribute.
1319 * The 'lastUpdatedTimeStamp' field and `value' fields are set
1320 * to the attribute's value and the current time stamp.</LI>
1321 * <LI> <b>>0</b> Represents the number of seconds that the 'value'
1322 * field is valid.
1323 * The 'value' field is no longer valid when
1324 * 'lastUpdatedTimeStamp' + 'currencyTimeLimit' > Now.
1325 * <UL>
1326 * <LI>When 'value' is valid, 'value' is returned.</LI>
1327 * <LI>When 'value' is no longer valid then the getter
1328 * method is invoked for the attribute.
1329 * The 'lastUpdatedTimeStamp' field and `value' fields
1330 * are updated.</LI>
1331 * </UL></LI>
1332 * </UL>
1333 *
1334 * <p><b>Note:</b> because of inconsistencies in previous versions of
1335 * this specification, it is recommended not to use negative or zero
1336 * values for <code>currencyTimeLimit</code>. To indicate that a
1337 * cached value is never valid, omit the
1338 * <code>currencyTimeLimit</code> field. To indicate that it is
1339 * always valid, use a very large number for this field.</p>
1340 *
1341 * <p>If the 'getMethod' field contains the name of a valid
1342 * operation descriptor, then the method described by the
1343 * operation descriptor is executed. The response from the
1344 * method is returned as the value of the attribute. If the
1345 * operation fails or the returned value is not compatible with
1346 * the declared type of the attribute, an exception will be thrown.</p>
1347 *
1348 * <p>If no 'getMethod' field is defined then the default value of the
1349 * attribute is returned. If the returned value is not compatible with
1350 * the declared type of the attribute, an exception will be thrown.</p>
1351 *
1352 * <p>The declared type of the attribute is the String returned by
1353 * {@link ModelMBeanAttributeInfo#getType()}. A value is compatible
1354 * with this type if one of the following is true:
1355 * <ul>
1356 * <li>the value is null;</li>
1357 * <li>the declared name is a primitive type name (such as "int")
1358 * and the value is an instance of the corresponding wrapper
1359 * type (such as java.lang.Integer);</li>
1360 * <li>the name of the value's class is identical to the declared name;</li>
1361 * <li>the declared name can be loaded by the value's class loader and
1362 * produces a class to which the value can be assigned.</li>
1363 * </ul>
1364 *
1365 * <p>In this implementation, in every case where the getMethod needs to
1366 * be called, because the method is invoked through the standard "invoke"
1367 * method and thus needs operationInfo, an operation must be specified
1368 * for that getMethod so that the invocation works correctly.</p>
1369 *
1370 * @param attrName A String specifying the name of the
1371 * attribute to be retrieved. It must match the name of a
1372 * ModelMBeanAttributeInfo.
1373 *
1374 * @return The value of the retrieved attribute from the
1375 * descriptor 'value' field or from the invocation of the
1376 * operation in the 'getMethod' field of the descriptor.
1377 *
1378 * @exception AttributeNotFoundException The specified attribute is
1379 * not accessible in the MBean.
1380 * The following cases may result in an AttributeNotFoundException:
1381 * <UL>
1382 * <LI> No ModelMBeanInfo was found for the Model MBean.</LI>
1383 * <LI> No ModelMBeanAttributeInfo was found for the specified
1384 * attribute name.</LI>
1385 * <LI> The ModelMBeanAttributeInfo isReadable method returns
1386 * 'false'.</LI>
1387 * </UL>
1388 * @exception MBeanException Wraps one of the following Exceptions:
1389 * <UL>
1390 * <LI> {@link InvalidAttributeValueException}: A wrong value type
1391 * was received from the attribute's getter method or
1392 * no 'getMethod' field defined in the descriptor for
1393 * the attribute and no default value exists.</LI>
1394 * <LI> {@link ServiceNotFoundException}: No
1395 * ModelMBeanOperationInfo defined for the attribute's
1396 * getter method or no descriptor associated with the
1397 * ModelMBeanOperationInfo or the managed resource is
1398 * null.</LI>
1399 * <LI> {@link InvalidTargetObjectTypeException} The 'targetType'
1400 * field value is not 'objectReference'.</LI>
1401 * <LI> An Exception thrown by the managed object's getter.</LI>
1402 * </UL>
1403 * @exception ReflectionException Wraps an {@link java.lang.Exception}
1404 * thrown while trying to invoke the getter.
1405 * @exception RuntimeOperationsException Wraps an
1406 * {@link IllegalArgumentException}: The attribute name in
1407 * parameter is null.
1408 *
1409 * @see #setAttribute(javax.management.Attribute)
1410 **/
1411 public Object getAttribute(String attrName)
1412 throws AttributeNotFoundException, MBeanException,
1413 ReflectionException {
1414 if (attrName == null)
1415 throw new RuntimeOperationsException(new
1416 IllegalArgumentException("attributeName must not be null"),
1417 "Exception occurred trying to get attribute of a " +
1418 "RequiredModelMBean");
1419 final String mth = "getAttribute(String)";
1420 final boolean tracing = MODELMBEAN_LOGGER.isLoggable(Level.FINER);
1421 if (tracing) {
1422 MODELMBEAN_LOGGER.logp(Level.FINER,
1423 RequiredModelMBean.class.getName(),
1424 mth, "Entry with " + attrName);
1425 }
1426
1427 /* Check attributeDescriptor for getMethod */
1428 Object response;
1429
1430 try {
1431 if (modelMBeanInfo == null)
1432 throw new AttributeNotFoundException(
1433 "getAttribute failed: ModelMBeanInfo not found for "+
1434 attrName);
1435
1436 ModelMBeanAttributeInfo attrInfo = modelMBeanInfo.getAttribute(attrName);
1437 Descriptor mmbDesc = modelMBeanInfo.getMBeanDescriptor();
1438
1439 if (attrInfo == null)
1440 throw new AttributeNotFoundException("getAttribute failed:"+
1441 " ModelMBeanAttributeInfo not found for " + attrName);
1442
1443 Descriptor attrDescr = attrInfo.getDescriptor();
1444 if (attrDescr != null) {
1445 if (!attrInfo.isReadable())
1446 throw new AttributeNotFoundException(
1447 "getAttribute failed: " + attrName +
1448 " is not readable ");
1449
1450 response = resolveForCacheValue(attrDescr);
1451
1452 /* return current cached value */
1453 if (tracing) {
1454 MODELMBEAN_LOGGER.logp(Level.FINER,
1455 RequiredModelMBean.class.getName(), mth,
1456 "*** cached value is " + response);
1457 }
1458
1459 if (response == null) {
1460 /* no cached value, run getMethod */
1461 if (tracing) {
1462 MODELMBEAN_LOGGER.logp(Level.FINER,
1463 RequiredModelMBean.class.getName(), mth,
1464 "**** cached value is null - getting getMethod");
1465 }
1466 String attrGetMethod =
1467 (String)(attrDescr.getFieldValue("getMethod"));
1468
1469 if (attrGetMethod != null) {
1470 /* run method from operations descriptor */
1471 if (tracing) {
1472 MODELMBEAN_LOGGER.logp(Level.FINER,
1473 RequiredModelMBean.class.getName(),
1474 mth, "invoking a getMethod for " + attrName);
1475 }
1476
1477 Object getResponse =
1478 invoke(attrGetMethod, new Object[] {},
1479 new String[] {});
1480
1481 if (getResponse != null) {
1482 // error/validity check return value here
1483 if (tracing) {
1484 MODELMBEAN_LOGGER.logp(Level.FINER,
1485 RequiredModelMBean.class.getName(),
1486 mth, "got a non-null response " +
1487 "from getMethod\n");
1488 }
1489
1490 response = getResponse;
1491
1492 // change cached value in attribute descriptor
1493 Object objctl =
1494 attrDescr.getFieldValue("currencyTimeLimit");
1495
1496 String ctl;
1497 if (objctl != null) ctl = objctl.toString();
1498 else ctl = null;
1499
1500 if ((ctl == null) && (mmbDesc != null)) {
1501 objctl = mmbDesc.
1502 getFieldValue("currencyTimeLimit");
1503 if (objctl != null) ctl = objctl.toString();
1504 else ctl = null;
1505 }
1506
1507 if ((ctl != null) && !(ctl.equals("-1"))) {
1508 if (tracing) {
1509 MODELMBEAN_LOGGER.logp(Level.FINER,
1510 RequiredModelMBean.class.getName(),
1511 mth,
1512 "setting cached value and " +
1513 "lastUpdatedTime in descriptor");
1514 }
1515 attrDescr.setField("value", response);
1516 final String stamp = String.valueOf(
1517 (new Date()).getTime());
1518 attrDescr.setField("lastUpdatedTimeStamp",
1519 stamp);
1520 attrInfo.setDescriptor(attrDescr);
1521 modelMBeanInfo.setDescriptor(attrDescr,
1522 "attribute");
1523 if (tracing) {
1524 MODELMBEAN_LOGGER.logp(Level.FINER,
1525 RequiredModelMBean.class.getName(),
1526 mth,"new descriptor is " +attrDescr);
1527 MODELMBEAN_LOGGER.logp(Level.FINER,
1528 RequiredModelMBean.class.getName(),
1529 mth,"AttributeInfo descriptor is " +
1530 attrInfo.getDescriptor());
1531 final String attStr = modelMBeanInfo.
1532 getDescriptor(attrName,"attribute").
1533 toString();
1534 MODELMBEAN_LOGGER.logp(Level.FINER,
1535 RequiredModelMBean.class.getName(),
1536 mth,
1537 "modelMBeanInfo: AttributeInfo " +
1538 "descriptor is " + attStr);
1539 }
1540 }
1541 } else {
1542 // response was invalid or really returned null
1543 if (tracing) {
1544 MODELMBEAN_LOGGER.logp(Level.FINER,
1545 RequiredModelMBean.class.getName(), mth,
1546 "got a null response from getMethod\n");
1547 }
1548 response = null;
1549 }
1550 } else {
1551 // not getMethod so return descriptor (default) value
1552 String qualifier="";
1553 response = attrDescr.getFieldValue("value");
1554 if (response == null) {
1555 qualifier="default ";
1556 response = attrDescr.getFieldValue("default");
1557 }
1558 if (tracing) {
1559 MODELMBEAN_LOGGER.logp(Level.FINER,
1560 RequiredModelMBean.class.getName(), mth,
1561 "could not find getMethod for " +attrName +
1562 ", returning descriptor " +qualifier + "value");
1563 }
1564 // !! cast response to right class
1565 }
1566 }
1567
1568 // make sure response class matches type field
1569 String respType = attrInfo.getType();
1570 if (response != null) {
1571 String responseClass = response.getClass().getName();
1572 if (!respType.equals(responseClass)) {
1573 boolean wrongType = false;
1574 boolean primitiveType = false;
1575 boolean correspondingTypes = false;
1576 for (int i = 0; i < primitiveTypes.length; i++) {
1577 if (respType.equals(primitiveTypes[i])) {
1578 primitiveType = true;
1579 if (responseClass.equals(primitiveWrappers[i]))
1580 correspondingTypes = true;
1581 break;
1582 }
1583 }
1584 if (primitiveType) {
1585 // inequality may come from primitive/wrapper class
1586 if (!correspondingTypes)
1587 wrongType = true;
1588 } else {
1589 // inequality may come from type subclassing
1590 boolean subtype;
1591 try {
1592 ClassLoader cl =
1593 response.getClass().getClassLoader();
1594 Class c = Class.forName(respType, true, cl);
1595 subtype = c.isInstance(response);
1596 } catch (Exception e) {
1597 subtype = false;
1598
1599 if (tracing) {
1600 MODELMBEAN_LOGGER.logp(Level.FINER,
1601 RequiredModelMBean.class.getName(),
1602 mth, "Exception: ",e);
1603 }
1604 }
1605 if (!subtype)
1606 wrongType = true;
1607 }
1608 if (wrongType) {
1609 if (tracing) {
1610 MODELMBEAN_LOGGER.logp(Level.FINER,
1611 RequiredModelMBean.class.getName(), mth,
1612 "Wrong response type '" + respType + "'");
1613 }
1614 // throw exception, didn't get
1615 // back right attribute type
1616 throw new MBeanException(
1617 new InvalidAttributeValueException(
1618 "Wrong value type received for get attribute"),
1619 "An exception occurred while trying to get an " +
1620 "attribute value through a RequiredModelMBean");
1621 }
1622 }
1623 }
1624 } else {
1625 if (tracing) {
1626 MODELMBEAN_LOGGER.logp(Level.FINER,
1627 RequiredModelMBean.class.getName(), mth,
1628 "getMethod failed " + attrName +
1629 " not in attributeDescriptor\n");
1630 }
1631 throw new MBeanException(new
1632 InvalidAttributeValueException(
1633 "Unable to resolve attribute value, " +
1634 "no getMethod defined in descriptor for attribute"),
1635 "An exception occurred while trying to get an "+
1636 "attribute value through a RequiredModelMBean");
1637 }
1638
1639 } catch (MBeanException mbe) {
1640 throw mbe;
1641 } catch (AttributeNotFoundException t) {
1642 throw t;
1643 } catch (Exception e) {
1644 if (tracing) {
1645 MODELMBEAN_LOGGER.logp(Level.FINER,
1646 RequiredModelMBean.class.getName(), mth,
1647 "getMethod failed with " + e.getMessage() +
1648 " exception type " + (e.getClass()).toString());
1649 }
1650 throw new MBeanException(e,"An exception occurred while trying "+
1651 "to get an attribute value: " + e.getMessage());
1652 }
1653
1654 if (tracing) {
1655 MODELMBEAN_LOGGER.logp(Level.FINER,
1656 RequiredModelMBean.class.getName(), mth, "Exit");
1657 }
1658
1659 return response;
1660 }
1661
1662 /**
1663 * Returns the values of several attributes in the ModelMBean.
1664 * Executes a getAttribute for each attribute name in the
1665 * attrNames array passed in.
1666 *
1667 * @param attrNames A String array of names of the attributes
1668 * to be retrieved.
1669 *
1670 * @return The array of the retrieved attributes.
1671 *
1672 * @exception RuntimeOperationsException Wraps an
1673 * {@link IllegalArgumentException}: The object name in parameter is
1674 * null or attributes in parameter is null.
1675 *
1676 * @see #setAttributes(javax.management.AttributeList)
1677 */
1678 public AttributeList getAttributes(String[] attrNames) {
1679 if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) {
1680 MODELMBEAN_LOGGER.logp(Level.FINER,
1681 RequiredModelMBean.class.getName(),
1682 "getAttributes(String[])","Entry");
1683 }
1684
1685 if (attrNames == null)
1686 throw new RuntimeOperationsException(new
1687 IllegalArgumentException("attributeNames must not be null"),
1688 "Exception occurred trying to get attributes of a "+
1689 "RequiredModelMBean");
1690
1691 AttributeList responseList = new AttributeList();
1692 for (int i = 0; i < attrNames.length; i++) {
1693 try {
1694 responseList.add(new Attribute(attrNames[i],
1695 getAttribute(attrNames[i])));
1696 } catch (Exception e) {
1697 // eat exceptions because interface doesn't have an
1698 // exception on it
1699 if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) {
1700 MODELMBEAN_LOGGER.logp(Level.FINER,
1701 RequiredModelMBean.class.getName(),
1702 "getAttributes(String[])",
1703 "Failed to get \"" + attrNames[i] + "\": ", e);
1704 }
1705 }
1706 }
1707
1708 if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) {
1709 MODELMBEAN_LOGGER.logp(Level.FINER,
1710 RequiredModelMBean.class.getName(),
1711 "getAttributes(String[])","Exit");
1712 }
1713
1714 return responseList;
1715 }
1716
1717 /**
1718 * Sets the value of a specific attribute of a named ModelMBean.
1719 *
1720 * If the 'setMethod' field of the attribute's descriptor
1721 * contains the name of a valid operation descriptor, then the
1722 * method described by the operation descriptor is executed.
1723 * In this implementation, the operation descriptor must be specified
1724 * correctly and assigned to the modelMBeanInfo so that the 'setMethod'
1725 * works correctly.
1726 * The response from the method is set as the value of the attribute
1727 * in the descriptor.
1728 *
1729 * <p>If currencyTimeLimit is > 0, then the new value for the
1730 * attribute is cached in the attribute descriptor's
1731 * 'value' field and the 'lastUpdatedTimeStamp' field is set to
1732 * the current time stamp.
1733 *
1734 * <p>If the persist field of the attribute's descriptor is not null
1735 * then Persistence policy from the attribute descriptor is used to
1736 * guide storing the attribute in a persistent store.
1737 * <br>Store the MBean if 'persistPolicy' field is:
1738 * <UL>
1739 * <Li> != "never"</Li>
1740 * <Li> = "always"</Li>
1741 * <Li> = "onUpdate"</Li>
1742 * <Li> = "onTimer" and now > 'lastPersistTime' + 'persistPeriod'</Li>
1743 * <Li> = "NoMoreOftenThan" and now > 'lastPersistTime' +
1744 * 'persistPeriod'</Li>
1745 * </UL>
1746 * Do not store the MBean if 'persistPolicy' field is:
1747 * <UL>
1748 * <Li> = "never"</Li>
1749 * <Li> = "onTimer" && now < 'lastPersistTime' + 'persistPeriod'</Li>
1750 * <Li> = "onUnregister"</Li>
1751 * <Li> = "NoMoreOftenThan" and now < 'lastPersistTime' +
1752 * 'persistPeriod'</Li>
1753 * </UL>
1754 *
1755 * <p>The ModelMBeanInfo of the Model MBean is stored in a file.
1756 *
1757 * @param attribute The Attribute instance containing the name of
1758 * the attribute to be set and the value it is to be set to.
1759 *
1760 *
1761 * @exception AttributeNotFoundException The specified attribute is
1762 * not accessible in the MBean.
1763 * <br>The following cases may result in an AttributeNotFoundException:
1764 * <UL>
1765 * <LI> No ModelMBeanAttributeInfo is found for the specified
1766 * attribute.</LI>
1767 * <LI> The ModelMBeanAttributeInfo's isWritable method returns
1768 * 'false'.</LI>
1769 * </UL>
1770 * @exception InvalidAttributeValueException No descriptor is defined
1771 * for the specified attribute.
1772 * @exception MBeanException Wraps one of the following Exceptions:
1773 * <UL>
1774 * <LI> An Exception thrown by the managed object's setter.</LI>
1775 * <LI> A {@link ServiceNotFoundException} if a setMethod field is
1776 * defined in the descriptor for the attribute and the managed
1777 * resource is null; or if no setMethod field is defined and
1778 * caching is not enabled for the attribute.
1779 * Note that if there is no getMethod field either, then caching
1780 * is automatically enabled.</LI>
1781 * <LI> {@link InvalidTargetObjectTypeException} The 'targetType'
1782 * field value is not 'objectReference'.</LI>
1783 * <LI> An Exception thrown by the managed object's getter.</LI>
1784 * </UL>
1785 * @exception ReflectionException Wraps an {@link java.lang.Exception}
1786 * thrown while trying to invoke the setter.
1787 * @exception RuntimeOperationsException Wraps an
1788 * {@link IllegalArgumentException}: The attribute in parameter is
1789 * null.
1790 *
1791 * @see #getAttribute(java.lang.String)
1792 **/
1793 public void setAttribute(Attribute attribute)
1794 throws AttributeNotFoundException, InvalidAttributeValueException,
1795 MBeanException, ReflectionException {
1796 final boolean tracing = MODELMBEAN_LOGGER.isLoggable(Level.FINER);
1797 if (tracing) {
1798 MODELMBEAN_LOGGER.logp(Level.FINER,
1799 RequiredModelMBean.class.getName(),
1800 "setAttribute()","Entry");
1801 }
1802
1803 if (attribute == null)
1804 throw new RuntimeOperationsException(new
1805 IllegalArgumentException("attribute must not be null"),
1806 "Exception occurred trying to set an attribute of a "+
1807 "RequiredModelMBean");
1808
1809 /* run setMethod if there is one */
1810 /* return cached value if its current */
1811 /* set cached value in descriptor and set date/time */
1812 /* send attribute change Notification */
1813 /* check persistence policy and persist if need be */
1814 String attrName = attribute.getName();
1815 Object attrValue = attribute.getValue();
1816 boolean updateDescriptor = false;
1817
1818 ModelMBeanAttributeInfo attrInfo =
1819 modelMBeanInfo.getAttribute(attrName);
1820
1821 if (attrInfo == null)
1822 throw new AttributeNotFoundException("setAttribute failed: " +
1823 attrName + " is not found ");
1824
1825 Descriptor mmbDesc = modelMBeanInfo.getMBeanDescriptor();
1826 Descriptor attrDescr = attrInfo.getDescriptor();
1827
1828 if (attrDescr != null) {
1829 if (!attrInfo.isWritable())
1830 throw new AttributeNotFoundException("setAttribute failed: "
1831 + attrName + " is not writable ");
1832
1833 String attrSetMethod = (String)
1834 (attrDescr.getFieldValue("setMethod"));
1835 String attrGetMethod = (String)
1836 (attrDescr.getFieldValue("getMethod"));
1837
1838 String attrType = attrInfo.getType();
1839 Object currValue = "Unknown";
1840
1841 try {
1842 currValue = this.getAttribute(attrName);
1843 } catch (Throwable t) {
1844 // OK: Default "Unknown" value used for unknown attribute
1845 }
1846
1847 Attribute oldAttr = new Attribute(attrName, currValue);
1848
1849 /* run method from operations descriptor */
1850 if (attrSetMethod == null) {
1851 if (attrValue != null) {
1852 try {
1853 final Class clazz = loadClass(attrType);
1854 if (! clazz.isInstance(attrValue)) throw new
1855 InvalidAttributeValueException(clazz.getName() +
1856 " expected, " +
1857 attrValue.getClass().getName() +
1858 " received.");
1859 } catch (ClassNotFoundException x) {
1860 if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) {
1861 MODELMBEAN_LOGGER.logp(Level.FINER,
1862 RequiredModelMBean.class.getName(),
1863 "setAttribute(Attribute)","Class " +
1864 attrType + " for attribute "
1865 + attrName + " not found: ", x);
1866 }
1867 }
1868 }
1869 updateDescriptor = true;
1870 } else {
1871 invoke(attrSetMethod,
1872 (new Object[] {attrValue}),
1873 (new String[] {attrType}) );
1874 }
1875
1876 /* change cached value */
1877 Object objctl = attrDescr.getFieldValue("currencyTimeLimit");
1878 String ctl;
1879 if (objctl != null) ctl = objctl.toString();
1880 else ctl = null;
1881
1882 if ((ctl == null) && (mmbDesc != null)) {
1883 objctl = mmbDesc.getFieldValue("currencyTimeLimit");
1884 if (objctl != null) ctl = objctl.toString();
1885 else ctl = null;
1886 }
1887
1888 final boolean updateCache = ((ctl != null) && !(ctl.equals("-1")));
1889
1890 if(attrSetMethod == null && !updateCache && attrGetMethod != null)
1891 throw new MBeanException(new ServiceNotFoundException("No " +
1892 "setMethod field is defined in the descriptor for " +
1893 attrName + " attribute and caching is not enabled " +
1894 "for it"));
1895
1896 if (updateCache || updateDescriptor) {
1897 if (tracing) {
1898 MODELMBEAN_LOGGER.logp(Level.FINER,
1899 RequiredModelMBean.class.getName(),
1900 "setAttribute(Attribute)",
1901 "setting cached value of " +
1902 attrName + " to " + attrValue);
1903 }
1904
1905 attrDescr.setField("value", attrValue);
1906
1907 if (updateCache) {
1908 final String currtime = String.valueOf(
1909 (new Date()).getTime());
1910
1911 attrDescr.setField("lastUpdatedTimeStamp", currtime);
1912 }
1913
1914 attrInfo.setDescriptor(attrDescr);
1915
1916 modelMBeanInfo.setDescriptor(attrDescr,"attribute");
1917 if (tracing) {
1918 final StringBuilder strb = new StringBuilder()
1919 .append("new descriptor is ").append(attrDescr)
1920 .append(". AttributeInfo descriptor is ")
1921 .append(attrInfo.getDescriptor())
1922 .append(". AttributeInfo descriptor is ")
1923 .append(modelMBeanInfo.getDescriptor(attrName,"attribute"));
1924 MODELMBEAN_LOGGER.logp(Level.FINER,
1925 RequiredModelMBean.class.getName(),
1926 "setAttribute(Attribute)",strb.toString());
1927 }
1928
1929 }
1930
1931 if (tracing) {
1932 MODELMBEAN_LOGGER.logp(Level.FINER,
1933 RequiredModelMBean.class.getName(),
1934 "setAttribute(Attribute)","sending sendAttributeNotification");
1935 }
1936 sendAttributeChangeNotification(oldAttr,attribute);
1937
1938 } else { // if descriptor ... else no descriptor
1939
1940 if (tracing) {
1941 MODELMBEAN_LOGGER.logp(Level.FINER,
1942 RequiredModelMBean.class.getName(),
1943 "setAttribute(Attribute)","setMethod failed "+attrName+
1944 " not in attributeDescriptor\n");
1945 }
1946
1947 throw new InvalidAttributeValueException(
1948 "Unable to resolve attribute value, "+
1949 "no defined in descriptor for attribute");
1950 } // else no descriptor
1951
1952 if (tracing) {
1953 MODELMBEAN_LOGGER.logp(Level.FINER,
1954 RequiredModelMBean.class.getName(),
1955 "setAttribute(Attribute)", "Exit");
1956 }
1957
1958 }
1959
1960 /**
1961 * Sets the values of an array of attributes of this ModelMBean.
1962 * Executes the setAttribute() method for each attribute in the list.
1963 *
1964 * @param attributes A list of attributes: The identification of the
1965 * attributes to be set and the values they are to be set to.
1966 *
1967 * @return The array of attributes that were set, with their new
1968 * values in Attribute instances.
1969 *
1970 * @exception RuntimeOperationsException Wraps an
1971 * {@link IllegalArgumentException}: The object name in parameter
1972 * is null or attributes in parameter is null.
1973 *
1974 * @see #getAttributes
1975 **/
1976 public AttributeList setAttributes(AttributeList attributes) {
1977
1978 if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) {
1979 MODELMBEAN_LOGGER.logp(Level.FINER,
1980 RequiredModelMBean.class.getName(),
1981 "setAttribute(Attribute)", "Entry");
1982 }
1983
1984 if (attributes == null)
1985 throw new RuntimeOperationsException(new
1986 IllegalArgumentException("attributes must not be null"),
1987 "Exception occurred trying to set attributes of a "+
1988 "RequiredModelMBean");
1989
1990 final AttributeList responseList = new AttributeList();
1991
1992 // Go through the list of attributes
1993 for (Iterator i = attributes.iterator(); i.hasNext();) {
1994 final Attribute attr = (Attribute) i.next();
1995 try {
1996 setAttribute(attr);
1997 responseList.add(attr);
1998 } catch (Exception excep) {
1999 responseList.remove(attr);
2000 }
2001 }
2002
2003 return responseList;
2004 }
2005
2006
2007
2008 private ModelMBeanInfo createDefaultModelMBeanInfo() {
2009 return(new ModelMBeanInfoSupport((this.getClass().getName()),
2010 "Default ModelMBean", null, null, null, null));
2011 }
2012
2013 /*************************************/
2014 /* NotificationBroadcaster Interface */
2015 /*************************************/
2016
2017
2018 private synchronized void writeToLog(String logFileName,
2019 String logEntry) throws Exception {
2020
2021 if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) {
2022 MODELMBEAN_LOGGER.logp(Level.FINER,
2023 RequiredModelMBean.class.getName(),
2024 "writeToLog(String, String)",
2025 "Notification Logging to " + logFileName + ": " + logEntry);
2026 }
2027 if ((logFileName == null) || (logEntry == null)) {
2028 if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) {
2029 MODELMBEAN_LOGGER.logp(Level.FINER,
2030 RequiredModelMBean.class.getName(),
2031 "writeToLog(String, String)",
2032 "Bad input parameters, will not log this entry.");
2033 }
2034 return;
2035 }
2036
2037 FileOutputStream fos = new FileOutputStream(logFileName, true);
2038 try {
2039 PrintStream logOut = new PrintStream(fos);
2040 logOut.println(logEntry);
2041 logOut.close();
2042 if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) {
2043 MODELMBEAN_LOGGER.logp(Level.FINER,
2044 RequiredModelMBean.class.getName(),
2045 "writeToLog(String, String)","Successfully opened log " +
2046 logFileName);
2047 }
2048 } catch (Exception e) {
2049 if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) {
2050 MODELMBEAN_LOGGER.logp(Level.FINER,
2051 RequiredModelMBean.class.getName(),
2052 "writeToLog(String, String)",
2053 "Exception " + e.toString() +
2054 " trying to write to the Notification log file " +
2055 logFileName);
2056 }
2057 throw e;
2058 } finally {
2059 fos.close();
2060 }
2061 }
2062
2063
2064 /**
2065 * Registers an object which implements the NotificationListener
2066 * interface as a listener. This
2067 * object's 'handleNotification()' method will be invoked when any
2068 * notification is issued through or by the ModelMBean. This does
2069 * not include attributeChangeNotifications. They must be registered
2070 * for independently.
2071 *
2072 * @param listener The listener object which will handles
2073 * notifications emitted by the registered MBean.
2074 * @param filter The filter object. If null, no filtering will be
2075 * performed before handling notifications.
2076 * @param handback The context to be sent to the listener with
2077 * the notification when a notification is emitted.
2078 *
2079 * @exception IllegalArgumentException The listener cannot be null.
2080 *
2081 * @see #removeNotificationListener
2082 */
2083 public void addNotificationListener(NotificationListener listener,
2084 NotificationFilter filter,
2085 Object handback)
2086 throws java.lang.IllegalArgumentException {
2087 final String mth = "addNotificationListener(" +
2088 "NotificationListener, NotificationFilter, Object)";
2089 if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) {
2090 MODELMBEAN_LOGGER.logp(Level.FINER,
2091 RequiredModelMBean.class.getName(), mth, "Entry");
2092 }
2093
2094 if (listener == null)
2095 throw new IllegalArgumentException(
2096 "notification listener must not be null");
2097
2098 if (generalBroadcaster == null)
2099 generalBroadcaster = new NotificationBroadcasterSupport();
2100
2101 generalBroadcaster.addNotificationListener(listener, filter,
2102 handback);
2103 if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) {
2104 MODELMBEAN_LOGGER.logp(Level.FINER,
2105 RequiredModelMBean.class.getName(), mth,
2106 "NotificationListener added");
2107 MODELMBEAN_LOGGER.logp(Level.FINER,
2108 RequiredModelMBean.class.getName(), mth, "Exit");
2109 }
2110 }
2111
2112 /**
2113 * Removes a listener for Notifications from the RequiredModelMBean.
2114 *
2115 * @param listener The listener name which was handling notifications
2116 * emitted by the registered MBean.
2117 * This method will remove all information related to this l