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.lang.reflect.Constructor; 41 import java.security.AccessController; 42 import java.util.logging.Level; 43 44 import javax.management.Descriptor; 45 import javax.management.DescriptorAccess; 46 import javax.management.DescriptorKey; 47 import javax.management.MBeanConstructorInfo; 48 import javax.management.MBeanParameterInfo; 49 import javax.management.RuntimeOperationsException; 50 51 /** 52 * <p>The ModelMBeanConstructorInfo object describes a constructor of the ModelMBean. 53 * It is a subclass of MBeanConstructorInfo with the addition of an associated Descriptor 54 * and an implementation of the DescriptorAccess interface.</p> 55 * 56 * <P id="descriptor"> 57 * The fields in the descriptor are defined, but not limited to, the following. 58 * Note that when the Type in this table is Number, a String that is the decimal 59 * representation of a Long can also be used.</P> 60 * 61 * <table border="1" cellpadding="5"> 62 * <tr><th>Name</th><th>Type</th><th>Meaning</th></tr> 63 * <tr><td>name</td><td>String</td> 64 * <td>Constructor name.</td></tr> 65 * <tr><td>descriptorType</td><td>String</td> 66 * <td>Must be "operation".</td></tr> 67 * <tr><td>role</td><td>String</td> 68 * <td>Must be "constructor".</td></tr> 69 * <tr><td>displayName</td><td>String</td> 70 * <td>Human readable name of constructor.</td></tr> 71 * <tr><td>visibility</td><td>Number</td> 72 * <td>1-4 where 1: always visible 4: rarely visible.</td></tr> 73 * <tr><td>presentationString</td><td>String</td> 74 * <td>XML formatted string to describe how to present operation</td></tr> 75 * </table> 76 * 77 * <p>The {@code persistPolicy} and {@code currencyTimeLimit} fields 78 * are meaningless for constructors, but are not considered invalid.</p> 79 * 80 * <p>The default descriptor will have the {@code name}, {@code 81 * descriptorType}, {@code displayName} and {@code role} fields. 82 * 83 * <p>The <b>serialVersionUID</b> of this class is <code>3862947819818064362L</code>. 84 * 85 * @since 1.5 86 */ 87 88 @SuppressWarnings("serial") // serialVersionUID is not constant 89 public class ModelMBeanConstructorInfo 90 extends MBeanConstructorInfo 91 implements DescriptorAccess { 92 93 // Serialization compatibility stuff: 94 // Two serial forms are supported in this class. The selected form depends 95 // on system property "jmx.serial.form": 96 // - "1.0" for JMX 1.0 97 // - any other value for JMX 1.1 and higher 98 // 99 // Serial version for old serial form 100 private static final long oldSerialVersionUID = -4440125391095574518L; 101 // 102 // Serial version for new serial form 103 private static final long newSerialVersionUID = 3862947819818064362L; 104 // 105 // Serializable fields in old serial form 106 private static final ObjectStreamField[] oldSerialPersistentFields = 107 { 108 new ObjectStreamField("consDescriptor", Descriptor.class), 109 new ObjectStreamField("currClass", String.class) 110 }; 111 // 112 // Serializable fields in new serial form 113 private static final ObjectStreamField[] newSerialPersistentFields = 114 { 115 new ObjectStreamField("consDescriptor", Descriptor.class) 116 }; 117 // 118 // Actual serial version and serial form 119 private static final long serialVersionUID; 120 /** 121 * @serialField consDescriptor Descriptor The {@link Descriptor} containing the metadata for this instance 122 */ 123 private static final ObjectStreamField[] serialPersistentFields; 124 private static boolean compat = false; 125 static { 126 try { 127 GetPropertyAction act = new GetPropertyAction("jmx.serial.form"); 128 String form = AccessController.doPrivileged(act); 129 compat = (form != null && form.equals("1.0")); 130 } catch (Exception e) { 131 // OK: No compat with 1.0 132 } 133 if (compat) { 134 serialPersistentFields = oldSerialPersistentFields; 135 serialVersionUID = oldSerialVersionUID; 136 } else { 137 serialPersistentFields = newSerialPersistentFields; 138 serialVersionUID = newSerialVersionUID; 139 } 140 } 141 // 142 // END Serialization compatibility stuff 143 144 /** 145 * @serial The {@link Descriptor} containing the metadata for this instance 146 */ 147 private Descriptor consDescriptor = validDescriptor(null); 148 149 private final static String currClass = "ModelMBeanConstructorInfo"; 150 151 152 /** 153 * Constructs a ModelMBeanConstructorInfo object with a default 154 * descriptor. The {@link Descriptor} of the constructed 155 * object will include fields contributed by any annotations on 156 * the {@code Constructor} object that contain the {@link 157 * DescriptorKey} meta-annotation. 158 * 159 * @param description A human readable description of the constructor. 160 * @param constructorMethod The java.lang.reflect.Constructor object 161 * describing the MBean constructor. 162 */ 163 public ModelMBeanConstructorInfo(String description, 164 Constructor<?> constructorMethod) 165 { 166 super(description, constructorMethod); 167 if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) { 168 MODELMBEAN_LOGGER.logp(Level.FINER, 169 ModelMBeanConstructorInfo.class.getName(), 170 "ModelMBeanConstructorInfo(String,Constructor)", 171 "Entry"); 172 } 173 consDescriptor = validDescriptor(null); 174 175 // put getter and setter methods in constructors list 176 // create default descriptor 177 178 } 179 180 /** 181 * Constructs a ModelMBeanConstructorInfo object. The {@link 182 * Descriptor} of the constructed object will include fields 183 * contributed by any annotations on the {@code Constructor} 184 * object that contain the {@link DescriptorKey} 185 * meta-annotation. 186 * 187 * @param description A human readable description of the constructor. 188 * @param constructorMethod The java.lang.reflect.Constructor object 189 * describing the ModelMBean constructor. 190 * @param descriptor An instance of Descriptor containing the 191 * appropriate metadata for this instance of the 192 * ModelMBeanConstructorInfo. If it is null, then a default 193 * descriptor will be created. If the descriptor does not 194 * contain the field "displayName" this field is added in the 195 * descriptor with its default value. 196 * 197 * @exception RuntimeOperationsException Wraps an 198 * IllegalArgumentException. The descriptor is invalid, or 199 * descriptor field "name" is not equal to name 200 * parameter, or descriptor field "descriptorType" is 201 * not equal to "operation" or descriptor field "role" is 202 * present but not equal to "constructor". 203 */ 204 205 public ModelMBeanConstructorInfo(String description, 206 Constructor<?> constructorMethod, 207 Descriptor descriptor) 208 { 209 210 super(description, constructorMethod); 211 // put getter and setter methods in constructors list 212 if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) { 213 MODELMBEAN_LOGGER.logp(Level.FINER, 214 ModelMBeanConstructorInfo.class.getName(), 215 "ModelMBeanConstructorInfo(" + 216 "String,Constructor,Descriptor)", "Entry"); 217 } 218 consDescriptor = validDescriptor(descriptor); 219 } 220 /** 221 * Constructs a ModelMBeanConstructorInfo object with a default descriptor. 222 * 223 * @param name The name of the constructor. 224 * @param description A human readable description of the constructor. 225 * @param signature MBeanParameterInfo object array describing the parameters(arguments) of the constructor. 226 */ 227 228 public ModelMBeanConstructorInfo(String name, 229 String description, 230 MBeanParameterInfo[] signature) 231 { 232 233 super(name, description, signature); 234 // create default descriptor 235 if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) { 236 MODELMBEAN_LOGGER.logp(Level.FINER, 237 ModelMBeanConstructorInfo.class.getName(), 238 "ModelMBeanConstructorInfo(" + 239 "String,String,MBeanParameterInfo[])", "Entry"); 240 } 241 consDescriptor = validDescriptor(null); 242 } 243 /** 244 * Constructs a ModelMBeanConstructorInfo object. 245 * 246 * @param name The name of the constructor. 247 * @param description A human readable description of the constructor. 248 * @param signature MBeanParameterInfo objects describing the parameters(arguments) of the constructor. 249 * @param descriptor An instance of Descriptor containing the appropriate metadata 250 * for this instance of the MBeanConstructorInfo. If it is null then a default descriptor will be created. 251 * If the descriptor does not contain the field "displayName" this field 252 * is added in the descriptor with its default value. 253 * 254 * @exception RuntimeOperationsException Wraps an 255 * IllegalArgumentException. The descriptor is invalid, or 256 * descriptor field "name" is not equal to name 257 * parameter, or descriptor field "descriptorType" is 258 * not equal to "operation" or descriptor field "role" is 259 * present but not equal to "constructor". 260 */ 261 262 public ModelMBeanConstructorInfo(String name, 263 String description, 264 MBeanParameterInfo[] signature, 265 Descriptor descriptor) 266 { 267 super(name, description, signature); 268 if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) { 269 MODELMBEAN_LOGGER.logp(Level.FINER, 270 ModelMBeanConstructorInfo.class.getName(), 271 "ModelMBeanConstructorInfo(" + 272 "String,String,MBeanParameterInfo[],Descriptor)", 273 "Entry"); 274 } 275 consDescriptor = validDescriptor(descriptor); 276 } 277 278 /** 279 * Constructs a new ModelMBeanConstructorInfo object from this ModelMBeanConstructor Object. 280 * 281 * @param old the ModelMBeanConstructorInfo to be duplicated 282 * 283 */ 284 ModelMBeanConstructorInfo(ModelMBeanConstructorInfo old) 285 { 286 super(old.getName(), old.getDescription(), old.getSignature()); 287 if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) { 288 MODELMBEAN_LOGGER.logp(Level.FINER, 289 ModelMBeanConstructorInfo.class.getName(), 290 "ModelMBeanConstructorInfo(" + 291 "ModelMBeanConstructorInfo)", "Entry"); 292 } 293 consDescriptor = validDescriptor(consDescriptor); 294 } 295 296 /** 297 * Creates and returns a new ModelMBeanConstructorInfo which is a duplicate of this ModelMBeanConstructorInfo. 298 * 299 */ 300 @Override 301 public Object clone () 302 { 303 if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) { 304 MODELMBEAN_LOGGER.logp(Level.FINER, 305 ModelMBeanConstructorInfo.class.getName(), 306 "clone()", "Entry"); 307 } 308 return(new ModelMBeanConstructorInfo(this)) ; 309 } 310 311 /** 312 * Returns a copy of the associated Descriptor. 313 * 314 * @return Descriptor associated with the 315 * ModelMBeanConstructorInfo object. 316 * 317 * @see #setDescriptor 318 */ 319 320 321 @Override 322 public Descriptor getDescriptor() 323 { 324 if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) { 325 MODELMBEAN_LOGGER.logp(Level.FINER, 326 ModelMBeanConstructorInfo.class.getName(), 327 "getDescriptor()", "Entry"); 328 } 329 if (consDescriptor == null){ 330 consDescriptor = validDescriptor(null); 331 } 332 return((Descriptor)consDescriptor.clone()); 333 } 334 /** 335 * Sets associated Descriptor (full replace) of 336 * ModelMBeanConstructorInfo. If the new Descriptor is null, 337 * then the associated Descriptor reverts to a default 338 * descriptor. The Descriptor is validated before it is 339 * assigned. If the new Descriptor is invalid, then a 340 * RuntimeOperationsException wrapping an 341 * IllegalArgumentException is thrown. 342 * 343 * @param inDescriptor replaces the Descriptor associated with 344 * the ModelMBeanConstructor. If the descriptor does not 345 * contain all the following fields, the missing ones are added with 346 * their default values: displayName, name, role, descriptorType. 347 * 348 * @exception RuntimeOperationsException Wraps an 349 * IllegalArgumentException. The descriptor is invalid, or 350 * descriptor field "name" is present but not equal to name 351 * parameter, or descriptor field "descriptorType" is present 352 * but not equal to "operation" or descriptor field "role" is 353 * present but not equal to "constructor". 354 * 355 * @see #getDescriptor 356 */ 357 public void setDescriptor(Descriptor inDescriptor) 358 { 359 if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) { 360 MODELMBEAN_LOGGER.logp(Level.FINER, 361 ModelMBeanConstructorInfo.class.getName(), 362 "setDescriptor()", "Entry"); 363 } 364 consDescriptor = validDescriptor(inDescriptor); 365 } 366 367 /** 368 * Returns a string containing the entire contents of the ModelMBeanConstructorInfo in human readable form. 369 */ 370 @Override 371 public String toString() 372 { 373 if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) { 374 MODELMBEAN_LOGGER.logp(Level.FINER, 375 ModelMBeanConstructorInfo.class.getName(), 376 "toString()", "Entry"); 377 } 378 String retStr = 379 "ModelMBeanConstructorInfo: " + this.getName() + 380 " ; Description: " + this.getDescription() + 381 " ; Descriptor: " + this.getDescriptor() + 382 " ; Signature: "; 383 MBeanParameterInfo[] pTypes = this.getSignature(); 384 for (int i=0; i < pTypes.length; i++) 385 { 386 retStr = retStr.concat((pTypes[i]).getType() + ", "); 387 } 388 return retStr; 389 } 390 391 392 /** 393 * Clones the passed in Descriptor, sets default values, and checks for validity. 394 * If the Descriptor is invalid (for instance by having the wrong "name"), 395 * this indicates programming error and a RuntimeOperationsException will be thrown. 396 * 397 * The following fields will be defaulted if they are not already set: 398 * displayName=this.getName(), name=this.getName(), descriptorType="operation", 399 * role="constructor" 400 * 401 * 402 * @param in Descriptor to be checked, or null which is equivalent to 403 * an empty Descriptor. 404 * @exception RuntimeOperationsException if Descriptor is invalid 405 */ 406 private Descriptor validDescriptor(final Descriptor in) throws RuntimeOperationsException { 407 Descriptor clone; 408 boolean defaulted = (in == null); 409 if (defaulted) { 410 clone = new DescriptorSupport(); 411 MODELMBEAN_LOGGER.finer("Null Descriptor, creating new."); 412 } else { 413 clone = (Descriptor) in.clone(); 414 } 415 416 //Setting defaults. 417 if (defaulted && clone.getFieldValue("name")==null) { 418 clone.setField("name", this.getName()); 419 MODELMBEAN_LOGGER.finer("Defaulting Descriptor name to " + this.getName()); 420 } 421 if (defaulted && clone.getFieldValue("descriptorType")==null) { 422 clone.setField("descriptorType", "operation"); 423 MODELMBEAN_LOGGER.finer("Defaulting descriptorType to \"operation\""); 424 } 425 if (clone.getFieldValue("displayName") == null) { 426 clone.setField("displayName",this.getName()); 427 MODELMBEAN_LOGGER.finer("Defaulting Descriptor displayName to " + this.getName()); 428 } 429 if (clone.getFieldValue("role") == null) { 430 clone.setField("role","constructor"); 431 MODELMBEAN_LOGGER.finer("Defaulting Descriptor role field to \"constructor\""); 432 } 433 434 //Checking validity 435 if (!clone.isValid()) { 436 throw new RuntimeOperationsException(new IllegalArgumentException("Invalid Descriptor argument"), 437 "The isValid() method of the Descriptor object itself returned false,"+ 438 "one or more required fields are invalid. Descriptor:" + clone.toString()); 439 } 440 if (!getName().equalsIgnoreCase((String) clone.getFieldValue("name"))) { 441 throw new RuntimeOperationsException(new IllegalArgumentException("Invalid Descriptor argument"), 442 "The Descriptor \"name\" field does not match the object described. " + 443 " Expected: "+ this.getName() + " , was: " + clone.getFieldValue("name")); 444 } 445 if (!"operation".equalsIgnoreCase((String) clone.getFieldValue("descriptorType"))) { 446 throw new RuntimeOperationsException(new IllegalArgumentException("Invalid Descriptor argument"), 447 "The Descriptor \"descriptorType\" field does not match the object described. " + 448 " Expected: \"operation\" ," + " was: " + clone.getFieldValue("descriptorType")); 449 } 450 if (! ((String)clone.getFieldValue("role")).equalsIgnoreCase("constructor")) { 451 throw new RuntimeOperationsException(new IllegalArgumentException("Invalid Descriptor argument"), 452 "The Descriptor \"role\" field does not match the object described. " + 453 " Expected: \"constructor\" ," + " was: " + clone.getFieldValue("role")); 454 } 455 456 return clone; 457 } 458 459 /** 460 * Deserializes a {@link ModelMBeanConstructorInfo} from an {@link ObjectInputStream}. 461 */ 462 private void readObject(ObjectInputStream in) 463 throws IOException, ClassNotFoundException { 464 // New serial form ignores extra field "currClass" 465 in.defaultReadObject(); 466 } 467 468 469 /** 470 * Serializes a {@link ModelMBeanConstructorInfo} to an {@link ObjectOutputStream}. 471 */ 472 private void writeObject(ObjectOutputStream out) 473 throws IOException { 474 if (compat) 475 { 476 // Serializes this instance in the old serial form 477 // 478 ObjectOutputStream.PutField fields = out.putFields(); 479 fields.put("consDescriptor", consDescriptor); 480 fields.put("currClass", currClass); 481 out.writeFields(); 482 } 483 else 484 { 485 // Serializes this instance in the new serial form 486 // 487 out.defaultWriteObject(); 488 } 489 } 490 491 }