1 /*
   2  * Copyright (c) 2006, 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 {
  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 }