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