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