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"+ info.getClassName()); 720 retStr.append("\nDESCRIPTION: \t"+ info.getDescription()); 721 722 723 try { 724 retStr.append("\nMBEAN DESCRIPTOR: \t"+ 725 info.getMBeanDescriptor()); 726 } catch (Exception e) { 727 retStr.append("\nMBEAN DESCRIPTOR: \t" + " is invalid"); 728 } 729 730 retStr.append("\nATTRIBUTES"); 731 732 final MBeanAttributeInfo[] attrInfo = info.getAttributes(); 733 if ((attrInfo != null) && (attrInfo.length>0)) { 734 for (int i=0; i<attrInfo.length; i++) { 735 final ModelMBeanAttributeInfo attInfo = 736 (ModelMBeanAttributeInfo)attrInfo[i]; 737 retStr.append(" ** NAME: \t"+ attInfo.getName()); 738 retStr.append(" DESCR: \t"+ attInfo.getDescription()); 739 retStr.append(" TYPE: \t"+ attInfo.getType() + 740 " READ: \t"+ attInfo.isReadable() + 741 " WRITE: \t"+ attInfo.isWritable()); 742 retStr.append(" DESCRIPTOR: " + 743 attInfo.getDescriptor().toString()); 744 } 745 } else { 746 retStr.append(" ** No attributes **"); 747 } 748 749 retStr.append("\nCONSTRUCTORS"); 750 final MBeanConstructorInfo[] constrInfo = info.getConstructors(); 751 if ((constrInfo != null) && (constrInfo.length > 0 )) { 752 for (int i=0; i<constrInfo.length; i++) { 753 final ModelMBeanConstructorInfo ctorInfo = 754 (ModelMBeanConstructorInfo)constrInfo[i]; 755 retStr.append(" ** NAME: \t"+ ctorInfo.getName()); 756 retStr.append(" DESCR: \t"+ 757 ctorInfo.getDescription()); 758 retStr.append(" PARAM: \t"+ 759 ctorInfo.getSignature().length + 760 " parameter(s)"); 761 retStr.append(" DESCRIPTOR: " + 762 ctorInfo.getDescriptor().toString()); 763 } 764 } else { 765 retStr.append(" ** No Constructors **"); 766 } 767 768 retStr.append("\nOPERATIONS"); 769 final MBeanOperationInfo[] opsInfo = info.getOperations(); 770 if ((opsInfo != null) && (opsInfo.length>0)) { 771 for (int i=0; i<opsInfo.length; i++) { 772 final ModelMBeanOperationInfo operInfo = 773 (ModelMBeanOperationInfo)opsInfo[i]; 774 retStr.append(" ** NAME: \t"+ operInfo.getName()); 775 retStr.append(" DESCR: \t"+ operInfo.getDescription()); 776 retStr.append(" PARAM: \t"+ 777 operInfo.getSignature().length + 778 " parameter(s)"); 779 retStr.append(" DESCRIPTOR: " + 780 operInfo.getDescriptor().toString()); 781 } 782 } else { 783 retStr.append(" ** No operations ** "); 784 } 785 786 retStr.append("\nNOTIFICATIONS"); 787 788 MBeanNotificationInfo[] notifInfo = info.getNotifications(); 789 if ((notifInfo != null) && (notifInfo.length>0)) { 790 for (int i=0; i<notifInfo.length; i++) { 791 final ModelMBeanNotificationInfo nInfo = 792 (ModelMBeanNotificationInfo)notifInfo[i]; 793 retStr.append(" ** NAME: \t"+ nInfo.getName()); 794 retStr.append(" DESCR: \t"+ nInfo.getDescription()); 795 retStr.append(" DESCRIPTOR: " + 796 nInfo.getDescriptor().toString()); 797 } 798 } else { 799 retStr.append(" ** No notifications **"); 800 } 801 802 retStr.append(" ** ModelMBean: End of MBeanInfo ** "); 803 804 return retStr.toString(); 805 } 806 807 /** 808 * Invokes a method on or through a RequiredModelMBean and returns 809 * the result of the method execution. 810 * <P> 811 * If the given method to be invoked, together with the provided 812 * signature, matches one of RequiredModelMbean 813 * accessible methods, this one will be call. Otherwise the call to 814 * the given method will be tried on the managed resource. 815 * <P> 816 * The last value returned by an operation may be cached in 817 * the operation's descriptor which 818 * is in the ModelMBeanOperationInfo's descriptor. 819 * The valid value will be in the 'value' field if there is one. 820 * If the 'currencyTimeLimit' field in the descriptor is: 821 * <UL> 822 * <LI><b><0</b> Then the value is not cached and is never valid. 823 * The operation method is invoked. 824 * The 'value' and 'lastUpdatedTimeStamp' fields are cleared.</LI> 825 * <LI><b>=0</b> Then the value is always cached and always valid. 826 * The 'value' field is returned. If there is no 'value' field 827 * then the operation method is invoked for the attribute. 828 * The 'lastUpdatedTimeStamp' field and `value' fields are set to 829 * the operation's return value and the current time stamp.</LI> 830 * <LI><b>>0</b> Represents the number of seconds that the 'value' 831 * field is valid. 832 * The 'value' field is no longer valid when 833 * 'lastUpdatedTimeStamp' + 'currencyTimeLimit' > Now. 834 * <UL> 835 * <LI>When 'value' is valid, 'value' is returned.</LI> 836 * <LI>When 'value' is no longer valid then the operation 837 * method is invoked. The 'lastUpdatedTimeStamp' field 838 * and `value' fields are updated.</lI> 839 * </UL> 840 * </LI> 841 * </UL> 842 * 843 * <p><b>Note:</b> because of inconsistencies in previous versions of 844 * this specification, it is recommended not to use negative or zero 845 * values for <code>currencyTimeLimit</code>. To indicate that a 846 * cached value is never valid, omit the 847 * <code>currencyTimeLimit</code> field. To indicate that it is 848 * always valid, use a very large number for this field.</p> 849 * 850 * @param opName The name of the method to be invoked. The 851 * name can be the fully qualified method name including the 852 * classname, or just the method name if the classname is 853 * defined in the 'class' field of the operation descriptor. 854 * @param opArgs An array containing the parameters to be set 855 * when the operation is invoked 856 * @param sig An array containing the signature of the 857 * operation. The class objects will be loaded using the same 858 * class loader as the one used for loading the MBean on which 859 * the operation was invoked. 860 * 861 * @return The object returned by the method, which represents the 862 * result of invoking the method on the specified managed resource. 863 * 864 * @exception MBeanException Wraps one of the following Exceptions: 865 * <UL> 866 * <LI> An Exception thrown by the managed object's invoked method.</LI> 867 * <LI> {@link ServiceNotFoundException}: No ModelMBeanOperationInfo or 868 * no descriptor defined for the specified operation or the managed 869 * resource is null.</LI> 870 * <LI> {@link InvalidTargetObjectTypeException}: The 'targetType' 871 * field value is not 'objectReference'.</LI> 872 * </UL> 873 * @exception ReflectionException Wraps an {@link java.lang.Exception} 874 * thrown while trying to invoke the method. 875 * @exception RuntimeOperationsException Wraps an 876 * {@link IllegalArgumentException} Method name is null. 877 * 878 **/ 879 /* 880 The requirement to be able to invoke methods on the 881 RequiredModelMBean class itself makes this method considerably 882 more complicated than it might otherwise be. Note that, unlike 883 earlier versions, we do not allow you to invoke such methods if 884 they are not explicitly mentioned in the ModelMBeanInfo. Doing 885 so was potentially a security problem, and certainly very 886 surprising. 887 888 We do not look for the method in the RequiredModelMBean class 889 itself if: 890 (a) there is a "targetObject" field in the Descriptor for the 891 operation; or 892 (b) there is a "class" field in the Descriptor for the operation 893 and the named class is not RequiredModelMBean or one of its 894 superinterfaces; or 895 (c) the name of the operation is not the name of a method in 896 RequiredModelMBean (this is just an optimization). 897 898 In cases (a) and (b), if you have gone to the trouble of adding 899 those fields specifically for this operation then presumably you 900 do not want RequiredModelMBean's methods to be called. 901 902 We have to pay attention to class loading issues. If the 903 "class" field is present, the named class has to be resolved 904 relative to RequiredModelMBean's class loader to test the 905 condition (b) above, and relative to the managed resource's 906 class loader to ensure that the managed resource is in fact of 907 the named class (or a subclass). The class names in the sig 908 array likewise have to be resolved, first against 909 RequiredModelMBean's class loader, then against the managed 910 resource's class loader. There is no point in using any other 911 loader because when we call Method.invoke we must call it on 912 a Method that is implemented by the target object. 913 */ 914 public Object invoke(String opName, Object[] opArgs, String[] sig) 915 throws MBeanException, ReflectionException { 916 917 final boolean tracing = MODELMBEAN_LOGGER.isLoggable(Level.FINER); 918 final String mth = "invoke(String, Object[], String[])"; 919 920 if (tracing) { 921 MODELMBEAN_LOGGER.logp(Level.FINER, 922 RequiredModelMBean.class.getName(), mth, "Entry"); 923 } 924 925 if (opName == null) { 926 final RuntimeException x = 927 new IllegalArgumentException("Method name must not be null"); 928 throw new RuntimeOperationsException(x, 929 "An exception occurred while trying to " + 930 "invoke a method on a RequiredModelMBean"); 931 } 932 933 String opClassName = null; 934 String opMethodName; 935 936 // Parse for class name and method 937 int opSplitter = opName.lastIndexOf('.'); 938 if (opSplitter > 0) { 939 opClassName = opName.substring(0,opSplitter); 940 opMethodName = opName.substring(opSplitter+1); 941 } else 942 opMethodName = opName; 943 944 /* Ignore anything after a left paren. We keep this for 945 compatibility but it isn't specified. */ 946 opSplitter = opMethodName.indexOf('('); 947 if (opSplitter > 0) 948 opMethodName = opMethodName.substring(0,opSplitter); 949 950 if (tracing) { 951 MODELMBEAN_LOGGER.logp(Level.FINER, 952 RequiredModelMBean.class.getName(), 953 mth, "Finding operation " + opName + " as " + opMethodName); 954 } 955 956 ModelMBeanOperationInfo opInfo = 957 modelMBeanInfo.getOperation(opMethodName); 958 if (opInfo == null) { 959 final String msg = 960 "Operation " + opName + " not in ModelMBeanInfo"; 961 throw new MBeanException(new ServiceNotFoundException(msg), msg); 962 } 963 964 final Descriptor opDescr = opInfo.getDescriptor(); 965 if (opDescr == null) { 966 final String msg = "Operation descriptor null"; 967 throw new MBeanException(new ServiceNotFoundException(msg), msg); 968 } 969 970 final Object cached = resolveForCacheValue(opDescr); 971 if (cached != null) { 972 if (tracing) { 973 MODELMBEAN_LOGGER.logp(Level.FINER, 974 RequiredModelMBean.class.getName(), 975 mth, 976 "Returning cached value"); 977 } 978 return cached; 979 } 980 981 if (opClassName == null) 982 opClassName = (String) opDescr.getFieldValue("class"); 983 // may still be null now 984 985 opMethodName = (String) opDescr.getFieldValue("name"); 986 if (opMethodName == null) { 987 final String msg = 988 "Method descriptor must include `name' field"; 989 throw new MBeanException(new ServiceNotFoundException(msg), msg); 990 } 991 992 final String targetTypeField = (String) 993 opDescr.getFieldValue("targetType"); 994 if (targetTypeField != null 995 && !targetTypeField.equalsIgnoreCase("objectReference")) { 996 final String msg = 997 "Target type must be objectReference: " + targetTypeField; 998 throw new MBeanException(new InvalidTargetObjectTypeException(msg), 999 msg); 1000 } 1001 1002 final Object targetObjectField = opDescr.getFieldValue("targetObject"); 1003 if (tracing && targetObjectField != null) 1004 MODELMBEAN_LOGGER.logp(Level.FINER, 1005 RequiredModelMBean.class.getName(), 1006 mth, "Found target object in descriptor"); 1007 1008 /* Now look for the method, either in RequiredModelMBean itself 1009 or in the target object. Set "method" and "targetObject" 1010 appropriately. */ 1011 Method method; 1012 Object targetObject; 1013 1014 method = findRMMBMethod(opMethodName, targetObjectField, 1015 opClassName, sig); 1016 1017 if (method != null) 1018 targetObject = this; 1019 else { 1020 if (tracing) { 1021 MODELMBEAN_LOGGER.logp(Level.FINER, 1022 RequiredModelMBean.class.getName(), 1023 mth, "looking for method in managedResource class"); 1024 } 1025 if (targetObjectField != null) 1026 targetObject = targetObjectField; 1027 else { 1028 targetObject = managedResource; 1029 if (targetObject == null) { 1030 final String msg = 1031 "managedResource for invoke " + opName + 1032 " is null"; 1033 Exception snfe = new ServiceNotFoundException(msg); 1034 throw new MBeanException(snfe); 1035 } 1036 } 1037 1038 final Class<?> targetClass; 1039 1040 if (opClassName != null) { 1041 try { 1042 AccessControlContext stack = AccessController.getContext(); 1043 final Object obj = targetObject; 1044 final String className = opClassName; 1045 final ClassNotFoundException[] caughtException = new ClassNotFoundException[1]; 1046 1047 targetClass = javaSecurityAccess.doIntersectionPrivilege(new PrivilegedAction<Class<?>>() { 1048 1049 @Override 1050 public Class<?> run() { 1051 try { 1052 ReflectUtil.checkPackageAccess(className); 1053 final ClassLoader targetClassLoader = 1054 obj.getClass().getClassLoader(); 1055 return Class.forName(className, false, 1056 targetClassLoader); 1057 } catch (ClassNotFoundException e) { 1058 caughtException[0] = e; 1059 } 1060 return null; 1061 } 1062 }, stack, acc); 1063 1064 if (caughtException[0] != null) { 1065 throw caughtException[0]; 1066 } 1067 } catch (ClassNotFoundException e) { 1068 final String msg = 1069 "class for invoke " + opName + " not found"; 1070 throw new ReflectionException(e, msg); 1071 } 1072 } else 1073 targetClass = targetObject.getClass(); 1074 1075 method = resolveMethod(targetClass, opMethodName, sig); 1076 } 1077 1078 if (tracing) { 1079 MODELMBEAN_LOGGER.logp(Level.FINER, 1080 RequiredModelMBean.class.getName(), 1081 mth, "found " + opMethodName + ", now invoking"); 1082 } 1083 1084 final Object result = 1085 invokeMethod(opName, method, targetObject, opArgs); 1086 1087 if (tracing) { 1088 MODELMBEAN_LOGGER.logp(Level.FINER, 1089 RequiredModelMBean.class.getName(), 1090 mth, "successfully invoked method"); 1091 } 1092 1093 if (result != null) 1094 cacheResult(opInfo, opDescr, result); 1095 1096 return result; 1097 } 1098 1099 private Method resolveMethod(Class<?> targetClass, 1100 String opMethodName, 1101 final String[] sig) 1102 throws ReflectionException { 1103 final boolean tracing = MODELMBEAN_LOGGER.isLoggable(Level.FINER); 1104 1105 if (tracing) { 1106 MODELMBEAN_LOGGER.logp(Level.FINER, 1107 RequiredModelMBean.class.getName(),"resolveMethod", 1108 "resolving " + targetClass.getName() + "." + opMethodName); 1109 } 1110 1111 final Class<?>[] argClasses; 1112 1113 if (sig == null) 1114 argClasses = null; 1115 else { 1116 final AccessControlContext stack = AccessController.getContext(); 1117 final ReflectionException[] caughtException = new ReflectionException[1]; 1118 final ClassLoader targetClassLoader = targetClass.getClassLoader(); 1119 argClasses = new Class<?>[sig.length]; 1120 1121 javaSecurityAccess.doIntersectionPrivilege(new PrivilegedAction<Void>() { 1122 1123 @Override 1124 public Void run() { 1125 for (int i = 0; i < sig.length; i++) { 1126 if (tracing) { 1127 MODELMBEAN_LOGGER.logp(Level.FINER, 1128 RequiredModelMBean.class.getName(),"resolveMethod", 1129 "resolve type " + sig[i]); 1130 } 1131 argClasses[i] = (Class<?>) primitiveClassMap.get(sig[i]); 1132 if (argClasses[i] == null) { 1133 try { 1134 ReflectUtil.checkPackageAccess(sig[i]); 1135 argClasses[i] = 1136 Class.forName(sig[i], false, targetClassLoader); 1137 } catch (ClassNotFoundException e) { 1138 if (tracing) { 1139 MODELMBEAN_LOGGER.logp(Level.FINER, 1140 RequiredModelMBean.class.getName(), 1141 "resolveMethod", 1142 "class not found"); 1143 } 1144 final String msg = "Parameter class not found"; 1145 caughtException[0] = new ReflectionException(e, msg); 1146 } 1147 } 1148 } 1149 return null; 1150 } 1151 }, stack, acc); 1152 1153 if (caughtException[0] != null) { 1154 throw caughtException[0]; 1155 } 1156 } 1157 1158 try { 1159 return targetClass.getMethod(opMethodName, argClasses); 1160 } catch (NoSuchMethodException e) { 1161 final String msg = 1162 "Target method not found: " + targetClass.getName() + "." + 1163 opMethodName; 1164 throw new ReflectionException(e, msg); 1165 } 1166 } 1167 1168 /* Map e.g. "int" to int.class. Goodness knows how many time this 1169 particular wheel has been reinvented. */ 1170 private static final Class<?>[] primitiveClasses = { 1171 int.class, long.class, boolean.class, double.class, 1172 float.class, short.class, byte.class, char.class, 1173 }; 1174 private static final Map<String,Class<?>> primitiveClassMap = 1175 new HashMap<String,Class<?>>(); 1176 static { 1177 for (int i = 0; i < primitiveClasses.length; i++) { 1178 final Class<?> c = primitiveClasses[i]; 1179 primitiveClassMap.put(c.getName(), c); 1180 } 1181 } 1182 1183 /* Find a method in RequiredModelMBean as determined by the given 1184 parameters. Return null if there is none, or if the parameters 1185 exclude using it. Called from invoke. */ 1186 private Method findRMMBMethod(String opMethodName, 1187 Object targetObjectField, 1188 String opClassName, 1189 String[] sig) { 1190 final boolean tracing = MODELMBEAN_LOGGER.isLoggable(Level.FINER); 1191 1192 if (tracing) { 1193 MODELMBEAN_LOGGER.logp(Level.FINER, 1194 RequiredModelMBean.class.getName(), 1195 "invoke(String, Object[], String[])", 1196 "looking for method in RequiredModelMBean class"); 1197 } 1198 1199 if (!isRMMBMethodName(opMethodName)) 1200 return null; 1201 if (targetObjectField != null) 1202 return null; 1203 final Class<RequiredModelMBean> rmmbClass = RequiredModelMBean.class; 1204 final Class<?> targetClass; 1205 if (opClassName == null) 1206 targetClass = rmmbClass; 1207 else { 1208 AccessControlContext stack = AccessController.getContext(); 1209 final String className = opClassName; 1210 targetClass = javaSecurityAccess.doIntersectionPrivilege(new PrivilegedAction<Class<?>>() { 1211 1212 @Override 1213 public Class<?> run() { 1214 try { 1215 ReflectUtil.checkPackageAccess(className); 1216 final ClassLoader targetClassLoader = 1217 rmmbClass.getClassLoader(); 1218 Class<?> clz = Class.forName(className, false, 1219 targetClassLoader); 1220 if (!rmmbClass.isAssignableFrom(clz)) 1221 return null; 1222 return clz; 1223 } catch (ClassNotFoundException e) { 1224 return null; 1225 } 1226 } 1227 }, stack, acc); 1228 } 1229 try { 1230 return targetClass != null ? resolveMethod(targetClass, opMethodName, sig) : null; 1231 } catch (ReflectionException e) { 1232 return null; 1233 } 1234 } 1235 1236 /* 1237 * Invoke the given method, and throw the somewhat unpredictable 1238 * appropriate exception if the method itself gets an exception. 1239 */ 1240 private Object invokeMethod(String opName, final Method method, 1241 final Object targetObject, final Object[] opArgs) 1242 throws MBeanException, ReflectionException { 1243 try { 1244 final Throwable[] caughtException = new Throwable[1]; 1245 AccessControlContext stack = AccessController.getContext(); 1246 Object rslt = javaSecurityAccess.doIntersectionPrivilege(new PrivilegedAction<Object>() { 1247 1248 @Override 1249 public Object run() { 1250 try { 1251 ReflectUtil.checkPackageAccess(method.getDeclaringClass()); 1252 return MethodUtil.invoke(method, targetObject, opArgs); 1253 } catch (InvocationTargetException e) { 1254 caughtException[0] = e; 1255 } catch (IllegalAccessException e) { 1256 caughtException[0] = e; 1257 } 1258 return null; 1259 } 1260 }, stack, acc); 1261 if (caughtException[0] != null) { 1262 if (caughtException[0] instanceof Exception) { 1263 throw (Exception)caughtException[0]; 1264 } else if(caughtException[0] instanceof Error) { 1265 throw (Error)caughtException[0]; 1266 } 1267 } 1268 return rslt; 1269 } catch (RuntimeErrorException ree) { 1270 throw new RuntimeOperationsException(ree, 1271 "RuntimeException occurred in RequiredModelMBean "+ 1272 "while trying to invoke operation " + opName); 1273 } catch (RuntimeException re) { 1274 throw new RuntimeOperationsException(re, 1275 "RuntimeException occurred in RequiredModelMBean "+ 1276 "while trying to invoke operation " + opName); 1277 } catch (IllegalAccessException iae) { 1278 throw new ReflectionException(iae, 1279 "IllegalAccessException occurred in " + 1280 "RequiredModelMBean while trying to " + 1281 "invoke operation " + opName); 1282 } catch (InvocationTargetException ite) { 1283 Throwable mmbTargEx = ite.getTargetException(); 1284 if (mmbTargEx instanceof RuntimeException) { 1285 throw new MBeanException ((RuntimeException)mmbTargEx, 1286 "RuntimeException thrown in RequiredModelMBean "+ 1287 "while trying to invoke operation " + opName); 1288 } else if (mmbTargEx instanceof Error) { 1289 throw new RuntimeErrorException((Error)mmbTargEx, 1290 "Error occurred in RequiredModelMBean while trying "+ 1291 "to invoke operation " + opName); 1292 } else if (mmbTargEx instanceof ReflectionException) { 1293 throw (ReflectionException) mmbTargEx; 1294 } else { 1295 throw new MBeanException ((Exception)mmbTargEx, 1296 "Exception thrown in RequiredModelMBean "+ 1297 "while trying to invoke operation " + opName); 1298 } 1299 } catch (Error err) { 1300 throw new RuntimeErrorException(err, 1301 "Error occurred in RequiredModelMBean while trying "+ 1302 "to invoke operation " + opName); 1303 } catch (Exception e) { 1304 throw new ReflectionException(e, 1305 "Exception occurred in RequiredModelMBean while " + 1306 "trying to invoke operation " + opName); 1307 } 1308 } 1309 1310 /* 1311 * Cache the result of an operation in the descriptor, if that is 1312 * called for by the descriptor's configuration. Note that we 1313 * don't remember operation parameters when caching the result, so 1314 * this is unlikely to be useful if there are any. 1315 */ 1316 private void cacheResult(ModelMBeanOperationInfo opInfo, 1317 Descriptor opDescr, Object result) 1318 throws MBeanException { 1319 1320 Descriptor mmbDesc = 1321 modelMBeanInfo.getMBeanDescriptor(); 1322 1323 Object objctl = 1324 opDescr.getFieldValue("currencyTimeLimit"); 1325 String ctl; 1326 if (objctl != null) { 1327 ctl = objctl.toString(); 1328 } else { 1329 ctl = null; 1330 } 1331 if ((ctl == null) && (mmbDesc != null)) { 1332 objctl = 1333 mmbDesc.getFieldValue("currencyTimeLimit"); 1334 if (objctl != null) { 1335 ctl = objctl.toString(); 1336 } else { 1337 ctl = null; 1338 } 1339 } 1340 if ((ctl != null) && !(ctl.equals("-1"))) { 1341 opDescr.setField("value", result); 1342 opDescr.setField("lastUpdatedTimeStamp", 1343 String.valueOf((new Date()).getTime())); 1344 1345 1346 modelMBeanInfo.setDescriptor(opDescr, 1347 "operation"); 1348 if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) { 1349 MODELMBEAN_LOGGER.logp(Level.FINER, 1350 RequiredModelMBean.class.getName(), 1351 "invoke(String,Object[],Object[])", 1352 "new descriptor is " + opDescr); 1353 } 1354 } 1355 } 1356 1357 /* 1358 * Determine whether the given name is the name of a public method 1359 * in this class. This is only an optimization: it prevents us 1360 * from trying to do argument type lookups and reflection on a 1361 * method that will obviously fail because it has the wrong name. 1362 * 1363 * The first time this method is called we do the reflection, and 1364 * every other time we reuse the remembered values. 1365 * 1366 * It's conceivable that the (possibly malicious) first caller 1367 * doesn't have the required permissions to do reflection, in 1368 * which case we don't touch anything so as not to interfere 1369 * with a later permissionful caller. 1370 */ 1371 private static Set<String> rmmbMethodNames; 1372 private static synchronized boolean isRMMBMethodName(String name) { 1373 if (rmmbMethodNames == null) { 1374 try { 1375 Set<String> names = new HashSet<String>(); 1376 Method[] methods = RequiredModelMBean.class.getMethods(); 1377 for (int i = 0; i < methods.length; i++) 1378 names.add(methods[i].getName()); 1379 rmmbMethodNames = names; 1380 } catch (Exception e) { 1381 return true; 1382 // This is only an optimization so we'll go on to discover 1383 // whether the name really is an RMMB method. 1384 } 1385 } 1386 return rmmbMethodNames.contains(name); 1387 } 1388 1389 /** 1390 * Returns the value of a specific attribute defined for this 1391 * ModelMBean. 1392 * The last value returned by an attribute may be cached in the 1393 * attribute's descriptor. 1394 * The valid value will be in the 'value' field if there is one. 1395 * If the 'currencyTimeLimit' field in the descriptor is: 1396 * <UL> 1397 * <LI> <b><0</b> Then the value is not cached and is never valid. 1398 * The getter method is invoked for the attribute. 1399 * The 'value' and 'lastUpdatedTimeStamp' fields are cleared.</LI> 1400 * <LI> <b>=0</b> Then the value is always cached and always valid. 1401 * The 'value' field is returned. If there is no'value' field 1402 * then the getter method is invoked for the attribute. 1403 * The 'lastUpdatedTimeStamp' field and `value' fields are set 1404 * to the attribute's value and the current time stamp.</LI> 1405 * <LI> <b>>0</b> Represents the number of seconds that the 'value' 1406 * field is valid. 1407 * The 'value' field is no longer valid when 1408 * 'lastUpdatedTimeStamp' + 'currencyTimeLimit' > Now. 1409 * <UL> 1410 * <LI>When 'value' is valid, 'value' is returned.</LI> 1411 * <LI>When 'value' is no longer valid then the getter 1412 * method is invoked for the attribute. 1413 * The 'lastUpdatedTimeStamp' field and `value' fields 1414 * are updated.</LI> 1415 * </UL></LI> 1416 * </UL> 1417 * 1418 * <p><b>Note:</b> because of inconsistencies in previous versions of 1419 * this specification, it is recommended not to use negative or zero 1420 * values for <code>currencyTimeLimit</code>. To indicate that a 1421 * cached value is never valid, omit the 1422 * <code>currencyTimeLimit</code> field. To indicate that it is 1423 * always valid, use a very large number for this field.</p> 1424 * 1425 * <p>If the 'getMethod' field contains the name of a valid 1426 * operation descriptor, then the method described by the 1427 * operation descriptor is executed. The response from the 1428 * method is returned as the value of the attribute. If the 1429 * operation fails or the returned value is not compatible with 1430 * the declared type of the attribute, an exception will be thrown.</p> 1431 * 1432 * <p>If no 'getMethod' field is defined then the default value of the 1433 * attribute is returned. If the returned value is not compatible with 1434 * the declared type of the attribute, an exception will be thrown.</p> 1435 * 1436 * <p>The declared type of the attribute is the String returned by 1437 * {@link ModelMBeanAttributeInfo#getType()}. A value is compatible 1438 * with this type if one of the following is true: 1439 * <ul> 1440 * <li>the value is null;</li> 1441 * <li>the declared name is a primitive type name (such as "int") 1442 * and the value is an instance of the corresponding wrapper 1443 * type (such as java.lang.Integer);</li> 1444 * <li>the name of the value's class is identical to the declared name;</li> 1445 * <li>the declared name can be loaded by the value's class loader and 1446 * produces a class to which the value can be assigned.</li> 1447 * </ul> 1448 * 1449 * <p>In this implementation, in every case where the getMethod needs to 1450 * be called, because the method is invoked through the standard "invoke" 1451 * method and thus needs operationInfo, an operation must be specified 1452 * for that getMethod so that the invocation works correctly.</p> 1453 * 1454 * @param attrName A String specifying the name of the 1455 * attribute to be retrieved. It must match the name of a 1456 * ModelMBeanAttributeInfo. 1457 * 1458 * @return The value of the retrieved attribute from the 1459 * descriptor 'value' field or from the invocation of the 1460 * operation in the 'getMethod' field of the descriptor. 1461 * 1462 * @exception AttributeNotFoundException The specified attribute is 1463 * not accessible in the MBean. 1464 * The following cases may result in an AttributeNotFoundException: 1465 * <UL> 1466 * <LI> No ModelMBeanInfo was found for the Model MBean.</LI> 1467 * <LI> No ModelMBeanAttributeInfo was found for the specified 1468 * attribute name.</LI> 1469 * <LI> The ModelMBeanAttributeInfo isReadable method returns 1470 * 'false'.</LI> 1471 * </UL> 1472 * @exception MBeanException Wraps one of the following Exceptions: 1473 * <UL> 1474 * <LI> {@link InvalidAttributeValueException}: A wrong value type 1475 * was received from the attribute's getter method or 1476 * no 'getMethod' field defined in the descriptor for 1477 * the attribute and no default value exists.</LI> 1478 * <LI> {@link ServiceNotFoundException}: No 1479 * ModelMBeanOperationInfo defined for the attribute's 1480 * getter method or no descriptor associated with the 1481 * ModelMBeanOperationInfo or the managed resource is 1482 * null.</LI> 1483 * <LI> {@link InvalidTargetObjectTypeException} The 'targetType' 1484 * field value is not 'objectReference'.</LI> 1485 * <LI> An Exception thrown by the managed object's getter.</LI> 1486 * </UL> 1487 * @exception ReflectionException Wraps an {@link java.lang.Exception} 1488 * thrown while trying to invoke the getter. 1489 * @exception RuntimeOperationsException Wraps an 1490 * {@link IllegalArgumentException}: The attribute name in 1491 * parameter is null. 1492 * 1493 * @see #setAttribute(javax.management.Attribute) 1494 **/ 1495 public Object getAttribute(String attrName) 1496 throws AttributeNotFoundException, MBeanException, 1497 ReflectionException { 1498 if (attrName == null) 1499 throw new RuntimeOperationsException(new 1500 IllegalArgumentException("attributeName must not be null"), 1501 "Exception occurred trying to get attribute of a " + 1502 "RequiredModelMBean"); 1503 final String mth = "getAttribute(String)"; 1504 final boolean tracing = MODELMBEAN_LOGGER.isLoggable(Level.FINER); 1505 if (tracing) { 1506 MODELMBEAN_LOGGER.logp(Level.FINER, 1507 RequiredModelMBean.class.getName(), 1508 mth, "Entry with " + attrName); 1509 } 1510 1511 /* Check attributeDescriptor for getMethod */ 1512 Object response; 1513 1514 try { 1515 if (modelMBeanInfo == null) 1516 throw new AttributeNotFoundException( 1517 "getAttribute failed: ModelMBeanInfo not found for "+ 1518 attrName); 1519 1520 ModelMBeanAttributeInfo attrInfo = modelMBeanInfo.getAttribute(attrName); 1521 Descriptor mmbDesc = modelMBeanInfo.getMBeanDescriptor(); 1522 1523 if (attrInfo == null) 1524 throw new AttributeNotFoundException("getAttribute failed:"+ 1525 " ModelMBeanAttributeInfo not found for " + attrName); 1526 1527 Descriptor attrDescr = attrInfo.getDescriptor(); 1528 if (attrDescr != null) { 1529 if (!attrInfo.isReadable()) 1530 throw new AttributeNotFoundException( 1531 "getAttribute failed: " + attrName + 1532 " is not readable "); 1533 1534 response = resolveForCacheValue(attrDescr); 1535 1536 /* return current cached value */ 1537 if (tracing) { 1538 MODELMBEAN_LOGGER.logp(Level.FINER, 1539 RequiredModelMBean.class.getName(), mth, 1540 "*** cached value is " + response); 1541 } 1542 1543 if (response == null) { 1544 /* no cached value, run getMethod */ 1545 if (tracing) { 1546 MODELMBEAN_LOGGER.logp(Level.FINER, 1547 RequiredModelMBean.class.getName(), mth, 1548 "**** cached value is null - getting getMethod"); 1549 } 1550 String attrGetMethod = 1551 (String)(attrDescr.getFieldValue("getMethod")); 1552 1553 if (attrGetMethod != null) { 1554 /* run method from operations descriptor */ 1555 if (tracing) { 1556 MODELMBEAN_LOGGER.logp(Level.FINER, 1557 RequiredModelMBean.class.getName(), 1558 mth, "invoking a getMethod for " + attrName); 1559 } 1560 1561 Object getResponse = 1562 invoke(attrGetMethod, new Object[] {}, 1563 new String[] {}); 1564 1565 if (getResponse != null) { 1566 // error/validity check return value here 1567 if (tracing) { 1568 MODELMBEAN_LOGGER.logp(Level.FINER, 1569 RequiredModelMBean.class.getName(), 1570 mth, "got a non-null response " + 1571 "from getMethod\n"); 1572 } 1573 1574 response = getResponse; 1575 1576 // change cached value in attribute descriptor 1577 Object objctl = 1578 attrDescr.getFieldValue("currencyTimeLimit"); 1579 1580 String ctl; 1581 if (objctl != null) ctl = objctl.toString(); 1582 else ctl = null; 1583 1584 if ((ctl == null) && (mmbDesc != null)) { 1585 objctl = mmbDesc. 1586 getFieldValue("currencyTimeLimit"); 1587 if (objctl != null) ctl = objctl.toString(); 1588 else ctl = null; 1589 } 1590 1591 if ((ctl != null) && !(ctl.equals("-1"))) { 1592 if (tracing) { 1593 MODELMBEAN_LOGGER.logp(Level.FINER, 1594 RequiredModelMBean.class.getName(), 1595 mth, 1596 "setting cached value and " + 1597 "lastUpdatedTime in descriptor"); 1598 } 1599 attrDescr.setField("value", response); 1600 final String stamp = String.valueOf( 1601 (new Date()).getTime()); 1602 attrDescr.setField("lastUpdatedTimeStamp", 1603 stamp); 1604 attrInfo.setDescriptor(attrDescr); 1605 modelMBeanInfo.setDescriptor(attrDescr, 1606 "attribute"); 1607 if (tracing) { 1608 MODELMBEAN_LOGGER.logp(Level.FINER, 1609 RequiredModelMBean.class.getName(), 1610 mth,"new descriptor is " +attrDescr); 1611 MODELMBEAN_LOGGER.logp(Level.FINER, 1612 RequiredModelMBean.class.getName(), 1613 mth,"AttributeInfo descriptor is " + 1614 attrInfo.getDescriptor()); 1615 final String attStr = modelMBeanInfo. 1616 getDescriptor(attrName,"attribute"). 1617 toString(); 1618 MODELMBEAN_LOGGER.logp(Level.FINER, 1619 RequiredModelMBean.class.getName(), 1620 mth, 1621 "modelMBeanInfo: AttributeInfo " + 1622 "descriptor is " + attStr); 1623 } 1624 } 1625 } else { 1626 // response was invalid or really returned null 1627 if (tracing) { 1628 MODELMBEAN_LOGGER.logp(Level.FINER, 1629 RequiredModelMBean.class.getName(), mth, 1630 "got a null response from getMethod\n"); 1631 } 1632 response = null; 1633 } 1634 } else { 1635 // not getMethod so return descriptor (default) value 1636 String qualifier=""; 1637 response = attrDescr.getFieldValue("value"); 1638 if (response == null) { 1639 qualifier="default "; 1640 response = attrDescr.getFieldValue("default"); 1641 } 1642 if (tracing) { 1643 MODELMBEAN_LOGGER.logp(Level.FINER, 1644 RequiredModelMBean.class.getName(), mth, 1645 "could not find getMethod for " +attrName + 1646 ", returning descriptor " +qualifier + "value"); 1647 } 1648 // !! cast response to right class 1649 } 1650 } 1651 1652 // make sure response class matches type field 1653 final String respType = attrInfo.getType(); 1654 if (response != null) { 1655 String responseClass = response.getClass().getName(); 1656 if (!respType.equals(responseClass)) { 1657 boolean wrongType = false; 1658 boolean primitiveType = false; 1659 boolean correspondingTypes = false; 1660 for (int i = 0; i < primitiveTypes.length; i++) { 1661 if (respType.equals(primitiveTypes[i])) { 1662 primitiveType = true; 1663 if (responseClass.equals(primitiveWrappers[i])) 1664 correspondingTypes = true; 1665 break; 1666 } 1667 } 1668 if (primitiveType) { 1669 // inequality may come from primitive/wrapper class 1670 if (!correspondingTypes) 1671 wrongType = true; 1672 } else { 1673 // inequality may come from type subclassing 1674 boolean subtype; 1675 try { 1676 final Class<?> respClass = response.getClass(); 1677 final Exception[] caughException = new Exception[1]; 1678 1679 AccessControlContext stack = AccessController.getContext(); 1680 1681 Class<?> c = javaSecurityAccess.doIntersectionPrivilege(new PrivilegedAction<Class<?>>() { 1682 1683 @Override 1684 public Class<?> run() { 1685 try { 1686 ReflectUtil.checkPackageAccess(respType); 1687 ClassLoader cl = 1688 respClass.getClassLoader(); 1689 return Class.forName(respType, true, cl); 1690 } catch (Exception e) { 1691 caughException[0] = e; 1692 } 1693 return null; 1694 } 1695 }, stack, acc); 1696 1697 if (caughException[0] != null) { 1698 throw caughException[0]; 1699 } 1700 1701 subtype = c.isInstance(response); 1702 } catch (Exception e) { 1703 subtype = false; 1704 1705 if (tracing) { 1706 MODELMBEAN_LOGGER.logp(Level.FINER, 1707 RequiredModelMBean.class.getName(), 1708 mth, "Exception: ",e); 1709 } 1710 } 1711 if (!subtype) 1712 wrongType = true; 1713 } 1714 if (wrongType) { 1715 if (tracing) { 1716 MODELMBEAN_LOGGER.logp(Level.FINER, 1717 RequiredModelMBean.class.getName(), mth, 1718 "Wrong response type '" + respType + "'"); 1719 } 1720 // throw exception, didn't get 1721 // back right attribute type 1722 throw new MBeanException( 1723 new InvalidAttributeValueException( 1724 "Wrong value type received for get attribute"), 1725 "An exception occurred while trying to get an " + 1726 "attribute value through a RequiredModelMBean"); 1727 } 1728 } 1729 } 1730 } else { 1731 if (tracing) { 1732 MODELMBEAN_LOGGER.logp(Level.FINER, 1733 RequiredModelMBean.class.getName(), mth, 1734 "getMethod failed " + attrName + 1735 " not in attributeDescriptor\n"); 1736 } 1737 throw new MBeanException(new 1738 InvalidAttributeValueException( 1739 "Unable to resolve attribute value, " + 1740 "no getMethod defined in descriptor for attribute"), 1741 "An exception occurred while trying to get an "+ 1742 "attribute value through a RequiredModelMBean"); 1743 } 1744 1745 } catch (MBeanException mbe) { 1746 throw mbe; 1747 } catch (AttributeNotFoundException t) { 1748 throw t; 1749 } catch (Exception e) { 1750 if (tracing) { 1751 MODELMBEAN_LOGGER.logp(Level.FINER, 1752 RequiredModelMBean.class.getName(), mth, 1753 "getMethod failed with " + e.getMessage() + 1754 " exception type " + (e.getClass()).toString()); 1755 } 1756 throw new MBeanException(e,"An exception occurred while trying "+ 1757 "to get an attribute value: " + e.getMessage()); 1758 } 1759 1760 if (tracing) { 1761 MODELMBEAN_LOGGER.logp(Level.FINER, 1762 RequiredModelMBean.class.getName(), mth, "Exit"); 1763 } 1764 1765 return response; 1766 } 1767 1768 /** 1769 * Returns the values of several attributes in the ModelMBean. 1770 * Executes a getAttribute for each attribute name in the 1771 * attrNames array passed in. 1772 * 1773 * @param attrNames A String array of names of the attributes 1774 * to be retrieved. 1775 * 1776 * @return The array of the retrieved attributes. 1777 * 1778 * @exception RuntimeOperationsException Wraps an 1779 * {@link IllegalArgumentException}: The object name in parameter is 1780 * null or attributes in parameter is null. 1781 * 1782 * @see #setAttributes(javax.management.AttributeList) 1783 */ 1784 public AttributeList getAttributes(String[] attrNames) { 1785 if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) { 1786 MODELMBEAN_LOGGER.logp(Level.FINER, 1787 RequiredModelMBean.class.getName(), 1788 "getAttributes(String[])","Entry"); 1789 } 1790 1791 if (attrNames == null) 1792 throw new RuntimeOperationsException(new 1793 IllegalArgumentException("attributeNames must not be null"), 1794 "Exception occurred trying to get attributes of a "+ 1795 "RequiredModelMBean"); 1796 1797 AttributeList responseList = new AttributeList(); 1798 for (int i = 0; i < attrNames.length; i++) { 1799 try { 1800 responseList.add(new Attribute(attrNames[i], 1801 getAttribute(attrNames[i]))); 1802 } catch (Exception e) { 1803 // eat exceptions because interface doesn't have an 1804 // exception on it 1805 if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) { 1806 MODELMBEAN_LOGGER.logp(Level.FINER, 1807 RequiredModelMBean.class.getName(), 1808 "getAttributes(String[])", 1809 "Failed to get \"" + attrNames[i] + "\": ", e); 1810 } 1811 } 1812 } 1813 1814 if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) { 1815 MODELMBEAN_LOGGER.logp(Level.FINER, 1816 RequiredModelMBean.class.getName(), 1817 "getAttributes(String[])","Exit"); 1818 } 1819 1820 return responseList; 1821 } 1822 1823 /** 1824 * Sets the value of a specific attribute of a named ModelMBean. 1825 * 1826 * If the 'setMethod' field of the attribute's descriptor 1827 * contains the name of a valid operation descriptor, then the 1828 * method described by the operation descriptor is executed. 1829 * In this implementation, the operation descriptor must be specified 1830 * correctly and assigned to the modelMBeanInfo so that the 'setMethod' 1831 * works correctly. 1832 * The response from the method is set as the value of the attribute 1833 * in the descriptor. 1834 * 1835 * <p>If currencyTimeLimit is > 0, then the new value for the 1836 * attribute is cached in the attribute descriptor's 1837 * 'value' field and the 'lastUpdatedTimeStamp' field is set to 1838 * the current time stamp. 1839 * 1840 * <p>If the persist field of the attribute's descriptor is not null 1841 * then Persistence policy from the attribute descriptor is used to 1842 * guide storing the attribute in a persistent store. 1843 * <br>Store the MBean if 'persistPolicy' field is: 1844 * <UL> 1845 * <Li> != "never"</Li> 1846 * <Li> = "always"</Li> 1847 * <Li> = "onUpdate"</Li> 1848 * <Li> {@literal = "onTimer" and now > 'lastPersistTime' + 'persistPeriod'}</Li> 1849 * <Li> {@literal = "NoMoreOftenThan" and now > 'lastPersistTime' + 1850 * 'persistPeriod'}</Li> 1851 * </UL> 1852 * Do not store the MBean if 'persistPolicy' field is: 1853 * <UL> 1854 * <Li> = "never"</Li> 1855 * <Li> = {@literal = "onTimer" && now < 'lastPersistTime' + 'persistPeriod'}</Li> 1856 * <Li> = "onUnregister"</Li> 1857 * <Li> = {@literal = "NoMoreOftenThan" and now < 'lastPersistTime' + 1858 * 'persistPeriod'}</Li> 1859 * </UL> 1860 * 1861 * <p>The ModelMBeanInfo of the Model MBean is stored in a file. 1862 * 1863 * @param attribute The Attribute instance containing the name of 1864 * the attribute to be set and the value it is to be set to. 1865 * 1866 * 1867 * @exception AttributeNotFoundException The specified attribute is 1868 * not accessible in the MBean. 1869 * <br>The following cases may result in an AttributeNotFoundException: 1870 * <UL> 1871 * <LI> No ModelMBeanAttributeInfo is found for the specified 1872 * attribute.</LI> 1873 * <LI> The ModelMBeanAttributeInfo's isWritable method returns 1874 * 'false'.</LI> 1875 * </UL> 1876 * @exception InvalidAttributeValueException No descriptor is defined 1877 * for the specified attribute. 1878 * @exception MBeanException Wraps one of the following Exceptions: 1879 * <UL> 1880 * <LI> An Exception thrown by the managed object's setter.</LI> 1881 * <LI> A {@link ServiceNotFoundException} if a setMethod field is 1882 * defined in the descriptor for the attribute and the managed 1883 * resource is null; or if no setMethod field is defined and 1884 * caching is not enabled for the attribute. 1885 * Note that if there is no getMethod field either, then caching 1886 * is automatically enabled.</LI> 1887 * <LI> {@link InvalidTargetObjectTypeException} The 'targetType' 1888 * field value is not 'objectReference'.</LI> 1889 * <LI> An Exception thrown by the managed object's getter.</LI> 1890 * </UL> 1891 * @exception ReflectionException Wraps an {@link java.lang.Exception} 1892 * thrown while trying to invoke the setter. 1893 * @exception RuntimeOperationsException Wraps an 1894 * {@link IllegalArgumentException}: The attribute in parameter is 1895 * null. 1896 * 1897 * @see #getAttribute(java.lang.String) 1898 **/ 1899 public void setAttribute(Attribute attribute) 1900 throws AttributeNotFoundException, InvalidAttributeValueException, 1901 MBeanException, ReflectionException { 1902 final boolean tracing = MODELMBEAN_LOGGER.isLoggable(Level.FINER); 1903 if (tracing) { 1904 MODELMBEAN_LOGGER.logp(Level.FINER, 1905 RequiredModelMBean.class.getName(), 1906 "setAttribute()","Entry"); 1907 } 1908 1909 if (attribute == null) 1910 throw new RuntimeOperationsException(new 1911 IllegalArgumentException("attribute must not be null"), 1912 "Exception occurred trying to set an attribute of a "+ 1913 "RequiredModelMBean"); 1914 1915 /* run setMethod if there is one */ 1916 /* return cached value if its current */ 1917 /* set cached value in descriptor and set date/time */ 1918 /* send attribute change Notification */ 1919 /* check persistence policy and persist if need be */ 1920 String attrName = attribute.getName(); 1921 Object attrValue = attribute.getValue(); 1922 boolean updateDescriptor = false; 1923 1924 ModelMBeanAttributeInfo attrInfo = 1925 modelMBeanInfo.getAttribute(attrName); 1926 1927 if (attrInfo == null) 1928 throw new AttributeNotFoundException("setAttribute failed: " + 1929 attrName + " is not found "); 1930 1931 Descriptor mmbDesc = modelMBeanInfo.getMBeanDescriptor(); 1932 Descriptor attrDescr = attrInfo.getDescriptor(); 1933 1934 if (attrDescr != null) { 1935 if (!attrInfo.isWritable()) 1936 throw new AttributeNotFoundException("setAttribute failed: " 1937 + attrName + " is not writable "); 1938 1939 String attrSetMethod = (String) 1940 (attrDescr.getFieldValue("setMethod")); 1941 String attrGetMethod = (String) 1942 (attrDescr.getFieldValue("getMethod")); 1943 1944 String attrType = attrInfo.getType(); 1945 Object currValue = "Unknown"; 1946 1947 try { 1948 currValue = this.getAttribute(attrName); 1949 } catch (Throwable t) { 1950 // OK: Default "Unknown" value used for unknown attribute 1951 } 1952 1953 Attribute oldAttr = new Attribute(attrName, currValue); 1954 1955 /* run method from operations descriptor */ 1956 if (attrSetMethod == null) { 1957 if (attrValue != null) { 1958 try { 1959 final Class<?> clazz = loadClass(attrType); 1960 if (! clazz.isInstance(attrValue)) throw new 1961 InvalidAttributeValueException(clazz.getName() + 1962 " expected, " + 1963 attrValue.getClass().getName() + 1964 " received."); 1965 } catch (ClassNotFoundException x) { 1966 if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) { 1967 MODELMBEAN_LOGGER.logp(Level.FINER, 1968 RequiredModelMBean.class.getName(), 1969 "setAttribute(Attribute)","Class " + 1970 attrType + " for attribute " 1971 + attrName + " not found: ", x); 1972 } 1973 } 1974 } 1975 updateDescriptor = true; 1976 } else { 1977 invoke(attrSetMethod, 1978 (new Object[] {attrValue}), 1979 (new String[] {attrType}) ); 1980 } 1981 1982 /* change cached value */ 1983 Object objctl = attrDescr.getFieldValue("currencyTimeLimit"); 1984 String ctl; 1985 if (objctl != null) ctl = objctl.toString(); 1986 else ctl = null; 1987 1988 if ((ctl == null) && (mmbDesc != null)) { 1989 objctl = mmbDesc.getFieldValue("currencyTimeLimit"); 1990 if (objctl != null) ctl = objctl.toString(); 1991 else ctl = null; 1992 } 1993 1994 final boolean updateCache = ((ctl != null) && !(ctl.equals("-1"))); 1995 1996 if(attrSetMethod == null && !updateCache && attrGetMethod != null) 1997 throw new MBeanException(new ServiceNotFoundException("No " + 1998 "setMethod field is defined in the descriptor for " + 1999 attrName + " attribute and caching is not enabled " + 2000 "for it")); 2001 2002 if (updateCache || updateDescriptor) { 2003 if (tracing) { 2004 MODELMBEAN_LOGGER.logp(Level.FINER, 2005 RequiredModelMBean.class.getName(), 2006 "setAttribute(Attribute)", 2007 "setting cached value of " + 2008 attrName + " to " + attrValue); 2009 } 2010 2011 attrDescr.setField("value", attrValue); 2012 2013 if (updateCache) { 2014 final String currtime = String.valueOf( 2015 (new Date()).getTime()); 2016 2017 attrDescr.setField("lastUpdatedTimeStamp", currtime); 2018 } 2019 2020 attrInfo.setDescriptor(attrDescr); 2021 2022 modelMBeanInfo.setDescriptor(attrDescr,"attribute"); 2023 if (tracing) { 2024 final StringBuilder strb = new StringBuilder() 2025 .append("new descriptor is ").append(attrDescr) 2026 .append(". AttributeInfo descriptor is ") 2027 .append(attrInfo.getDescriptor()) 2028 .append(". AttributeInfo descriptor is ") 2029 .append(modelMBeanInfo.getDescriptor(attrName,"attribute")); 2030 MODELMBEAN_LOGGER.logp(Level.FINER, 2031 RequiredModelMBean.class.getName(), 2032 "setAttribute(Attribute)",strb.toString()); 2033 } 2034 2035 } 2036 2037 if (tracing) { 2038 MODELMBEAN_LOGGER.logp(Level.FINER, 2039 RequiredModelMBean.class.getName(), 2040 "setAttribute(Attribute)","sending sendAttributeNotification"); 2041 } 2042 sendAttributeChangeNotification(oldAttr,attribute); 2043 2044 } else { // if descriptor ... else no descriptor 2045 2046 if (tracing) { 2047 MODELMBEAN_LOGGER.logp(Level.FINER, 2048 RequiredModelMBean.class.getName(), 2049 "setAttribute(Attribute)","setMethod failed "+attrName+ 2050 " not in attributeDescriptor\n"); 2051 } 2052 2053 throw new InvalidAttributeValueException( 2054 "Unable to resolve attribute value, "+ 2055 "no defined in descriptor for attribute"); 2056 } // else no descriptor 2057 2058 if (tracing) { 2059 MODELMBEAN_LOGGER.logp(Level.FINER, 2060 RequiredModelMBean.class.getName(), 2061 "setAttribute(Attribute)", "Exit"); 2062 } 2063 2064 } 2065 2066 /** 2067 * Sets the values of an array of attributes of this ModelMBean. 2068 * Executes the setAttribute() method for each attribute in the list. 2069 * 2070 * @param attributes A list of attributes: The identification of the 2071 * attributes to be set and the values they are to be set to. 2072 * 2073 * @return The array of attributes that were set, with their new 2074 * values in Attribute instances. 2075 * 2076 * @exception RuntimeOperationsException Wraps an 2077 * {@link IllegalArgumentException}: The object name in parameter 2078 * is null or attributes in parameter is null. 2079 * 2080 * @see #getAttributes 2081 **/ 2082 public AttributeList setAttributes(AttributeList attributes) { 2083 2084 if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) { 2085 MODELMBEAN_LOGGER.logp(Level.FINER, 2086 RequiredModelMBean.class.getName(), 2087 "setAttribute(Attribute)", "Entry"); 2088 } 2089 2090 if (attributes == null) 2091 throw new RuntimeOperationsException(new 2092 IllegalArgumentException("attributes must not be null"), 2093 "Exception occurred trying to set attributes of a "+ 2094 "RequiredModelMBean"); 2095 2096 final AttributeList responseList = new AttributeList(); 2097 2098 // Go through the list of attributes 2099 for (Attribute attr : attributes.asList()) { 2100 try { 2101 setAttribute(attr); 2102 responseList.add(attr); 2103 } catch (Exception excep) { 2104 responseList.remove(attr); 2105 } 2106 } 2107 2108 return responseList; 2109 } 2110 2111 2112 2113 private ModelMBeanInfo createDefaultModelMBeanInfo() { 2114 return(new ModelMBeanInfoSupport((this.getClass().getName()), 2115 "Default ModelMBean", null, null, null, null)); 2116 } 2117 2118 /*************************************/ 2119 /* NotificationBroadcaster Interface */ 2120 /*************************************/ 2121 2122 2123 private synchronized void writeToLog(String logFileName, 2124 String logEntry) throws Exception { 2125 2126 if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) { 2127 MODELMBEAN_LOGGER.logp(Level.FINER, 2128 RequiredModelMBean.class.getName(), 2129 "writeToLog(String, String)", 2130 "Notification Logging to " + logFileName + ": " + logEntry); 2131 } 2132 if ((logFileName == null) || (logEntry == null)) { 2133 if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) { 2134 MODELMBEAN_LOGGER.logp(Level.FINER, 2135 RequiredModelMBean.class.getName(), 2136 "writeToLog(String, String)", 2137 "Bad input parameters, will not log this entry."); 2138 } 2139 return; 2140 } 2141 2142 FileOutputStream fos = new FileOutputStream(logFileName, true); 2143 try { 2144 PrintStream logOut = new PrintStream(fos); 2145 logOut.println(logEntry); 2146 logOut.close(); 2147 if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) { 2148 MODELMBEAN_LOGGER.logp(Level.FINER, 2149 RequiredModelMBean.class.getName(), 2150 "writeToLog(String, String)","Successfully opened log " + 2151 logFileName); 2152 } 2153 } catch (Exception e) { 2154 if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) { 2155 MODELMBEAN_LOGGER.logp(Level.FINER, 2156 RequiredModelMBean.class.getName(), 2157 "writeToLog(String, String)", 2158 "Exception " + e.toString() + 2159 " trying to write to the Notification log file " + 2160 logFileName); 2161 } 2162 throw e; 2163 } finally { 2164 fos.close(); 2165 } 2166 } 2167 2168 2169 /** 2170 * Registers an object which implements the NotificationListener 2171 * interface as a listener. This 2172 * object's 'handleNotification()' method will be invoked when any 2173 * notification is issued through or by the ModelMBean. This does 2174 * not include attributeChangeNotifications. They must be registered 2175 * for independently. 2176 * 2177 * @param listener The listener object which will handles 2178 * notifications emitted by the registered MBean. 2179 * @param filter The filter object. If null, no filtering will be 2180 * performed before handling notifications. 2181 * @param handback The context to be sent to the listener with 2182 * the notification when a notification is emitted. 2183 * 2184 * @exception IllegalArgumentException The listener cannot be null. 2185 * 2186 * @see #removeNotificationListener 2187 */ 2188 public void addNotificationListener(NotificationListener listener, 2189 NotificationFilter filter, 2190 Object handback) 2191 throws java.lang.IllegalArgumentException { 2192 final String mth = "addNotificationListener(" + 2193 "NotificationListener, NotificationFilter, Object)"; 2194 if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) { 2195 MODELMBEAN_LOGGER.logp(Level.FINER, 2196 RequiredModelMBean.class.getName(), mth, "Entry"); 2197 } 2198 2199 if (listener == null) 2200 throw new IllegalArgumentException( 2201 "notification listener must not be null"); 2202 2203 if (generalBroadcaster == null) 2204 generalBroadcaster = new NotificationBroadcasterSupport(); 2205 2206 generalBroadcaster.addNotificationListener(listener, filter, 2207 handback); 2208 if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) { 2209 MODELMBEAN_LOGGER.logp(Level.FINER, 2210 RequiredModelMBean.class.getName(), mth, 2211 "NotificationListener added"); 2212 MODELMBEAN_LOGGER.logp(Level.FINER, 2213 RequiredModelMBean.class.getName(), mth, "Exit"); 2214 } 2215 } 2216 2217 /** 2218 * Removes a listener for Notifications from the RequiredModelMBean. 2219 * 2220 * @param listener The listener name which was handling notifications 2221 * emitted by the registered MBean. 2222 * This method will remove all information related to this listener. 2223 * 2224 * @exception ListenerNotFoundException The listener is not registered 2225 * in the MBean or is null. 2226 * 2227 * @see #addNotificationListener 2228 **/ 2229 public void removeNotificationListener(NotificationListener listener) 2230 throws ListenerNotFoundException { 2231 if (listener == null) 2232 throw new ListenerNotFoundException( 2233 "Notification listener is null"); 2234 2235 final String mth="removeNotificationListener(NotificationListener)"; 2236 if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) { 2237 MODELMBEAN_LOGGER.logp(Level.FINER, 2238 RequiredModelMBean.class.getName(), mth, "Entry"); 2239 } 2240 2241 if (generalBroadcaster == null) 2242 throw new ListenerNotFoundException( 2243 "No notification listeners registered"); 2244 2245 2246 generalBroadcaster.removeNotificationListener(listener); 2247 if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) { 2248 MODELMBEAN_LOGGER.logp(Level.FINER, 2249 RequiredModelMBean.class.getName(), mth, "Exit"); 2250 } 2251 2252 } 2253 2254 public void removeNotificationListener(NotificationListener listener, 2255 NotificationFilter filter, 2256 Object handback) 2257 throws ListenerNotFoundException { 2258 2259 if (listener == null) 2260 throw new ListenerNotFoundException( 2261 "Notification listener is null"); 2262 2263 final String mth = "removeNotificationListener(" + 2264 "NotificationListener, NotificationFilter, Object)"; 2265 2266 if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) { 2267 MODELMBEAN_LOGGER.logp(Level.FINER, 2268 RequiredModelMBean.class.getName(), mth, "Entry"); 2269 } 2270 2271 if (generalBroadcaster == null) 2272 throw new ListenerNotFoundException( 2273 "No notification listeners registered"); 2274 2275 2276 generalBroadcaster.removeNotificationListener(listener,filter, 2277 handback); 2278 2279 if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) { 2280 MODELMBEAN_LOGGER.logp(Level.FINER, 2281 RequiredModelMBean.class.getName(), mth, "Exit"); 2282 } 2283 2284 } 2285 2286 public void sendNotification(Notification ntfyObj) 2287 throws MBeanException, RuntimeOperationsException { 2288 if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) { 2289 MODELMBEAN_LOGGER.logp(Level.FINER, 2290 RequiredModelMBean.class.getName(), 2291 "sendNotification(Notification)", "Entry"); 2292 } 2293 2294 if (ntfyObj == null) 2295 throw new RuntimeOperationsException(new 2296 IllegalArgumentException("notification object must not be "+ 2297 "null"), 2298 "Exception occurred trying to send a notification from a "+ 2299 "RequiredModelMBean"); 2300 2301 2302 // log notification if specified in descriptor 2303 Descriptor ntfyDesc = 2304 modelMBeanInfo.getDescriptor(ntfyObj.getType(),"notification"); 2305 Descriptor mmbDesc = modelMBeanInfo.getMBeanDescriptor(); 2306 2307 if (ntfyDesc != null) { 2308 String logging = (String) ntfyDesc.getFieldValue("log"); 2309 2310 if (logging == null) { 2311 if (mmbDesc != null) 2312 logging = (String) mmbDesc.getFieldValue("log"); 2313 } 2314 2315 if ((logging != null) && 2316 (logging.equalsIgnoreCase("t") || 2317 logging.equalsIgnoreCase("true"))) { 2318 2319 String logfile = (String) ntfyDesc.getFieldValue("logfile"); 2320 if (logfile == null) { 2321 if (mmbDesc != null) 2322 logfile = (String)mmbDesc.getFieldValue("logfile"); 2323 } 2324 if (logfile != null) { 2325 try { 2326 writeToLog(logfile,"LogMsg: " + 2327 ((new Date(ntfyObj.getTimeStamp())).toString())+ 2328 " " + ntfyObj.getType() + " " + 2329 ntfyObj.getMessage() + " Severity = " + 2330 (String)ntfyDesc.getFieldValue("severity")); 2331 } catch (Exception e) { 2332 if (MODELMBEAN_LOGGER.isLoggable(Level.FINE)) { 2333 MODELMBEAN_LOGGER.logp(Level.FINE, 2334 RequiredModelMBean.class.getName(), 2335 "sendNotification(Notification)", 2336 "Failed to log " + 2337 ntfyObj.getType() + " notification: ", e); 2338 } 2339 } 2340 } 2341 } 2342 } 2343 if (generalBroadcaster != null) { 2344 generalBroadcaster.sendNotification(ntfyObj); 2345 } 2346 2347 if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) { 2348 MODELMBEAN_LOGGER.logp(Level.FINER, 2349 RequiredModelMBean.class.getName(), 2350 "sendNotification(Notification)", 2351 "sendNotification sent provided notification object"); 2352 MODELMBEAN_LOGGER.logp(Level.FINER, 2353 RequiredModelMBean.class.getName(), 2354 "sendNotification(Notification)"," Exit"); 2355 } 2356 2357 } 2358 2359 2360 public void sendNotification(String ntfyText) 2361 throws MBeanException, RuntimeOperationsException { 2362 if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) { 2363 MODELMBEAN_LOGGER.logp(Level.FINER, 2364 RequiredModelMBean.class.getName(), 2365 "sendNotification(String)","Entry"); 2366 } 2367 2368 if (ntfyText == null) 2369 throw new RuntimeOperationsException(new 2370 IllegalArgumentException("notification message must not "+ 2371 "be null"), 2372 "Exception occurred trying to send a text notification "+ 2373 "from a ModelMBean"); 2374 2375 Notification myNtfyObj = new Notification("jmx.modelmbean.generic", 2376 this, 1, ntfyText); 2377 sendNotification(myNtfyObj); 2378 if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) { 2379 MODELMBEAN_LOGGER.logp(Level.FINER, 2380 RequiredModelMBean.class.getName(), 2381 "sendNotification(String)","Notification sent"); 2382 MODELMBEAN_LOGGER.logp(Level.FINER, 2383 RequiredModelMBean.class.getName(), 2384 "sendNotification(String)","Exit"); 2385 } 2386 } 2387 2388 /** 2389 * Returns `true' if the notification `notifName' is found 2390 * in `info'. (bug 4744667) 2391 **/ 2392 private static final 2393 boolean hasNotification(final ModelMBeanInfo info, 2394 final String notifName) { 2395 try { 2396 if (info == null) return false; 2397 else return (info.getNotification(notifName)!=null); 2398 } catch (MBeanException x) { 2399 return false; 2400 } catch (RuntimeOperationsException r) { 2401 return false; 2402 } 2403 } 2404 2405 /** 2406 * Creates a default ModelMBeanNotificationInfo for GENERIC 2407 * notification. (bug 4744667) 2408 **/ 2409 private static final ModelMBeanNotificationInfo makeGenericInfo() { 2410 final Descriptor genericDescriptor = new DescriptorSupport( new 2411 String[] { 2412 "name=GENERIC", 2413 "descriptorType=notification", 2414 "log=T", 2415 "severity=6", 2416 "displayName=jmx.modelmbean.generic"} ); 2417 2418 return new ModelMBeanNotificationInfo(new 2419 String[] {"jmx.modelmbean.generic"}, 2420 "GENERIC", 2421 "A text notification has been issued by the managed resource", 2422 genericDescriptor); 2423 } 2424 2425 /** 2426 * Creates a default ModelMBeanNotificationInfo for ATTRIBUTE_CHANGE 2427 * notification. (bug 4744667) 2428 **/ 2429 private static final 2430 ModelMBeanNotificationInfo makeAttributeChangeInfo() { 2431 final Descriptor attributeDescriptor = new DescriptorSupport(new 2432 String[] { 2433 "name=ATTRIBUTE_CHANGE", 2434 "descriptorType=notification", 2435 "log=T", 2436 "severity=6", 2437 "displayName=jmx.attribute.change"}); 2438 2439 return new ModelMBeanNotificationInfo(new 2440 String[] {"jmx.attribute.change"}, 2441 "ATTRIBUTE_CHANGE", 2442 "Signifies that an observed MBean attribute value has changed", 2443 attributeDescriptor ); 2444 } 2445 2446 /** 2447 * Returns the array of Notifications always generated by the 2448 * RequiredModelMBean. 2449 * <P> 2450 * 2451 * RequiredModelMBean may always send also two additional notifications: 2452 * <UL> 2453 * <LI> One with descriptor <code>"name=GENERIC,descriptorType=notification,log=T,severity=6,displayName=jmx.modelmbean.generic"</code></LI> 2454 * <LI> Second is a standard attribute change notification 2455 * with descriptor <code>"name=ATTRIBUTE_CHANGE,descriptorType=notification,log=T,severity=6,displayName=jmx.attribute.change"</code></LI> 2456 * </UL> 2457 * Thus these two notifications are always added to those specified 2458 * by the application. 2459 * 2460 * @return MBeanNotificationInfo[] 2461 * 2462 **/ 2463 public MBeanNotificationInfo[] getNotificationInfo() { 2464 if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) { 2465 MODELMBEAN_LOGGER.logp(Level.FINER, 2466 RequiredModelMBean.class.getName(), 2467 "getNotificationInfo()","Entry"); 2468 } 2469 2470 // Using hasNotification() is not optimal, but shouldn't really 2471 // matter in this context... 2472 2473 // hasGeneric==true if GENERIC notification is present. 2474 // (bug 4744667) 2475 final boolean hasGeneric = hasNotification(modelMBeanInfo,"GENERIC"); 2476 2477 // hasAttributeChange==true if ATTRIBUTE_CHANGE notification is 2478 // present. 2479 // (bug 4744667) 2480 final boolean hasAttributeChange = 2481 hasNotification(modelMBeanInfo,"ATTRIBUTE_CHANGE"); 2482 2483 // User supplied list of notification infos. 2484 // 2485 final ModelMBeanNotificationInfo[] currInfo = 2486 (ModelMBeanNotificationInfo[])modelMBeanInfo.getNotifications(); 2487 2488 // Length of the returned list of notification infos: 2489 // length of user suplied list + possibly 1 for GENERIC, + 2490 // possibly 1 for ATTRIBUTE_CHANGE 2491 // (bug 4744667) 2492 final int len = ((currInfo==null?0:currInfo.length) + 2493 (hasGeneric?0:1) + (hasAttributeChange?0:1)); 2494 2495 // Returned list of notification infos: 2496 // 2497 final ModelMBeanNotificationInfo[] respInfo = 2498 new ModelMBeanNotificationInfo[len]; 2499 2500 // Preserve previous ordering (JMX 1.1) 2501 // 2502 2503 // Counter of "standard" notification inserted before user 2504 // supplied notifications. 2505 // 2506 int inserted=0; 2507 if (!hasGeneric) 2508 // We need to add description for GENERIC notification 2509 // (bug 4744667) 2510 respInfo[inserted++] = makeGenericInfo(); 2511 2512 2513 if (!hasAttributeChange) 2514 // We need to add description for ATTRIBUTE_CHANGE notification 2515 // (bug 4744667) 2516 respInfo[inserted++] = makeAttributeChangeInfo(); 2517 2518 // Now copy user supplied list in returned list. 2519 // 2520 final int count = currInfo.length; 2521 final int offset = inserted; 2522 for (int j=0; j < count; j++) { 2523 respInfo[offset+j] = currInfo[j]; 2524 } 2525 2526 if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) { 2527 MODELMBEAN_LOGGER.logp(Level.FINER, 2528 RequiredModelMBean.class.getName(), 2529 "getNotificationInfo()","Exit"); 2530 } 2531 2532 return respInfo; 2533 } 2534 2535 2536 public void addAttributeChangeNotificationListener(NotificationListener 2537 inlistener, 2538 String 2539 inAttributeName, 2540 Object inhandback) 2541 throws MBeanException, RuntimeOperationsException, 2542 IllegalArgumentException { 2543 final String mth="addAttributeChangeNotificationListener(" + 2544 "NotificationListener, String, Object)"; 2545 2546 if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) { 2547 MODELMBEAN_LOGGER.logp(Level.FINER, 2548 RequiredModelMBean.class.getName(),mth,"Entry"); 2549 } 2550 2551 if (inlistener == null) 2552 throw new IllegalArgumentException( 2553 "Listener to be registered must not be null"); 2554 2555 2556 if (attributeBroadcaster == null) 2557 attributeBroadcaster = new NotificationBroadcasterSupport(); 2558 2559 AttributeChangeNotificationFilter currFilter = 2560 new AttributeChangeNotificationFilter(); 2561 2562 MBeanAttributeInfo[] attrInfo = modelMBeanInfo.getAttributes(); 2563 boolean found = false; 2564 if (inAttributeName == null) { 2565 if ((attrInfo != null) && (attrInfo.length>0)) { 2566 for (int i=0; i<attrInfo.length; i++) { 2567 currFilter.enableAttribute(attrInfo[i].getName()); 2568 } 2569 } 2570 } else { 2571 if ((attrInfo != null) && (attrInfo.length>0)) { 2572 for (int i=0; i<attrInfo.length; i++) { 2573 if (inAttributeName.equals(attrInfo[i].getName())) { 2574 found = true; 2575 currFilter.enableAttribute(inAttributeName); 2576 break; 2577 } 2578 } 2579 } 2580 if (!found) { 2581 throw new RuntimeOperationsException(new 2582 IllegalArgumentException( 2583 "The attribute name does not exist"), 2584 "Exception occurred trying to add an "+ 2585 "AttributeChangeNotification listener"); 2586 } 2587 } 2588 2589 if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) { 2590 Vector<String> enabledAttrs = currFilter.getEnabledAttributes(); 2591 String s = (enabledAttrs.size() > 1) ? 2592 "[" + enabledAttrs.firstElement() + ", ...]" : 2593 enabledAttrs.toString(); 2594 MODELMBEAN_LOGGER.logp(Level.FINER, 2595 RequiredModelMBean.class.getName(), mth, 2596 "Set attribute change filter to " + s); 2597 } 2598 2599 attributeBroadcaster.addNotificationListener(inlistener,currFilter, 2600 inhandback); 2601 if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) { 2602 MODELMBEAN_LOGGER.logp(Level.FINER, 2603 RequiredModelMBean.class.getName(),mth, 2604 "Notification listener added for " + inAttributeName); 2605 MODELMBEAN_LOGGER.logp(Level.FINER, 2606 RequiredModelMBean.class.getName(),mth,"Exit"); 2607 } 2608 } 2609 2610 public void removeAttributeChangeNotificationListener( 2611 NotificationListener inlistener, String inAttributeName) 2612 throws MBeanException, RuntimeOperationsException, 2613 ListenerNotFoundException { 2614 if (inlistener == null) throw new 2615 ListenerNotFoundException("Notification listener is null"); 2616 2617 final String mth = "removeAttributeChangeNotificationListener(" + 2618 "NotificationListener, String)"; 2619 2620 if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) { 2621 MODELMBEAN_LOGGER.logp(Level.FINER, 2622 RequiredModelMBean.class.getName(),mth,"Entry"); 2623 } 2624 2625 2626 if (attributeBroadcaster == null) 2627 throw new ListenerNotFoundException( 2628 "No attribute change notification listeners registered"); 2629 2630 2631 MBeanAttributeInfo[] attrInfo = modelMBeanInfo.getAttributes(); 2632 boolean found = false; 2633 if ((attrInfo != null) && (attrInfo.length>0)) { 2634 for (int i=0; i<attrInfo.length; i++) { 2635 if (attrInfo[i].getName().equals(inAttributeName)) { 2636 found = true; 2637 break; 2638 } 2639 } 2640 } 2641 2642 if ((!found) && (inAttributeName != null)) { 2643 throw new RuntimeOperationsException(new 2644 IllegalArgumentException("Invalid attribute name"), 2645 "Exception occurred trying to remove "+ 2646 "attribute change notification listener"); 2647 } 2648 2649 /* note: */ 2650 /* this may be a problem if the same listener is registered for 2651 multiple attributes with multiple filters and/or handback 2652 objects. It may remove all of them */ 2653 2654 attributeBroadcaster.removeNotificationListener(inlistener); 2655 2656 if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) { 2657 MODELMBEAN_LOGGER.logp(Level.FINER, 2658 RequiredModelMBean.class.getName(),mth,"Exit"); 2659 } 2660 } 2661 2662 public void sendAttributeChangeNotification(AttributeChangeNotification 2663 ntfyObj) 2664 throws MBeanException, RuntimeOperationsException { 2665 final String mth = "sendAttributeChangeNotification(" + 2666 "AttributeChangeNotification)"; 2667 2668 if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) { 2669 MODELMBEAN_LOGGER.logp(Level.FINER, 2670 RequiredModelMBean.class.getName(),mth,"Entry"); 2671 } 2672 2673 if (ntfyObj == null) 2674 throw new RuntimeOperationsException(new 2675 IllegalArgumentException( 2676 "attribute change notification object must not be null"), 2677 "Exception occurred trying to send "+ 2678 "attribute change notification of a ModelMBean"); 2679 2680 Object oldv = ntfyObj.getOldValue(); 2681 Object newv = ntfyObj.getNewValue(); 2682 2683 if (oldv == null) oldv = "null"; 2684 if (newv == null) newv = "null"; 2685 2686 if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) { 2687 MODELMBEAN_LOGGER.logp(Level.FINER, 2688 RequiredModelMBean.class.getName(),mth, 2689 "Sending AttributeChangeNotification with " + 2690 ntfyObj.getAttributeName() + ntfyObj.getAttributeType() + 2691 ntfyObj.getNewValue() + ntfyObj.getOldValue()); 2692 } 2693 2694 // log notification if specified in descriptor 2695 Descriptor ntfyDesc = 2696 modelMBeanInfo.getDescriptor(ntfyObj.getType(),"notification"); 2697 Descriptor mmbDesc = modelMBeanInfo.getMBeanDescriptor(); 2698 2699 String logging, logfile; 2700 2701 if (ntfyDesc != null) { 2702 logging =(String) ntfyDesc.getFieldValue("log"); 2703 if (logging == null) { 2704 if (mmbDesc != null) 2705 logging = (String) mmbDesc.getFieldValue("log"); 2706 } 2707 if ((logging != null) && 2708 ( logging.equalsIgnoreCase("t") || 2709 logging.equalsIgnoreCase("true"))) { 2710 logfile = (String) ntfyDesc.getFieldValue("logfile"); 2711 if (logfile == null) { 2712 if (mmbDesc != null) 2713 logfile = (String)mmbDesc.getFieldValue("logfile"); 2714 } 2715 2716 if (logfile != null) { 2717 try { 2718 writeToLog(logfile,"LogMsg: " + 2719 ((new Date(ntfyObj.getTimeStamp())).toString())+ 2720 " " + ntfyObj.getType() + " " + 2721 ntfyObj.getMessage() + 2722 " Name = " + ntfyObj.getAttributeName() + 2723 " Old value = " + oldv + 2724 " New value = " + newv); 2725 } catch (Exception e) { 2726 if (MODELMBEAN_LOGGER.isLoggable(Level.FINE)) { 2727 MODELMBEAN_LOGGER.logp(Level.FINE, 2728 RequiredModelMBean.class.getName(),mth, 2729 "Failed to log " + ntfyObj.getType() + 2730 " notification: ", e); 2731 } 2732 } 2733 } 2734 } 2735 } else if (mmbDesc != null) { 2736 logging = (String) mmbDesc.getFieldValue("log"); 2737 if ((logging != null) && 2738 ( logging.equalsIgnoreCase("t") || 2739 logging.equalsIgnoreCase("true") )) { 2740 logfile = (String) mmbDesc.getFieldValue("logfile"); 2741 2742 if (logfile != null) { 2743 try { 2744 writeToLog(logfile,"LogMsg: " + 2745 ((new Date(ntfyObj.getTimeStamp())).toString())+ 2746 " " + ntfyObj.getType() + " " + 2747 ntfyObj.getMessage() + 2748 " Name = " + ntfyObj.getAttributeName() + 2749 " Old value = " + oldv + 2750 " New value = " + newv); 2751 } catch (Exception e) { 2752 if (MODELMBEAN_LOGGER.isLoggable(Level.FINE)) { 2753 MODELMBEAN_LOGGER.logp(Level.FINE, 2754 RequiredModelMBean.class.getName(),mth, 2755 "Failed to log " + ntfyObj.getType() + 2756 " notification: ", e); 2757 } 2758 } 2759 } 2760 } 2761 } 2762 if (attributeBroadcaster != null) { 2763 attributeBroadcaster.sendNotification(ntfyObj); 2764 } 2765 2766 // XXX Revisit: This is a quickfix: it would be better to have a 2767 // single broadcaster. However, it is not so simple because 2768 // removeAttributeChangeNotificationListener() should 2769 // remove only listeners whose filter is an instanceof 2770 // AttributeChangeNotificationFilter. 2771 // 2772 if (generalBroadcaster != null) { 2773 generalBroadcaster.sendNotification(ntfyObj); 2774 } 2775 2776 if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) { 2777 MODELMBEAN_LOGGER.logp(Level.FINER, 2778 RequiredModelMBean.class.getName(),mth, 2779 "sent notification"); 2780 MODELMBEAN_LOGGER.logp(Level.FINER, 2781 RequiredModelMBean.class.getName(),mth, 2782 "Exit"); 2783 } 2784 } 2785 2786 public void sendAttributeChangeNotification(Attribute inOldVal, 2787 Attribute inNewVal) 2788 throws MBeanException, RuntimeOperationsException { 2789 final String mth = 2790 "sendAttributeChangeNotification(Attribute, Attribute)"; 2791 if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) { 2792 MODELMBEAN_LOGGER.logp(Level.FINER, 2793 RequiredModelMBean.class.getName(),mth, 2794 "Entry"); 2795 } 2796 2797 // do we really want to do this? 2798 if ((inOldVal == null) || (inNewVal == null)) 2799 throw new RuntimeOperationsException(new 2800 IllegalArgumentException("Attribute object must not be null"), 2801 "Exception occurred trying to send " + 2802 "attribute change notification of a ModelMBean"); 2803 2804 2805 if (!(inOldVal.getName().equals(inNewVal.getName()))) 2806 throw new RuntimeOperationsException(new 2807 IllegalArgumentException("Attribute names are not the same"), 2808 "Exception occurred trying to send " + 2809 "attribute change notification of a ModelMBean"); 2810 2811 2812 Object newVal = inNewVal.getValue(); 2813 Object oldVal = inOldVal.getValue(); 2814 String className = "unknown"; 2815 if (newVal != null) 2816 className = newVal.getClass().getName(); 2817 if (oldVal != null) 2818 className = oldVal.getClass().getName(); 2819 2820 AttributeChangeNotification myNtfyObj = new 2821 AttributeChangeNotification(this, 2822 1, 2823 ((new Date()).getTime()), 2824 "AttributeChangeDetected", 2825 inOldVal.getName(), 2826 className, 2827 inOldVal.getValue(), 2828 inNewVal.getValue()); 2829 2830 sendAttributeChangeNotification(myNtfyObj); 2831 2832 if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) { 2833 MODELMBEAN_LOGGER.logp(Level.FINER, 2834 RequiredModelMBean.class.getName(),mth, 2835 "Exit"); 2836 } 2837 2838 } 2839 2840 /** 2841 * Return the Class Loader Repository used to perform class loading. 2842 * Subclasses may wish to redefine this method in order to return 2843 * the appropriate {@link javax.management.loading.ClassLoaderRepository} 2844 * that should be used in this object. 2845 * 2846 * @return the Class Loader Repository. 2847 * 2848 */ 2849 protected ClassLoaderRepository getClassLoaderRepository() { 2850 return MBeanServerFactory.getClassLoaderRepository(server); 2851 } 2852 2853 private Class<?> loadClass(final String className) 2854 throws ClassNotFoundException { 2855 AccessControlContext stack = AccessController.getContext(); 2856 final ClassNotFoundException[] caughtException = new ClassNotFoundException[1]; 2857 2858 Class<?> c = javaSecurityAccess.doIntersectionPrivilege(new PrivilegedAction<Class<?>>() { 2859 2860 @Override 2861 public Class<?> run() { 2862 try { 2863 ReflectUtil.checkPackageAccess(className); 2864 return Class.forName(className); 2865 } catch (ClassNotFoundException e) { 2866 final ClassLoaderRepository clr = 2867 getClassLoaderRepository(); 2868 try { 2869 if (clr == null) throw new ClassNotFoundException(className); 2870 return clr.loadClass(className); 2871 } catch (ClassNotFoundException ex) { 2872 caughtException[0] = ex; 2873 } 2874 } 2875 return null; 2876 } 2877 }, stack, acc); 2878 2879 if (caughtException[0] != null) { 2880 throw caughtException[0]; 2881 } 2882 2883 return c; 2884 } 2885 2886 2887 /*************************************/ 2888 /* MBeanRegistration Interface */ 2889 /*************************************/ 2890 2891 /** 2892 * Allows the MBean to perform any operations it needs before 2893 * being registered in the MBean server. If the name of the MBean 2894 * is not specified, the MBean can provide a name for its 2895 * registration. If any exception is raised, the MBean will not be 2896 * registered in the MBean server. 2897 * <P> 2898 * In order to ensure proper run-time semantics of RequireModelMBean, 2899 * Any subclass of RequiredModelMBean overloading or overriding this 2900 * method should call <code>super.preRegister(server, name)</code> 2901 * in its own <code>preRegister</code> implementation. 2902 * 2903 * @param server The MBean server in which the MBean will be registered. 2904 * 2905 * @param name The object name of the MBean. This name is null if 2906 * the name parameter to one of the <code>createMBean</code> or 2907 * <code>registerMBean</code> methods in the {@link MBeanServer} 2908 * interface is null. In that case, this method must return a 2909 * non-null ObjectName for the new MBean. 2910 * 2911 * @return The name under which the MBean is to be registered. 2912 * This value must not be null. If the <code>name</code> 2913 * parameter is not null, it will usually but not necessarily be 2914 * the returned value. 2915 * 2916 * @exception java.lang.Exception This exception will be caught by 2917 * the MBean server and re-thrown as an 2918 * {@link javax.management.MBeanRegistrationException 2919 * MBeanRegistrationException}. 2920 */ 2921 public ObjectName preRegister(MBeanServer server, 2922 ObjectName name) 2923 throws java.lang.Exception { 2924 // Since ModelMbeanInfo cannot be null (otherwise exception 2925 // thrown at creation) 2926 // no exception thrown on ModelMBeanInfo not set. 2927 if (name == null) throw new NullPointerException( 2928 "name of RequiredModelMBean to registered is null"); 2929 this.server = server; 2930 return name; 2931 } 2932 2933 /** 2934 * Allows the MBean to perform any operations needed after having been 2935 * registered in the MBean server or after the registration has failed. 2936 * <P> 2937 * In order to ensure proper run-time semantics of RequireModelMBean, 2938 * Any subclass of RequiredModelMBean overloading or overriding this 2939 * method should call <code>super.postRegister(registrationDone)</code> 2940 * in its own <code>postRegister</code> implementation. 2941 * 2942 * @param registrationDone Indicates whether or not the MBean has 2943 * been successfully registered in the MBean server. The value 2944 * false means that the registration phase has failed. 2945 */ 2946 public void postRegister(Boolean registrationDone) { 2947 registered = registrationDone.booleanValue(); 2948 } 2949 2950 /** 2951 * Allows the MBean to perform any operations it needs before 2952 * being unregistered by the MBean server. 2953 * <P> 2954 * In order to ensure proper run-time semantics of RequireModelMBean, 2955 * Any subclass of RequiredModelMBean overloading or overriding this 2956 * method should call <code>super.preDeregister()</code> in its own 2957 * <code>preDeregister</code> implementation. 2958 * 2959 * @exception java.lang.Exception This exception will be caught by 2960 * the MBean server and re-thrown as an 2961 * {@link javax.management.MBeanRegistrationException 2962 * MBeanRegistrationException}. 2963 */ 2964 public void preDeregister() throws java.lang.Exception { 2965 } 2966 2967 /** 2968 * Allows the MBean to perform any operations needed after having been 2969 * unregistered in the MBean server. 2970 * <P> 2971 * In order to ensure proper run-time semantics of RequireModelMBean, 2972 * Any subclass of RequiredModelMBean overloading or overriding this 2973 * method should call <code>super.postDeregister()</code> in its own 2974 * <code>postDeregister</code> implementation. 2975 */ 2976 public void postDeregister() { 2977 registered = false; 2978 this.server=null; 2979 } 2980 2981 private static final String[] primitiveTypes; 2982 private static final String[] primitiveWrappers; 2983 static { 2984 primitiveTypes = new String[] { 2985 Boolean.TYPE.getName(), 2986 Byte.TYPE.getName(), 2987 Character.TYPE.getName(), 2988 Short.TYPE.getName(), 2989 Integer.TYPE.getName(), 2990 Long.TYPE.getName(), 2991 Float.TYPE.getName(), 2992 Double.TYPE.getName(), 2993 Void.TYPE.getName() 2994 }; 2995 primitiveWrappers = new String[] { 2996 Boolean.class.getName(), 2997 Byte.class.getName(), 2998 Character.class.getName(), 2999 Short.class.getName(), 3000 Integer.class.getName(), 3001 Long.class.getName(), 3002 Float.class.getName(), 3003 Double.class.getName(), 3004 Void.class.getName() 3005 }; 3006 } 3007 }