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
37import java.lang.management.ManagementFactory;
38import java.lang.reflect.Method;
39import java.math.BigInteger;
40import java.util.ArrayList;
41import java.util.Collections;
42import java.util.List;
43import javax.management.MBeanAttributeInfo;
44import javax.management.MBeanInfo;
45import javax.management.MBeanOperationInfo;
46import javax.management.MBeanServer;
47import javax.management.ObjectName;
48import javax.management.StandardMBean;
49
50public class FeatureOrderTest {
51    private static boolean failed;
52
53    public static interface OrderMXBean {
54        public int getMercury();
55
56        public String getVenus();
57        public void setVenus(String x);
58
59        public BigInteger getEarth();
60        public void setEarth(BigInteger x);
61
62        public boolean isMars();
63
64        public double getJupiter();
65
66        public byte getSaturn();
67
68        public short getUranus();
69        public void setUranus(short x);
70
71        public long getNeptune();
72
73        // No more Pluto!  Yay!
74
75        public void neptune();
76        public void uranus(int x);
77        public int saturn(int x, int y);
78        public short jupiter(int x, long y, double z);
79        public void mars(boolean x);
80        public BigInteger earth();
81        public double earth(double x);  // http://www.imdb.com/title/tt0064519/
82        public String venus();
83        public int mercury();
84    }
85
86    public static interface OrderMBean extends OrderMXBean {}
87
88    public static class OrderImpl implements OrderMXBean {
89        public int getMercury() {
90            return 0;
91        }
92
93        public String getVenus() {
94            return null;
95        }
96
97        public void setVenus(String x) {
98        }
99
100        public BigInteger getEarth() {
101            return null;
102        }
103
104        public void setEarth(BigInteger x) {
105        }
106
107        public boolean isMars() {
108            return true;
109        }
110
111        public double getJupiter() {
112            return 0;
113        }
114
115        public byte getSaturn() {
116            return 0;
117        }
118
119        public short getUranus() {
120            return 0;
121        }
122
123        public void setUranus(short x) {
124        }
125
126        public long getNeptune() {
127            return 0;
128        }
129
130        public void neptune() {
131        }
132
133        public void uranus(int x) {
134        }
135
136        public int saturn(int x, int y) {
137            return 0;
138        }
139
140        public short jupiter(int x, long y, double z) {
141            return 0;
142        }
143
144        public void mars(boolean x) {
145        }
146
147        public BigInteger earth() {
148            return null;
149        }
150
151        public double earth(double x) {
152            return 0;
153        }
154
155        public String venus() {
156            return null;
157        }
158
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
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
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