1 /*
   2  * Copyright (c) 2000, 2006, 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 package javax.management.relation;
  27 
  28 
  29 import com.sun.jmx.mbeanserver.GetPropertyAction;
  30 
  31 import java.io.IOException;
  32 import java.io.ObjectInputStream;
  33 import java.io.ObjectOutputStream;
  34 import java.io.ObjectStreamField;
  35 import java.io.Serializable;
  36 import java.security.AccessController;
  37 
  38 import javax.management.MBeanServer;
  39 
  40 import javax.management.NotCompliantMBeanException;
  41 
  42 /**
  43  * A RoleInfo object summarises a role in a relation type.
  44  *
  45  * <p>The <b>serialVersionUID</b> of this class is <code>2504952983494636987L</code>.
  46  *
  47  * @since 1.5
  48  */
  49 @SuppressWarnings("serial")  // serialVersionUID not constant
  50 public class RoleInfo implements Serializable {
  51 
  52     // Serialization compatibility stuff:
  53     // Two serial forms are supported in this class. The selected form depends
  54     // on system property "jmx.serial.form":
  55     //  - "1.0" for JMX 1.0
  56     //  - any other value for JMX 1.1 and higher
  57     //
  58     // Serial version for old serial form
  59     private static final long oldSerialVersionUID = 7227256952085334351L;
  60     //
  61     // Serial version for new serial form
  62     private static final long newSerialVersionUID = 2504952983494636987L;
  63     //
  64     // Serializable fields in old serial form
  65     private static final ObjectStreamField[] oldSerialPersistentFields =
  66     {
  67       new ObjectStreamField("myName", String.class),
  68       new ObjectStreamField("myIsReadableFlg", boolean.class),
  69       new ObjectStreamField("myIsWritableFlg", boolean.class),
  70       new ObjectStreamField("myDescription", String.class),
  71       new ObjectStreamField("myMinDegree", int.class),
  72       new ObjectStreamField("myMaxDegree", int.class),
  73       new ObjectStreamField("myRefMBeanClassName", String.class)
  74     };
  75     //
  76     // Serializable fields in new serial form
  77     private static final ObjectStreamField[] newSerialPersistentFields =
  78     {
  79       new ObjectStreamField("name", String.class),
  80       new ObjectStreamField("isReadable", boolean.class),
  81       new ObjectStreamField("isWritable", boolean.class),
  82       new ObjectStreamField("description", String.class),
  83       new ObjectStreamField("minDegree", int.class),
  84       new ObjectStreamField("maxDegree", int.class),
  85       new ObjectStreamField("referencedMBeanClassName", String.class)
  86     };
  87     //
  88     // Actual serial version and serial form
  89     private static final long serialVersionUID;
  90     /**
  91      * @serialField name String Role name
  92      * @serialField isReadable boolean Read access mode: <code>true</code> if role is readable
  93      * @serialField isWritable boolean Write access mode: <code>true</code> if role is writable
  94      * @serialField description String Role description
  95      * @serialField minDegree int Minimum degree (i.e. minimum number of referenced MBeans in corresponding role)
  96      * @serialField maxDegree int Maximum degree (i.e. maximum number of referenced MBeans in corresponding role)
  97      * @serialField referencedMBeanClassName String Name of class of MBean(s) expected to be referenced in corresponding role
  98      */
  99     private static final ObjectStreamField[] serialPersistentFields;
 100     private static boolean compat = false;
 101     static {
 102         try {
 103             GetPropertyAction act = new GetPropertyAction("jmx.serial.form");
 104             String form = AccessController.doPrivileged(act);
 105             compat = (form != null && form.equals("1.0"));
 106         } catch (Exception e) {
 107             // OK : Too bad, no compat with 1.0
 108         }
 109         if (compat) {
 110             serialPersistentFields = oldSerialPersistentFields;
 111             serialVersionUID = oldSerialVersionUID;
 112         } else {
 113             serialPersistentFields = newSerialPersistentFields;
 114             serialVersionUID = newSerialVersionUID;
 115         }
 116     }
 117     //
 118     // END Serialization compatibility stuff
 119 
 120     //
 121     // Public constants
 122     //
 123 
 124     /**
 125      * To specify an unlimited cardinality.
 126      */
 127     public static final int ROLE_CARDINALITY_INFINITY = -1;
 128 
 129     //
 130     // Private members
 131     //
 132 
 133     /**
 134      * @serial Role name
 135      */
 136     private String name = null;
 137 
 138     /**
 139      * @serial Read access mode: <code>true</code> if role is readable
 140      */
 141     private boolean isReadable;
 142 
 143     /**
 144      * @serial Write access mode: <code>true</code> if role is writable
 145      */
 146     private boolean isWritable;
 147 
 148     /**
 149      * @serial Role description
 150      */
 151     private String description = null;
 152 
 153     /**
 154      * @serial Minimum degree (i.e. minimum number of referenced MBeans in corresponding role)
 155      */
 156     private int minDegree;
 157 
 158     /**
 159      * @serial Maximum degree (i.e. maximum number of referenced MBeans in corresponding role)
 160      */
 161     private int maxDegree;
 162 
 163     /**
 164      * @serial Name of class of MBean(s) expected to be referenced in corresponding role
 165      */
 166     private String referencedMBeanClassName = null;
 167 
 168     //
 169     // Constructors
 170     //
 171 
 172     /**
 173      * Constructor.
 174      *
 175      * @param roleName  name of the role.
 176      * @param mbeanClassName  name of the class of MBean(s) expected to
 177      * be referenced in corresponding role.  If an MBean <em>M</em> is in
 178      * this role, then the MBean server must return true for
 179      * {@link MBeanServer#isInstanceOf isInstanceOf(M, mbeanClassName)}.
 180      * @param read  flag to indicate if the corresponding role
 181      * can be read
 182      * @param write  flag to indicate if the corresponding role
 183      * can be set
 184      * @param min  minimum degree for role, i.e. minimum number of
 185      * MBeans to provide in corresponding role
 186      * Must be less than or equal to <tt>max</tt>.
 187      * (ROLE_CARDINALITY_INFINITY for unlimited)
 188      * @param max  maximum degree for role, i.e. maximum number of
 189      * MBeans to provide in corresponding role
 190      * Must be greater than or equal to <tt>min</tt>
 191      * (ROLE_CARDINALITY_INFINITY for unlimited)
 192      * @param descr  description of the role (can be null)
 193      *
 194      * @exception IllegalArgumentException  if null parameter
 195      * @exception InvalidRoleInfoException  if the minimum degree is
 196      * greater than the maximum degree.
 197      * @exception ClassNotFoundException As of JMX 1.2, this exception
 198      * can no longer be thrown.  It is retained in the declaration of
 199      * this class for compatibility with existing code.
 200      * @exception NotCompliantMBeanException  if the class mbeanClassName
 201      * is not a MBean class.
 202      */
 203     public RoleInfo(String roleName,
 204                     String mbeanClassName,
 205                     boolean read,
 206                     boolean write,
 207                     int min,
 208                     int max,
 209                     String descr)
 210     throws IllegalArgumentException,
 211            InvalidRoleInfoException,
 212            ClassNotFoundException,
 213            NotCompliantMBeanException {
 214 
 215         init(roleName,
 216              mbeanClassName,
 217              read,
 218              write,
 219              min,
 220              max,
 221              descr);
 222         return;
 223     }
 224 
 225     /**
 226      * Constructor.
 227      *
 228      * @param roleName  name of the role
 229      * @param mbeanClassName  name of the class of MBean(s) expected to
 230      * be referenced in corresponding role.  If an MBean <em>M</em> is in
 231      * this role, then the MBean server must return true for
 232      * {@link MBeanServer#isInstanceOf isInstanceOf(M, mbeanClassName)}.
 233      * @param read  flag to indicate if the corresponding role
 234      * can be read
 235      * @param write  flag to indicate if the corresponding role
 236      * can be set
 237      *
 238      * <P>Minimum and maximum degrees defaulted to 1.
 239      * <P>Description of role defaulted to null.
 240      *
 241      * @exception IllegalArgumentException  if null parameter
 242      * @exception ClassNotFoundException As of JMX 1.2, this exception
 243      * can no longer be thrown.  It is retained in the declaration of
 244      * this class for compatibility with existing code.
 245      * @exception NotCompliantMBeanException As of JMX 1.2, this
 246      * exception can no longer be thrown.  It is retained in the
 247      * declaration of this class for compatibility with existing code.
 248      */
 249     public RoleInfo(String roleName,
 250                     String mbeanClassName,
 251                     boolean read,
 252                     boolean write)
 253     throws IllegalArgumentException,
 254            ClassNotFoundException,
 255            NotCompliantMBeanException {
 256 
 257         try {
 258             init(roleName,
 259                  mbeanClassName,
 260                  read,
 261                  write,
 262                  1,
 263                  1,
 264                  null);
 265         } catch (InvalidRoleInfoException exc) {
 266             // OK : Can never happen as the minimum
 267             //      degree equals the maximum degree.
 268         }
 269 
 270         return;
 271     }
 272 
 273     /**
 274      * Constructor.
 275      *
 276      * @param roleName  name of the role
 277      * @param mbeanClassName  name of the class of MBean(s) expected to
 278      * be referenced in corresponding role.  If an MBean <em>M</em> is in
 279      * this role, then the MBean server must return true for
 280      * {@link MBeanServer#isInstanceOf isInstanceOf(M, mbeanClassName)}.
 281      *
 282      * <P>IsReadable and IsWritable defaulted to true.
 283      * <P>Minimum and maximum degrees defaulted to 1.
 284      * <P>Description of role defaulted to null.
 285      *
 286      * @exception IllegalArgumentException  if null parameter
 287      * @exception ClassNotFoundException As of JMX 1.2, this exception
 288      * can no longer be thrown.  It is retained in the declaration of
 289      * this class for compatibility with existing code.
 290      * @exception NotCompliantMBeanException As of JMX 1.2, this
 291      * exception can no longer be thrown.  It is retained in the
 292      * declaration of this class for compatibility with existing code.
 293       */
 294     public RoleInfo(String roleName,
 295                     String mbeanClassName)
 296     throws IllegalArgumentException,
 297            ClassNotFoundException,
 298            NotCompliantMBeanException {
 299 
 300         try {
 301             init(roleName,
 302                  mbeanClassName,
 303                  true,
 304                  true,
 305                  1,
 306                  1,
 307                  null);
 308         } catch (InvalidRoleInfoException exc) {
 309             // OK : Can never happen as the minimum
 310             //      degree equals the maximum degree.
 311         }
 312 
 313         return;
 314     }
 315 
 316     /**
 317      * Copy constructor.
 318      *
 319      * @param roleInfo the <tt>RoleInfo</tt> instance to be copied.
 320      *
 321      * @exception IllegalArgumentException  if null parameter
 322      */
 323     public RoleInfo(RoleInfo roleInfo)
 324         throws IllegalArgumentException {
 325 
 326         if (roleInfo == null) {
 327             // Revisit [cebro] Localize message
 328             String excMsg = "Invalid parameter.";
 329             throw new IllegalArgumentException(excMsg);
 330         }
 331 
 332         try {
 333             init(roleInfo.getName(),
 334                  roleInfo.getRefMBeanClassName(),
 335                  roleInfo.isReadable(),
 336                  roleInfo.isWritable(),
 337                  roleInfo.getMinDegree(),
 338                  roleInfo.getMaxDegree(),
 339                  roleInfo.getDescription());
 340         } catch (InvalidRoleInfoException exc3) {
 341             // OK : Can never happen as the minimum degree and the maximum
 342             //      degree were already checked at the time the roleInfo
 343             //      instance was created.
 344         }
 345     }
 346 
 347     //
 348     // Accessors
 349     //
 350 
 351     /**
 352      * Returns the name of the role.
 353      *
 354      * @return the name of the role.
 355      */
 356     public String getName() {
 357         return name;
 358     }
 359 
 360     /**
 361      * Returns read access mode for the role (true if it is readable).
 362      *
 363      * @return true if the role is readable.
 364      */
 365     public boolean isReadable() {
 366         return isReadable;
 367     }
 368 
 369     /**
 370      * Returns write access mode for the role (true if it is writable).
 371      *
 372      * @return true if the role is writable.
 373      */
 374     public boolean isWritable() {
 375         return isWritable;
 376     }
 377 
 378     /**
 379      * Returns description text for the role.
 380      *
 381      * @return the description of the role.
 382      */
 383     public String getDescription() {
 384         return description;
 385     }
 386 
 387     /**
 388      * Returns minimum degree for corresponding role reference.
 389      *
 390      * @return the minimum degree.
 391      */
 392     public int getMinDegree() {
 393         return minDegree;
 394     }
 395 
 396     /**
 397      * Returns maximum degree for corresponding role reference.
 398      *
 399      * @return the maximum degree.
 400      */
 401     public int getMaxDegree() {
 402         return maxDegree;
 403     }
 404 
 405     /**
 406      * <p>Returns name of type of MBean expected to be referenced in
 407      * corresponding role.</p>
 408      *
 409      * @return the name of the referenced type.
 410      */
 411     public String getRefMBeanClassName() {
 412         return referencedMBeanClassName;
 413     }
 414 
 415     /**
 416      * Returns true if the <tt>value</tt> parameter is greater than or equal to
 417      * the expected minimum degree, false otherwise.
 418      *
 419      * @param value  the value to be checked
 420      *
 421      * @return true if greater than or equal to minimum degree, false otherwise.
 422      */
 423     public boolean checkMinDegree(int value) {
 424         if (value >= ROLE_CARDINALITY_INFINITY &&
 425             (minDegree == ROLE_CARDINALITY_INFINITY
 426              || value >= minDegree)) {
 427             return true;
 428         } else {
 429             return false;
 430         }
 431     }
 432 
 433     /**
 434      * Returns true if the <tt>value</tt> parameter is lower than or equal to
 435      * the expected maximum degree, false otherwise.
 436      *
 437      * @param value  the value to be checked
 438      *
 439      * @return true if lower than or equal to maximum degree, false otherwise.
 440      */
 441     public boolean checkMaxDegree(int value) {
 442         if (value >= ROLE_CARDINALITY_INFINITY &&
 443             (maxDegree == ROLE_CARDINALITY_INFINITY ||
 444              (value != ROLE_CARDINALITY_INFINITY &&
 445               value <= maxDegree))) {
 446             return true;
 447         } else {
 448             return false;
 449         }
 450     }
 451 
 452     /**
 453      * Returns a string describing the role info.
 454      *
 455      * @return a description of the role info.
 456      */
 457     public String toString() {
 458         StringBuilder result = new StringBuilder();
 459         result.append("role info name: " + name);
 460         result.append("; isReadable: " + isReadable);
 461         result.append("; isWritable: " + isWritable);
 462         result.append("; description: " + description);
 463         result.append("; minimum degree: " + minDegree);
 464         result.append("; maximum degree: " + maxDegree);
 465         result.append("; MBean class: " + referencedMBeanClassName);
 466         return result.toString();
 467     }
 468 
 469     //
 470     // Misc
 471     //
 472 
 473     // Initialization
 474     private void init(String roleName,
 475                       String mbeanClassName,
 476                       boolean read,
 477                       boolean write,
 478                       int min,
 479                       int max,
 480                       String descr)
 481             throws IllegalArgumentException,
 482                    InvalidRoleInfoException {
 483 
 484         if (roleName == null ||
 485             mbeanClassName == null) {
 486             // Revisit [cebro] Localize message
 487             String excMsg = "Invalid parameter.";
 488             throw new IllegalArgumentException(excMsg);
 489         }
 490 
 491         name = roleName;
 492         isReadable = read;
 493         isWritable = write;
 494         if (descr != null) {
 495             description = descr;
 496         }
 497 
 498         boolean invalidRoleInfoFlg = false;
 499         StringBuilder excMsgStrB = new StringBuilder();
 500         if (max != ROLE_CARDINALITY_INFINITY &&
 501             (min == ROLE_CARDINALITY_INFINITY ||
 502              min > max)) {
 503             // Revisit [cebro] Localize message
 504             excMsgStrB.append("Minimum degree ");
 505             excMsgStrB.append(min);
 506             excMsgStrB.append(" is greater than maximum degree ");
 507             excMsgStrB.append(max);
 508             invalidRoleInfoFlg = true;
 509 
 510         } else if (min < ROLE_CARDINALITY_INFINITY ||
 511                    max < ROLE_CARDINALITY_INFINITY) {
 512             // Revisit [cebro] Localize message
 513             excMsgStrB.append("Minimum or maximum degree has an illegal value, must be [0, ROLE_CARDINALITY_INFINITY].");
 514             invalidRoleInfoFlg = true;
 515         }
 516         if (invalidRoleInfoFlg) {
 517             throw new InvalidRoleInfoException(excMsgStrB.toString());
 518         }
 519         minDegree = min;
 520         maxDegree = max;
 521 
 522         referencedMBeanClassName = mbeanClassName;
 523 
 524         return;
 525     }
 526 
 527     /**
 528      * Deserializes a {@link RoleInfo} from an {@link ObjectInputStream}.
 529      */
 530     private void readObject(ObjectInputStream in)
 531             throws IOException, ClassNotFoundException {
 532       if (compat)
 533       {
 534         // Read an object serialized in the old serial form
 535         //
 536         ObjectInputStream.GetField fields = in.readFields();
 537         name = (String) fields.get("myName", null);
 538         if (fields.defaulted("myName"))
 539         {
 540           throw new NullPointerException("myName");
 541         }
 542         isReadable = fields.get("myIsReadableFlg", false);
 543         if (fields.defaulted("myIsReadableFlg"))
 544         {
 545           throw new NullPointerException("myIsReadableFlg");
 546         }
 547         isWritable = fields.get("myIsWritableFlg", false);
 548         if (fields.defaulted("myIsWritableFlg"))
 549         {
 550           throw new NullPointerException("myIsWritableFlg");
 551         }
 552         description = (String) fields.get("myDescription", null);
 553         if (fields.defaulted("myDescription"))
 554         {
 555           throw new NullPointerException("myDescription");
 556         }
 557         minDegree = fields.get("myMinDegree", 0);
 558         if (fields.defaulted("myMinDegree"))
 559         {
 560           throw new NullPointerException("myMinDegree");
 561         }
 562         maxDegree = fields.get("myMaxDegree", 0);
 563         if (fields.defaulted("myMaxDegree"))
 564         {
 565           throw new NullPointerException("myMaxDegree");
 566         }
 567         referencedMBeanClassName = (String) fields.get("myRefMBeanClassName", null);
 568         if (fields.defaulted("myRefMBeanClassName"))
 569         {
 570           throw new NullPointerException("myRefMBeanClassName");
 571         }
 572       }
 573       else
 574       {
 575         // Read an object serialized in the new serial form
 576         //
 577         in.defaultReadObject();
 578       }
 579     }
 580 
 581 
 582     /**
 583      * Serializes a {@link RoleInfo} to an {@link ObjectOutputStream}.
 584      */
 585     private void writeObject(ObjectOutputStream out)
 586             throws IOException {
 587       if (compat)
 588       {
 589         // Serializes this instance in the old serial form
 590         //
 591         ObjectOutputStream.PutField fields = out.putFields();
 592         fields.put("myName", name);
 593         fields.put("myIsReadableFlg", isReadable);
 594         fields.put("myIsWritableFlg", isWritable);
 595         fields.put("myDescription", description);
 596         fields.put("myMinDegree", minDegree);
 597         fields.put("myMaxDegree", maxDegree);
 598         fields.put("myRefMBeanClassName", referencedMBeanClassName);
 599         out.writeFields();
 600       }
 601       else
 602       {
 603         // Serializes this instance in the new serial form
 604         //
 605         out.defaultWriteObject();
 606       }
 607     }
 608 
 609 }