blob: 0b9072a5e4127fcc0229802fba6b77f2f8091b62 [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
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
32package javax.management.modelmbean;
33
34/* java imports */
35
36import static com.sun.jmx.defaults.JmxProperties.MODELMBEAN_LOGGER;
37import java.io.FileOutputStream;
38import java.io.PrintStream;
39import java.lang.reflect.InvocationTargetException;
40
41import java.lang.reflect.Method;
42
43import java.util.Date;
44import java.util.HashMap;
45import java.util.HashSet;
46import java.util.Iterator;
47import java.util.logging.Level;
48import java.util.Map;
49import java.util.Set;
50
51import javax.management.Attribute;
52import javax.management.AttributeChangeNotification;
53import javax.management.AttributeChangeNotificationFilter;
54import javax.management.AttributeList;
55import javax.management.AttributeNotFoundException;
56import javax.management.Descriptor;
57import javax.management.InstanceNotFoundException;
58import javax.management.InvalidAttributeValueException;
59import javax.management.ListenerNotFoundException;
60import javax.management.MBeanAttributeInfo;
61import javax.management.MBeanConstructorInfo;
62import javax.management.MBeanException;
63import javax.management.MBeanInfo;
64import javax.management.MBeanNotificationInfo;
65import javax.management.MBeanOperationInfo;
66import javax.management.MBeanRegistration;
67import javax.management.MBeanServer;
68import javax.management.MBeanServerFactory;
69import javax.management.Notification;
70import javax.management.NotificationBroadcasterSupport;
71import javax.management.NotificationEmitter;
72import javax.management.NotificationFilter;
73import javax.management.NotificationListener;
74import javax.management.ObjectName;
75import javax.management.ReflectionException;
76import javax.management.RuntimeErrorException;
77import javax.management.RuntimeOperationsException;
78import javax.management.ServiceNotFoundException;
79import javax.management.loading.ClassLoaderRepository;
80
81import sun.reflect.misc.MethodUtil;
82import sun.reflect.misc.ReflectUtil;
83
84/**
85 * This class is the implementation of a ModelMBean. An appropriate
86 * implementation of a ModelMBean must be shipped with every JMX Agent
87 * and the class must be named RequiredModelMBean.
88 * <P>
89 * Java resources wishing to be manageable instantiate the
90 * RequiredModelMBean using the MBeanServer's createMBean method.
91 * The resource then sets the MBeanInfo and Descriptors for the
92 * RequiredModelMBean instance. The attributes and operations exposed
93 * via the ModelMBeanInfo for the ModelMBean are accessible
94 * from MBeans, connectors/adaptors like other MBeans. Through the
95 * Descriptors, values and methods in the managed application can be
96 * defined and mapped to attributes and operations of the ModelMBean.
97 * This mapping can be defined in an XML formatted file or dynamically and
98 * programmatically at runtime.
99 * <P>
100 * Every RequiredModelMBean which is instantiated in the MBeanServer
101 * becomes manageable:<br>
102 * its attributes and operations become remotely accessible through the
103 * connectors/adaptors connected to that MBeanServer.
104 * <P>
105 * A Java object cannot be registered in the MBeanServer unless it is a
106 * JMX compliant MBean. By instantiating a RequiredModelMBean, resources
107 * are guaranteed that the MBean is valid.
108 *
109 * MBeanException and RuntimeOperationsException must be thrown on every
110 * public method. This allows for wrapping exceptions from distributed
111 * communications (RMI, EJB, etc.)
112 *
113 * @since 1.5
114 */
115
116public class RequiredModelMBean
117 implements ModelMBean, MBeanRegistration, NotificationEmitter {
118
119 /*************************************/
120 /* attributes */
121 /*************************************/
122 ModelMBeanInfo modelMBeanInfo;
123
124 /* Notification broadcaster for any notification to be sent
125 * from the application through the RequiredModelMBean. */
126 private NotificationBroadcasterSupport generalBroadcaster = null;
127
128 /* Notification broadcaster for attribute change notifications */
129 private NotificationBroadcasterSupport attributeBroadcaster = null;
130
131 /* handle, name, or reference for instance on which the actual invoke
132 * and operations will be executed */
133 private Object managedResource = null;
134
135 private static final String currClass = "RequiredModelMBean";
136
137 /* records the registering in MBeanServer */
138 private boolean registered = false;
139 private transient MBeanServer server = null;
140
141 /*************************************/
142 /* constructors */
143 /*************************************/
144
145 /**
146 * Constructs an <CODE>RequiredModelMBean</CODE> with an empty
147 * ModelMBeanInfo.
148 * <P>
149 * The RequiredModelMBean's MBeanInfo and Descriptors
150 * can be customized using the {@link #setModelMBeanInfo} method.
151 * After the RequiredModelMBean's MBeanInfo and Descriptors are
152 * customized, the RequiredModelMBean can be registered with
153 * the MBeanServer.
154 *
155 * @exception MBeanException Wraps a distributed communication Exception.
156 *
157 * @exception RuntimeOperationsException Wraps a {@link
158 * RuntimeException} during the construction of the object.
159 **/
160 public RequiredModelMBean()
161 throws MBeanException, RuntimeOperationsException {
162 if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) {
163 MODELMBEAN_LOGGER.logp(Level.FINER,
164 RequiredModelMBean.class.getName(),
165 "RequiredModelMBean()", "Entry");
166 }
167 modelMBeanInfo = createDefaultModelMBeanInfo();
168 if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) {
169 MODELMBEAN_LOGGER.logp(Level.FINER,
170 RequiredModelMBean.class.getName(),
171 "RequiredModelMBean()", "Exit");
172 }
173 }
174
175 /**
176 * Constructs a RequiredModelMBean object using ModelMBeanInfo passed in.
177 * As long as the RequiredModelMBean is not registered
178 * with the MBeanServer yet, the RequiredModelMBean's MBeanInfo and
179 * Descriptors can be customized using the {@link #setModelMBeanInfo}
180 * method.
181 * After the RequiredModelMBean's MBeanInfo and Descriptors are
182 * customized, the RequiredModelMBean can be registered with the
183 * MBeanServer.
184 *
185 * @param mbi The ModelMBeanInfo object to be used by the
186 * RequiredModelMBean. The given ModelMBeanInfo is cloned
187 * and modified as specified by {@link #setModelMBeanInfo}
188 *
189 * @exception MBeanException Wraps a distributed communication Exception.
190 * @exception RuntimeOperationsException Wraps an
191 * {link java.lang.IllegalArgumentException}:
192 * The MBeanInfo passed in parameter is null.
193 *
194 **/
195 public RequiredModelMBean(ModelMBeanInfo mbi)
196 throws MBeanException, RuntimeOperationsException {
197
198 if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) {
199 MODELMBEAN_LOGGER.logp(Level.FINER,
200 RequiredModelMBean.class.getName(),
201 "RequiredModelMBean(MBeanInfo)", "Entry");
202 }
203 setModelMBeanInfo(mbi);
204
205 if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) {
206 MODELMBEAN_LOGGER.logp(Level.FINER,
207 RequiredModelMBean.class.getName(),
208 "RequiredModelMBean(MBeanInfo)", "Exit");
209 }
210 }
211
212
213 /*************************************/
214 /* initializers */
215 /*************************************/
216
217 /**
218 * Initializes a ModelMBean object using ModelMBeanInfo passed in.
219 * This method makes it possible to set a customized ModelMBeanInfo on
220 * the ModelMBean as long as it is not registered with the MBeanServer.
221 * <br>
222 * Once the ModelMBean's ModelMBeanInfo (with Descriptors) are
223 * customized and set on the ModelMBean, the ModelMBean be
224 * registered with the MBeanServer.
225 * <P>
226 * If the ModelMBean is currently registered, this method throws
227 * a {@link javax.management.RuntimeOperationsException} wrapping an
228 * {@link IllegalStateException}
229 * <P>
230 * If the given <var>inModelMBeanInfo</var> does not contain any
231 * {@link ModelMBeanNotificationInfo} for the <code>GENERIC</code>
232 * or <code>ATTRIBUTE_CHANGE</code> notifications, then the
233 * RequiredModelMBean will supply its own default
234 * {@link ModelMBeanNotificationInfo ModelMBeanNotificationInfo}s for
235 * those missing notifications.
236 *
237 * @param mbi The ModelMBeanInfo object to be used
238 * by the ModelMBean.
239 *
240 * @exception MBeanException Wraps a distributed communication
241 * Exception.
242 * @exception RuntimeOperationsException
243 * <ul><li>Wraps an {@link IllegalArgumentException} if
244 * the MBeanInfo passed in parameter is null.</li>
245 * <li>Wraps an {@link IllegalStateException} if the ModelMBean
246 * is currently registered in the MBeanServer.</li>
247 * </ul>
248 *
249 **/
250 public void setModelMBeanInfo(ModelMBeanInfo mbi)
251 throws MBeanException, RuntimeOperationsException {
252
253 if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) {
254 MODELMBEAN_LOGGER.logp(Level.FINER,
255 RequiredModelMBean.class.getName(),
256 "setModelMBeanInfo(ModelMBeanInfo)","Entry");
257 }
258
259 if (mbi == null) {
260 if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) {
261 MODELMBEAN_LOGGER.logp(Level.FINER,
262 RequiredModelMBean.class.getName(),
263 "setModelMBeanInfo(ModelMBeanInfo)",
264 "ModelMBeanInfo is null: Raising exception.");
265 }
266 final RuntimeException x = new
267 IllegalArgumentException("ModelMBeanInfo must not be null");
268 final String exceptionText =
269 "Exception occurred trying to initialize the " +
270 "ModelMBeanInfo of the RequiredModelMBean";
271 throw new RuntimeOperationsException(x,exceptionText);
272 }
273
274 if (registered) {
275 if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) {
276 MODELMBEAN_LOGGER.logp(Level.FINER,
277 RequiredModelMBean.class.getName(),
278 "setModelMBeanInfo(ModelMBeanInfo)",
279 "RequiredMBean is registered: Raising exception.");
280 }
281 final String exceptionText =
282 "Exception occurred trying to set the " +
283 "ModelMBeanInfo of the RequiredModelMBean";
284 final RuntimeException x = new IllegalStateException(
285 "cannot call setModelMBeanInfo while ModelMBean is registered");
286 throw new RuntimeOperationsException(x,exceptionText);
287 }
288
289 if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) {
290 MODELMBEAN_LOGGER.logp(Level.FINER,
291 RequiredModelMBean.class.getName(),
292 "setModelMBeanInfo(ModelMBeanInfo)",
293 "Setting ModelMBeanInfo to " + printModelMBeanInfo(mbi));
294 MODELMBEAN_LOGGER.logp(Level.FINER,
295 RequiredModelMBean.class.getName(),
296 "setModelMBeanInfo(ModelMBeanInfo)",
297 "ModelMBeanInfo notifications has " +
298 (mbi.getNotifications()).length + " elements");
299 }
300
301 modelMBeanInfo = (ModelMBeanInfo)mbi.clone();
302
303 if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) {
304 MODELMBEAN_LOGGER.logp(Level.FINER,
305 RequiredModelMBean.class.getName(),
306 "setModelMBeanInfo(ModelMBeanInfo)","set mbeanInfo to: "+
307 printModelMBeanInfo(modelMBeanInfo));
308 MODELMBEAN_LOGGER.logp(Level.FINER,
309 RequiredModelMBean.class.getName(),
310 "setModelMBeanInfo(ModelMBeanInfo)","Exit");
311 }
312 }
313
314
315 /**
316 * Sets the instance handle of the object against which to
317 * execute all methods in this ModelMBean management interface
318 * (MBeanInfo and Descriptors).
319 *
320 * @param mr Object that is the managed resource
321 * @param mr_type The type of reference for the managed resource.
322 * <br>Can be: "ObjectReference", "Handle", "IOR", "EJBHandle",
323 * or "RMIReference".
324 * <br>In this implementation only "ObjectReference" is supported.
325 *
326 * @exception MBeanException The initializer of the object has
327 * thrown an exception.
328 * @exception InstanceNotFoundException The managed resource
329 * object could not be found
330 * @exception InvalidTargetObjectTypeException The managed
331 * resource type should be "ObjectReference".
332 * @exception RuntimeOperationsException Wraps a {@link
333 * RuntimeException} when setting the resource.
334 **/
335 public void setManagedResource(Object mr, String mr_type)
336 throws MBeanException, RuntimeOperationsException,
337 InstanceNotFoundException, InvalidTargetObjectTypeException {
338 if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) {
339 MODELMBEAN_LOGGER.logp(Level.FINER,
340 RequiredModelMBean.class.getName(),
341 "setManagedResource(Object,String)","Entry");
342 }
343
344 // check that the mr_type is supported by this JMXAgent
345 // only "objectReference" is supported
346 if ((mr_type == null) ||
347 (! mr_type.equalsIgnoreCase("objectReference"))) {
348 if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) {
349 MODELMBEAN_LOGGER.logp(Level.FINER,
350 RequiredModelMBean.class.getName(),
351 "setManagedResource(Object,String)",
352 "Managed Resouce Type is not supported: " + mr_type);
353 }
354 throw new InvalidTargetObjectTypeException(mr_type);
355 }
356
357 if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) {
358 MODELMBEAN_LOGGER.logp(Level.FINER,
359 RequiredModelMBean.class.getName(),
360 "setManagedResource(Object,String)",
361 "Managed Resouce is valid");
362 }
363 managedResource = mr;
364
365 if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) {
366 MODELMBEAN_LOGGER.logp(Level.FINER,
367 RequiredModelMBean.class.getName(),
368 "setManagedResource(Object, String)", "Exit");
369 }
370 }
371
372 /**
373 * <p>Instantiates this MBean instance with the data found for
374 * the MBean in the persistent store. The data loaded could include
375 * attribute and operation values.</p>
376 *
377 * <p>This method should be called during construction or
378 * initialization of this instance, and before the MBean is
379 * registered with the MBeanServer.</p>
380 *
381 * <p>If the implementation of this class does not support
382 * persistence, an {@link MBeanException} wrapping a {@link
383 * ServiceNotFoundException} is thrown.</p>
384 *
385 * @exception MBeanException Wraps another exception, or
386 * persistence is not supported
387 * @exception RuntimeOperationsException Wraps exceptions from the
388 * persistence mechanism
389 * @exception InstanceNotFoundException Could not find or load
390 * this MBean from persistent storage
391 */
392 public void load()
393 throws MBeanException, RuntimeOperationsException,
394 InstanceNotFoundException {
395 final ServiceNotFoundException x = new ServiceNotFoundException(
396 "Persistence not supported for this MBean");
397 throw new MBeanException(x, x.getMessage());
398 }
399
400 /**
401 * <p>Captures the current state of this MBean instance and writes
402 * it out to the persistent store. The state stored could include
403 * attribute and operation values.</p>
404 *
405 * <p>If the implementation of this class does not support
406 * persistence, an {@link MBeanException} wrapping a {@link
407 * ServiceNotFoundException} is thrown.</p>
408 *
409 * <p>Persistence policy from the MBean and attribute descriptor
410 * is used to guide execution of this method. The MBean should be
411 * stored if 'persistPolicy' field is:</p>
412 *
413 * <PRE> != "never"
414 * = "always"
415 * = "onTimer" and now > 'lastPersistTime' + 'persistPeriod'
416 * = "NoMoreOftenThan" and now > 'lastPersistTime' + 'persistPeriod'
417 * = "onUnregister"
418 * </PRE>
419 *
420 * <p>Do not store the MBean if 'persistPolicy' field is:</p>
421 * <PRE>
422 * = "never"
423 * = "onUpdate"
424 * = "onTimer" && now < 'lastPersistTime' + 'persistPeriod'
425 * </PRE>
426 *
427 * @exception MBeanException Wraps another exception, or
428 * persistence is not supported
429 * @exception RuntimeOperationsException Wraps exceptions from the
430 * persistence mechanism
431 * @exception InstanceNotFoundException Could not find/access the
432 * persistent store
433 */
434 public void store()
435 throws MBeanException, RuntimeOperationsException,
436 InstanceNotFoundException {
437 final ServiceNotFoundException x = new ServiceNotFoundException(
438 "Persistence not supported for this MBean");
439 throw new MBeanException(x, x.getMessage());
440 }
441
442 /*************************************/
443 /* DynamicMBean Interface */
444 /*************************************/
445
446 /**
447 * The resolveForCacheValue method checks the descriptor passed in to
448 * see if there is a valid cached value in the descriptor.
449 * The valid value will be in the 'value' field if there is one.
450 * If the 'currencyTimeLimit' field in the descriptor is:
451 * <ul>
452 * <li><b>&lt;0</b> Then the value is not cached and is never valid.
453 * Null is returned. The 'value' and 'lastUpdatedTimeStamp'
454 * fields are cleared.</li>
455 * <li><b>=0</b> Then the value is always cached and always valid.
456 * The 'value' field is returned.
457 * The 'lastUpdatedTimeStamp' field is not checked.</li>
458 * <li><b>&gt;0</b> Represents the number of seconds that the
459 * 'value' field is valid.
460 * The 'value' field is no longer valid when
461 * 'lastUpdatedTimeStamp' + 'currencyTimeLimit' &gt; Now.</li>
462 * </ul>
463 * <li>When 'value' is valid, 'valid' is returned.</li>
464 * <li>When 'value' is no longer valid then null is returned and
465 * 'value' and 'lastUpdatedTimeStamp' fields are cleared.</li>
466 *
467 **/
468 private Object resolveForCacheValue(Descriptor descr)
469 throws MBeanException, RuntimeOperationsException {
470
471 final boolean tracing = MODELMBEAN_LOGGER.isLoggable(Level.FINER);
472 final String mth = "resolveForCacheValue(Descriptor)";
473 if (tracing) {
474 MODELMBEAN_LOGGER.logp(Level.FINER,
475 RequiredModelMBean.class.getName(),mth,"Entry");
476 }
477
478 Object response = null;
479 boolean resetValue = false, returnCachedValue = true;
480 long currencyPeriod = 0;
481
482 if (descr == null) {
483 if (tracing) {
484 MODELMBEAN_LOGGER.logp(Level.FINER,
485 RequiredModelMBean.class.getName(),mth,
486 "Input Descriptor is null");
487 }
488 return response;
489 }
490
491 if (tracing) {
492 MODELMBEAN_LOGGER.logp(Level.FINER,
493 RequiredModelMBean.class.getName(),
494 mth, "descriptor is " + descr);
495 }
496
497 final Descriptor mmbDescr = modelMBeanInfo.getMBeanDescriptor();
498 if (mmbDescr == null) {
499 if (tracing) {
500 MODELMBEAN_LOGGER.logp(Level.FINER,
501 RequiredModelMBean.class.getName(),
502 mth,"MBean Descriptor is null");
503 }
504 //return response;
505 }
506
507 Object objExpTime = descr.getFieldValue("currencyTimeLimit");
508
509 String expTime;
510 if (objExpTime != null) {
511 expTime = objExpTime.toString();
512 } else {
513 expTime = null;
514 }
515
516 if ((expTime == null) && (mmbDescr != null)) {
517 objExpTime = mmbDescr.getFieldValue("currencyTimeLimit");
518 if (objExpTime != null) {
519 expTime = objExpTime.toString();
520 } else {
521 expTime = null;
522 }
523 }
524
525 if (expTime != null) {
526 if (tracing) {
527 MODELMBEAN_LOGGER.logp(Level.FINER,
528 RequiredModelMBean.class.getName(),
529 mth,"currencyTimeLimit: " + expTime);
530 }
531
532 // convert seconds to milliseconds for time comparison
533 currencyPeriod = ((new Long(expTime)).longValue()) * 1000;
534 if (currencyPeriod < 0) {
535 /* if currencyTimeLimit is -1 then value is never cached */
536 returnCachedValue = false;
537 resetValue = true;
538 if (tracing) {
539 MODELMBEAN_LOGGER.logp(Level.FINER,
540 RequiredModelMBean.class.getName(),mth,
541 currencyPeriod + ": never Cached");
542 }
543 } else if (currencyPeriod == 0) {
544 /* if currencyTimeLimit is 0 then value is always cached */
545 returnCachedValue = true;
546 resetValue = false;
547 if (tracing) {
548 MODELMBEAN_LOGGER.logp(Level.FINER,
549 RequiredModelMBean.class.getName(),mth,
550 "always valid Cache");
551 }
552 } else {
553 Object objtStamp =
554 descr.getFieldValue("lastUpdatedTimeStamp");
555
556 String tStamp;
557 if (objtStamp != null) tStamp = objtStamp.toString();
558 else tStamp = null;
559
560 if (tracing) {
561 MODELMBEAN_LOGGER.logp(Level.FINER,
562 RequiredModelMBean.class.getName(),mth,
563 "lastUpdatedTimeStamp: " + tStamp);
564 }
565
566 if (tStamp == null)
567 tStamp = "0";
568
569 long lastTime = (new Long(tStamp)).longValue();
570
571 if (tracing) {
572 MODELMBEAN_LOGGER.logp(Level.FINER,
573 RequiredModelMBean.class.getName(),mth,
574 "currencyPeriod:" + currencyPeriod +
575 " lastUpdatedTimeStamp:" + lastTime);
576 }
577
578 long now = (new Date()).getTime();
579
580 if (now < (lastTime + currencyPeriod)) {
581 returnCachedValue = true;
582 resetValue = false;
583 if (tracing) {
584 MODELMBEAN_LOGGER.logp(Level.FINER,
585 RequiredModelMBean.class.getName(),mth,
586 " timed valid Cache for " + now + " < " +
587 (lastTime + currencyPeriod));
588 }
589 } else { /* value is expired */
590 returnCachedValue = false;
591 resetValue = true;
592 if (tracing) {
593 MODELMBEAN_LOGGER.logp(Level.FINER,
594 RequiredModelMBean.class.getName(),mth,
595 "timed expired cache for " + now + " > " +
596 (lastTime + currencyPeriod));
597 }
598 }
599 }
600 if (tracing) {
601 MODELMBEAN_LOGGER.logp(Level.FINER,
602 RequiredModelMBean.class.getName(),mth,
603 "returnCachedValue:" + returnCachedValue +
604 " resetValue: " + resetValue);
605 }
606
607 if (returnCachedValue == true) {
608 Object currValue = descr.getFieldValue("value");
609 if (currValue != null) {
610 /* error/validity check return value here */
611 response = currValue;
612 /* need to cast string cached value to type */
613 if (tracing) {
614 MODELMBEAN_LOGGER.logp(Level.FINER,
615 RequiredModelMBean.class.getName(),mth,
616 "valid Cache value: " + currValue);
617 }
618
619 } else {
620 response = null;
621 if (tracing) {
622 MODELMBEAN_LOGGER.logp(Level.FINER,
623 RequiredModelMBean.class.getName(),
624 mth,"no Cached value");
625 }
626 }
627 }
628
629 if (resetValue == true) {
630 /* value is not current, so remove it */
631 descr.removeField("lastUpdatedTimeStamp");
632 descr.removeField("value");
633 response = null;
634 modelMBeanInfo.setDescriptor(descr,null);
635 if (tracing) {
636 MODELMBEAN_LOGGER.logp(Level.FINER,
637 RequiredModelMBean.class.getName(),
638 mth,"reset cached value to null");
639 }
640 }
641 }
642
643 if (tracing) {
644 MODELMBEAN_LOGGER.logp(Level.FINER,
645 RequiredModelMBean.class.getName(),mth,"Exit");
646 }
647
648 return response;
649 }
650
651 /**
652 * Returns the attributes, operations, constructors and notifications
653 * that this RequiredModelMBean exposes for management.
654 *
655 * @return An instance of ModelMBeanInfo allowing retrieval all
656 * attributes, operations, and Notifications of this MBean.
657 *
658 **/
659 public MBeanInfo getMBeanInfo() {
660
661 if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) {
662 MODELMBEAN_LOGGER.logp(Level.FINER,
663 RequiredModelMBean.class.getName(),
664 "getMBeanInfo()","Entry");
665 }
666
667 if (modelMBeanInfo == null) {
668 if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) {
669 MODELMBEAN_LOGGER.logp(Level.FINER,
670 RequiredModelMBean.class.getName(),
671 "getMBeanInfo()","modelMBeanInfo is null");
672 }
673 modelMBeanInfo = createDefaultModelMBeanInfo();
674 //return new ModelMBeanInfo(" ", "", null, null, null, null);
675 }
676
677 if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) {
678 MODELMBEAN_LOGGER.logp(Level.FINER,
679 RequiredModelMBean.class.getName(),
680 "getMBeanInfo()","ModelMBeanInfo is " +
681 modelMBeanInfo.getClassName() + " for " +
682 modelMBeanInfo.getDescription());
683 MODELMBEAN_LOGGER.logp(Level.FINER,
684 RequiredModelMBean.class.getName(),
685 "getMBeanInfo()",printModelMBeanInfo(modelMBeanInfo));
686 }
687
688 return((MBeanInfo) modelMBeanInfo.clone());
689 }
690
691 private String printModelMBeanInfo(ModelMBeanInfo info) {
692 final StringBuilder retStr = new StringBuilder();
693 if (info == null) {
694 if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) {
695 MODELMBEAN_LOGGER.logp(Level.FINER,
696 RequiredModelMBean.class.getName(),
697 "printModelMBeanInfo(ModelMBeanInfo)",
698 "ModelMBeanInfo to print is null, " +
699 "printing local ModelMBeanInfo");
700 }
701 info = modelMBeanInfo;
702 }
703
704 retStr.append("\nMBeanInfo for ModelMBean is:");
705 retStr.append("\nCLASSNAME: \t"+ info.getClassName());
706 retStr.append("\nDESCRIPTION: \t"+ info.getDescription());
707
708
709 try {
710 retStr.append("\nMBEAN DESCRIPTOR: \t"+
711 info.getMBeanDescriptor());
712 } catch (Exception e) {
713 retStr.append("\nMBEAN DESCRIPTOR: \t" + " is invalid");
714 }
715
716 retStr.append("\nATTRIBUTES");
717
718 final MBeanAttributeInfo[] attrInfo = info.getAttributes();
719 if ((attrInfo != null) && (attrInfo.length>0)) {
720 for (int i=0; i<attrInfo.length; i++) {
721 final ModelMBeanAttributeInfo attInfo =
722 (ModelMBeanAttributeInfo)attrInfo[i];
723 retStr.append(" ** NAME: \t"+ attInfo.getName());
724 retStr.append(" DESCR: \t"+ attInfo.getDescription());
725 retStr.append(" TYPE: \t"+ attInfo.getType() +
726 " READ: \t"+ attInfo.isReadable() +
727 " WRITE: \t"+ attInfo.isWritable());
728 retStr.append(" DESCRIPTOR: " +
729 attInfo.getDescriptor().toString());
730 }
731 } else {
732 retStr.append(" ** No attributes **");
733 }
734
735 retStr.append("\nCONSTRUCTORS");
736 final MBeanConstructorInfo[] constrInfo = info.getConstructors();
737 if ((constrInfo != null) && (constrInfo.length > 0 )) {
738 for (int i=0; i<constrInfo.length; i++) {
739 final ModelMBeanConstructorInfo ctorInfo =
740 (ModelMBeanConstructorInfo)constrInfo[i];
741 retStr.append(" ** NAME: \t"+ ctorInfo.getName());
742 retStr.append(" DESCR: \t"+
743 ctorInfo.getDescription());
744 retStr.append(" PARAM: \t"+
745 ctorInfo.getSignature().length +
746 " parameter(s)");
747 retStr.append(" DESCRIPTOR: " +
748 ctorInfo.getDescriptor().toString());
749 }
750 } else {
751 retStr.append(" ** No Constructors **");
752 }
753
754 retStr.append("\nOPERATIONS");
755 final MBeanOperationInfo[] opsInfo = info.getOperations();
756 if ((opsInfo != null) && (opsInfo.length>0)) {
757 for (int i=0; i<opsInfo.length; i++) {
758 final ModelMBeanOperationInfo operInfo =
759 (ModelMBeanOperationInfo)opsInfo[i];
760 retStr.append(" ** NAME: \t"+ operInfo.getName());
761 retStr.append(" DESCR: \t"+ operInfo.getDescription());
762 retStr.append(" PARAM: \t"+
763 operInfo.getSignature().length +
764 " parameter(s)");
765 retStr.append(" DESCRIPTOR: " +
766 operInfo.getDescriptor().toString());
767 }
768 } else {
769 retStr.append(" ** No operations ** ");
770 }
771
772 retStr.append("\nNOTIFICATIONS");
773
774 MBeanNotificationInfo[] notifInfo = info.getNotifications();
775 if ((notifInfo != null) && (notifInfo.length>0)) {
776 for (int i=0; i<notifInfo.length; i++) {
777 final ModelMBeanNotificationInfo nInfo =
778 (ModelMBeanNotificationInfo)notifInfo[i];
779 retStr.append(" ** NAME: \t"+ nInfo.getName());
780 retStr.append(" DESCR: \t"+ nInfo.getDescription());
781 retStr.append(" DESCRIPTOR: " +
782 nInfo.getDescriptor().toString());
783 }
784 } else {
785 retStr.append(" ** No notifications **");
786 }
787
788 retStr.append(" ** ModelMBean: End of MBeanInfo ** ");
789
790 return retStr.toString();
791 }
792
793 /**
794 * Invokes a method on or through a RequiredModelMBean and returns
795 * the result of the method execution.
796 * <P>
797 * If the given method to be invoked, together with the provided
798 * signature, matches one of RequiredModelMbean
799 * accessible methods, this one will be call. Otherwise the call to
800 * the given method will be tried on the managed resource.
801 * <P>
802 * The last value returned by an operation may be cached in
803 * the operation's descriptor which
804 * is in the ModelMBeanOperationInfo's descriptor.
805 * The valid value will be in the 'value' field if there is one.
806 * If the 'currencyTimeLimit' field in the descriptor is:
807 * <UL>
808 * <LI><b>&lt;0</b> Then the value is not cached and is never valid.
809 * The operation method is invoked.
810 * The 'value' and 'lastUpdatedTimeStamp' fields are cleared.</LI>
811 * <LI><b>=0</b> Then the value is always cached and always valid.
812 * The 'value' field is returned. If there is no 'value' field
813 * then the operation method is invoked for the attribute.
814 * The 'lastUpdatedTimeStamp' field and `value' fields are set to
815 * the operation's return value and the current time stamp.</LI>
816 * <LI><b>&gt;0</b> Represents the number of seconds that the 'value'
817 * field is valid.
818 * The 'value' field is no longer valid when
819 * 'lastUpdatedTimeStamp' + 'currencyTimeLimit' &gt; Now.
820 * <UL>
821 * <LI>When 'value' is valid, 'value' is returned.</LI>
822 * <LI>When 'value' is no longer valid then the operation
823 * method is invoked. The 'lastUpdatedTimeStamp' field
824 * and `value' fields are updated.</lI>
825 * </UL>
826 * </LI>
827 * </UL>
828 *
829 * <p><b>Note:</b> because of inconsistencies in previous versions of
830 * this specification, it is recommended not to use negative or zero
831 * values for <code>currencyTimeLimit</code>. To indicate that a
832 * cached value is never valid, omit the
833 * <code>currencyTimeLimit</code> field. To indicate that it is
834 * always valid, use a very large number for this field.</p>
835 *
836 * @param opName The name of the method to be invoked. The
837 * name can be the fully qualified method name including the
838 * classname, or just the method name if the classname is
839 * defined in the 'class' field of the operation descriptor.
840 * @param opArgs An array containing the parameters to be set
841 * when the operation is invoked
842 * @param sig An array containing the signature of the
843 * operation. The class objects will be loaded using the same
844 * class loader as the one used for loading the MBean on which
845 * the operation was invoked.
846 *
847 * @return The object returned by the method, which represents the
848 * result of invoking the method on the specified managed resource.
849 *
850 * @exception MBeanException Wraps one of the following Exceptions:
851 * <UL>
852 * <LI> An Exception thrown by the managed object's invoked method.</LI>
853 * <LI> {@link ServiceNotFoundException}: No ModelMBeanOperationInfo or
854 * no descriptor defined for the specified operation or the managed
855 * resource is null.</LI>
856 * <LI> {@link InvalidTargetObjectTypeException}: The 'targetType'
857 * field value is not 'objectReference'.</LI>
858 * </UL>
859 * @exception ReflectionException Wraps an {@link java.lang.Exception}
860 * thrown while trying to invoke the method.
861 * @exception RuntimeOperationsException Wraps an
862 * {@link IllegalArgumentException} Method name is null.
863 *
864 **/
865 /*
866 The requirement to be able to invoke methods on the
867 RequiredModelMBean class itself makes this method considerably
868 more complicated than it might otherwise be. Note that, unlike
869 earlier versions, we do not allow you to invoke such methods if
870 they are not explicitly mentioned in the ModelMBeanInfo. Doing
871 so was potentially a security problem, and certainly very
872 surprising.
873
874 We do not look for the method in the RequiredModelMBean class
875 itself if:
876 (a) there is a "targetObject" field in the Descriptor for the
877 operation; or
878 (b) there is a "class" field in the Descriptor for the operation
879 and the named class is not RequiredModelMBean or one of its
880 superinterfaces; or
881 (c) the name of the operation is not the name of a method in
882 RequiredModelMBean (this is just an optimization).
883
884 In cases (a) and (b), if you have gone to the trouble of adding
885 those fields specifically for this operation then presumably you
886 do not want RequiredModelMBean's methods to be called.
887
888 We have to pay attention to class loading issues. If the
889 "class" field is present, the named class has to be resolved
890 relative to RequiredModelMBean's class loader to test the
891 condition (b) above, and relative to the managed resource's
892 class loader to ensure that the managed resource is in fact of
893 the named class (or a subclass). The class names in the sig
894 array likewise have to be resolved, first against
895 RequiredModelMBean's class loader, then against the managed
896 resource's class loader. There is no point in using any other
897 loader because when we call Method.invoke we must call it on
898 a Method that is implemented by the target object.
899 */
900 public Object invoke(String opName, Object[] opArgs, String[] sig)
901 throws MBeanException, ReflectionException {
902
903 final boolean tracing = MODELMBEAN_LOGGER.isLoggable(Level.FINER);
904 final String mth = "invoke(String, Object[], String[])";
905
906 if (tracing) {
907 MODELMBEAN_LOGGER.logp(Level.FINER,
908 RequiredModelMBean.class.getName(), mth, "Entry");
909 }
910
911 if (opName == null) {
912 final RuntimeException x =
913 new IllegalArgumentException("Method name must not be null");
914 throw new RuntimeOperationsException(x,
915 "An exception occurred while trying to " +
916 "invoke a method on a RequiredModelMBean");
917 }
918
919 String opClassName = null;
920 String opMethodName;
921
922 // Parse for class name and method
923 int opSplitter = opName.lastIndexOf(".");
924 if (opSplitter > 0) {
925 opClassName = opName.substring(0,opSplitter);
926 opMethodName = opName.substring(opSplitter+1);
927 } else
928 opMethodName = opName;
929
930 /* Ignore anything after a left paren. We keep this for
931 compatibility but it isn't specified. */
932 opSplitter = opMethodName.indexOf("(");
933 if (opSplitter > 0)
934 opMethodName = opMethodName.substring(0,opSplitter);
935
936 if (tracing) {
937 MODELMBEAN_LOGGER.logp(Level.FINER,
938 RequiredModelMBean.class.getName(),
939 mth, "Finding operation " + opName + " as " + opMethodName);
940 }
941
942 ModelMBeanOperationInfo opInfo =
943 modelMBeanInfo.getOperation(opMethodName);
944 if (opInfo == null) {
945 final String msg =
946 "Operation " + opName + " not in ModelMBeanInfo";
947 throw new MBeanException(new ServiceNotFoundException(msg), msg);
948 }
949
950 final Descriptor opDescr = opInfo.getDescriptor();
951 if (opDescr == null) {
952 final String msg = "Operation descriptor null";
953 throw new MBeanException(new ServiceNotFoundException(msg), msg);
954 }
955
956 final Object cached = resolveForCacheValue(opDescr);
957 if (cached != null) {
958 if (tracing) {
959 MODELMBEAN_LOGGER.logp(Level.FINER,
960 RequiredModelMBean.class.getName(),
961 mth,
962 "Returning cached value");
963 }
964 return cached;
965 }
966
967 if (opClassName == null)
968 opClassName = (String) opDescr.getFieldValue("class");
969 // may still be null now
970
971 opMethodName = (String) opDescr.getFieldValue("name");
972 if (opMethodName == null) {
973 final String msg =
974 "Method descriptor must include `name' field";
975 throw new MBeanException(new ServiceNotFoundException(msg), msg);
976 }
977
978 final String targetTypeField = (String)
979 opDescr.getFieldValue("targetType");
980 if (targetTypeField != null
981 && !targetTypeField.equalsIgnoreCase("objectReference")) {
982 final String msg =
983 "Target type must be objectReference: " + targetTypeField;
984 throw new MBeanException(new InvalidTargetObjectTypeException(msg),
985 msg);
986 }
987
988 final Object targetObjectField = opDescr.getFieldValue("targetObject");
989 if (tracing && targetObjectField != null)
990 MODELMBEAN_LOGGER.logp(Level.FINER,
991 RequiredModelMBean.class.getName(),
992 mth, "Found target object in descriptor");
993
994 /* Now look for the method, either in RequiredModelMBean itself
995 or in the target object. Set "method" and "targetObject"
996 appropriately. */
997 Method method;
998 Object targetObject;
999
1000 method = findRMMBMethod(opMethodName, targetObjectField,
1001 opClassName, sig);
1002
1003 if (method != null)
1004 targetObject = this;
1005 else {
1006 if (tracing) {
1007 MODELMBEAN_LOGGER.logp(Level.FINER,
1008 RequiredModelMBean.class.getName(),
1009 mth, "looking for method in managedResource class");
1010 }
1011 if (targetObjectField != null)
1012 targetObject = targetObjectField;
1013 else {
1014 targetObject = managedResource;
1015 if (targetObject == null) {
1016 final String msg =
1017 "managedResource for invoke " + opName +
1018 " is null";
1019 Exception snfe = new ServiceNotFoundException(msg);
1020 throw new MBeanException(snfe);
1021 }
1022 }
1023
1024 final Class targetClass;
1025
1026 if (opClassName != null) {
1027 try {
1028 final ClassLoader targetClassLoader =
1029 targetObject.getClass().getClassLoader();
1030 targetClass = Class.forName(opClassName, false,
1031 targetClassLoader);
1032 } catch (ClassNotFoundException e) {
1033 final String msg =
1034 "class for invoke " + opName + " not found";
1035 throw new ReflectionException(e, msg);
1036 }
1037 } else
1038 targetClass = targetObject.getClass();
1039
1040 method = resolveMethod(targetClass, opMethodName, sig);
1041 }
1042
1043 if (tracing) {
1044 MODELMBEAN_LOGGER.logp(Level.FINER,
1045 RequiredModelMBean.class.getName(),
1046 mth, "found " + opMethodName + ", now invoking");
1047 }
1048
1049 final Object result =
1050 invokeMethod(opName, method, targetObject, opArgs);
1051
1052 if (tracing) {
1053 MODELMBEAN_LOGGER.logp(Level.FINER,
1054 RequiredModelMBean.class.getName(),
1055 mth, "successfully invoked method");
1056 }
1057
1058 if (result != null)
1059 cacheResult(opInfo, opDescr, result);
1060
1061 return result;
1062 }
1063
1064 private static Method resolveMethod(Class<?> targetClass,
1065 String opMethodName,
1066 String[] sig)
1067 throws ReflectionException {
1068 final boolean tracing = MODELMBEAN_LOGGER.isLoggable(Level.FINER);
1069
1070 if (tracing) {
1071 MODELMBEAN_LOGGER.logp(Level.FINER,
1072 RequiredModelMBean.class.getName(),"resolveMethod",
1073 "resolving " + targetClass + "." + opMethodName);
1074 }
1075
1076 final Class[] argClasses;
1077
1078 if (sig == null)
1079 argClasses = null;
1080 else {
1081 final ClassLoader targetClassLoader = targetClass.getClassLoader();
1082 argClasses = new Class[sig.length];
1083 for (int i = 0; i < sig.length; i++) {
1084 if (tracing) {
1085 MODELMBEAN_LOGGER.logp(Level.FINER,
1086 RequiredModelMBean.class.getName(),"resolveMethod",
1087 "resolve type " + sig[i]);
1088 }
1089 argClasses[i] = (Class) primitiveClassMap.get(sig[i]);
1090 if (argClasses[i] == null) {
1091 try {
1092 argClasses[i] =
1093 Class.forName(sig[i], false, targetClassLoader);
1094 } catch (ClassNotFoundException e) {
1095 if (tracing) {
1096 MODELMBEAN_LOGGER.logp(Level.FINER,
1097 RequiredModelMBean.class.getName(),
1098 "resolveMethod",
1099 "class not found");
1100 }
1101 final String msg = "Parameter class not found";
1102 throw new ReflectionException(e, msg);
1103 }
1104 }
1105 }
1106 }
1107
1108 try {
1109 return targetClass.getMethod(opMethodName, argClasses);
1110 } catch (NoSuchMethodException e) {
1111 final String msg =
1112 "Target method not found: " + targetClass.getName() + "." +
1113 opMethodName;
1114 throw new ReflectionException(e, msg);
1115 }
1116 }
1117
1118 /* Map e.g. "int" to int.class. Goodness knows how many time this
1119 particular wheel has been reinvented. */
1120 private static final Class[] primitiveClasses = {
1121 int.class, long.class, boolean.class, double.class,
1122 float.class, short.class, byte.class, char.class,
1123 };
1124 private static final Map<String,Class<?>> primitiveClassMap =
1125 new HashMap<String,Class<?>>();
1126 static {
1127 for (int i = 0; i < primitiveClasses.length; i++) {
1128 final Class c = primitiveClasses[i];
1129 primitiveClassMap.put(c.getName(), c);
1130 }
1131 }
1132
1133 /* Find a method in RequiredModelMBean as determined by the given
1134 parameters. Return null if there is none, or if the parameters
1135 exclude using it. Called from invoke. */
1136 private static Method findRMMBMethod(String opMethodName,
1137 Object targetObjectField,
1138 String opClassName,
1139 String[] sig) {
1140 final boolean tracing = MODELMBEAN_LOGGER.isLoggable(Level.FINER);
1141
1142 if (tracing) {
1143 MODELMBEAN_LOGGER.logp(Level.FINER,
1144 RequiredModelMBean.class.getName(),
1145 "invoke(String, Object[], String[])",
1146 "looking for method in RequiredModelMBean class");
1147 }
1148
1149 if (!isRMMBMethodName(opMethodName))
1150 return null;
1151 if (targetObjectField != null)
1152 return null;
1153 final Class<RequiredModelMBean> rmmbClass = RequiredModelMBean.class;
1154 final Class<?> targetClass;
1155 if (opClassName == null)
1156 targetClass = rmmbClass;
1157 else {
1158 try {
1159 final ClassLoader targetClassLoader =
1160 rmmbClass.getClassLoader();
1161 targetClass = Class.forName(opClassName, false,
1162 targetClassLoader);
1163 if (!rmmbClass.isAssignableFrom(targetClass))
1164 return null;
1165 } catch (ClassNotFoundException e) {
1166 return null;
1167 }
1168 }
1169 try {
1170 return resolveMethod(targetClass, opMethodName, sig);
1171 } catch (ReflectionException e) {
1172 return null;
1173 }
1174 }
1175
1176 /*
1177 * Invoke the given method, and throw the somewhat unpredictable
1178 * appropriate exception if the method itself gets an exception.
1179 */
1180 private Object invokeMethod(String opName, Method method,
1181 Object targetObject, Object[] opArgs)
1182 throws MBeanException, ReflectionException {
1183 try {
1184 ReflectUtil.checkPackageAccess(method.getDeclaringClass());
1185 return MethodUtil.invoke(method, targetObject, opArgs);
1186 } catch (RuntimeErrorException ree) {
1187 throw new RuntimeOperationsException(ree,
1188 "RuntimeException occurred in RequiredModelMBean "+
1189 "while trying to invoke operation " + opName);
1190 } catch (RuntimeException re) {
1191 throw new RuntimeOperationsException(re,
1192 "RuntimeException occurred in RequiredModelMBean "+
1193 "while trying to invoke operation " + opName);
1194 } catch (IllegalAccessException iae) {
1195 throw new ReflectionException(iae,
1196 "IllegalAccessException occurred in " +
1197 "RequiredModelMBean while trying to " +
1198 "invoke operation " + opName);
1199 } catch (InvocationTargetException ite) {
1200 Throwable mmbTargEx = ite.getTargetException();
1201 if (mmbTargEx instanceof RuntimeException) {
1202 throw new MBeanException ((RuntimeException)mmbTargEx,
1203 "RuntimeException thrown in RequiredModelMBean "+
1204 "while trying to invoke operation " + opName);
1205 } else if (mmbTargEx instanceof Error) {
1206 throw new RuntimeErrorException((Error)mmbTargEx,
1207 "Error occurred in RequiredModelMBean while trying "+
1208 "to invoke operation " + opName);
1209 } else if (mmbTargEx instanceof ReflectionException) {
1210 throw (ReflectionException) mmbTargEx;
1211 } else {
1212 throw new MBeanException ((Exception)mmbTargEx,
1213 "Exception thrown in RequiredModelMBean "+
1214 "while trying to invoke operation " + opName);
1215 }
1216 } catch (Error err) {
1217 throw new RuntimeErrorException(err,
1218 "Error occurred in RequiredModelMBean while trying "+
1219 "to invoke operation " + opName);
1220 } catch (Exception e) {
1221 throw new ReflectionException(e,
1222 "Exception occurred in RequiredModelMBean while " +
1223 "trying to invoke operation " + opName);
1224 }
1225 }
1226
1227 /*
1228 * Cache the result of an operation in the descriptor, if that is
1229 * called for by the descriptor's configuration. Note that we
1230 * don't remember operation parameters when caching the result, so
1231 * this is unlikely to be useful if there are any.
1232 */
1233 private void cacheResult(ModelMBeanOperationInfo opInfo,
1234 Descriptor opDescr, Object result)
1235 throws MBeanException {
1236
1237 Descriptor mmbDesc =
1238 modelMBeanInfo.getMBeanDescriptor();
1239
1240 Object objctl =
1241 opDescr.getFieldValue("currencyTimeLimit");
1242 String ctl;
1243 if (objctl != null) {
1244 ctl = objctl.toString();
1245 } else {
1246 ctl = null;
1247 }
1248 if ((ctl == null) && (mmbDesc != null)) {
1249 objctl =
1250 mmbDesc.getFieldValue("currencyTimeLimit");
1251 if (objctl != null) {
1252 ctl = objctl.toString();
1253 } else {
1254 ctl = null;
1255 }
1256 }
1257 if ((ctl != null) && !(ctl.equals("-1"))) {
1258 opDescr.setField("value", result);
1259 opDescr.setField("lastUpdatedTimeStamp",
1260 String.valueOf((new Date()).getTime()));
1261
1262
1263 modelMBeanInfo.setDescriptor(opDescr,
1264 "operation");
1265 if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) {
1266 MODELMBEAN_LOGGER.logp(Level.FINER,
1267 RequiredModelMBean.class.getName(),
1268 "invoke(String,Object[],Object[])",
1269 "new descriptor is " + opDescr);
1270 }
1271 }
1272 }
1273
1274 /*
1275 * Determine whether the given name is the name of a public method
1276 * in this class. This is only an optimization: it prevents us
1277 * from trying to do argument type lookups and reflection on a
1278 * method that will obviously fail because it has the wrong name.
1279 *
1280 * The first time this method is called we do the reflection, and
1281 * every other time we reuse the remembered values.
1282 *
1283 * It's conceivable that the (possibly malicious) first caller
1284 * doesn't have the required permissions to do reflection, in
1285 * which case we don't touch anything so as not to interfere
1286 * with a later permissionful caller.
1287 */
1288 private static Set<String> rmmbMethodNames;
1289 private static synchronized boolean isRMMBMethodName(String name) {
1290 if (rmmbMethodNames == null) {
1291 try {
1292 Set<String> names = new HashSet<String>();
1293 Method[] methods = RequiredModelMBean.class.getMethods();
1294 for (int i = 0; i < methods.length; i++)
1295 names.add(methods[i].getName());
1296 rmmbMethodNames = names;
1297 } catch (Exception e) {
1298 return true;
1299 // This is only an optimization so we'll go on to discover
1300 // whether the name really is an RMMB method.
1301 }
1302 }
1303 return rmmbMethodNames.contains(name);
1304 }
1305
1306 /**
1307 * Returns the value of a specific attribute defined for this
1308 * ModelMBean.
1309 * The last value returned by an attribute may be cached in the
1310 * attribute's descriptor.
1311 * The valid value will be in the 'value' field if there is one.
1312 * If the 'currencyTimeLimit' field in the descriptor is:
1313 * <UL>
1314 * <LI> <b>&lt;0</b> Then the value is not cached and is never valid.
1315 * The getter method is invoked for the attribute.
1316 * The 'value' and 'lastUpdatedTimeStamp' fields are cleared.</LI>
1317 * <LI> <b>=0</b> Then the value is always cached and always valid.
1318 * The 'value' field is returned. If there is no'value' field
1319 * then the getter method is invoked for the attribute.
1320 * The 'lastUpdatedTimeStamp' field and `value' fields are set
1321 * to the attribute's value and the current time stamp.</LI>
1322 * <LI> <b>&gt;0</b> Represents the number of seconds that the 'value'
1323 * field is valid.
1324 * The 'value' field is no longer valid when
1325 * 'lastUpdatedTimeStamp' + 'currencyTimeLimit' &gt; Now.
1326 * <UL>
1327 * <LI>When 'value' is valid, 'value' is returned.</LI>
1328 * <LI>When 'value' is no longer valid then the getter
1329 * method is invoked for the attribute.
1330 * The 'lastUpdatedTimeStamp' field and `value' fields
1331 * are updated.</LI>
1332 * </UL></LI>
1333 * </UL>
1334 *
1335 * <p><b>Note:</b> because of inconsistencies in previous versions of
1336 * this specification, it is recommended not to use negative or zero
1337 * values for <code>currencyTimeLimit</code>. To indicate that a
1338 * cached value is never valid, omit the
1339 * <code>currencyTimeLimit</code> field. To indicate that it is
1340 * always valid, use a very large number for this field.</p>
1341 *
1342 * <p>If the 'getMethod' field contains the name of a valid
1343 * operation descriptor, then the method described by the
1344 * operation descriptor is executed. The response from the
1345 * method is returned as the value of the attribute. If the
1346 * operation fails or the returned value is not compatible with
1347 * the declared type of the attribute, an exception will be thrown.</p>
1348 *
1349 * <p>If no 'getMethod' field is defined then the default value of the
1350 * attribute is returned. If the returned value is not compatible with
1351 * the declared type of the attribute, an exception will be thrown.</p>
1352 *
1353 * <p>The declared type of the attribute is the String returned by
1354 * {@link ModelMBeanAttributeInfo#getType()}. A value is compatible
1355 * with this type if one of the following is true:
1356 * <ul>
1357 * <li>the value is null;</li>
1358 * <li>the declared name is a primitive type name (such as "int")
1359 * and the value is an instance of the corresponding wrapper
1360 * type (such as java.lang.Integer);</li>
1361 * <li>the name of the value's class is identical to the declared name;</li>
1362 * <li>the declared name can be loaded by the value's class loader and
1363 * produces a class to which the value can be assigned.</li>
1364 * </ul>
1365 *
1366 * <p>In this implementation, in every case where the getMethod needs to
1367 * be called, because the method is invoked through the standard "invoke"
1368 * method and thus needs operationInfo, an operation must be specified
1369 * for that getMethod so that the invocation works correctly.</p>
1370 *
1371 * @param attrName A String specifying the name of the
1372 * attribute to be retrieved. It must match the name of a
1373 * ModelMBeanAttributeInfo.
1374 *
1375 * @return The value of the retrieved attribute from the
1376 * descriptor 'value' field or from the invocation of the
1377 * operation in the 'getMethod' field of the descriptor.
1378 *
1379 * @exception AttributeNotFoundException The specified attribute is
1380 * not accessible in the MBean.
1381 * The following cases may result in an AttributeNotFoundException:
1382 * <UL>
1383 * <LI> No ModelMBeanInfo was found for the Model MBean.</LI>
1384 * <LI> No ModelMBeanAttributeInfo was found for the specified
1385 * attribute name.</LI>
1386 * <LI> The ModelMBeanAttributeInfo isReadable method returns
1387 * 'false'.</LI>
1388 * </UL>
1389 * @exception MBeanException Wraps one of the following Exceptions:
1390 * <UL>
1391 * <LI> {@link InvalidAttributeValueException}: A wrong value type
1392 * was received from the attribute's getter method or
1393 * no 'getMethod' field defined in the descriptor for
1394 * the attribute and no default value exists.</LI>
1395 * <LI> {@link ServiceNotFoundException}: No
1396 * ModelMBeanOperationInfo defined for the attribute's
1397 * getter method or no descriptor associated with the
1398 * ModelMBeanOperationInfo or the managed resource is
1399 * null.</LI>
1400 * <LI> {@link InvalidTargetObjectTypeException} The 'targetType'
1401 * field value is not 'objectReference'.</LI>
1402 * <LI> An Exception thrown by the managed object's getter.</LI>
1403 * </UL>
1404 * @exception ReflectionException Wraps an {@link java.lang.Exception}
1405 * thrown while trying to invoke the getter.
1406 * @exception RuntimeOperationsException Wraps an
1407 * {@link IllegalArgumentException}: The attribute name in
1408 * parameter is null.
1409 *
1410 * @see #setAttribute(javax.management.Attribute)
1411 **/
1412 public Object getAttribute(String attrName)
1413 throws AttributeNotFoundException, MBeanException,
1414 ReflectionException {
1415 if (attrName == null)
1416 throw new RuntimeOperationsException(new
1417 IllegalArgumentException("attributeName must not be null"),
1418 "Exception occurred trying to get attribute of a " +
1419 "RequiredModelMBean");
1420 final String mth = "getAttribute(String)";
1421 final boolean tracing = MODELMBEAN_LOGGER.isLoggable(Level.FINER);
1422 if (tracing) {
1423 MODELMBEAN_LOGGER.logp(Level.FINER,
1424 RequiredModelMBean.class.getName(),
1425 mth, "Entry with " + attrName);
1426 }
1427
1428 /* Check attributeDescriptor for getMethod */
1429 ModelMBeanAttributeInfo attrInfo=null;
1430 Descriptor attrDescr=null;
1431 Object response = null;
1432
1433 try {
1434 if (modelMBeanInfo == null)
1435 throw new AttributeNotFoundException(
1436 "getAttribute failed: ModelMBeanInfo not found for "+
1437 attrName);
1438
1439 attrInfo = modelMBeanInfo.getAttribute(attrName);
1440 Descriptor mmbDesc = modelMBeanInfo.getMBeanDescriptor();
1441
1442 if (attrInfo == null)
1443 throw new AttributeNotFoundException("getAttribute failed:"+
1444 " ModelMBeanAttributeInfo not found for " + attrName);
1445
1446 attrDescr = attrInfo.getDescriptor();
1447 if (attrDescr != null) {
1448 if (!attrInfo.isReadable())
1449 throw new AttributeNotFoundException(
1450 "getAttribute failed: " + attrName +
1451 " is not readable ");
1452
1453 response = resolveForCacheValue(attrDescr);
1454
1455 /* return current cached value */
1456 if (tracing) {
1457 MODELMBEAN_LOGGER.logp(Level.FINER,
1458 RequiredModelMBean.class.getName(), mth,
1459 "*** cached value is " + response);
1460 }
1461
1462 if (response == null) {
1463 /* no cached value, run getMethod */
1464 if (tracing) {
1465 MODELMBEAN_LOGGER.logp(Level.FINER,
1466 RequiredModelMBean.class.getName(), mth,
1467 "**** cached value is null - getting getMethod");
1468 }
1469 String attrGetMethod =
1470 (String)(attrDescr.getFieldValue("getMethod"));
1471
1472 if (attrGetMethod != null) {
1473 /* run method from operations descriptor */
1474 if (tracing) {
1475 MODELMBEAN_LOGGER.logp(Level.FINER,
1476 RequiredModelMBean.class.getName(),
1477 mth, "invoking a getMethod for " + attrName);
1478 }
1479
1480 Object getResponse =
1481 invoke(attrGetMethod, new Object[] {},
1482 new String[] {});
1483
1484 if (getResponse != null) {
1485 // error/validity check return value here
1486 if (tracing) {
1487 MODELMBEAN_LOGGER.logp(Level.FINER,
1488 RequiredModelMBean.class.getName(),
1489 mth, "got a non-null response " +
1490 "from getMethod\n");
1491 }
1492
1493 response = getResponse;
1494
1495 // change cached value in attribute descriptor
1496 Object objctl =
1497 attrDescr.getFieldValue("currencyTimeLimit");
1498
1499 String ctl;
1500 if (objctl != null) ctl = objctl.toString();
1501 else ctl = null;
1502
1503 if ((ctl == null) && (mmbDesc != null)) {
1504 objctl = mmbDesc.
1505 getFieldValue("currencyTimeLimit");
1506 if (objctl != null) ctl = objctl.toString();
1507 else ctl = null;
1508 }
1509
1510 if ((ctl != null) && !(ctl.equals("-1"))) {
1511 if (tracing) {
1512 MODELMBEAN_LOGGER.logp(Level.FINER,
1513 RequiredModelMBean.class.getName(),
1514 mth,
1515 "setting cached value and " +
1516 "lastUpdatedTime in descriptor");
1517 }
1518 attrDescr.setField("value", response);
1519 final String stamp = String.valueOf(
1520 (new Date()).getTime());
1521 attrDescr.setField("lastUpdatedTimeStamp",
1522 stamp);
1523 attrInfo.setDescriptor(attrDescr);
1524 modelMBeanInfo.setDescriptor(attrDescr,
1525 "attribute");
1526 if (tracing) {
1527 MODELMBEAN_LOGGER.logp(Level.FINER,
1528 RequiredModelMBean.class.getName(),
1529 mth,"new descriptor is " +attrDescr);
1530 MODELMBEAN_LOGGER.logp(Level.FINER,
1531 RequiredModelMBean.class.getName(),
1532 mth,"AttributeInfo descriptor is " +
1533 attrInfo.getDescriptor());
1534 final String attStr = modelMBeanInfo.
1535 getDescriptor(attrName,"attribute").
1536 toString();
1537 MODELMBEAN_LOGGER.logp(Level.FINER,
1538 RequiredModelMBean.class.getName(),
1539 mth,
1540 "modelMBeanInfo: AttributeInfo " +
1541 "descriptor is " + attStr);
1542 }
1543 }
1544 } else {
1545 // response was invalid or really returned null
1546 if (tracing) {
1547 MODELMBEAN_LOGGER.logp(Level.FINER,
1548 RequiredModelMBean.class.getName(), mth,
1549 "got a null response from getMethod\n");
1550 }
1551 response = null;
1552 }
1553 } else {
1554 // not getMethod so return descriptor (default) value
1555 String qualifier="";
1556 response = attrDescr.getFieldValue("value");
1557 if (response == null) {
1558 qualifier="default ";
1559 response = attrDescr.getFieldValue("default");
1560 }
1561 if (tracing) {
1562 MODELMBEAN_LOGGER.logp(Level.FINER,
1563 RequiredModelMBean.class.getName(), mth,
1564 "could not find getMethod for " +attrName +
1565 ", returning descriptor " +qualifier + "value");
1566 }
1567 // !! cast response to right class
1568 }
1569 }
1570
1571 // make sure response class matches type field
1572 String respType = attrInfo.getType();
1573 if (response != null) {
1574 String responseClass = response.getClass().getName();
1575 if (!respType.equals(responseClass)) {
1576 boolean wrongType = false;
1577 boolean primitiveType = false;
1578 boolean correspondingTypes = false;
1579 for (int i = 0; i < primitiveTypes.length; i++) {
1580 if (respType.equals(primitiveTypes[i])) {
1581 primitiveType = true;
1582 if (responseClass.equals(primitiveWrappers[i]))
1583 correspondingTypes = true;
1584 break;
1585 }
1586 }
1587 if (primitiveType) {
1588 // inequality may come from primitive/wrapper class
1589 if (!correspondingTypes)
1590 wrongType = true;
1591 } else {
1592 // inequality may come from type subclassing
1593 boolean subtype;
1594 try {
1595 ClassLoader cl =
1596 response.getClass().getClassLoader();
1597 Class c = Class.forName(respType, true, cl);
1598 subtype = c.isInstance(response);
1599 } catch (Exception e) {
1600 subtype = false;
1601
1602 if (tracing) {
1603 MODELMBEAN_LOGGER.logp(Level.FINER,
1604 RequiredModelMBean.class.getName(),
1605 mth, "Exception: ",e);
1606 }
1607 }
1608 if (!subtype)
1609 wrongType = true;
1610 }
1611 if (wrongType) {
1612 if (tracing) {
1613 MODELMBEAN_LOGGER.logp(Level.FINER,
1614 RequiredModelMBean.class.getName(), mth,
1615 "Wrong response type '" + respType + "'");
1616 }
1617 // throw exception, didn't get
1618 // back right attribute type
1619 throw new MBeanException(
1620 new InvalidAttributeValueException(
1621 "Wrong value type received for get attribute"),
1622 "An exception occurred while trying to get an " +
1623 "attribute value through a RequiredModelMBean");
1624 }
1625 }
1626 }
1627 } else {
1628 if (tracing) {
1629 MODELMBEAN_LOGGER.logp(Level.FINER,
1630 RequiredModelMBean.class.getName(), mth,
1631 "getMethod failed " + attrName +
1632 " not in attributeDescriptor\n");
1633 }
1634 throw new MBeanException(new
1635 InvalidAttributeValueException(
1636 "Unable to resolve attribute value, " +
1637 "no getMethod defined in descriptor for attribute"),
1638 "An exception occurred while trying to get an "+
1639 "attribute value through a RequiredModelMBean");
1640 }
1641
1642 } catch (MBeanException mbe) {
1643 throw mbe;
1644 } catch (AttributeNotFoundException t) {
1645 throw t;
1646 } catch (Exception e) {
1647 if (tracing) {
1648 MODELMBEAN_LOGGER.logp(Level.FINER,
1649 RequiredModelMBean.class.getName(), mth,
1650 "getMethod failed with " + e.getMessage() +
1651 " exception type " + (e.getClass()).toString());
1652 }
1653 throw new MBeanException(e,"An exception occurred while trying "+
1654 "to get an attribute value: " + e.getMessage());
1655 }
1656
1657 if (tracing) {
1658 MODELMBEAN_LOGGER.logp(Level.FINER,
1659 RequiredModelMBean.class.getName(), mth, "Exit");
1660 }
1661
1662 return response;
1663 }
1664
1665 /**
1666 * Returns the values of several attributes in the ModelMBean.
1667 * Executes a getAttribute for each attribute name in the
1668 * attrNames array passed in.
1669 *
1670 * @param attrNames A String array of names of the attributes
1671 * to be retrieved.
1672 *
1673 * @return The array of the retrieved attributes.
1674 *
1675 * @exception RuntimeOperationsException Wraps an
1676 * {@link IllegalArgumentException}: The object name in parameter is
1677 * null or attributes in parameter is null.
1678 *
1679 * @see #setAttributes(javax.management.AttributeList)
1680 */
1681 public AttributeList getAttributes(String[] attrNames) {
1682 if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) {
1683 MODELMBEAN_LOGGER.logp(Level.FINER,
1684 RequiredModelMBean.class.getName(),
1685 "getAttributes(String[])","Entry");
1686 }
1687
1688 AttributeList responseList = null;
1689 if (attrNames == null)
1690 throw new RuntimeOperationsException(new
1691 IllegalArgumentException("attributeNames must not be null"),
1692 "Exception occurred trying to get attributes of a "+
1693 "RequiredModelMBean");
1694
1695 responseList = new AttributeList();
1696 for (int i = 0; i < attrNames.length; i++) {
1697 try {
1698 responseList.add(new Attribute(attrNames[i],
1699 getAttribute(attrNames[i])));
1700 } catch (Exception e) {
1701 // eat exceptions because interface doesn't have an
1702 // exception on it
1703 if (MODELMBEAN_LOGGER.isLoggable(Level.WARNING)) {
1704 MODELMBEAN_LOGGER.logp(Level.WARNING,
1705 RequiredModelMBean.class.getName(),
1706 "getAttributes(String[])",
1707 "Failed to get \"" + attrNames[i] + "\": ", e);
1708 }
1709 }
1710 }
1711
1712 if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) {
1713 MODELMBEAN_LOGGER.logp(Level.FINER,
1714 RequiredModelMBean.class.getName(),
1715 "getAttributes(String[])","Exit");
1716 }
1717
1718 return responseList;
1719 }
1720
1721 /**
1722 * Sets the value of a specific attribute of a named ModelMBean.
1723 *
1724 * If the 'setMethod' field of the attribute's descriptor
1725 * contains the name of a valid operation descriptor, then the
1726 * method described by the operation descriptor is executed.
1727 * In this implementation, the operation descriptor must be specified
1728 * correctly and assigned to the modelMBeanInfo so that the 'setMethod'
1729 * works correctly.
1730 * The response from the method is set as the value of the attribute
1731 * in the descriptor.
1732 *
1733 * <p>If currencyTimeLimit is &gt; 0, then the new value for the
1734 * attribute is cached in the attribute descriptor's
1735 * 'value' field and the 'lastUpdatedTimeStamp' field is set to
1736 * the current time stamp.
1737 *
1738 * <p>If the persist field of the attribute's descriptor is not null
1739 * then Persistence policy from the attribute descriptor is used to
1740 * guide storing the attribute in a persistent store.
1741 * <br>Store the MBean if 'persistPolicy' field is:
1742 * <UL>
1743 * <Li> != "never"</Li>
1744 * <Li> = "always"</Li>
1745 * <Li> = "onUpdate"</Li>
1746 * <Li> = "onTimer" and now &gt; 'lastPersistTime' + 'persistPeriod'</Li>
1747 * <Li> = "NoMoreOftenThan" and now &gt; 'lastPersistTime' +
1748 * 'persistPeriod'</Li>
1749 * </UL>
1750 * Do not store the MBean if 'persistPolicy' field is:
1751 * <UL>
1752 * <Li> = "never"</Li>
1753 * <Li> = "onTimer" && now &lt; 'lastPersistTime' + 'persistPeriod'</Li>
1754 * <Li> = "onUnregister"</Li>
1755 * <Li> = "NoMoreOftenThan" and now &lt; 'lastPersistTime' +
1756 * 'persistPeriod'</Li>
1757 * </UL>
1758 *
1759 * <p>The ModelMBeanInfo of the Model MBean is stored in a file.
1760 *
1761 * @param attribute The Attribute instance containing the name of
1762 * the attribute to be set and the value it is to be set to.
1763 *
1764 *
1765 * @exception AttributeNotFoundException The specified attribute is
1766 * not accessible in the MBean.
1767 * <br>The following cases may result in an AttributeNotFoundException:
1768 * <UL>
1769 * <LI> No ModelMBeanAttributeInfo is found for the specified
1770 * attribute.</LI>
1771 * <LI> The ModelMBeanAttributeInfo's isWritable method returns
1772 * 'false'.</LI>
1773 * </UL>
1774 * @exception InvalidAttributeValueException No descriptor is defined
1775 * for the specified attribute.
1776 * @exception MBeanException Wraps one of the following Exceptions:
1777 * <UL>
1778 * <LI> An Exception thrown by the managed object's setter.</LI>
1779 * <LI> A {@link ServiceNotFoundException} if a setMethod field is
1780 * defined in the descriptor for the attribute and the managed
1781 * resource is null; or if no setMethod field is defined and
1782 * caching is not enabled for the attribute.
1783 * Note that if there is no getMethod field either, then caching
1784 * is automatically enabled.</LI>
1785 * <LI> {@link InvalidTargetObjectTypeException} The 'targetType'
1786 * field value is not 'objectReference'.</LI>
1787 * <LI> An Exception thrown by the managed object's getter.</LI>
1788 * </UL>
1789 * @exception ReflectionException Wraps an {@link java.lang.Exception}
1790 * thrown while trying to invoke the setter.
1791 * @exception RuntimeOperationsException Wraps an
1792 * {@link IllegalArgumentException}: The attribute in parameter is
1793 * null.
1794 *
1795 * @see #getAttribute(java.lang.String)
1796 **/
1797 public void setAttribute(Attribute attribute)
1798 throws AttributeNotFoundException, InvalidAttributeValueException,
1799 MBeanException, ReflectionException {
1800 final boolean tracing = MODELMBEAN_LOGGER.isLoggable(Level.FINER);
1801 if (tracing) {
1802 MODELMBEAN_LOGGER.logp(Level.FINER,
1803 RequiredModelMBean.class.getName(),
1804 "setAttribute()","Entry");
1805 }
1806
1807 if (attribute == null)
1808 throw new RuntimeOperationsException(new
1809 IllegalArgumentException("attribute must not be null"),
1810 "Exception occurred trying to set an attribute of a "+
1811 "RequiredModelMBean");
1812
1813 /* run setMethod if there is one */
1814 /* return cached value if its current */
1815 /* set cached value in descriptor and set date/time */
1816 /* send attribute change Notification */
1817 /* check persistence policy and persist if need be */
1818 String attrName = attribute.getName();
1819 Object attrValue = attribute.getValue();
1820 boolean updateDescriptor = false;
1821
1822 ModelMBeanAttributeInfo attrInfo =
1823 modelMBeanInfo.getAttribute(attrName);
1824
1825 if (attrInfo == null)
1826 throw new AttributeNotFoundException("setAttribute failed: " +
1827 attrName + " is not found ");
1828
1829 Descriptor mmbDesc = modelMBeanInfo.getMBeanDescriptor();
1830 Descriptor attrDescr = attrInfo.getDescriptor();
1831
1832 if (attrDescr != null) {
1833 if (!attrInfo.isWritable())
1834 throw new AttributeNotFoundException("setAttribute failed: "
1835 + attrName + " is not writable ");
1836
1837 Object setResponse = null;
1838
1839 String attrSetMethod = (String)
1840 (attrDescr.getFieldValue("setMethod"));
1841 String attrGetMethod = (String)
1842 (attrDescr.getFieldValue("getMethod"));
1843
1844 String attrType = attrInfo.getType();
1845 Object currValue = "Unknown";
1846
1847 try {
1848 currValue = this.getAttribute(attrName);
1849 } catch (Throwable t) {
1850 // OK: Default "Unknown" value used for unknown attribute
1851 }
1852
1853 Attribute oldAttr = new Attribute(attrName, currValue);
1854
1855 /* run method from operations descriptor */
1856 if (attrSetMethod == null) {
1857 if (attrValue != null) {
1858 try {
1859 final Class clazz = loadClass(attrType);
1860 if (! clazz.isInstance(attrValue)) throw new
1861 InvalidAttributeValueException(clazz.getName() +
1862 " expected, " +
1863 attrValue.getClass().getName() +
1864 " received.");
1865 } catch (ClassNotFoundException x) {
1866 if (MODELMBEAN_LOGGER.isLoggable(Level.WARNING)) {
1867 MODELMBEAN_LOGGER.logp(Level.WARNING,
1868 RequiredModelMBean.class.getName(),
1869 "setAttribute(Attribute)","Class " +
1870 attrType + " for attribute "
1871 + attrName + " not found: ", x);
1872 }
1873 }
1874 }
1875 updateDescriptor = true;
1876 } else {
1877 setResponse = invoke(attrSetMethod,
1878 (new Object[] {attrValue}),
1879 (new String[] {attrType}) );
1880 }
1881
1882 /* change cached value */
1883 Object objctl = attrDescr.getFieldValue("currencyTimeLimit");
1884 String ctl;
1885 if (objctl != null) ctl = objctl.toString();
1886 else ctl = null;
1887
1888 if ((ctl == null) && (mmbDesc != null)) {
1889 objctl = mmbDesc.getFieldValue("currencyTimeLimit");
1890 if (objctl != null) ctl = objctl.toString();
1891 else ctl = null;
1892 }
1893
1894 final boolean updateCache = ((ctl != null) && !(ctl.equals("-1")));
1895
1896 if(attrSetMethod == null && !updateCache && attrGetMethod != null)
1897 throw new MBeanException(new ServiceNotFoundException("No " +
1898 "setMethod field is defined in the descriptor for " +
1899 attrName + " attribute and caching is not enabled " +
1900 "for it"));
1901
1902 if (updateCache || updateDescriptor) {
1903 if (tracing) {
1904 MODELMBEAN_LOGGER.logp(Level.FINER,
1905 RequiredModelMBean.class.getName(),
1906 "setAttribute(Attribute)",
1907 "setting cached value of " +
1908 attrName + " to " + attrValue);
1909 }
1910
1911 attrDescr.setField("value", attrValue);
1912
1913 if (updateCache) {
1914 final String currtime = String.valueOf(
1915 (new Date()).getTime());
1916
1917 attrDescr.setField("lastUpdatedTimeStamp", currtime);
1918 }
1919
1920 attrInfo.setDescriptor(attrDescr);
1921
1922 modelMBeanInfo.setDescriptor(attrDescr,"attribute");
1923 if (tracing) {
1924 final StringBuilder strb = new StringBuilder()
1925 .append("new descriptor is ").append(attrDescr)
1926 .append(". AttributeInfo descriptor is ")
1927 .append(attrInfo.getDescriptor())
1928 .append(". AttributeInfo descriptor is ")
1929 .append(modelMBeanInfo.getDescriptor(attrName,"attribute"));
1930 MODELMBEAN_LOGGER.logp(Level.FINER,
1931 RequiredModelMBean.class.getName(),
1932 "setAttribute(Attribute)",strb.toString());
1933 }
1934
1935 }
1936
1937 if (tracing) {
1938 MODELMBEAN_LOGGER.logp(Level.FINER,
1939 RequiredModelMBean.class.getName(),
1940 "setAttribute(Attribute)","sending sendAttributeNotification");
1941 }
1942 sendAttributeChangeNotification(oldAttr,attribute);
1943
1944 } else { // if descriptor ... else no descriptor
1945
1946 if (tracing) {
1947 MODELMBEAN_LOGGER.logp(Level.FINER,
1948 RequiredModelMBean.class.getName(),
1949 "setAttribute(Attribute)","setMethod failed "+attrName+
1950 " not in attributeDescriptor\n");
1951 }
1952
1953 throw new InvalidAttributeValueException(
1954 "Unable to resolve attribute value, "+
1955 "no defined in descriptor for attribute");
1956 } // else no descriptor
1957
1958 if (tracing) {
1959 MODELMBEAN_LOGGER.logp(Level.FINER,
1960 RequiredModelMBean.class.getName(),
1961 "setAttribute(Attribute)", "Exit");
1962 }
1963
1964 }
1965
1966 /**
1967 * Sets the values of an array of attributes of this ModelMBean.
1968 * Executes the setAttribute() method for each attribute in the list.
1969 *
1970 * @param attributes A list of attributes: The identification of the
1971 * attributes to be set and the values they are to be set to.
1972 *
1973 * @return The array of attributes that were set, with their new
1974 * values in Attribute instances.
1975 *
1976 * @exception RuntimeOperationsException Wraps an
1977 * {@link IllegalArgumentException}: The object name in parameter
1978 * is null or attributes in parameter is null.
1979 *
1980 * @see #getAttributes
1981 **/
1982 public AttributeList setAttributes(AttributeList attributes) {
1983
1984 if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) {
1985 MODELMBEAN_LOGGER.logp(Level.FINER,
1986 RequiredModelMBean.class.getName(),
1987 "setAttribute(Attribute)", "Entry");
1988 }
1989
1990 if (attributes == null)
1991 throw new RuntimeOperationsException(new
1992 IllegalArgumentException("attributes must not be null"),
1993 "Exception occurred trying to set attributes of a "+
1994 "RequiredModelMBean");
1995
1996 final AttributeList responseList = new AttributeList();
1997
1998 // Go through the list of attributes
1999 for (Iterator i = attributes.iterator(); i.hasNext();) {
2000 final Attribute attr = (Attribute) i.next();
2001 try {
2002 setAttribute(attr);
2003 responseList.add(attr);
2004 } catch (Exception excep) {
2005 responseList.remove(attr);
2006 }
2007 }
2008
2009 return responseList;
2010 }
2011
2012
2013
2014 private ModelMBeanInfo createDefaultModelMBeanInfo() {
2015 return(new ModelMBeanInfoSupport((this.getClass().getName()),
2016 "Default ModelMBean", null, null, null, null));
2017 }
2018
2019 /*************************************/
2020 /* NotificationBroadcaster Interface */
2021 /*************************************/
2022
2023
2024 private synchronized void writeToLog(String logFileName,
2025 String logEntry) throws Exception {
2026
2027 PrintStream logOut = null;
2028 FileOutputStream fos = null;
2029 if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) {
2030 MODELMBEAN_LOGGER.logp(Level.FINER,
2031 RequiredModelMBean.class.getName(),
2032 "writeToLog(String, String)",
2033 "Notification Logging to " + logFileName + ": " + logEntry);
2034 }
2035 if ((logFileName == null) || (logEntry == null)) {
2036 if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) {
2037 MODELMBEAN_LOGGER.logp(Level.FINER,
2038 RequiredModelMBean.class.getName(),
2039 "writeToLog(String, String)",
2040 "Bad input parameters, will not log this entry.");
2041 }
2042 return;
2043 }
2044
2045 try {
2046 fos = new FileOutputStream(logFileName, true);
2047 logOut = new PrintStream(fos);
2048 logOut.println(logEntry);
2049 logOut.close();
2050 if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) {
2051 MODELMBEAN_LOGGER.logp(Level.FINER,
2052 RequiredModelMBean.class.getName(),
2053 "writeToLog(String, String)","Successfully opened log " +
2054 logFileName);
2055 }
2056 } catch (Exception e) {
2057 if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) {
2058 MODELMBEAN_LOGGER.logp(Level.FINER,
2059 RequiredModelMBean.class.getName(),
2060 "writeToLog(String, String)",
2061 "Exception " + e.toString() +
2062 " trying to write to the Notification log file " +
2063 logFileName);
2064 }
2065 throw e;
2066 }
2067 }
2068
2069
2070 /**
2071 * Registers an object which implements the NotificationListener
2072 * interface as a listener. This
2073 * object's 'handleNotification()' method will be invoked when any
2074 * notification is issued through or by the ModelMBean. This does
2075 * not include attributeChangeNotifications. They must be registered
2076 * for independently.
2077 *
2078 * @param listener The listener object which will handles
2079 * notifications emitted by the registered MBean.
2080 * @param filter The filter object. If null, no filtering will be
2081 * performed before handling notifications.
2082 * @param handback The context to be sent to the listener with
2083 * the notification when a notification is emitted.
2084 *
2085 * @exception IllegalArgumentException The listener cannot be null.
2086 *
2087 * @see #removeNotificationListener
2088 */
2089 public void addNotificationListener(NotificationListener listener,
2090 NotificationFilter filter,
2091 Object handback)
2092 throws java.lang.IllegalArgumentException {
2093 final String mth = "addNotificationListener(" +
2094 "NotificationListener, NotificationFilter, Object)";
2095 if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) {
2096 MODELMBEAN_LOGGER.logp(Level.FINER,
2097 RequiredModelMBean.class.getName(), mth, "Entry");
2098 }
2099
2100 if (listener == null)
2101 throw new IllegalArgumentException(
2102 "notification listener must not be null");
2103
2104 if (generalBroadcaster == null)
2105 generalBroadcaster = new NotificationBroadcasterSupport();
2106
2107 generalBroadcaster.addNotificationListener(listener, filter,
2108 handback);
2109 if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) {
2110 MODELMBEAN_LOGGER.logp(Level.FINER,
2111 RequiredModelMBean.class.getName(), mth,
2112 "NotificationListener added");
2113 MODELMBEAN_LOGGER.logp(Level.FINER,
2114 RequiredModelMBean.class.getName(), mth, "Exit");
2115 }
2116 }
2117
2118 /**
2119 * Removes a listener for Notifications from the RequiredModelMBean.
2120 *
2121 * @param listener The listener name which was handling notifications
2122 * emitted by the registered MBean.
2123 * This method will remove all information related to this listener.
2124 *
2125 * @exception ListenerNotFoundException The listener is not registered
2126 * in the MBean or is null.
2127 *
2128 * @see #addNotificationListener
2129 **/
2130 public void removeNotificationListener(NotificationListener listener)
2131 throws ListenerNotFoundException {
2132 if (listener == null)
2133 throw new ListenerNotFoundException(
2134 "Notification listener is null");
2135
2136 final String mth="removeNotificationListener(NotificationListener)";
2137 if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) {
2138 MODELMBEAN_LOGGER.logp(Level.FINER,
2139 RequiredModelMBean.class.getName(), mth, "Entry");
2140 }
2141
2142 if (generalBroadcaster == null)
2143 throw new ListenerNotFoundException(
2144 "No notification listeners registered");
2145
2146
2147 generalBroadcaster.removeNotificationListener(listener);
2148 if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) {
2149 MODELMBEAN_LOGGER.logp(Level.FINER,
2150 RequiredModelMBean.class.getName(), mth, "Exit");
2151 }
2152
2153 }
2154
2155 public void removeNotificationListener(NotificationListener listener,
2156 NotificationFilter filter,
2157 Object handback)
2158 throws ListenerNotFoundException {
2159
2160 if (listener == null)
2161 throw new ListenerNotFoundException(
2162 "Notification listener is null");
2163
2164 final String mth = "removeNotificationListener(" +
2165 "NotificationListener, NotificationFilter, Object)";
2166
2167 if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) {
2168 MODELMBEAN_LOGGER.logp(Level.FINER,
2169 RequiredModelMBean.class.getName(), mth, "Entry");
2170 }
2171
2172 if (generalBroadcaster == null)
2173 throw new ListenerNotFoundException(
2174 "No notification listeners registered");
2175
2176
2177 generalBroadcaster.removeNotificationListener(listener,filter,
2178 handback);
2179
2180 if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) {
2181 MODELMBEAN_LOGGER.logp(Level.FINER,
2182 RequiredModelMBean.class.getName(), mth, "Exit");
2183 }
2184
2185 }
2186
2187 public void sendNotification(Notification ntfyObj)
2188 throws MBeanException, RuntimeOperationsException {
2189 if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) {
2190 MODELMBEAN_LOGGER.logp(Level.FINER,
2191 RequiredModelMBean.class.getName(),
2192 "sendNotification(Notification)", "Entry");
2193 }
2194
2195 if (ntfyObj == null)
2196 throw new RuntimeOperationsException(new
2197 IllegalArgumentException("notification object must not be "+
2198 "null"),
2199 "Exception occurred trying to send a notification from a "+
2200 "RequiredModelMBean");
2201
2202
2203 // log notification if specified in descriptor
2204 Descriptor ntfyDesc =
2205 modelMBeanInfo.getDescriptor(ntfyObj.getType(),"notification");
2206 Descriptor mmbDesc = modelMBeanInfo.getMBeanDescriptor();
2207
2208 if (ntfyDesc != null) {
2209 String logging = (String) ntfyDesc.getFieldValue("log");
2210
2211 if (logging == null) {
2212 if (mmbDesc != null)
2213 logging = (String) mmbDesc.getFieldValue("log");
2214 }
2215
2216 if ((logging != null) &&
2217 (logging.equalsIgnoreCase("t") ||
2218 logging.equalsIgnoreCase("true"))) {
2219
2220 String logfile = (String) ntfyDesc.getFieldValue("logfile");
2221 if (logfile == null) {
2222 if (mmbDesc != null)
2223 logfile = (String)mmbDesc.getFieldValue("logfile");
2224 }
2225 if (logfile != null) {
2226 try {
2227 writeToLog(logfile,"LogMsg: " +
2228 ((new Date(ntfyObj.getTimeStamp())).toString())+
2229 " " + ntfyObj.getType() + " " +
2230 ntfyObj.getMessage() + " Severity = " +
2231 (String)ntfyDesc.getFieldValue("severity"));
2232 } catch (Exception e) {
2233 if (MODELMBEAN_LOGGER.isLoggable(Level.WARNING)) {
2234 MODELMBEAN_LOGGER.logp(Level.WARNING,
2235 RequiredModelMBean.class.getName(),
2236 "sendNotification(Notification)",
2237 "Failed to log " +
2238 ntfyObj.getType() + " notification: ", e);
2239 }
2240 }
2241 }
2242 }
2243 }
2244 if (generalBroadcaster != null) {
2245 generalBroadcaster.sendNotification(ntfyObj);
2246 }
2247
2248 if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) {
2249 MODELMBEAN_LOGGER.logp(Level.FINER,
2250 RequiredModelMBean.class.getName(),
2251 "sendNotification(Notification)",
2252 "sendNotification sent provided notification object");
2253 MODELMBEAN_LOGGER.logp(Level.FINER,
2254 RequiredModelMBean.class.getName(),
2255 "sendNotification(Notification)"," Exit");
2256 }
2257
2258 }
2259
2260
2261 public void sendNotification(String ntfyText)
2262 throws MBeanException, RuntimeOperationsException {
2263 if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) {
2264 MODELMBEAN_LOGGER.logp(Level.FINER,
2265 RequiredModelMBean.class.getName(),
2266 "sendNotification(String)","Entry");
2267 }
2268
2269 if (ntfyText == null)
2270 throw new RuntimeOperationsException(new
2271 IllegalArgumentException("notification message must not "+
2272 "be null"),
2273 "Exception occurred trying to send a text notification "+
2274 "from a ModelMBean");
2275
2276 Notification myNtfyObj = new Notification("jmx.modelmbean.generic",
2277 this, 1, ntfyText);
2278 sendNotification(myNtfyObj);
2279 if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) {
2280 MODELMBEAN_LOGGER.logp(Level.FINER,
2281 RequiredModelMBean.class.getName(),
2282 "sendNotification(String)","Notification sent");
2283 MODELMBEAN_LOGGER.logp(Level.FINER,
2284 RequiredModelMBean.class.getName(),
2285 "sendNotification(String)","Exit");
2286 }
2287 }
2288
2289 /**
2290 * Returns `true' if the notification `notifName' is found
2291 * in `info'. (bug 4744667)
2292 **/
2293 private static final
2294 boolean hasNotification(final ModelMBeanInfo info,
2295 final String notifName) {
2296 try {
2297 if (info == null) return false;
2298 else return (info.getNotification(notifName)!=null);
2299 } catch (MBeanException x) {
2300 return false;
2301 } catch (RuntimeOperationsException r) {
2302 return false;
2303 }
2304 }
2305
2306 /**
2307 * Creates a default ModelMBeanNotificationInfo for GENERIC
2308 * notification. (bug 4744667)
2309 **/
2310 private static final ModelMBeanNotificationInfo makeGenericInfo() {
2311 final Descriptor genericDescriptor = new DescriptorSupport( new
2312 String[] {
2313 "name=GENERIC",
2314 "descriptorType=notification",
2315 "log=T",
2316 "severity=6",
2317 "displayName=jmx.modelmbean.generic"} );
2318
2319 return new ModelMBeanNotificationInfo(new
2320 String[] {"jmx.modelmbean.generic"},
2321 "GENERIC",
2322 "A text notification has been issued by the managed resource",
2323 genericDescriptor);
2324 }
2325
2326 /**
2327 * Creates a default ModelMBeanNotificationInfo for ATTRIBUTE_CHANGE
2328 * notification. (bug 4744667)
2329 **/
2330 private static final
2331 ModelMBeanNotificationInfo makeAttributeChangeInfo() {
2332 final Descriptor attributeDescriptor = new DescriptorSupport(new
2333 String[] {
2334 "name=ATTRIBUTE_CHANGE",
2335 "descriptorType=notification",
2336 "log=T",
2337 "severity=6",
2338 "displayName=jmx.attribute.change"});
2339
2340 return new ModelMBeanNotificationInfo(new
2341 String[] {"jmx.attribute.change"},
2342 "ATTRIBUTE_CHANGE",
2343 "Signifies that an observed MBean attribute value has changed",
2344 attributeDescriptor );
2345 }
2346
2347 /**
2348 * Returns the array of Notifications always generated by the
2349 * RequiredModelMBean.
2350 * <P>
2351 *
2352 * RequiredModelMBean may always send also two additional notifications:
2353 * <UL>
2354 * <LI> One with descriptor <code>"name=GENERIC,descriptorType=notification,log=T,severity=6,displayName=jmx.modelmbean.generic"</code></LI>
2355 * <LI> Second is a standard attribute change notification
2356 * with descriptor <code>"name=ATTRIBUTE_CHANGE,descriptorType=notification,log=T,severity=6,displayName=jmx.attribute.change"</code></LI>
2357 * </UL>
2358 * Thus these two notifications are always added to those specified
2359 * by the application.
2360 *
2361 * @return MBeanNotificationInfo[]
2362 *
2363 **/
2364 public MBeanNotificationInfo[] getNotificationInfo() {
2365 if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) {
2366 MODELMBEAN_LOGGER.logp(Level.FINER,
2367 RequiredModelMBean.class.getName(),
2368 "getNotificationInfo()","Entry");
2369 }
2370
2371 // Using hasNotification() is not optimal, but shouldn't really
2372 // matter in this context...
2373
2374 // hasGeneric==true if GENERIC notification is present.
2375 // (bug 4744667)
2376 final boolean hasGeneric = hasNotification(modelMBeanInfo,"GENERIC");
2377
2378 // hasAttributeChange==true if ATTRIBUTE_CHANGE notification is
2379 // present.
2380 // (bug 4744667)
2381 final boolean hasAttributeChange =
2382 hasNotification(modelMBeanInfo,"ATTRIBUTE_CHANGE");
2383
2384 // User supplied list of notification infos.
2385 //
2386 final ModelMBeanNotificationInfo[] currInfo =
2387 (ModelMBeanNotificationInfo[])modelMBeanInfo.getNotifications();
2388
2389 // Length of the returned list of notification infos:
2390 // length of user suplied list + possibly 1 for GENERIC, +
2391 // possibly 1 for ATTRIBUTE_CHANGE
2392 // (bug 4744667)
2393 final int len = ((currInfo==null?0:currInfo.length) +
2394 (hasGeneric?0:1) + (hasAttributeChange?0:1));
2395
2396 // Returned list of notification infos:
2397 //
2398 final ModelMBeanNotificationInfo[] respInfo =
2399 new ModelMBeanNotificationInfo[len];
2400
2401 // Preserve previous ordering (JMX 1.1)
2402 //
2403
2404 // Counter of "standard" notification inserted before user
2405 // supplied notifications.
2406 //
2407 int inserted=0;
2408 if (!hasGeneric)
2409 // We need to add description for GENERIC notification
2410 // (bug 4744667)
2411 respInfo[inserted++] = makeGenericInfo();
2412
2413
2414 if (!hasAttributeChange)
2415 // We need to add description for ATTRIBUTE_CHANGE notification
2416 // (bug 4744667)
2417 respInfo[inserted++] = makeAttributeChangeInfo();
2418
2419 // Now copy user supplied list in returned list.
2420 //
2421 final int count = currInfo.length;
2422 final int offset = inserted;
2423 for (int j=0; j < count; j++) {
2424 respInfo[offset+j] = currInfo[j];
2425 }
2426
2427 if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) {
2428 MODELMBEAN_LOGGER.logp(Level.FINER,
2429 RequiredModelMBean.class.getName(),
2430 "getNotificationInfo()","Exit");
2431 }
2432
2433 return respInfo;
2434 }
2435
2436
2437 public void addAttributeChangeNotificationListener(NotificationListener
2438 inlistener,
2439 String
2440 inAttributeName,
2441 Object inhandback)
2442 throws MBeanException, RuntimeOperationsException,
2443 IllegalArgumentException {
2444 final String mth="addAttributeChangeNotificationListener(" +
2445 "NotificationListener, String, Object)";
2446
2447 if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) {
2448 MODELMBEAN_LOGGER.logp(Level.FINER,
2449 RequiredModelMBean.class.getName(),mth,"Entry");
2450 }
2451
2452 if (inlistener == null)
2453 throw new IllegalArgumentException(
2454 "Listener to be registered must not be null");
2455
2456
2457 if (attributeBroadcaster == null)
2458 attributeBroadcaster = new NotificationBroadcasterSupport();
2459
2460 AttributeChangeNotificationFilter currFilter =
2461 new AttributeChangeNotificationFilter();
2462
2463 MBeanAttributeInfo[] attrInfo = modelMBeanInfo.getAttributes();
2464 boolean found = false;
2465 if (inAttributeName == null) {
2466 if ((attrInfo != null) && (attrInfo.length>0)) {
2467 for (int i=0; i<attrInfo.length; i++) {
2468 currFilter.enableAttribute(attrInfo[i].getName());
2469 }
2470 }
2471 } else {
2472 if ((attrInfo != null) && (attrInfo.length>0)) {
2473 for (int i=0; i<attrInfo.length; i++) {
2474 if (inAttributeName.equals(attrInfo[i].getName())) {
2475 found = true;
2476 currFilter.enableAttribute(inAttributeName);
2477 break;
2478 }
2479 }
2480 }
2481 if (!found) {
2482 throw new RuntimeOperationsException(new
2483 IllegalArgumentException(
2484 "The attribute name does not exist"),
2485 "Exception occurred trying to add an "+
2486 "AttributeChangeNotification listener");
2487 }
2488 }
2489
2490 if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) {
2491 MODELMBEAN_LOGGER.logp(Level.FINER,
2492 RequiredModelMBean.class.getName(), mth,
2493 "Set attribute change filter to " +
2494 currFilter.getEnabledAttributes().firstElement());
2495 }
2496
2497 attributeBroadcaster.addNotificationListener(inlistener,currFilter,
2498 inhandback);
2499 if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) {
2500 MODELMBEAN_LOGGER.logp(Level.FINER,
2501 RequiredModelMBean.class.getName(),mth,
2502 "Notification listener added for " + inAttributeName);
2503 MODELMBEAN_LOGGER.logp(Level.FINER,
2504 RequiredModelMBean.class.getName(),mth,"Exit");
2505 }
2506 }
2507
2508 public void removeAttributeChangeNotificationListener(
2509 NotificationListener inlistener, String inAttributeName)
2510 throws MBeanException, RuntimeOperationsException,
2511 ListenerNotFoundException {
2512 if (inlistener == null) throw new
2513 ListenerNotFoundException("Notification listener is null");
2514
2515 final String mth = "removeAttributeChangeNotificationListener(" +
2516 "NotificationListener, String)";
2517
2518 if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) {
2519 MODELMBEAN_LOGGER.logp(Level.FINER,
2520 RequiredModelMBean.class.getName(),mth,"Entry");
2521 }
2522
2523
2524 if (attributeBroadcaster == null)
2525 throw new ListenerNotFoundException(
2526 "No attribute change notification listeners registered");
2527
2528
2529 MBeanAttributeInfo[] attrInfo = modelMBeanInfo.getAttributes();
2530 boolean found = false;
2531 if ((attrInfo != null) && (attrInfo.length>0)) {
2532 for (int i=0; i<attrInfo.length; i++) {
2533 if (attrInfo[i].getName().equals(inAttributeName)) {
2534 found = true;
2535 break;
2536 }
2537 }
2538 }
2539
2540 if ((!found) && (inAttributeName != null)) {
2541 throw new RuntimeOperationsException(new
2542 IllegalArgumentException("Invalid attribute name"),
2543 "Exception occurred trying to remove "+
2544 "attribute change notification listener");
2545 }
2546
2547 /* note: */
2548 /* this may be a problem if the same listener is registered for
2549 multiple attributes with multiple filters and/or handback
2550 objects. It may remove all of them */
2551
2552 attributeBroadcaster.removeNotificationListener(inlistener);
2553
2554 if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) {
2555 MODELMBEAN_LOGGER.logp(Level.FINER,
2556 RequiredModelMBean.class.getName(),mth,"Exit");
2557 }
2558 }
2559
2560 public void sendAttributeChangeNotification(AttributeChangeNotification
2561 ntfyObj)
2562 throws MBeanException, RuntimeOperationsException {
2563 final String mth = "sendAttributeChangeNotification(" +
2564 "AttributeChangeNotification)";
2565
2566 if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) {
2567 MODELMBEAN_LOGGER.logp(Level.FINER,
2568 RequiredModelMBean.class.getName(),mth,"Entry");
2569 }
2570
2571 if (ntfyObj == null)
2572 throw new RuntimeOperationsException(new
2573 IllegalArgumentException(
2574 "attribute change notification object must not be null"),
2575 "Exception occurred trying to send "+
2576 "attribute change notification of a ModelMBean");
2577
2578 Object oldv = ntfyObj.getOldValue();
2579 Object newv = ntfyObj.getNewValue();
2580
2581 if (oldv == null) oldv = "null";
2582 if (newv == null) newv = "null";
2583
2584 if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) {
2585 MODELMBEAN_LOGGER.logp(Level.FINER,
2586 RequiredModelMBean.class.getName(),mth,
2587 "Sending AttributeChangeNotification with " +
2588 ntfyObj.getAttributeName() + ntfyObj.getAttributeType() +
2589 ntfyObj.getNewValue() + ntfyObj.getOldValue());
2590 }
2591
2592 // log notification if specified in descriptor
2593 Descriptor ntfyDesc =
2594 modelMBeanInfo.getDescriptor(ntfyObj.getType(),"notification");
2595 Descriptor mmbDesc = modelMBeanInfo.getMBeanDescriptor();
2596
2597 String logging, logfile;
2598
2599 if (ntfyDesc != null) {
2600 logging =(String) ntfyDesc.getFieldValue("log");
2601 if (logging == null) {
2602 if (mmbDesc != null)
2603 logging = (String) mmbDesc.getFieldValue("log");
2604 }
2605 if ((logging != null) &&
2606 ( logging.equalsIgnoreCase("t") ||
2607 logging.equalsIgnoreCase("true"))) {
2608 logfile = (String) ntfyDesc.getFieldValue("logfile");
2609 if (logfile == null) {
2610 if (mmbDesc != null)
2611 logfile = (String)mmbDesc.getFieldValue("logfile");
2612 }
2613
2614 if (logfile != null) {
2615 try {
2616 writeToLog(logfile,"LogMsg: " +
2617 ((new Date(ntfyObj.getTimeStamp())).toString())+
2618 " " + ntfyObj.getType() + " " +
2619 ntfyObj.getMessage() +
2620 " Name = " + ntfyObj.getAttributeName() +
2621 " Old value = " + oldv +
2622 " New value = " + newv);
2623 } catch (Exception e) {
2624 if (MODELMBEAN_LOGGER.isLoggable(Level.WARNING)) {
2625 MODELMBEAN_LOGGER.logp(Level.WARNING,
2626 RequiredModelMBean.class.getName(),mth,
2627 "Failed to log " + ntfyObj.getType() +
2628 " notification: ", e);
2629 }
2630 }
2631 }
2632 }
2633 } else if (mmbDesc != null) {
2634 logging = (String) mmbDesc.getFieldValue("log");
2635 if ((logging != null) &&
2636 ( logging.equalsIgnoreCase("t") ||
2637 logging.equalsIgnoreCase("true") )) {
2638 logfile = (String) mmbDesc.getFieldValue("logfile");
2639
2640 if (logfile != null) {
2641 try {
2642 writeToLog(logfile,"LogMsg: " +
2643 ((new Date(ntfyObj.getTimeStamp())).toString())+
2644 " " + ntfyObj.getType() + " " +
2645 ntfyObj.getMessage() +
2646 " Name = " + ntfyObj.getAttributeName() +
2647 " Old value = " + oldv +
2648 " New value = " + newv);
2649 } catch (Exception e) {
2650 if (MODELMBEAN_LOGGER.isLoggable(Level.WARNING)) {
2651 MODELMBEAN_LOGGER.logp(Level.WARNING,
2652 RequiredModelMBean.class.getName(),mth,
2653 "Failed to log " + ntfyObj.getType() +
2654 " notification: ", e);
2655 }
2656 }
2657 }
2658 }
2659 }
2660 if (attributeBroadcaster != null) {
2661 attributeBroadcaster.sendNotification(ntfyObj);
2662 }
2663
2664 // XXX Revisit: This is a quickfix: it would be better to have a
2665 // single broadcaster. However, it is not so simple because
2666 // removeAttributeChangeNotificationListener() should
2667 // remove only listeners whose filter is an instanceof
2668 // AttributeChangeNotificationFilter.
2669 //
2670 if (generalBroadcaster != null) {
2671 generalBroadcaster.sendNotification(ntfyObj);
2672 }
2673
2674 if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) {
2675 MODELMBEAN_LOGGER.logp(Level.FINER,
2676 RequiredModelMBean.class.getName(),mth,
2677 "sent notification");
2678 MODELMBEAN_LOGGER.logp(Level.FINER,
2679 RequiredModelMBean.class.getName(),mth,
2680 "Exit");
2681 }
2682 }
2683
2684 public void sendAttributeChangeNotification(Attribute inOldVal,
2685 Attribute inNewVal)
2686 throws MBeanException, RuntimeOperationsException {
2687 final String mth =
2688 "sendAttributeChangeNotification(Attribute, Attribute)";
2689 if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) {
2690 MODELMBEAN_LOGGER.logp(Level.FINER,
2691 RequiredModelMBean.class.getName(),mth,
2692 "Entry");
2693 }
2694
2695 // do we really want to do this?
2696 if ((inOldVal == null) || (inNewVal == null))
2697 throw new RuntimeOperationsException(new
2698 IllegalArgumentException("Attribute object must not be null"),
2699 "Exception occurred trying to send " +
2700 "attribute change notification of a ModelMBean");
2701
2702
2703 if (!(inOldVal.getName().equals(inNewVal.getName())))
2704 throw new RuntimeOperationsException(new
2705 IllegalArgumentException("Attribute names are not the same"),
2706 "Exception occurred trying to send " +
2707 "attribute change notification of a ModelMBean");
2708
2709
2710 Object newVal = inNewVal.getValue();
2711 Object oldVal = inOldVal.getValue();
2712 String className = "unknown";
2713 if (newVal != null)
2714 className = newVal.getClass().getName();
2715 if (oldVal != null)
2716 className = oldVal.getClass().getName();
2717
2718 AttributeChangeNotification myNtfyObj = new
2719 AttributeChangeNotification(this,
2720 1,
2721 ((new Date()).getTime()),
2722 "AttributeChangeDetected",
2723 inOldVal.getName(),
2724 className,
2725 inOldVal.getValue(),
2726 inNewVal.getValue());
2727
2728 sendAttributeChangeNotification(myNtfyObj);
2729
2730 if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) {
2731 MODELMBEAN_LOGGER.logp(Level.FINER,
2732 RequiredModelMBean.class.getName(),mth,
2733 "Exit");
2734 }
2735
2736 }
2737
2738 /**
2739 * Return the Class Loader Repository used to perform class loading.
2740 * Subclasses may wish to redefine this method in order to return
2741 * the appropriate {@link javax.management.loading.ClassLoaderRepository}
2742 * that should be used in this object.
2743 *
2744 * @return the Class Loader Repository.
2745 *
2746 */
2747 protected ClassLoaderRepository getClassLoaderRepository() {
2748 return MBeanServerFactory.getClassLoaderRepository(server);
2749 }
2750
2751 private Class loadClass(String className)
2752 throws ClassNotFoundException {
2753 try {
2754 return Class.forName(className);
2755 } catch (ClassNotFoundException e) {
2756 final ClassLoaderRepository clr =
2757 getClassLoaderRepository();
2758 if (clr == null) throw new ClassNotFoundException(className);
2759 return clr.loadClass(className);
2760 }
2761 }
2762
2763
2764 /*************************************/
2765 /* MBeanRegistration Interface */
2766 /*************************************/
2767
2768 /**
2769 * Allows the MBean to perform any operations it needs before
2770 * being registered in the MBean server. If the name of the MBean
2771 * is not specified, the MBean can provide a name for its
2772 * registration. If any exception is raised, the MBean will not be
2773 * registered in the MBean server.
2774 * <P>
2775 * In order to ensure proper run-time semantics of RequireModelMBean,
2776 * Any subclass of RequiredModelMBean overloading or overriding this
2777 * method should call <code>super.preRegister(server, name)</code>
2778 * in its own <code>preRegister</code> implementation.
2779 *
2780 * @param server The MBean server in which the MBean will be registered.
2781 *
2782 * @param name The object name of the MBean. This name is null if
2783 * the name parameter to one of the <code>createMBean</code> or
2784 * <code>registerMBean</code> methods in the {@link MBeanServer}
2785 * interface is null. In that case, this method must return a
2786 * non-null ObjectName for the new MBean.
2787 *
2788 * @return The name under which the MBean is to be registered.
2789 * This value must not be null. If the <code>name</code>
2790 * parameter is not null, it will usually but not necessarily be
2791 * the returned value.
2792 *
2793 * @exception java.lang.Exception This exception will be caught by
2794 * the MBean server and re-thrown as an
2795 * {@link javax.management.MBeanRegistrationException
2796 * MBeanRegistrationException}.
2797 */
2798 public ObjectName preRegister(MBeanServer server,
2799 ObjectName name)
2800 throws java.lang.Exception {
2801 // Since ModelMbeanInfo cannot be null (otherwise exception
2802 // thrown at creation)
2803 // no exception thrown on ModelMBeanInfo not set.
2804 if (name == null) throw new NullPointerException(
2805 "name of RequiredModelMBean to registered is null");
2806 this.server = server;
2807 return name;
2808 }
2809
2810 /**
2811 * Allows the MBean to perform any operations needed after having been
2812 * registered in the MBean server or after the registration has failed.
2813 * <P>
2814 * In order to ensure proper run-time semantics of RequireModelMBean,
2815 * Any subclass of RequiredModelMBean overloading or overriding this
2816 * method should call <code>super.postRegister(registrationDone)</code>
2817 * in its own <code>postRegister</code> implementation.
2818 *
2819 * @param registrationDone Indicates whether or not the MBean has
2820 * been successfully registered in the MBean server. The value
2821 * false means that the registration phase has failed.
2822 */
2823 public void postRegister(Boolean registrationDone) {
2824 registered = registrationDone.booleanValue();
2825 }
2826
2827 /**
2828 * Allows the MBean to perform any operations it needs before
2829 * being unregistered by the MBean server.
2830 * <P>
2831 * In order to ensure proper run-time semantics of RequireModelMBean,
2832 * Any subclass of RequiredModelMBean overloading or overriding this
2833 * method should call <code>super.preDeregister()</code> in its own
2834 * <code>preDeregister</code> implementation.
2835 *
2836 * @exception java.lang.Exception This exception will be caught by
2837 * the MBean server and re-thrown as an
2838 * {@link javax.management.MBeanRegistrationException
2839 * MBeanRegistrationException}.
2840 */
2841 public void preDeregister() throws java.lang.Exception {
2842 }
2843
2844 /**
2845 * Allows the MBean to perform any operations needed after having been
2846 * unregistered in the MBean server.
2847 * <P>
2848 * In order to ensure proper run-time semantics of RequireModelMBean,
2849 * Any subclass of RequiredModelMBean overloading or overriding this
2850 * method should call <code>super.postDeregister()</code> in its own
2851 * <code>postDeregister</code> implementation.
2852 */
2853 public void postDeregister() {
2854 registered = false;
2855 this.server=null;
2856 }
2857
2858 private static final String[] primitiveTypes;
2859 private static final String[] primitiveWrappers;
2860 static {
2861 primitiveTypes = new String[] {
2862 Boolean.TYPE.getName(),
2863 Byte.TYPE.getName(),
2864 Character.TYPE.getName(),
2865 Short.TYPE.getName(),
2866 Integer.TYPE.getName(),
2867 Long.TYPE.getName(),
2868 Float.TYPE.getName(),
2869 Double.TYPE.getName(),
2870 Void.TYPE.getName()
2871 };
2872 primitiveWrappers = new String[] {
2873 Boolean.class.getName(),
2874 Byte.class.getName(),
2875 Character.class.getName(),
2876 Short.class.getName(),
2877 Integer.class.getName(),
2878 Long.class.getName(),
2879 Float.class.getName(),
2880 Double.class.getName(),
2881 Void.class.getName()
2882 };
2883 }
2884}