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