1 /*
   2  * Copyright (c) 2005, 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.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  */
  23 
  24 /*
  25  * @test
  26  * @bug 6221321 6295867
  27  * @summary Test that annotations in Standard MBean interfaces
  28  * correctly produce Descriptor entries
  29  * @author Eamonn McManus
  30  * @run clean AnnotationTest
  31  * @run build AnnotationTest
  32  * @run main AnnotationTest
  33  */
  34 
  35 import java.lang.annotation.Retention;
  36 import java.lang.annotation.RetentionPolicy;
  37 import javax.management.Descriptor;
  38 import javax.management.DescriptorRead;
  39 import javax.management.DescriptorKey;
  40 import javax.management.ImmutableDescriptor;
  41 import javax.management.MBeanAttributeInfo;
  42 import javax.management.MBeanConstructorInfo;
  43 import javax.management.MBeanInfo;
  44 import javax.management.MBeanOperationInfo;
  45 import javax.management.MBeanServer;
  46 import javax.management.ObjectName;
  47 
  48 /*
  49   This test checks that annotations produce Descriptor entries as
  50   specified in javax.management.DescriptorKey.  It does two things:
  51 
  52   - An annotation consisting of an int and a String, each with an
  53     appropriate @DescriptorKey annotation, is placed on every program
  54     element where it can map to a Descriptor, namely:
  55 
  56     . on an MBean interface
  57     . on a getter for a read-only attribute
  58     . on a setter for a write-only attribute
  59     . on the getter but not the setter for a read/write attribute
  60     . on the setter but not the getter for a read/write attribute
  61     . on both the getter and the setter for a read/write attribute
  62     . on an operation
  63     . on each parameter of an operation
  64     . on a public constructor with no parameters
  65     . on a public constructor with a parameter
  66     . on the parameter of that public constructor
  67     . on all of the above for an MXBean instead of an MBean
  68 
  69     The test checks that in each case the corresponding Descriptor
  70     appears in the appropriate place inside the MBean's MBeanInfo.
  71 
  72   - An annotation consisting of enough other types to ensure coverage
  73     is placed on a getter.  The test checks that the generated
  74     MBeanAttributeInfo contains the corresponding Descriptor.  The tested
  75     types are the following:
  76 
  77     . Class
  78     . an enumeration type (java.lang.annotation.RetentionPolicy)
  79     . boolean
  80     . String[]
  81     . Class[]
  82     . int[]
  83     . an array of enumeration type (RetentionPolicy[])
  84     . boolean[]
  85  */
  86 public class AnnotationTest {
  87     private static String failed = null;
  88 
  89     @Retention(RetentionPolicy.RUNTIME)
  90     public static @interface Pair {
  91         @DescriptorKey("x")
  92         int x();
  93         @DescriptorKey("y")
  94         String y();
  95     }
  96 
  97     @Retention(RetentionPolicy.RUNTIME)
  98     public static @interface Full {
  99         @DescriptorKey("class")
 100         Class classValue();
 101         @DescriptorKey("enum")
 102         RetentionPolicy enumValue();
 103         @DescriptorKey("boolean")
 104         boolean booleanValue();
 105         @DescriptorKey("stringArray")
 106         String[] stringArrayValue();
 107         @DescriptorKey("classArray")
 108         Class[] classArrayValue();
 109         @DescriptorKey("intArray")
 110         int[] intArrayValue();
 111         @DescriptorKey("enumArray")
 112         RetentionPolicy[] enumArrayValue();
 113         @DescriptorKey("booleanArray")
 114         boolean[] booleanArrayValue();
 115     }
 116 
 117     /* We use the annotation @Pair(x = 3, y = "foo") everywhere, and this is
 118        the Descriptor that it should produce: */
 119     private static Descriptor expectedDescriptor =
 120         new ImmutableDescriptor(new String[] {"x", "y"},
 121                                 new Object[] {3, "foo"});
 122 
 123     private static Descriptor expectedFullDescriptor =
 124         new ImmutableDescriptor(new String[] {
 125                                     "class", "enum", "boolean", "stringArray",
 126                                     "classArray", "intArray", "enumArray",
 127                                     "booleanArray",
 128                                 },
 129                                 new Object[] {
 130                                     Full.class.getName(),
 131                                     RetentionPolicy.RUNTIME.name(),
 132                                     false,
 133                                     new String[] {"foo", "bar"},
 134                                     new String[] {Full.class.getName()},
 135                                     new int[] {1, 2},
 136                                     new String[] {RetentionPolicy.RUNTIME.name()},
 137                                     new boolean[] {false, true},
 138                                 });
 139 
 140     @Pair(x = 3, y = "foo")
 141     public static interface ThingMBean {
 142         @Pair(x = 3, y = "foo")
 143         @Full(classValue=Full.class,
 144               enumValue=RetentionPolicy.RUNTIME,
 145               booleanValue=false,
 146               stringArrayValue={"foo", "bar"},
 147               classArrayValue={Full.class},
 148               intArrayValue={1, 2},
 149               enumArrayValue={RetentionPolicy.RUNTIME},
 150               booleanArrayValue={false, true})
 151         int getReadOnly();
 152 
 153         @Pair(x = 3, y = "foo")
 154         void setWriteOnly(int x);
 155 
 156         @Pair(x = 3, y = "foo")
 157         int getReadWrite1();
 158         void setReadWrite1(int x);
 159 
 160         @Pair(x = 3, y = "foo")
 161         int getReadWrite2();
 162         @Pair(x = 3, y = "foo")
 163         void setReadWrite2(int x);
 164 
 165         int getReadWrite3();
 166         @Pair(x = 3, y = "foo")
 167         void setReadWrite3(int x);
 168 
 169         @Pair(x = 3, y = "foo")
 170         int operation(@Pair(x = 3, y = "foo") int p1,
 171                       @Pair(x = 3, y = "foo") int p2);
 172     }
 173 
 174     public static class Thing implements ThingMBean {
 175         @Pair(x = 3, y = "foo")
 176         public Thing() {}
 177 
 178         @Pair(x = 3, y = "foo")
 179         public Thing(@Pair(x = 3, y = "foo") int p1) {}
 180 
 181         public int getReadOnly() {return 0;}
 182 
 183         public void setWriteOnly(int x) {}
 184 
 185         public int getReadWrite1() {return 0;}
 186         public void setReadWrite1(int x) {}
 187 
 188         public int getReadWrite2() {return 0;}
 189         public void setReadWrite2(int x) {}
 190 
 191         public int getReadWrite3() {return 0;}
 192         public void setReadWrite3(int x) {}
 193 
 194         public int operation(int p1, int p2) {return 0;}
 195     }
 196 
 197     @Pair(x = 3, y = "foo")
 198     public static interface ThingMXBean extends ThingMBean {}
 199 
 200     public static class ThingImpl implements ThingMXBean {
 201         @Pair(x = 3, y = "foo")
 202         public ThingImpl() {}
 203 
 204         @Pair(x = 3, y = "foo")
 205         public ThingImpl(@Pair(x = 3, y = "foo") int p1) {}
 206 
 207         public int getReadOnly() {return 0;}
 208 
 209         public void setWriteOnly(int x) {}
 210 
 211         public int getReadWrite1() {return 0;}
 212         public void setReadWrite1(int x) {}
 213 
 214         public int getReadWrite2() {return 0;}
 215         public void setReadWrite2(int x) {}
 216 
 217         public int getReadWrite3() {return 0;}
 218         public void setReadWrite3(int x) {}
 219 
 220         public int operation(int p1, int p2) {return 0;}
 221     }
 222 
 223     public static void main(String[] args) throws Exception {
 224         System.out.println("Testing that annotations are correctly " +
 225                            "reflected in Descriptor entries");
 226 
 227         MBeanServer mbs =
 228             java.lang.management.ManagementFactory.getPlatformMBeanServer();
 229         ObjectName on = new ObjectName("a:b=c");
 230 
 231         Thing thing = new Thing();
 232         mbs.registerMBean(thing, on);
 233         check(mbs, on);
 234         mbs.unregisterMBean(on);
 235 
 236         ThingImpl thingImpl = new ThingImpl();
 237         mbs.registerMBean(thingImpl, on);
 238         Descriptor d = mbs.getMBeanInfo(on).getDescriptor();
 239         if (!d.getFieldValue("mxbean").equals("true")) {
 240             System.out.println("NOT OK: expected MXBean");
 241             failed = "Expected MXBean";
 242         }
 243         check(mbs, on);
 244 
 245         if (failed == null)
 246             System.out.println("Test passed");
 247         else
 248             throw new Exception("TEST FAILED: " + failed);
 249     }
 250 
 251     private static void check(MBeanServer mbs, ObjectName on) throws Exception {
 252         MBeanInfo mbi = mbs.getMBeanInfo(on);
 253 
 254         // check the MBean itself
 255         check(mbi);
 256 
 257         // check attributes
 258         MBeanAttributeInfo[] attrs = mbi.getAttributes();
 259         for (MBeanAttributeInfo attr : attrs) {
 260             check(attr);
 261             if (attr.getName().equals("ReadOnly"))
 262                 check("@Full", attr.getDescriptor(), expectedFullDescriptor);
 263         }
 264 
 265         // check operations
 266         MBeanOperationInfo[] ops = mbi.getOperations();
 267         for (MBeanOperationInfo op : ops) {
 268             check(op);
 269             check(op.getSignature());
 270         }
 271 
 272         MBeanConstructorInfo[] constrs = mbi.getConstructors();
 273         for (MBeanConstructorInfo constr : constrs) {
 274             check(constr);
 275             check(constr.getSignature());
 276         }
 277     }
 278 
 279     private static void check(DescriptorRead x) {
 280         check(x, x.getDescriptor(), expectedDescriptor);
 281     }
 282 
 283     private static void check(Object x, Descriptor d, Descriptor expect) {
 284         String fail = null;
 285         try {
 286             Descriptor u = ImmutableDescriptor.union(d, expect);
 287             if (!u.equals(d))
 288                 fail = "should contain " + expect + "; is " + d;
 289         } catch (IllegalArgumentException e) {
 290             fail = e.getMessage();
 291         }
 292         if (fail == null) {
 293             System.out.println("OK: " + x);
 294         } else {
 295             failed = "NOT OK: Incorrect descriptor for: " + x;
 296             System.out.println(failed);
 297             System.out.println("..." + fail);
 298         }
 299     }
 300 
 301     private static void check(DescriptorRead[] xx) {
 302         for (DescriptorRead x : xx)
 303             check(x);
 304     }
 305 }