1 /*
2  * Copyright (c) 2006, 2015, 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 6486655
27  * @summary Test that attributes and operations appear in the same order
28  * in MBeanInfo as they did in the Standard MBean or MXBean Interface.
29  * @author Eamonn McManus
30  */
31 
32 /*
33  * For more background on this test, see:
34  * http://weblogs.java.net/blog/emcmanus/archive/2006/11/notes_on_unspec.html
35  */
36 
37 import java.lang.management.ManagementFactory;
38 import java.lang.reflect.Method;
39 import java.math.BigInteger;
40 import java.util.ArrayList;
41 import java.util.Collections;
42 import java.util.List;
43 import javax.management.MBeanAttributeInfo;
44 import javax.management.MBeanInfo;
45 import javax.management.MBeanOperationInfo;
46 import javax.management.MBeanServer;
47 import javax.management.ObjectName;
48 import javax.management.StandardMBean;
49 
50 public class FeatureOrderTest {
51     private static boolean failed;
52 
53     public static interface OrderMXBean {
getMercury()54         public int getMercury();
55 
getVenus()56         public String getVenus();
setVenus(String x)57         public void setVenus(String x);
58 
getEarth()59         public BigInteger getEarth();
setEarth(BigInteger x)60         public void setEarth(BigInteger x);
61 
isMars()62         public boolean isMars();
63 
getJupiter()64         public double getJupiter();
65 
getSaturn()66         public byte getSaturn();
67 
getUranus()68         public short getUranus();
setUranus(short x)69         public void setUranus(short x);
70 
getNeptune()71         public long getNeptune();
72 
73         // No more Pluto!  Yay!
74 
neptune()75         public void neptune();
uranus(int x)76         public void uranus(int x);
saturn(int x, int y)77         public int saturn(int x, int y);
jupiter(int x, long y, double z)78         public short jupiter(int x, long y, double z);
mars(boolean x)79         public void mars(boolean x);
earth()80         public BigInteger earth();
earth(double x)81         public double earth(double x);  // http://www.imdb.com/title/tt0064519/
venus()82         public String venus();
mercury()83         public int mercury();
84     }
85 
86     public static interface OrderMBean extends OrderMXBean {}
87 
88     public static class OrderImpl implements OrderMXBean {
getMercury()89         public int getMercury() {
90             return 0;
91         }
92 
getVenus()93         public String getVenus() {
94             return null;
95         }
96 
setVenus(String x)97         public void setVenus(String x) {
98         }
99 
getEarth()100         public BigInteger getEarth() {
101             return null;
102         }
103 
setEarth(BigInteger x)104         public void setEarth(BigInteger x) {
105         }
106 
isMars()107         public boolean isMars() {
108             return true;
109         }
110 
getJupiter()111         public double getJupiter() {
112             return 0;
113         }
114 
getSaturn()115         public byte getSaturn() {
116             return 0;
117         }
118 
getUranus()119         public short getUranus() {
120             return 0;
121         }
122 
setUranus(short x)123         public void setUranus(short x) {
124         }
125 
getNeptune()126         public long getNeptune() {
127             return 0;
128         }
129 
neptune()130         public void neptune() {
131         }
132 
uranus(int x)133         public void uranus(int x) {
134         }
135 
saturn(int x, int y)136         public int saturn(int x, int y) {
137             return 0;
138         }
139 
jupiter(int x, long y, double z)140         public short jupiter(int x, long y, double z) {
141             return 0;
142         }
143 
mars(boolean x)144         public void mars(boolean x) {
145         }
146 
earth()147         public BigInteger earth() {
148             return null;
149         }
150 
earth(double x)151         public double earth(double x) {
152             return 0;
153         }
154 
venus()155         public String venus() {
156             return null;
157         }
158 
mercury()159         public int mercury() {
160             return 0;
161         }
162     }
163 
164     public static class Order extends OrderImpl implements OrderMBean {}
165 
166     private static final boolean[] booleans = {false, true};
167 
main(String[] args)168     public static void main(String[] args) throws Exception {
169         // Build the lists of attributes and operations that we would expect
170         // if they are derived by reflection and preserve the reflection order
171         List<String> expectedAttributeNames = new ArrayList<String>();
172         List<String> expectedOperationNames = new ArrayList<String>();
173         for (Method m : OrderMXBean.class.getMethods()) {
174             String name = m.getName();
175             String attrName = null;
176             if (name.startsWith("get") && !name.equals("get") &&
177                     m.getParameterTypes().length == 0 &&
178                     m.getReturnType() != void.class)
179                 attrName = name.substring(3);
180             else if (name.startsWith("is") && !name.equals("is") &&
181                     m.getParameterTypes().length == 0 &&
182                     m.getReturnType() == boolean.class)
183                 attrName = name.substring(2);
184             else if (name.startsWith("set") && !name.equals("set") &&
185                     m.getReturnType() == void.class &&
186                     m.getParameterTypes().length == 1)
187                 attrName = name.substring(3);
188             if (attrName != null) {
189                 if (!expectedAttributeNames.contains(attrName))
190                     expectedAttributeNames.add(attrName);
191             } else
192                 expectedOperationNames.add(name);
193         }
194 
195         MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
196         for (boolean mxbean : booleans) {
197             for (boolean withStandardMBean : booleans) {
198                 String testName = "MXBean: " + mxbean + "; " +
199                         "using javax.management.StandardMBean: " +
200                         withStandardMBean;
201                 System.out.println("Test case: " + testName);
202                 Object mbean;
203                 if (mxbean) {
204                     if (withStandardMBean) {
205                         mbean = new StandardMBean(
206                                 new OrderImpl(), OrderMXBean.class, true);
207                     } else
208                         mbean = new OrderImpl();
209                 } else {
210                     if (withStandardMBean)
211                         mbean = new StandardMBean(new Order(), OrderMBean.class);
212                     else
213                         mbean = new Order();
214                 }
215                 ObjectName name = new ObjectName(
216                         ":mxbean=" + mxbean + "," + "withStandardMBean=" +
217                         withStandardMBean);
218                 mbs.registerMBean(mbean, name);
219 
220                 /* Make sure we are testing what we think. */
221                 MBeanInfo mbi = mbs.getMBeanInfo(name);
222                 boolean isWithStandardMBean =
223                         mbs.isInstanceOf(name, StandardMBean.class.getName());
224                 System.out.println("classname " +mbi.getClassName());
225                 String mxbeanField =
226                         (String) mbi.getDescriptor().getFieldValue("mxbean");
227                 boolean isMXBean = "true".equalsIgnoreCase(mxbeanField);
228 
229                 if (mxbean != isMXBean)
230                     throw new Exception("Test error: MXBean mismatch");
231                 if (withStandardMBean != isWithStandardMBean)
232                     throw new Exception("Test error: StandardMBean mismatch");
233 
234                 // Check that order of attributes and operations matches
235                 MBeanAttributeInfo[] mbais = mbi.getAttributes();
236                 checkEqual(expectedAttributeNames.size(), mbais.length,
237                         "number of attributes");
238                 List<String> attributeNames = new ArrayList<String>();
239                 for (MBeanAttributeInfo mbai : mbais)
240                     attributeNames.add(mbai.getName());
241                 checkEqual(expectedAttributeNames, attributeNames,
242                         "order of attributes");
243 
244                 MBeanOperationInfo[] mbois = mbi.getOperations();
245                 checkEqual(expectedOperationNames.size(), mbois.length,
246                         "number of operations");
247                 List<String> operationNames = new ArrayList<String>();
248                 for (MBeanOperationInfo mboi : mbois)
249                     operationNames.add(mboi.getName());
250                 checkEqual(expectedOperationNames, operationNames,
251                         "order of operations");
252                 System.out.println();
253             }
254         }
255 
256         if (failed)
257             throw new Exception("TEST FAILED");
258         System.out.println("TEST PASSED");
259     }
260 
checkEqual(Object expected, Object actual, String what)261     private static void checkEqual(Object expected, Object actual, String what) {
262         if (expected.equals(actual))
263             System.out.println("OK: " + what + " matches");
264         else {
265             System.out.println("FAILED: " + what + " differs:");
266             System.out.println("  expected: " + expected);
267             System.out.println("  actual:   " + actual);
268             failed = true;
269         }
270     }
271 }
272