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
26package javax.management.relation;
27
28
29import com.sun.jmx.mbeanserver.GetPropertyAction;
30
31import java.io.IOException;
32import java.io.ObjectInputStream;
33import java.io.ObjectOutputStream;
34import java.io.ObjectStreamField;
35import java.io.Serializable;
36import java.security.AccessController;
37
38import javax.management.MBeanServer;
39
40import 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}.
46 *
47 * @since 1.5
48 */
49@SuppressWarnings("serial")  // serialVersionUID not constant
50public 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} if role is readable
93     * @serialField isWritable boolean Write access mode: {@code true} 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} if role is readable
140     */
141    private boolean isReadable;
142
143    /**
144     * @serial Write access mode: {@code true} 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 {@code max}.
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 {@code min}
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 {@code RoleInfo} 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 {@code value} 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 {@code value} 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}
610