1 /* 2 * Copyright (c) 2000, 2008, Oracle and/or its affiliates. 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. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 /* 26 * @author IBM Corp. 27 * 28 * Copyright IBM Corp. 1999-2000. All rights reserved. 29 */ 30 31 32 package javax.management.modelmbean; 33 34 /* java imports */ 35 36 import static com.sun.jmx.defaults.JmxProperties.MODELMBEAN_LOGGER; 37 import java.io.FileOutputStream; 38 import java.io.PrintStream; 39 import java.lang.reflect.InvocationTargetException; 40 41 import java.lang.reflect.Method; 42 43 import java.util.Date; 44 import java.util.HashMap; 45 import java.util.HashSet; 46 import java.util.Iterator; 47 import java.util.logging.Level; 48 import java.util.Map; 49 import java.util.Set; 50 51 import java.util.Vector; 52 import javax.management.Attribute; 53 import javax.management.AttributeChangeNotification; 54 import javax.management.AttributeChangeNotificationFilter; 55 import javax.management.AttributeList; 56 import javax.management.AttributeNotFoundException; 57 import javax.management.Descriptor; 58 import javax.management.InstanceNotFoundException; 59 import javax.management.InvalidAttributeValueException; 60 import javax.management.ListenerNotFoundException; 61 import javax.management.MBeanAttributeInfo; 62 import javax.management.MBeanConstructorInfo; 63 import javax.management.MBeanException; 64 import javax.management.MBeanInfo; 65 import javax.management.MBeanNotificationInfo; 66 import javax.management.MBeanOperationInfo; 67 import javax.management.MBeanRegistration; 68 import javax.management.MBeanServer; 69 import javax.management.MBeanServerFactory; 70 import javax.management.Notification; 71 import javax.management.NotificationBroadcasterSupport; 72 import javax.management.NotificationEmitter; 73 import javax.management.NotificationFilter; 74 import javax.management.NotificationListener; 75 import javax.management.ObjectName; 76 import javax.management.ReflectionException; 77 import javax.management.RuntimeErrorException; 78 import javax.management.RuntimeOperationsException; 79 import javax.management.ServiceNotFoundException; 80 import javax.management.loading.ClassLoaderRepository; 81 82 import sun.reflect.misc.MethodUtil; 83 import sun.reflect.misc.ReflectUtil; 84 85 /** 86 * This class is the implementation of a ModelMBean. An appropriate 87 * implementation of a ModelMBean must be shipped with every JMX Agent 88 * and the class must be named RequiredModelMBean. 89 * <P> 90 * Java resources wishing to be manageable instantiate the 91 * RequiredModelMBean using the MBeanServer's createMBean method. 92 * The resource then sets the MBeanInfo and Descriptors for the 93 * RequiredModelMBean instance. The attributes and operations exposed 94 * via the ModelMBeanInfo for the ModelMBean are accessible 95 * from MBeans, connectors/adaptors like other MBeans. Through the 96 * Descriptors, values and methods in the managed application can be 97 * defined and mapped to attributes and operations of the ModelMBean. 98 * This mapping can be defined in an XML formatted file or dynamically and 99 * programmatically at runtime. 100 * <P> 101 * Every RequiredModelMBean which is instantiated in the MBeanServer 102 * becomes manageable:<br> 103 * its attributes and operations become remotely accessible through the 104 * connectors/adaptors connected to that MBeanServer. 105 * <P> 106 * A Java object cannot be registered in the MBeanServer unless it is a 107 * JMX compliant MBean. By instantiating a RequiredModelMBean, resources 108 * are guaranteed that the MBean is valid. 109 * 110 * MBeanException and RuntimeOperationsException must be thrown on every 111 * public method. This allows for wrapping exceptions from distributed 112 * communications (RMI, EJB, etc.) 113 * 114 * @since 1.5 115 */ 116 117 public class RequiredModelMBean 118 implements ModelMBean, MBeanRegistration, NotificationEmitter { 119 120 /*************************************/ 121 /* attributes */ 122 /*************************************/ 123 ModelMBeanInfo modelMBeanInfo; 124 125 /* Notification broadcaster for any notification to be sent 126 * from the application through the RequiredModelMBean. */ 127 private NotificationBroadcasterSupport generalBroadcaster = null; 128 129 /* Notification broadcaster for attribute change notifications */ 130 private NotificationBroadcasterSupport attributeBroadcaster = null; 131 132 /* handle, name, or reference for instance on which the actual invoke 133 * and operations will be executed */ 134 private Object managedResource = null; 135 136 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><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>>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' > 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><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>>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' > 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.getName() + "." + 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><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>>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' > 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 Object response; 1430 1431 try { 1432 if (modelMBeanInfo == null) 1433 throw new AttributeNotFoundException( 1434 "getAttribute failed: ModelMBeanInfo not found for "+ 1435 attrName); 1436 1437 ModelMBeanAttributeInfo attrInfo = modelMBeanInfo.getAttribute(attrName); 1438 Descriptor mmbDesc = modelMBeanInfo.getMBeanDescriptor(); 1439 1440 if (attrInfo == null) 1441 throw new AttributeNotFoundException("getAttribute failed:"+ 1442 " ModelMBeanAttributeInfo not found for " + attrName); 1443 1444 Descriptor attrDescr = attrInfo.getDescriptor(); 1445 if (attrDescr != null) { 1446 if (!attrInfo.isReadable()) 1447 throw new AttributeNotFoundException( 1448 "getAttribute failed: " + attrName + 1449 " is not readable "); 1450 1451 response = resolveForCacheValue(attrDescr); 1452 1453 /* return current cached value */ 1454 if (tracing) { 1455 MODELMBEAN_LOGGER.logp(Level.FINER, 1456 RequiredModelMBean.class.getName(), mth, 1457 "*** cached value is " + response); 1458 } 1459 1460 if (response == null) { 1461 /* no cached value, run getMethod */ 1462 if (tracing) { 1463 MODELMBEAN_LOGGER.logp(Level.FINER, 1464 RequiredModelMBean.class.getName(), mth, 1465 "**** cached value is null - getting getMethod"); 1466 } 1467 String attrGetMethod = 1468 (String)(attrDescr.getFieldValue("getMethod")); 1469 1470 if (attrGetMethod != null) { 1471 /* run method from operations descriptor */ 1472 if (tracing) { 1473 MODELMBEAN_LOGGER.logp(Level.FINER, 1474 RequiredModelMBean.class.getName(), 1475 mth, "invoking a getMethod for " + attrName); 1476 } 1477 1478 Object getResponse = 1479 invoke(attrGetMethod, new Object[] {}, 1480 new String[] {}); 1481 1482 if (getResponse != null) { 1483 // error/validity check return value here 1484 if (tracing) { 1485 MODELMBEAN_LOGGER.logp(Level.FINER, 1486 RequiredModelMBean.class.getName(), 1487 mth, "got a non-null response " + 1488 "from getMethod\n"); 1489 } 1490 1491 response = getResponse; 1492 1493 // change cached value in attribute descriptor 1494 Object objctl = 1495 attrDescr.getFieldValue("currencyTimeLimit"); 1496 1497 String ctl; 1498 if (objctl != null) ctl = objctl.toString(); 1499 else ctl = null; 1500 1501 if ((ctl == null) && (mmbDesc != null)) { 1502 objctl = mmbDesc. 1503 getFieldValue("currencyTimeLimit"); 1504 if (objctl != null) ctl = objctl.toString(); 1505 else ctl = null; 1506 } 1507 1508 if ((ctl != null) && !(ctl.equals("-1"))) { 1509 if (tracing) { 1510 MODELMBEAN_LOGGER.logp(Level.FINER, 1511 RequiredModelMBean.class.getName(), 1512 mth, 1513 "setting cached value and " + 1514 "lastUpdatedTime in descriptor"); 1515 } 1516 attrDescr.setField("value", response); 1517 final String stamp = String.valueOf( 1518 (new Date()).getTime()); 1519 attrDescr.setField("lastUpdatedTimeStamp", 1520 stamp); 1521 attrInfo.setDescriptor(attrDescr); 1522 modelMBeanInfo.setDescriptor(attrDescr, 1523 "attribute"); 1524 if (tracing) { 1525 MODELMBEAN_LOGGER.logp(Level.FINER, 1526 RequiredModelMBean.class.getName(), 1527 mth,"new descriptor is " +attrDescr); 1528 MODELMBEAN_LOGGER.logp(Level.FINER, 1529 RequiredModelMBean.class.getName(), 1530 mth,"AttributeInfo descriptor is " + 1531 attrInfo.getDescriptor()); 1532 final String attStr = modelMBeanInfo. 1533 getDescriptor(attrName,"attribute"). 1534 toString(); 1535 MODELMBEAN_LOGGER.logp(Level.FINER, 1536 RequiredModelMBean.class.getName(), 1537 mth, 1538 "modelMBeanInfo: AttributeInfo " + 1539 "descriptor is " + attStr); 1540 } 1541 } 1542 } else { 1543 // response was invalid or really returned null 1544 if (tracing) { 1545 MODELMBEAN_LOGGER.logp(Level.FINER, 1546 RequiredModelMBean.class.getName(), mth, 1547 "got a null response from getMethod\n"); 1548 } 1549 response = null; 1550 } 1551 } else { 1552 // not getMethod so return descriptor (default) value 1553 String qualifier=""; 1554 response = attrDescr.getFieldValue("value"); 1555 if (response == null) { 1556 qualifier="default "; 1557 response = attrDescr.getFieldValue("default"); 1558 } 1559 if (tracing) { 1560 MODELMBEAN_LOGGER.logp(Level.FINER, 1561 RequiredModelMBean.class.getName(), mth, 1562 "could not find getMethod for " +attrName + 1563 ", returning descriptor " +qualifier + "value"); 1564 } 1565 // !! cast response to right class 1566 } 1567 } 1568 1569 // make sure response class matches type field 1570 String respType = attrInfo.getType(); 1571 if (response != null) { 1572 String responseClass = response.getClass().getName(); 1573 if (!respType.equals(responseClass)) { 1574 boolean wrongType = false; 1575 boolean primitiveType = false; 1576 boolean correspondingTypes = false; 1577 for (int i = 0; i < primitiveTypes.length; i++) { 1578 if (respType.equals(primitiveTypes[i])) { 1579 primitiveType = true; 1580 if (responseClass.equals(primitiveWrappers[i])) 1581 correspondingTypes = true; 1582 break; 1583 } 1584 } 1585 if (primitiveType) { 1586 // inequality may come from primitive/wrapper class 1587 if (!correspondingTypes) 1588 wrongType = true; 1589 } else { 1590 // inequality may come from type subclassing 1591 boolean subtype; 1592 try { 1593 ClassLoader cl = 1594 response.getClass().getClassLoader(); 1595 Class<?> c = Class.forName(respType, true, cl); 1596 subtype = c.isInstance(response); 1597 } catch (Exception e) { 1598 subtype = false; 1599 1600 if (tracing) { 1601 MODELMBEAN_LOGGER.logp(Level.FINER, 1602 RequiredModelMBean.class.getName(), 1603 mth, "Exception: ",e); 1604 } 1605 } 1606 if (!subtype) 1607 wrongType = true; 1608 } 1609 if (wrongType) { 1610 if (tracing) { 1611 MODELMBEAN_LOGGER.logp(Level.FINER, 1612 RequiredModelMBean.class.getName(), mth, 1613 "Wrong response type '" + respType + "'"); 1614 } 1615 // throw exception, didn't get 1616 // back right attribute type 1617 throw new MBeanException( 1618 new InvalidAttributeValueException( 1619 "Wrong value type received for get attribute"), 1620 "An exception occurred while trying to get an " + 1621 "attribute value through a RequiredModelMBean"); 1622 } 1623 } 1624 } 1625 } else { 1626 if (tracing) { 1627 MODELMBEAN_LOGGER.logp(Level.FINER, 1628 RequiredModelMBean.class.getName(), mth, 1629 "getMethod failed " + attrName + 1630 " not in attributeDescriptor\n"); 1631 } 1632 throw new MBeanException(new 1633 InvalidAttributeValueException( 1634 "Unable to resolve attribute value, " + 1635 "no getMethod defined in descriptor for attribute"), 1636 "An exception occurred while trying to get an "+ 1637 "attribute value through a RequiredModelMBean"); 1638 } 1639 1640 } catch (MBeanException mbe) { 1641 throw mbe; 1642 } catch (AttributeNotFoundException t) { 1643 throw t; 1644 } catch (Exception e) { 1645 if (tracing) { 1646 MODELMBEAN_LOGGER.logp(Level.FINER, 1647 RequiredModelMBean.class.getName(), mth, 1648 "getMethod failed with " + e.getMessage() + 1649 " exception type " + (e.getClass()).toString()); 1650 } 1651 throw new MBeanException(e,"An exception occurred while trying "+ 1652 "to get an attribute value: " + e.getMessage()); 1653 } 1654 1655 if (tracing) { 1656 MODELMBEAN_LOGGER.logp(Level.FINER, 1657 RequiredModelMBean.class.getName(), mth, "Exit"); 1658 } 1659 1660 return response; 1661 } 1662 1663 /** 1664 * Returns the values of several attributes in the ModelMBean. 1665 * Executes a getAttribute for each attribute name in the 1666 * attrNames array passed in. 1667 * 1668 * @param attrNames A String array of names of the attributes 1669 * to be retrieved. 1670 * 1671 * @return The array of the retrieved attributes. 1672 * 1673 * @exception RuntimeOperationsException Wraps an 1674 * {@link IllegalArgumentException}: The object name in parameter is 1675 * null or attributes in parameter is null. 1676 * 1677 * @see #setAttributes(javax.management.AttributeList) 1678 */ 1679 public AttributeList getAttributes(String[] attrNames) { 1680 if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) { 1681 MODELMBEAN_LOGGER.logp(Level.FINER, 1682 RequiredModelMBean.class.getName(), 1683 "getAttributes(String[])","Entry"); 1684 } 1685 1686 if (attrNames == null) 1687 throw new RuntimeOperationsException(new 1688 IllegalArgumentException("attributeNames must not be null"), 1689 "Exception occurred trying to get attributes of a "+ 1690 "RequiredModelMBean"); 1691 1692 AttributeList responseList = new AttributeList(); 1693 for (int i = 0; i < attrNames.length; i++) { 1694 try { 1695 responseList.add(new Attribute(attrNames[i], 1696 getAttribute(attrNames[i]))); 1697 } catch (Exception e) { 1698 // eat exceptions because interface doesn't have an 1699 // exception on it 1700 if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) { 1701 MODELMBEAN_LOGGER.logp(Level.FINER, 1702 RequiredModelMBean.class.getName(), 1703 "getAttributes(String[])", 1704 "Failed to get \"" + attrNames[i] + "\": ", e); 1705 } 1706 } 1707 } 1708 1709 if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) { 1710 MODELMBEAN_LOGGER.logp(Level.FINER, 1711 RequiredModelMBean.class.getName(), 1712 "getAttributes(String[])","Exit"); 1713 } 1714 1715 return responseList; 1716 } 1717 1718 /** 1719 * Sets the value of a specific attribute of a named ModelMBean. 1720 * 1721 * If the 'setMethod' field of the attribute's descriptor 1722 * contains the name of a valid operation descriptor, then the 1723 * method described by the operation descriptor is executed. 1724 * In this implementation, the operation descriptor must be specified 1725 * correctly and assigned to the modelMBeanInfo so that the 'setMethod' 1726 * works correctly. 1727 * The response from the method is set as the value of the attribute 1728 * in the descriptor. 1729 * 1730 * <p>If currencyTimeLimit is > 0, then the new value for the 1731 * attribute is cached in the attribute descriptor's 1732 * 'value' field and the 'lastUpdatedTimeStamp' field is set to 1733 * the current time stamp. 1734 * 1735 * <p>If the persist field of the attribute's descriptor is not null 1736 * then Persistence policy from the attribute descriptor is used to 1737 * guide storing the attribute in a persistent store. 1738 * <br>Store the MBean if 'persistPolicy' field is: 1739 * <UL> 1740 * <Li> != "never"</Li> 1741 * <Li> = "always"</Li> 1742 * <Li> = "onUpdate"</Li> 1743 * <Li> = "onTimer" and now > 'lastPersistTime' + 'persistPeriod'</Li> 1744 * <Li> = "NoMoreOftenThan" and now > 'lastPersistTime' + 1745 * 'persistPeriod'</Li> 1746 * </UL> 1747 * Do not store the MBean if 'persistPolicy' field is: 1748 * <UL> 1749 * <Li> = "never"</Li> 1750 * <Li> = "onTimer" && now < 'lastPersistTime' + 'persistPeriod'</Li> 1751 * <Li> = "onUnregister"</Li> 1752 * <Li> = "NoMoreOftenThan" and now < 'lastPersistTime' + 1753 * 'persistPeriod'</Li> 1754 * </UL> 1755 * 1756 * <p>The ModelMBeanInfo of the Model MBean is stored in a file. 1757 * 1758 * @param attribute The Attribute instance containing the name of 1759 * the attribute to be set and the value it is to be set to. 1760 * 1761 * 1762 * @exception AttributeNotFoundException The specified attribute is 1763 * not accessible in the MBean. 1764 * <br>The following cases may result in an AttributeNotFoundException: 1765 * <UL> 1766 * <LI> No ModelMBeanAttributeInfo is found for the specified 1767 * attribute.</LI> 1768 * <LI> The ModelMBeanAttributeInfo's isWritable method returns 1769 * 'false'.</LI> 1770 * </UL> 1771 * @exception InvalidAttributeValueException No descriptor is defined 1772 * for the specified attribute. 1773 * @exception MBeanException Wraps one of the following Exceptions: 1774 * <UL> 1775 * <LI> An Exception thrown by the managed object's setter.</LI> 1776 * <LI> A {@link ServiceNotFoundException} if a setMethod field is 1777 * defined in the descriptor for the attribute and the managed 1778 * resource is null; or if no setMethod field is defined and 1779 * caching is not enabled for the attribute. 1780 * Note that if there is no getMethod field either, then caching 1781 * is automatically enabled.</LI> 1782 * <LI> {@link InvalidTargetObjectTypeException} The 'targetType' 1783 * field value is not 'objectReference'.</LI> 1784 * <LI> An Exception thrown by the managed object's getter.</LI> 1785 * </UL> 1786 * @exception ReflectionException Wraps an {@link java.lang.Exception} 1787 * thrown while trying to invoke the setter. 1788 * @exception RuntimeOperationsException Wraps an 1789 * {@link IllegalArgumentException}: The attribute in parameter is 1790 * null. 1791 * 1792 * @see #getAttribute(java.lang.String) 1793 **/ 1794 public void setAttribute(Attribute attribute) 1795 throws AttributeNotFoundException, InvalidAttributeValueException, 1796 MBeanException, ReflectionException { 1797 final boolean tracing = MODELMBEAN_LOGGER.isLoggable(Level.FINER); 1798 if (tracing) { 1799 MODELMBEAN_LOGGER.logp(Level.FINER, 1800 RequiredModelMBean.class.getName(), 1801 "setAttribute()","Entry"); 1802 } 1803 1804 if (attribute == null) 1805 throw new RuntimeOperationsException(new 1806 IllegalArgumentException("attribute must not be null"), 1807 "Exception occurred trying to set an attribute of a "+ 1808 "RequiredModelMBean"); 1809 1810 /* run setMethod if there is one */ 1811 /* return cached value if its current */ 1812 /* set cached value in descriptor and set date/time */ 1813 /* send attribute change Notification */ 1814 /* check persistence policy and persist if need be */ 1815 String attrName = attribute.getName(); 1816 Object attrValue = attribute.getValue(); 1817 boolean updateDescriptor = false; 1818 1819 ModelMBeanAttributeInfo attrInfo = 1820 modelMBeanInfo.getAttribute(attrName); 1821 1822 if (attrInfo == null) 1823 throw new AttributeNotFoundException("setAttribute failed: " + 1824 attrName + " is not found "); 1825 1826 Descriptor mmbDesc = modelMBeanInfo.getMBeanDescriptor(); 1827 Descriptor attrDescr = attrInfo.getDescriptor(); 1828 1829 if (attrDescr != null) { 1830 if (!attrInfo.isWritable()) 1831 throw new AttributeNotFoundException("setAttribute failed: " 1832 + attrName + " is not writable "); 1833 1834 String attrSetMethod = (String) 1835 (attrDescr.getFieldValue("setMethod")); 1836 String attrGetMethod = (String) 1837 (attrDescr.getFieldValue("getMethod")); 1838 1839 String attrType = attrInfo.getType(); 1840 Object currValue = "Unknown"; 1841 1842 try { 1843 currValue = this.getAttribute(attrName); 1844 } catch (Throwable t) { 1845 // OK: Default "Unknown" value used for unknown attribute 1846 } 1847 1848 Attribute oldAttr = new Attribute(attrName, currValue); 1849 1850 /* run method from operations descriptor */ 1851 if (attrSetMethod == null) { 1852 if (attrValue != null) { 1853 try { 1854 final Class<?> clazz = loadClass(attrType); 1855 if (! clazz.isInstance(attrValue)) throw new 1856 InvalidAttributeValueException(clazz.getName() + 1857 " expected, " + 1858 attrValue.getClass().getName() + 1859 " received."); 1860 } catch (ClassNotFoundException x) { 1861 if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) { 1862 MODELMBEAN_LOGGER.logp(Level.FINER, 1863 RequiredModelMBean.class.getName(), 1864 "setAttribute(Attribute)","Class " + 1865 attrType + " for attribute " 1866 + attrName + " not found: ", x); 1867 } 1868 } 1869 } 1870 updateDescriptor = true; 1871 } else { 1872 invoke(attrSetMethod, 1873 (new Object[] {attrValue}), 1874 (new String[] {attrType}) ); 1875 } 1876 1877 /* change cached value */ 1878 Object objctl = attrDescr.getFieldValue("currencyTimeLimit"); 1879 String ctl; 1880 if (objctl != null) ctl = objctl.toString(); 1881 else ctl = null; 1882 1883 if ((ctl == null) && (mmbDesc != null)) { 1884 objctl = mmbDesc.getFieldValue("currencyTimeLimit"); 1885 if (objctl != null) ctl = objctl.toString(); 1886 else ctl = null; 1887 } 1888 1889 final boolean updateCache = ((ctl != null) && !(ctl.equals("-1"))); 1890 1891 if(attrSetMethod == null && !updateCache && attrGetMethod != null) 1892 throw new MBeanException(new ServiceNotFoundException("No " + 1893 "setMethod field is defined in the descriptor for " + 1894 attrName + " attribute and caching is not enabled " + 1895 "for it")); 1896 1897 if (updateCache || updateDescriptor) { 1898 if (tracing) { 1899 MODELMBEAN_LOGGER.logp(Level.FINER, 1900 RequiredModelMBean.class.getName(), 1901 "setAttribute(Attribute)", 1902 "setting cached value of " + 1903 attrName + " to " + attrValue); 1904 } 1905 1906 attrDescr.setField("value", attrValue); 1907 1908 if (updateCache) { 1909 final String currtime = String.valueOf( 1910 (new Date()).getTime()); 1911 1912 attrDescr.setField("lastUpdatedTimeStamp", currtime); 1913 } 1914 1915 attrInfo.setDescriptor(attrDescr); 1916 1917 modelMBeanInfo.setDescriptor(attrDescr,"attribute"); 1918 if (tracing) { 1919 final StringBuilder strb = new StringBuilder() 1920 .append("new descriptor is ").append(attrDescr) 1921 .append(". AttributeInfo descriptor is ") 1922 .append(attrInfo.getDescriptor()) 1923 .append(". AttributeInfo descriptor is ") 1924 .append(modelMBeanInfo.getDescriptor(attrName,"attribute")); 1925 MODELMBEAN_LOGGER.logp(Level.FINER, 1926 RequiredModelMBean.class.getName(), 1927 "setAttribute(Attribute)",strb.toString()); 1928 } 1929 1930 } 1931 1932 if (tracing) { 1933 MODELMBEAN_LOGGER.logp(Level.FINER, 1934 RequiredModelMBean.class.getName(), 1935 "setAttribute(Attribute)","sending sendAttributeNotification"); 1936 } 1937 sendAttributeChangeNotification(oldAttr,attribute); 1938 1939 } else { // if descriptor ... else no descriptor 1940 1941 if (tracing) { 1942 MODELMBEAN_LOGGER.logp(Level.FINER, 1943 RequiredModelMBean.class.getName(), 1944 "setAttribute(Attribute)","setMethod failed "+attrName+ 1945 " not in attributeDescriptor\n"); 1946 } 1947 1948 throw new InvalidAttributeValueException( 1949 "Unable to resolve attribute value, "+ 1950 "no defined in descriptor for attribute"); 1951 } // else no descriptor 1952 1953 if (tracing) { 1954 MODELMBEAN_LOGGER.logp(Level.FINER, 1955 RequiredModelMBean.class.getName(), 1956 "setAttribute(Attribute)", "Exit"); 1957 } 1958 1959 } 1960 1961 /** 1962 * Sets the values of an array of attributes of this ModelMBean. 1963 * Executes the setAttribute() method for each attribute in the list. 1964 * 1965 * @param attributes A list of attributes: The identification of the 1966 * attributes to be set and the values they are to be set to. 1967 * 1968 * @return The array of attributes that were set, with their new 1969 * values in Attribute instances. 1970 * 1971 * @exception RuntimeOperationsException Wraps an 1972 * {@link IllegalArgumentException}: The object name in parameter 1973 * is null or attributes in parameter is null. 1974 * 1975 * @see #getAttributes 1976 **/ 1977 public AttributeList setAttributes(AttributeList attributes) { 1978 1979 if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) { 1980 MODELMBEAN_LOGGER.logp(Level.FINER, 1981 RequiredModelMBean.class.getName(), 1982 "setAttribute(Attribute)", "Entry"); 1983 } 1984 1985 if (attributes == null) 1986 throw new RuntimeOperationsException(new 1987 IllegalArgumentException("attributes must not be null"), 1988 "Exception occurred trying to set attributes of a "+ 1989 "RequiredModelMBean"); 1990 1991 final AttributeList responseList = new AttributeList(); 1992 1993 // Go through the list of attributes 1994 for (Attribute attr : attributes.asList()) { 1995 try { 1996 setAttribute(attr); 1997 responseList.add(attr); 1998 } catch (Exception excep) { 1999 responseList.remove(attr); 2000 } 2001 } 2002 2003 return responseList; 2004 } 2005 2006 2007 2008 private ModelMBeanInfo createDefaultModelMBeanInfo() { 2009 return(new ModelMBeanInfoSupport((this.getClass().getName()), 2010 "Default ModelMBean", null, null, null, null)); 2011 } 2012 2013 /*************************************/ 2014 /* NotificationBroadcaster Interface */ 2015 /*************************************/ 2016 2017 2018 private synchronized void writeToLog(String logFileName, 2019 String logEntry) throws Exception { 2020 2021 if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) { 2022 MODELMBEAN_LOGGER.logp(Level.FINER, 2023 RequiredModelMBean.class.getName(), 2024 "writeToLog(String, String)", 2025 "Notification Logging to " + logFileName + ": " + logEntry); 2026 } 2027 if ((logFileName == null) || (logEntry == null)) { 2028 if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) { 2029 MODELMBEAN_LOGGER.logp(Level.FINER, 2030 RequiredModelMBean.class.getName(), 2031 "writeToLog(String, String)", 2032 "Bad input parameters, will not log this entry."); 2033 } 2034 return; 2035 } 2036 2037 FileOutputStream fos = new FileOutputStream(logFileName, true); 2038 try { 2039 PrintStream logOut = new PrintStream(fos); 2040 logOut.println(logEntry); 2041 logOut.close(); 2042 if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) { 2043 MODELMBEAN_LOGGER.logp(Level.FINER, 2044 RequiredModelMBean.class.getName(), 2045 "writeToLog(String, String)","Successfully opened log " + 2046 logFileName); 2047 } 2048 } catch (Exception e) { 2049 if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) { 2050 MODELMBEAN_LOGGER.logp(Level.FINER, 2051 RequiredModelMBean.class.getName(), 2052 "writeToLog(String, String)", 2053 "Exception " + e.toString() + 2054 " trying to write to the Notification log file " + 2055 logFileName); 2056 } 2057 throw e; 2058 } finally { 2059 fos.close(); 2060 } 2061 } 2062 2063 2064 /** 2065 * Registers an object which implements the NotificationListener 2066 * interface as a listener. This 2067 * object's 'handleNotification()' method will be invoked when any 2068 * notification is issued through or by the ModelMBean. This does 2069 * not include attributeChangeNotifications. They must be registered 2070 * for independently. 2071 * 2072 * @param listener The listener object which will handles 2073 * notifications emitted by the registered MBean. 2074 * @param filter The filter object. If null, no filtering will be 2075 * performed before handling notifications. 2076 * @param handback The context to be sent to the listener with 2077 * the notification when a notification is emitted. 2078 * 2079 * @exception IllegalArgumentException The listener cannot be null. 2080 * 2081 * @see #removeNotificationListener 2082 */ 2083 public void addNotificationListener(NotificationListener listener, 2084 NotificationFilter filter, 2085 Object handback) 2086 throws java.lang.IllegalArgumentException { 2087 final String mth = "addNotificationListener(" + 2088 "NotificationListener, NotificationFilter, Object)"; 2089 if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) { 2090 MODELMBEAN_LOGGER.logp(Level.FINER, 2091 RequiredModelMBean.class.getName(), mth, "Entry"); 2092 } 2093 2094 if (listener == null) 2095 throw new IllegalArgumentException( 2096 "notification listener must not be null"); 2097 2098 if (generalBroadcaster == null) 2099 generalBroadcaster = new NotificationBroadcasterSupport(); 2100 2101 generalBroadcaster.addNotificationListener(listener, filter, 2102 handback); 2103 if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) { 2104 MODELMBEAN_LOGGER.logp(Level.FINER, 2105 RequiredModelMBean.class.getName(), mth, 2106 "NotificationListener added"); 2107 MODELMBEAN_LOGGER.logp(Level.FINER, 2108 RequiredModelMBean.class.getName(), mth, "Exit"); 2109 } 2110 } 2111 2112 /** 2113 * Removes a listener for Notifications from the RequiredModelMBean. 2114 * 2115 * @param listener The listener name which was handling notifications 2116 * emitted by the registered MBean. 2117 * This method will remove all information related to this listener. 2118 * 2119 * @exception ListenerNotFoundException The listener is not registered 2120 * in the MBean or is null. 2121 * 2122 * @see #addNotificationListener 2123 **/ 2124 public void removeNotificationListener(NotificationListener listener) 2125 throws ListenerNotFoundException { 2126 if (listener == null) 2127 throw new ListenerNotFoundException( 2128 "Notification listener is null"); 2129 2130 final String mth="removeNotificationListener(NotificationListener)"; 2131 if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) { 2132 MODELMBEAN_LOGGER.logp(Level.FINER, 2133 RequiredModelMBean.class.getName(), mth, "Entry"); 2134 } 2135 2136 if (generalBroadcaster == null) 2137 throw new ListenerNotFoundException( 2138 "No notification listeners registered"); 2139 2140 2141 generalBroadcaster.removeNotificationListener(listener); 2142 if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) { 2143 MODELMBEAN_LOGGER.logp(Level.FINER, 2144 RequiredModelMBean.class.getName(), mth, "Exit"); 2145 } 2146 2147 } 2148 2149 public void removeNotificationListener(NotificationListener listener, 2150 NotificationFilter filter, 2151 Object handback) 2152 throws ListenerNotFoundException { 2153 2154 if (listener == null) 2155 throw new ListenerNotFoundException( 2156 "Notification listener is null"); 2157 2158 final String mth = "removeNotificationListener(" + 2159 "NotificationListener, NotificationFilter, Object)"; 2160 2161 if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) { 2162 MODELMBEAN_LOGGER.logp(Level.FINER, 2163 RequiredModelMBean.class.getName(), mth, "Entry"); 2164 } 2165 2166 if (generalBroadcaster == null) 2167 throw new ListenerNotFoundException( 2168 "No notification listeners registered"); 2169 2170 2171 generalBroadcaster.removeNotificationListener(listener,filter, 2172 handback); 2173 2174 if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) { 2175 MODELMBEAN_LOGGER.logp(Level.FINER, 2176 RequiredModelMBean.class.getName(), mth, "Exit"); 2177 } 2178 2179 } 2180 2181 public void sendNotification(Notification ntfyObj) 2182 throws MBeanException, RuntimeOperationsException { 2183 if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) { 2184 MODELMBEAN_LOGGER.logp(Level.FINER, 2185 RequiredModelMBean.class.getName(), 2186 "sendNotification(Notification)", "Entry"); 2187 } 2188 2189 if (ntfyObj == null) 2190 throw new RuntimeOperationsException(new 2191 IllegalArgumentException("notification object must not be "+ 2192 "null"), 2193 "Exception occurred trying to send a notification from a "+ 2194 "RequiredModelMBean"); 2195 2196 2197 // log notification if specified in descriptor 2198 Descriptor ntfyDesc = 2199 modelMBeanInfo.getDescriptor(ntfyObj.getType(),"notification"); 2200 Descriptor mmbDesc = modelMBeanInfo.getMBeanDescriptor(); 2201 2202 if (ntfyDesc != null) { 2203 String logging = (String) ntfyDesc.getFieldValue("log"); 2204 2205 if (logging == null) { 2206 if (mmbDesc != null) 2207 logging = (String) mmbDesc.getFieldValue("log"); 2208 } 2209 2210 if ((logging != null) && 2211 (logging.equalsIgnoreCase("t") || 2212 logging.equalsIgnoreCase("true"))) { 2213 2214 String logfile = (String) ntfyDesc.getFieldValue("logfile"); 2215 if (logfile == null) { 2216 if (mmbDesc != null) 2217 logfile = (String)mmbDesc.getFieldValue("logfile"); 2218 } 2219 if (logfile != null) { 2220 try { 2221 writeToLog(logfile,"LogMsg: " + 2222 ((new Date(ntfyObj.getTimeStamp())).toString())+ 2223 " " + ntfyObj.getType() + " " + 2224 ntfyObj.getMessage() + " Severity = " + 2225 (String)ntfyDesc.getFieldValue("severity")); 2226 } catch (Exception e) { 2227 if (MODELMBEAN_LOGGER.isLoggable(Level.FINE)) { 2228 MODELMBEAN_LOGGER.logp(Level.FINE, 2229 RequiredModelMBean.class.getName(), 2230 "sendNotification(Notification)", 2231 "Failed to log " + 2232 ntfyObj.getType() + " notification: ", e); 2233 } 2234 } 2235 } 2236 } 2237 } 2238 if (generalBroadcaster != null) { 2239 generalBroadcaster.sendNotification(ntfyObj); 2240 } 2241 2242 if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) { 2243 MODELMBEAN_LOGGER.logp(Level.FINER, 2244 RequiredModelMBean.class.getName(), 2245 "sendNotification(Notification)", 2246 "sendNotification sent provided notification object"); 2247 MODELMBEAN_LOGGER.logp(Level.FINER, 2248 RequiredModelMBean.class.getName(), 2249 "sendNotification(Notification)"," Exit"); 2250 } 2251 2252 } 2253 2254 2255 public void sendNotification(String ntfyText) 2256 throws MBeanException, RuntimeOperationsException { 2257 if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) { 2258 MODELMBEAN_LOGGER.logp(Level.FINER, 2259 RequiredModelMBean.class.getName(), 2260 "sendNotification(String)","Entry"); 2261 } 2262 2263 if (ntfyText == null) 2264 throw new RuntimeOperationsException(new 2265 IllegalArgumentException("notification message must not "+ 2266 "be null"), 2267 "Exception occurred trying to send a text notification "+ 2268 "from a ModelMBean"); 2269 2270 Notification myNtfyObj = new Notification("jmx.modelmbean.generic", 2271 this, 1, ntfyText); 2272 sendNotification(myNtfyObj); 2273 if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) { 2274 MODELMBEAN_LOGGER.logp(Level.FINER, 2275 RequiredModelMBean.class.getName(), 2276 "sendNotification(String)","Notification sent"); 2277 MODELMBEAN_LOGGER.logp(Level.FINER, 2278 RequiredModelMBean.class.getName(), 2279 "sendNotification(String)","Exit"); 2280 } 2281 } 2282 2283 /** 2284 * Returns `true' if the notification `notifName' is found 2285 * in `info'. (bug 4744667) 2286 **/ 2287 private static final 2288 boolean hasNotification(final ModelMBeanInfo info, 2289 final String notifName) { 2290 try { 2291 if (info == null) return false; 2292 else return (info.getNotification(notifName)!=null); 2293 } catch (MBeanException x) { 2294 return false; 2295 } catch (RuntimeOperationsException r) { 2296 return false; 2297 } 2298 } 2299 2300 /** 2301 * Creates a default ModelMBeanNotificationInfo for GENERIC 2302 * notification. (bug 4744667) 2303 **/ 2304 private static final ModelMBeanNotificationInfo makeGenericInfo() { 2305 final Descriptor genericDescriptor = new DescriptorSupport( new 2306 String[] { 2307 "name=GENERIC", 2308 "descriptorType=notification", 2309 "log=T", 2310 "severity=6", 2311 "displayName=jmx.modelmbean.generic"} ); 2312 2313 return new ModelMBeanNotificationInfo(new 2314 String[] {"jmx.modelmbean.generic"}, 2315 "GENERIC", 2316 "A text notification has been issued by the managed resource", 2317 genericDescriptor); 2318 } 2319 2320 /** 2321 * Creates a default ModelMBeanNotificationInfo for ATTRIBUTE_CHANGE 2322 * notification. (bug 4744667) 2323 **/ 2324 private static final 2325 ModelMBeanNotificationInfo makeAttributeChangeInfo() { 2326 final Descriptor attributeDescriptor = new DescriptorSupport(new 2327 String[] { 2328 "name=ATTRIBUTE_CHANGE", 2329 "descriptorType=notification", 2330 "log=T", 2331 "severity=6", 2332 "displayName=jmx.attribute.change"}); 2333 2334 return new ModelMBeanNotificationInfo(new 2335 String[] {"jmx.attribute.change"}, 2336 "ATTRIBUTE_CHANGE", 2337 "Signifies that an observed MBean attribute value has changed", 2338 attributeDescriptor ); 2339 } 2340 2341 /** 2342 * Returns the array of Notifications always generated by the 2343 * RequiredModelMBean. 2344 * <P> 2345 * 2346 * RequiredModelMBean may always send also two additional notifications: 2347 * <UL> 2348 * <LI> One with descriptor <code>"name=GENERIC,descriptorType=notification,log=T,severity=6,displayName=jmx.modelmbean.generic"</code></LI> 2349 * <LI> Second is a standard attribute change notification 2350 * with descriptor <code>"name=ATTRIBUTE_CHANGE,descriptorType=notification,log=T,severity=6,displayName=jmx.attribute.change"</code></LI> 2351 * </UL> 2352 * Thus these two notifications are always added to those specified 2353 * by the application. 2354 * 2355 * @return MBeanNotificationInfo[] 2356 * 2357 **/ 2358 public MBeanNotificationInfo[] getNotificationInfo() { 2359 if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) { 2360 MODELMBEAN_LOGGER.logp(Level.FINER, 2361 RequiredModelMBean.class.getName(), 2362 "getNotificationInfo()","Entry"); 2363 } 2364 2365 // Using hasNotification() is not optimal, but shouldn't really 2366 // matter in this context... 2367 2368 // hasGeneric==true if GENERIC notification is present. 2369 // (bug 4744667) 2370 final boolean hasGeneric = hasNotification(modelMBeanInfo,"GENERIC"); 2371 2372 // hasAttributeChange==true if ATTRIBUTE_CHANGE notification is 2373 // present. 2374 // (bug 4744667) 2375 final boolean hasAttributeChange = 2376 hasNotification(modelMBeanInfo,"ATTRIBUTE_CHANGE"); 2377 2378 // User supplied list of notification infos. 2379 // 2380 final ModelMBeanNotificationInfo[] currInfo = 2381 (ModelMBeanNotificationInfo[])modelMBeanInfo.getNotifications(); 2382 2383 // Length of the returned list of notification infos: 2384 // length of user suplied list + possibly 1 for GENERIC, + 2385 // possibly 1 for ATTRIBUTE_CHANGE 2386 // (bug 4744667) 2387 final int len = ((currInfo==null?0:currInfo.length) + 2388 (hasGeneric?0:1) + (hasAttributeChange?0:1)); 2389 2390 // Returned list of notification infos: 2391 // 2392 final ModelMBeanNotificationInfo[] respInfo = 2393 new ModelMBeanNotificationInfo[len]; 2394 2395 // Preserve previous ordering (JMX 1.1) 2396 // 2397 2398 // Counter of "standard" notification inserted before user 2399 // supplied notifications. 2400 // 2401 int inserted=0; 2402 if (!hasGeneric) 2403 // We need to add description for GENERIC notification 2404 // (bug 4744667) 2405 respInfo[inserted++] = makeGenericInfo(); 2406 2407 2408 if (!hasAttributeChange) 2409 // We need to add description for ATTRIBUTE_CHANGE notification 2410 // (bug 4744667) 2411 respInfo[inserted++] = makeAttributeChangeInfo(); 2412 2413 // Now copy user supplied list in returned list. 2414 // 2415 final int count = currInfo.length; 2416 final int offset = inserted; 2417 for (int j=0; j < count; j++) { 2418 respInfo[offset+j] = currInfo[j]; 2419 } 2420 2421 if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) { 2422 MODELMBEAN_LOGGER.logp(Level.FINER, 2423 RequiredModelMBean.class.getName(), 2424 "getNotificationInfo()","Exit"); 2425 } 2426 2427 return respInfo; 2428 } 2429 2430 2431 public void addAttributeChangeNotificationListener(NotificationListener 2432 inlistener, 2433 String 2434 inAttributeName, 2435 Object inhandback) 2436 throws MBeanException, RuntimeOperationsException, 2437 IllegalArgumentException { 2438 final String mth="addAttributeChangeNotificationListener(" + 2439 "NotificationListener, String, Object)"; 2440 2441 if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) { 2442 MODELMBEAN_LOGGER.logp(Level.FINER, 2443 RequiredModelMBean.class.getName(),mth,"Entry"); 2444 } 2445 2446 if (inlistener == null) 2447 throw new IllegalArgumentException( 2448 "Listener to be registered must not be null"); 2449 2450 2451 if (attributeBroadcaster == null) 2452 attributeBroadcaster = new NotificationBroadcasterSupport(); 2453 2454 AttributeChangeNotificationFilter currFilter = 2455 new AttributeChangeNotificationFilter(); 2456 2457 MBeanAttributeInfo[] attrInfo = modelMBeanInfo.getAttributes(); 2458 boolean found = false; 2459 if (inAttributeName == null) { 2460 if ((attrInfo != null) && (attrInfo.length>0)) { 2461 for (int i=0; i<attrInfo.length; i++) { 2462 currFilter.enableAttribute(attrInfo[i].getName()); 2463 } 2464 } 2465 } else { 2466 if ((attrInfo != null) && (attrInfo.length>0)) { 2467 for (int i=0; i<attrInfo.length; i++) { 2468 if (inAttributeName.equals(attrInfo[i].getName())) { 2469 found = true; 2470 currFilter.enableAttribute(inAttributeName); 2471 break; 2472 } 2473 } 2474 } 2475 if (!found) { 2476 throw new RuntimeOperationsException(new 2477 IllegalArgumentException( 2478 "The attribute name does not exist"), 2479 "Exception occurred trying to add an "+ 2480 "AttributeChangeNotification listener"); 2481 } 2482 } 2483 2484 if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) { 2485 Vector<String> enabledAttrs = currFilter.getEnabledAttributes(); 2486 String s = (enabledAttrs.size() > 1) ? 2487 "[" + enabledAttrs.firstElement() + ", ...]" : 2488 enabledAttrs.toString(); 2489 MODELMBEAN_LOGGER.logp(Level.FINER, 2490 RequiredModelMBean.class.getName(), mth, 2491 "Set attribute change filter to " + s); 2492 } 2493 2494 attributeBroadcaster.addNotificationListener(inlistener,currFilter, 2495 inhandback); 2496 if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) { 2497 MODELMBEAN_LOGGER.logp(Level.FINER, 2498 RequiredModelMBean.class.getName(),mth, 2499 "Notification listener added for " + inAttributeName); 2500 MODELMBEAN_LOGGER.logp(Level.FINER, 2501 RequiredModelMBean.class.getName(),mth,"Exit"); 2502 } 2503 } 2504 2505 public void removeAttributeChangeNotificationListener( 2506 NotificationListener inlistener, String inAttributeName) 2507 throws MBeanException, RuntimeOperationsException, 2508 ListenerNotFoundException { 2509 if (inlistener == null) throw new 2510 ListenerNotFoundException("Notification listener is null"); 2511 2512 final String mth = "removeAttributeChangeNotificationListener(" + 2513 "NotificationListener, String)"; 2514 2515 if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) { 2516 MODELMBEAN_LOGGER.logp(Level.FINER, 2517 RequiredModelMBean.class.getName(),mth,"Entry"); 2518 } 2519 2520 2521 if (attributeBroadcaster == null) 2522 throw new ListenerNotFoundException( 2523 "No attribute change notification listeners registered"); 2524 2525 2526 MBeanAttributeInfo[] attrInfo = modelMBeanInfo.getAttributes(); 2527 boolean found = false; 2528 if ((attrInfo != null) && (attrInfo.length>0)) { 2529 for (int i=0; i<attrInfo.length; i++) { 2530 if (attrInfo[i].getName().equals(inAttributeName)) { 2531 found = true; 2532 break; 2533 } 2534 } 2535 } 2536 2537 if ((!found) && (inAttributeName != null)) { 2538 throw new RuntimeOperationsException(new 2539 IllegalArgumentException("Invalid attribute name"), 2540 "Exception occurred trying to remove "+ 2541 "attribute change notification listener"); 2542 } 2543 2544 /* note: */ 2545 /* this may be a problem if the same listener is registered for 2546 multiple attributes with multiple filters and/or handback 2547 objects. It may remove all of them */ 2548 2549 attributeBroadcaster.removeNotificationListener(inlistener); 2550 2551 if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) { 2552 MODELMBEAN_LOGGER.logp(Level.FINER, 2553 RequiredModelMBean.class.getName(),mth,"Exit"); 2554 } 2555 } 2556 2557 public void sendAttributeChangeNotification(AttributeChangeNotification 2558 ntfyObj) 2559 throws MBeanException, RuntimeOperationsException { 2560 final String mth = "sendAttributeChangeNotification(" + 2561 "AttributeChangeNotification)"; 2562 2563 if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) { 2564 MODELMBEAN_LOGGER.logp(Level.FINER, 2565 RequiredModelMBean.class.getName(),mth,"Entry"); 2566 } 2567 2568 if (ntfyObj == null) 2569 throw new RuntimeOperationsException(new 2570 IllegalArgumentException( 2571 "attribute change notification object must not be null"), 2572 "Exception occurred trying to send "+ 2573 "attribute change notification of a ModelMBean"); 2574 2575 Object oldv = ntfyObj.getOldValue(); 2576 Object newv = ntfyObj.getNewValue(); 2577 2578 if (oldv == null) oldv = "null"; 2579 if (newv == null) newv = "null"; 2580 2581 if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) { 2582 MODELMBEAN_LOGGER.logp(Level.FINER, 2583 RequiredModelMBean.class.getName(),mth, 2584 "Sending AttributeChangeNotification with " + 2585 ntfyObj.getAttributeName() + ntfyObj.getAttributeType() + 2586 ntfyObj.getNewValue() + ntfyObj.getOldValue()); 2587 } 2588 2589 // log notification if specified in descriptor 2590 Descriptor ntfyDesc = 2591 modelMBeanInfo.getDescriptor(ntfyObj.getType(),"notification"); 2592 Descriptor mmbDesc = modelMBeanInfo.getMBeanDescriptor(); 2593 2594 String logging, logfile; 2595 2596 if (ntfyDesc != null) { 2597 logging =(String) ntfyDesc.getFieldValue("log"); 2598 if (logging == null) { 2599 if (mmbDesc != null) 2600 logging = (String) mmbDesc.getFieldValue("log"); 2601 } 2602 if ((logging != null) && 2603 ( logging.equalsIgnoreCase("t") || 2604 logging.equalsIgnoreCase("true"))) { 2605 logfile = (String) ntfyDesc.getFieldValue("logfile"); 2606 if (logfile == null) { 2607 if (mmbDesc != null) 2608 logfile = (String)mmbDesc.getFieldValue("logfile"); 2609 } 2610 2611 if (logfile != null) { 2612 try { 2613 writeToLog(logfile,"LogMsg: " + 2614 ((new Date(ntfyObj.getTimeStamp())).toString())+ 2615 " " + ntfyObj.getType() + " " + 2616 ntfyObj.getMessage() + 2617 " Name = " + ntfyObj.getAttributeName() + 2618 " Old value = " + oldv + 2619 " New value = " + newv); 2620 } catch (Exception e) { 2621 if (MODELMBEAN_LOGGER.isLoggable(Level.FINE)) { 2622 MODELMBEAN_LOGGER.logp(Level.FINE, 2623 RequiredModelMBean.class.getName(),mth, 2624 "Failed to log " + ntfyObj.getType() + 2625 " notification: ", e); 2626 } 2627 } 2628 } 2629 } 2630 } else if (mmbDesc != null) { 2631 logging = (String) mmbDesc.getFieldValue("log"); 2632 if ((logging != null) && 2633 ( logging.equalsIgnoreCase("t") || 2634 logging.equalsIgnoreCase("true") )) { 2635 logfile = (String) mmbDesc.getFieldValue("logfile"); 2636 2637 if (logfile != null) { 2638 try { 2639 writeToLog(logfile,"LogMsg: " + 2640 ((new Date(ntfyObj.getTimeStamp())).toString())+ 2641 " " + ntfyObj.getType() + " " + 2642 ntfyObj.getMessage() + 2643 " Name = " + ntfyObj.getAttributeName() + 2644 " Old value = " + oldv + 2645 " New value = " + newv); 2646 } catch (Exception e) { 2647 if (MODELMBEAN_LOGGER.isLoggable(Level.FINE)) { 2648 MODELMBEAN_LOGGER.logp(Level.FINE, 2649 RequiredModelMBean.class.getName(),mth, 2650 "Failed to log " + ntfyObj.getType() + 2651 " notification: ", e); 2652 } 2653 } 2654 } 2655 } 2656 } 2657 if (attributeBroadcaster != null) { 2658 attributeBroadcaster.sendNotification(ntfyObj); 2659 } 2660 2661 // XXX Revisit: This is a quickfix: it would be better to have a 2662 // single broadcaster. However, it is not so simple because 2663 // removeAttributeChangeNotificationListener() should 2664 // remove only listeners whose filter is an instanceof 2665 // AttributeChangeNotificationFilter. 2666 // 2667 if (generalBroadcaster != null) { 2668 generalBroadcaster.sendNotification(ntfyObj); 2669 } 2670 2671 if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) { 2672 MODELMBEAN_LOGGER.logp(Level.FINER, 2673 RequiredModelMBean.class.getName(),mth, 2674 "sent notification"); 2675 MODELMBEAN_LOGGER.logp(Level.FINER, 2676 RequiredModelMBean.class.getName(),mth, 2677 "Exit"); 2678 } 2679 } 2680 2681 public void sendAttributeChangeNotification(Attribute inOldVal, 2682 Attribute inNewVal) 2683 throws MBeanException, RuntimeOperationsException { 2684 final String mth = 2685 "sendAttributeChangeNotification(Attribute, Attribute)"; 2686 if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) { 2687 MODELMBEAN_LOGGER.logp(Level.FINER, 2688 RequiredModelMBean.class.getName(),mth, 2689 "Entry"); 2690 } 2691 2692 // do we really want to do this? 2693 if ((inOldVal == null) || (inNewVal == null)) 2694 throw new RuntimeOperationsException(new 2695 IllegalArgumentException("Attribute object must not be null"), 2696 "Exception occurred trying to send " + 2697 "attribute change notification of a ModelMBean"); 2698 2699 2700 if (!(inOldVal.getName().equals(inNewVal.getName()))) 2701 throw new RuntimeOperationsException(new 2702 IllegalArgumentException("Attribute names are not the same"), 2703 "Exception occurred trying to send " + 2704 "attribute change notification of a ModelMBean"); 2705 2706 2707 Object newVal = inNewVal.getValue(); 2708 Object oldVal = inOldVal.getValue(); 2709 String className = "unknown"; 2710 if (newVal != null) 2711 className = newVal.getClass().getName(); 2712 if (oldVal != null) 2713 className = oldVal.getClass().getName(); 2714 2715 AttributeChangeNotification myNtfyObj = new 2716 AttributeChangeNotification(this, 2717 1, 2718 ((new Date()).getTime()), 2719 "AttributeChangeDetected", 2720 inOldVal.getName(), 2721 className, 2722 inOldVal.getValue(), 2723 inNewVal.getValue()); 2724 2725 sendAttributeChangeNotification(myNtfyObj); 2726 2727 if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) { 2728 MODELMBEAN_LOGGER.logp(Level.FINER, 2729 RequiredModelMBean.class.getName(),mth, 2730 "Exit"); 2731 } 2732 2733 } 2734 2735 /** 2736 * Return the Class Loader Repository used to perform class loading. 2737 * Subclasses may wish to redefine this method in order to return 2738 * the appropriate {@link javax.management.loading.ClassLoaderRepository} 2739 * that should be used in this object. 2740 * 2741 * @return the Class Loader Repository. 2742 * 2743 */ 2744 protected ClassLoaderRepository getClassLoaderRepository() { 2745 return MBeanServerFactory.getClassLoaderRepository(server); 2746 } 2747 2748 private Class<?> loadClass(String className) 2749 throws ClassNotFoundException { 2750 try { 2751 return Class.forName(className); 2752 } catch (ClassNotFoundException e) { 2753 final ClassLoaderRepository clr = 2754 getClassLoaderRepository(); 2755 if (clr == null) throw new ClassNotFoundException(className); 2756 return clr.loadClass(className); 2757 } 2758 } 2759 2760 2761 /*************************************/ 2762 /* MBeanRegistration Interface */ 2763 /*************************************/ 2764 2765 /** 2766 * Allows the MBean to perform any operations it needs before 2767 * being registered in the MBean server. If the name of the MBean 2768 * is not specified, the MBean can provide a name for its 2769 * registration. If any exception is raised, the MBean will not be 2770 * registered in the MBean server. 2771 * <P> 2772 * In order to ensure proper run-time semantics of RequireModelMBean, 2773 * Any subclass of RequiredModelMBean overloading or overriding this 2774 * method should call <code>super.preRegister(server, name)</code> 2775 * in its own <code>preRegister</code> implementation. 2776 * 2777 * @param server The MBean server in which the MBean will be registered. 2778 * 2779 * @param name The object name of the MBean. This name is null if 2780 * the name parameter to one of the <code>createMBean</code> or 2781 * <code>registerMBean</code> methods in the {@link MBeanServer} 2782 * interface is null. In that case, this method must return a 2783 * non-null ObjectName for the new MBean. 2784 * 2785 * @return The name under which the MBean is to be registered. 2786 * This value must not be null. If the <code>name</code> 2787 * parameter is not null, it will usually but not necessarily be 2788 * the returned value. 2789 * 2790 * @exception java.lang.Exception This exception will be caught by 2791 * the MBean server and re-thrown as an 2792 * {@link javax.management.MBeanRegistrationException 2793 * MBeanRegistrationException}. 2794 */ 2795 public ObjectName preRegister(MBeanServer server, 2796 ObjectName name) 2797 throws java.lang.Exception { 2798 // Since ModelMbeanInfo cannot be null (otherwise exception 2799 // thrown at creation) 2800 // no exception thrown on ModelMBeanInfo not set. 2801 if (name == null) throw new NullPointerException( 2802 "name of RequiredModelMBean to registered is null"); 2803 this.server = server; 2804 return name; 2805 } 2806 2807 /** 2808 * Allows the MBean to perform any operations needed after having been 2809 * registered in the MBean server or after the registration has failed. 2810 * <P> 2811 * In order to ensure proper run-time semantics of RequireModelMBean, 2812 * Any subclass of RequiredModelMBean overloading or overriding this 2813 * method should call <code>super.postRegister(registrationDone)</code> 2814 * in its own <code>postRegister</code> implementation. 2815 * 2816 * @param registrationDone Indicates whether or not the MBean has 2817 * been successfully registered in the MBean server. The value 2818 * false means that the registration phase has failed. 2819 */ 2820 public void postRegister(Boolean registrationDone) { 2821 registered = registrationDone.booleanValue(); 2822 } 2823 2824 /** 2825 * Allows the MBean to perform any operations it needs before 2826 * being unregistered by the MBean server. 2827 * <P> 2828 * In order to ensure proper run-time semantics of RequireModelMBean, 2829 * Any subclass of RequiredModelMBean overloading or overriding this 2830 * method should call <code>super.preDeregister()</code> in its own 2831 * <code>preDeregister</code> implementation. 2832 * 2833 * @exception java.lang.Exception This exception will be caught by 2834 * the MBean server and re-thrown as an 2835 * {@link javax.management.MBeanRegistrationException 2836 * MBeanRegistrationException}. 2837 */ 2838 public void preDeregister() throws java.lang.Exception { 2839 } 2840 2841 /** 2842 * Allows the MBean to perform any operations needed after having been 2843 * unregistered in the MBean server. 2844 * <P> 2845 * In order to ensure proper run-time semantics of RequireModelMBean, 2846 * Any subclass of RequiredModelMBean overloading or overriding this 2847 * method should call <code>super.postDeregister()</code> in its own 2848 * <code>postDeregister</code> implementation. 2849 */ 2850 public void postDeregister() { 2851 registered = false; 2852 this.server=null; 2853 } 2854 2855 private static final String[] primitiveTypes; 2856 private static final String[] primitiveWrappers; 2857 static { 2858 primitiveTypes = new String[] { 2859 Boolean.TYPE.getName(), 2860 Byte.TYPE.getName(), 2861 Character.TYPE.getName(), 2862 Short.TYPE.getName(), 2863 Integer.TYPE.getName(), 2864 Long.TYPE.getName(), 2865 Float.TYPE.getName(), 2866 Double.TYPE.getName(), 2867 Void.TYPE.getName() 2868 }; 2869 primitiveWrappers = new String[] { 2870 Boolean.class.getName(), 2871 Byte.class.getName(), 2872 Character.class.getName(), 2873 Short.class.getName(), 2874 Integer.class.getName(), 2875 Long.class.getName(), 2876 Float.class.getName(), 2877 Double.class.getName(), 2878 Void.class.getName() 2879 }; 2880 } 2881 }