1 /* 2 * Copyright (c) 2000, 2008, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 /* 26 * @author IBM Corp. 27 * 28 * Copyright IBM Corp. 1999-2000. All rights reserved. 29 */ 30 31 package javax.management.modelmbean; 32 33 import static com.sun.jmx.defaults.JmxProperties.MODELMBEAN_LOGGER; 34 import com.sun.jmx.mbeanserver.GetPropertyAction; 35 36 import java.io.IOException; 37 import java.io.ObjectInputStream; 38 import java.io.ObjectOutputStream; 39 import java.io.ObjectStreamField; 40 import java.security.AccessController; 41 import java.util.logging.Level; 42 43 import javax.management.Descriptor; 44 import javax.management.DescriptorAccess; 45 import javax.management.MBeanNotificationInfo; 46 import javax.management.RuntimeOperationsException; 47 48 /** 49 * <p>The ModelMBeanNotificationInfo object describes a notification emitted 50 * by a ModelMBean. 51 * It is a subclass of MBeanNotificationInfo with the addition of an 52 * associated Descriptor and an implementation of the Descriptor interface.</p> 53 * 54 * <P id="descriptor"> 55 * The fields in the descriptor are defined, but not limited to, the following. 56 * Note that when the Type in this table is Number, a String that is the decimal 57 * representation of a Long can also be used.</P> 58 * 59 * <table border="1" cellpadding="5"> 60 * <tr><th>Name</th><th>Type</th><th>Meaning</th></tr> 61 * <tr><td>name</td><td>String</td> 62 * <td>Notification name.</td></tr> 63 * <tr><td>descriptorType</td><td>String</td> 64 * <td>Must be "notification".</td></tr> 65 * <tr><td>severity</td><td>Number</td> 66 * <td>0-6 where 0: unknown; 1: non-recoverable; 67 * 2: critical, failure; 3: major, severe; 68 * 4: minor, marginal, error; 5: warning; 69 * 6: normal, cleared, informative</td></tr> 70 * <tr><td>messageID</td><td>String</td> 71 * <td>Unique key for message text (to allow translation, analysis).</td></tr> 72 * <tr><td>messageText</td><td>String</td> 73 * <td>Text of notification.</td></tr> 74 * <tr><td>log</td><td>String</td> 75 * <td>T - log message, F - do not log message.</td></tr> 76 * <tr><td>logfile</td><td>String</td> 77 * <td>fully qualified file name appropriate for operating system.</td></tr> 78 * <tr><td>visibility</td><td>Number</td> 79 * <td>1-4 where 1: always visible 4: rarely visible.</td></tr> 80 * <tr><td>presentationString</td><td>String</td> 81 * <td>XML formatted string to allow presentation of data.</td></tr> 82 * </table> 83 * 84 * <p>The default descriptor contains the name, descriptorType, 85 * displayName and severity(=6) fields. The default value of the name 86 * and displayName fields is the name of the Notification class (as 87 * specified by the <code>name</code> parameter of the 88 * ModelMBeanNotificationInfo constructor).</p> 89 * 90 * <p>The <b>serialVersionUID</b> of this class is <code>-7445681389570207141L</code>. 91 * 92 * @since 1.5 93 */ 94 95 @SuppressWarnings("serial") // serialVersionUID is not constant 96 public class ModelMBeanNotificationInfo 97 extends MBeanNotificationInfo 98 implements DescriptorAccess { 99 100 // Serialization compatibility stuff: 101 // Two serial forms are supported in this class. The selected form 102 // depends on system property "jmx.serial.form": 103 // - "1.0" for JMX 1.0 104 // - any other value for JMX 1.1 and higher 105 // 106 // Serial version for old serial form 107 private static final long oldSerialVersionUID = -5211564525059047097L; 108 // 109 // Serial version for new serial form 110 private static final long newSerialVersionUID = -7445681389570207141L; 111 // 112 // Serializable fields in old serial form 113 private static final ObjectStreamField[] oldSerialPersistentFields = 114 { 115 new ObjectStreamField("notificationDescriptor", Descriptor.class), 116 new ObjectStreamField("currClass", String.class) 117 }; 118 // 119 // Serializable fields in new serial form 120 private static final ObjectStreamField[] newSerialPersistentFields = 121 { 122 new ObjectStreamField("notificationDescriptor", Descriptor.class) 123 }; 124 // 125 // Actual serial version and serial form 126 private static final long serialVersionUID; 127 /** 128 * @serialField notificationDescriptor Descriptor The descriptor 129 * containing the appropriate metadata for this instance 130 */ 131 private static final ObjectStreamField[] serialPersistentFields; 132 private static boolean compat = false; 133 static { 134 try { 135 GetPropertyAction act = new GetPropertyAction("jmx.serial.form"); 136 String form = AccessController.doPrivileged(act); 137 compat = (form != null && form.equals("1.0")); 138 } catch (Exception e) { 139 // OK: No compat with 1.0 140 } 141 if (compat) { 142 serialPersistentFields = oldSerialPersistentFields; 143 serialVersionUID = oldSerialVersionUID; 144 } else { 145 serialPersistentFields = newSerialPersistentFields; 146 serialVersionUID = newSerialVersionUID; 147 } 148 } 149 // 150 // END Serialization compatibility stuff 151 152 /** 153 * @serial The descriptor containing the appropriate metadata for 154 * this instance 155 */ 156 private Descriptor notificationDescriptor; 157 158 private static final String currClass = "ModelMBeanNotificationInfo"; 159 160 /** 161 * Constructs a ModelMBeanNotificationInfo object with a default 162 * descriptor. 163 * 164 * @param notifTypes The array of strings (in dot notation) containing 165 * the notification types that may be emitted. 166 * @param name The name of the Notification class. 167 * @param description A human readable description of the 168 * Notification. Optional. 169 **/ 170 public ModelMBeanNotificationInfo(String[] notifTypes, 171 String name, 172 String description) { 173 this(notifTypes,name,description,null); 174 } 175 176 /** 177 * Constructs a ModelMBeanNotificationInfo object. 178 * 179 * @param notifTypes The array of strings (in dot notation) 180 * containing the notification types that may be emitted. 181 * @param name The name of the Notification class. 182 * @param description A human readable description of the Notification. 183 * Optional. 184 * @param descriptor An instance of Descriptor containing the 185 * appropriate metadata for this instance of the 186 * MBeanNotificationInfo. If it is null a default descriptor 187 * will be created. If the descriptor does not contain the 188 * fields "displayName" or "severity", 189 * the missing ones are added with their default values. 190 * 191 * @exception RuntimeOperationsException Wraps an 192 * {@link IllegalArgumentException}. The descriptor is invalid, or 193 * descriptor field "name" is not equal to parameter name, or 194 * descriptor field "descriptorType" is not equal to "notification". 195 * 196 **/ 197 public ModelMBeanNotificationInfo(String[] notifTypes, 198 String name, 199 String description, 200 Descriptor descriptor) { 201 super(notifTypes, name, description); 202 if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) { 203 MODELMBEAN_LOGGER.logp(Level.FINER, 204 ModelMBeanNotificationInfo.class.getName(), 205 "ModelMBeanNotificationInfo", "Entry"); 206 } 207 notificationDescriptor = validDescriptor(descriptor); 208 } 209 210 /** 211 * Constructs a new ModelMBeanNotificationInfo object from this 212 * ModelMBeanNotfication Object. 213 * 214 * @param inInfo the ModelMBeanNotificationInfo to be duplicated 215 * 216 **/ 217 public ModelMBeanNotificationInfo(ModelMBeanNotificationInfo inInfo) { 218 this(inInfo.getNotifTypes(), 219 inInfo.getName(), 220 inInfo.getDescription(),inInfo.getDescriptor()); 221 } 222 223 /** 224 * Creates and returns a new ModelMBeanNotificationInfo which is a 225 * duplicate of this ModelMBeanNotificationInfo. 226 **/ 227 public Object clone () { 228 if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) { 229 MODELMBEAN_LOGGER.logp(Level.FINER, 230 ModelMBeanNotificationInfo.class.getName(), 231 "clone()", "Entry"); 232 } 233 return(new ModelMBeanNotificationInfo(this)); 234 } 235 236 /** 237 * Returns a copy of the associated Descriptor for the 238 * ModelMBeanNotificationInfo. 239 * 240 * @return Descriptor associated with the 241 * ModelMBeanNotificationInfo object. 242 * 243 * @see #setDescriptor 244 **/ 245 public Descriptor getDescriptor() { 246 if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) { 247 MODELMBEAN_LOGGER.logp(Level.FINER, 248 ModelMBeanNotificationInfo.class.getName(), 249 "getDescriptor()", "Entry"); 250 } 251 252 if (notificationDescriptor == null) { 253 // Dead code. Should never happen. 254 if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) { 255 MODELMBEAN_LOGGER.logp(Level.FINER, 256 ModelMBeanNotificationInfo.class.getName(), 257 "getDescriptor()", "Descriptor value is null, " + 258 "setting descriptor to default values"); 259 } 260 notificationDescriptor = validDescriptor(null); 261 } 262 263 return((Descriptor)notificationDescriptor.clone()); 264 } 265 266 /** 267 * Sets associated Descriptor (full replace) for the 268 * ModelMBeanNotificationInfo If the new Descriptor is null, 269 * then the associated Descriptor reverts to a default 270 * descriptor. The Descriptor is validated before it is 271 * assigned. If the new Descriptor is invalid, then a 272 * RuntimeOperationsException wrapping an 273 * IllegalArgumentException is thrown. 274 * 275 * @param inDescriptor replaces the Descriptor associated with the 276 * ModelMBeanNotification interface 277 * 278 * @exception RuntimeOperationsException Wraps an 279 * {@link IllegalArgumentException} for invalid Descriptor. 280 * 281 * @see #getDescriptor 282 **/ 283 public void setDescriptor(Descriptor inDescriptor) { 284 if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) { 285 MODELMBEAN_LOGGER.logp(Level.FINER, 286 ModelMBeanNotificationInfo.class.getName(), 287 "setDescriptor(Descriptor)", "Entry"); 288 } 289 notificationDescriptor = validDescriptor(inDescriptor); 290 } 291 292 /** 293 * Returns a human readable string containing 294 * ModelMBeanNotificationInfo. 295 * 296 * @return a string describing this object. 297 **/ 298 public String toString() { 299 if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) { 300 MODELMBEAN_LOGGER.logp(Level.FINER, 301 ModelMBeanNotificationInfo.class.getName(), 302 "toString()", "Entry"); 303 } 304 305 final StringBuilder retStr = new StringBuilder(); 306 307 retStr.append("ModelMBeanNotificationInfo: ") 308 .append(this.getName()); 309 310 retStr.append(" ; Description: ") 311 .append(this.getDescription()); 312 313 retStr.append(" ; Descriptor: ") 314 .append(this.getDescriptor()); 315 316 retStr.append(" ; Types: "); 317 String[] nTypes = this.getNotifTypes(); 318 for (int i=0; i < nTypes.length; i++) { 319 if (i > 0) retStr.append(", "); 320 retStr.append(nTypes[i]); 321 } 322 return retStr.toString(); 323 } 324 325 326 /** 327 * Clones the passed in Descriptor, sets default values, and checks for validity. 328 * If the Descriptor is invalid (for instance by having the wrong "name"), 329 * this indicates programming error and a RuntimeOperationsException will be thrown. 330 * 331 * The following fields will be defaulted if they are not already set: 332 * descriptorType="notification",displayName=this.getName(), 333 * name=this.getName(),severity="6" 334 * 335 * 336 * @param in Descriptor to be checked, or null which is equivalent to an 337 * empty Descriptor. 338 * @exception RuntimeOperationsException if Descriptor is invalid 339 */ 340 private Descriptor validDescriptor(final Descriptor in) throws RuntimeOperationsException { 341 Descriptor clone; 342 boolean defaulted = (in == null); 343 if (defaulted) { 344 clone = new DescriptorSupport(); 345 MODELMBEAN_LOGGER.finer("Null Descriptor, creating new."); 346 } else { 347 clone = (Descriptor) in.clone(); 348 } 349 350 //Setting defaults. 351 if (defaulted && clone.getFieldValue("name")==null) { 352 clone.setField("name", this.getName()); 353 MODELMBEAN_LOGGER.finer("Defaulting Descriptor name to " + this.getName()); 354 } 355 if (defaulted && clone.getFieldValue("descriptorType")==null) { 356 clone.setField("descriptorType", "notification"); 357 MODELMBEAN_LOGGER.finer("Defaulting descriptorType to \"notification\""); 358 } 359 if (clone.getFieldValue("displayName") == null) { 360 clone.setField("displayName",this.getName()); 361 MODELMBEAN_LOGGER.finer("Defaulting Descriptor displayName to " + this.getName()); 362 } 363 if (clone.getFieldValue("severity") == null) { 364 clone.setField("severity", "6"); 365 MODELMBEAN_LOGGER.finer("Defaulting Descriptor severity field to 6"); 366 } 367 368 //Checking validity 369 if (!clone.isValid()) { 370 throw new RuntimeOperationsException(new IllegalArgumentException("Invalid Descriptor argument"), 371 "The isValid() method of the Descriptor object itself returned false,"+ 372 "one or more required fields are invalid. Descriptor:" + clone.toString()); 373 } 374 if (!getName().equalsIgnoreCase((String) clone.getFieldValue("name"))) { 375 throw new RuntimeOperationsException(new IllegalArgumentException("Invalid Descriptor argument"), 376 "The Descriptor \"name\" field does not match the object described. " + 377 " Expected: "+ this.getName() + " , was: " + clone.getFieldValue("name")); 378 } 379 if (!"notification".equalsIgnoreCase((String) clone.getFieldValue("descriptorType"))) { 380 throw new RuntimeOperationsException(new IllegalArgumentException("Invalid Descriptor argument"), 381 "The Descriptor \"descriptorType\" field does not match the object described. " + 382 " Expected: \"notification\" ," + " was: " + clone.getFieldValue("descriptorType")); 383 } 384 385 return clone; 386 } 387 388 389 /** 390 * Deserializes a {@link ModelMBeanNotificationInfo} from an 391 * {@link ObjectInputStream}. 392 **/ 393 private void readObject(ObjectInputStream in) 394 throws IOException, ClassNotFoundException { 395 // New serial form ignores extra field "currClass" 396 in.defaultReadObject(); 397 } 398 399 400 /** 401 * Serializes a {@link ModelMBeanNotificationInfo} to an 402 * {@link ObjectOutputStream}. 403 **/ 404 private void writeObject(ObjectOutputStream out) 405 throws IOException { 406 if (compat) { 407 // Serializes this instance in the old serial form 408 // 409 ObjectOutputStream.PutField fields = out.putFields(); 410 fields.put("notificationDescriptor", notificationDescriptor); 411 fields.put("currClass", currClass); 412 out.writeFields(); 413 } else { 414 // Serializes this instance in the new serial form 415 // 416 out.defaultWriteObject(); 417 } 418 } 419 420 }