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")
x()92         int x();
93         @DescriptorKey("y")
y()94         String y();
95     }
96 
97     @Retention(RetentionPolicy.RUNTIME)
98     public static @interface Full {
99         @DescriptorKey("class")
classValue()100         Class classValue();
101         @DescriptorKey("enum")
enumValue()102         RetentionPolicy enumValue();
103         @DescriptorKey("boolean")
booleanValue()104         boolean booleanValue();
105         @DescriptorKey("stringArray")
stringArrayValue()106         String[] stringArrayValue();
107         @DescriptorKey("classArray")
classArrayValue()108         Class[] classArrayValue();
109         @DescriptorKey("intArray")
intArrayValue()110         int[] intArrayValue();
111         @DescriptorKey("enumArray")
enumArrayValue()112         RetentionPolicy[] enumArrayValue();
113         @DescriptorKey("booleanArray")
booleanArrayValue()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})
getReadOnly()151         int getReadOnly();
152 
153         @Pair(x = 3, y = "foo")
setWriteOnly(int x)154         void setWriteOnly(int x);
155 
156         @Pair(x = 3, y = "foo")
getReadWrite1()157         int getReadWrite1();
setReadWrite1(int x)158         void setReadWrite1(int x);
159 
160         @Pair(x = 3, y = "foo")
getReadWrite2()161         int getReadWrite2();
162         @Pair(x = 3, y = "foo")
setReadWrite2(int x)163         void setReadWrite2(int x);
164 
getReadWrite3()165         int getReadWrite3();
166         @Pair(x = 3, y = "foo")
setReadWrite3(int x)167         void setReadWrite3(int x);
168 
169         @Pair(x = 3, y = "foo")
operation(@airx = 3, y = R) int p1, @Pair(x = 3, y = R) int p2)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")
Thing()176         public Thing() {}
177 
178         @Pair(x = 3, y = "foo")
Thing(@airx = 3, y = R) int p1)179         public Thing(@Pair(x = 3, y = "foo") int p1) {}
180 
getReadOnly()181         public int getReadOnly() {return 0;}
182 
setWriteOnly(int x)183         public void setWriteOnly(int x) {}
184 
getReadWrite1()185         public int getReadWrite1() {return 0;}
setReadWrite1(int x)186         public void setReadWrite1(int x) {}
187 
getReadWrite2()188         public int getReadWrite2() {return 0;}
setReadWrite2(int x)189         public void setReadWrite2(int x) {}
190 
getReadWrite3()191         public int getReadWrite3() {return 0;}
setReadWrite3(int x)192         public void setReadWrite3(int x) {}
193 
operation(int p1, int p2)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")
ThingImpl()202         public ThingImpl() {}
203 
204         @Pair(x = 3, y = "foo")
ThingImpl(@airx = 3, y = R) int p1)205         public ThingImpl(@Pair(x = 3, y = "foo") int p1) {}
206 
getReadOnly()207         public int getReadOnly() {return 0;}
208 
setWriteOnly(int x)209         public void setWriteOnly(int x) {}
210 
getReadWrite1()211         public int getReadWrite1() {return 0;}
setReadWrite1(int x)212         public void setReadWrite1(int x) {}
213 
getReadWrite2()214         public int getReadWrite2() {return 0;}
setReadWrite2(int x)215         public void setReadWrite2(int x) {}
216 
getReadWrite3()217         public int getReadWrite3() {return 0;}
setReadWrite3(int x)218         public void setReadWrite3(int x) {}
219 
operation(int p1, int p2)220         public int operation(int p1, int p2) {return 0;}
221     }
222 
main(String[] args)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 
check(MBeanServer mbs, ObjectName on)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 
check(DescriptorRead x)279     private static void check(DescriptorRead x) {
280         check(x, x.getDescriptor(), expectedDescriptor);
281     }
282 
check(Object x, Descriptor d, Descriptor expect)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 
check(DescriptorRead[] xx)301     private static void check(DescriptorRead[] xx) {
302         for (DescriptorRead x : xx)
303             check(x);
304     }
305 }
306