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