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 6398884 27 * @summary Test that a method inherited from two different interfaces 28 * appears only once in MBeanInfo. 29 * @author dfuchs 30 * 31 * @run clean TooManyFooTest 32 * @run build TooManyFooTest 33 * @run main TooManyFooTest 34 */ 35 36 import java.lang.management.ManagementFactory; 37 import java.lang.reflect.Method; 38 import java.util.Arrays; 39 import java.util.HashMap; 40 import java.util.HashSet; 41 import java.util.Map; 42 import java.util.Set; 43 import java.util.logging.Logger; 44 import javax.management.Descriptor; 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 import javax.management.openmbean.OpenMBeanOperationInfo; 51 52 /** 53 * Class TooManyFooTest 54 * @author Sun Microsystems, 2005 - All rights reserved. 55 */ 56 public class TooManyFooTest { 57 58 /** 59 * A logger for this class. 60 **/ 61 private static final Logger LOG = 62 Logger.getLogger(TooManyFooTest.class.getName()); 63 64 public static class NumberHolder { 65 public Integer getNumber() { return 0;} 66 public void setNumber(Integer n) {}; 67 } 68 public static class MyNumberHolder extends NumberHolder { 69 70 } 71 public interface Parent1 { 72 public int foo(); // Both in Parent1 and Parent2 73 public Integer barfoo(); // Subtype in Parent1, Super type in Parent2 74 public Long foobar(); // Subtype in Parent1 & MBean, Super type in 75 // Parent2 76 public Number toofoo(); // Subtype in Parent1, Super type in Parent2 77 // Concrete type in MBean 78 public Object toofoofoo(); // Super type in Parent1, Subtype in Parent2, 79 public NumberHolder toobarbar(); // toofoofoo reversed 80 } 81 82 public interface Parent2 { 83 public int foo(); // Both in Parent1 and Parent2 84 public Number barfoo(); 85 public Number foobar(); 86 public Object toofoo(); 87 public NumberHolder toofoofoo(); 88 public Object toobarbar(); 89 } 90 91 public interface ChildMBean extends Parent1, Parent2 { 92 public Long foobar(); 93 public Long toofoo(); 94 } 95 96 public interface ChildMXBean extends Parent1, Parent2 { 97 public Long foobar(); 98 public Long toofoo(); 99 } 100 101 public interface ChildMixMXBean extends ChildMBean, ChildMXBean { 102 } 103 104 public static class Child implements ChildMBean { 105 public int foo() {return 0;} 106 public Long foobar() {return 0L;} 107 public Long toofoo() {return 0L;} 108 public Integer barfoo() {return 0;} 109 public MyNumberHolder toofoofoo() { return null;} 110 public MyNumberHolder toobarbar() { return null;} 111 } 112 113 public static class ChildMix implements ChildMXBean { 114 public int foo() {return 0;} 115 public Long foobar() {return 0L;} 116 public Long toofoo() {return 0L;} 117 public Integer barfoo() {return 0;} 118 public MyNumberHolder toofoofoo() { return null;} 119 public MyNumberHolder toobarbar() { return null;} 120 } 121 122 public static class ChildMixMix extends Child implements ChildMixMXBean { 123 } 124 125 126 /** Creates a new instance of TooManyFooTest */ 127 public TooManyFooTest() { 128 } 129 130 private static final int OPCOUNT; 131 private static final Map<String,String> EXPECTED_TYPES; 132 private static final String[][] type_array = { 133 { "foo", int.class.getName() }, 134 { "foobar", Long.class.getName()}, 135 { "toofoo", Long.class.getName()}, 136 { "barfoo", Integer.class.getName()}, 137 { "toofoofoo", NumberHolder.class.getName()}, 138 { "toobarbar", NumberHolder.class.getName()}, 139 }; 140 static { 141 try { 142 final Set<String> declared = new HashSet<String>(); 143 for (Method m:Child.class.getDeclaredMethods()) { 144 declared.add(m.getName()+Arrays.asList(m.getParameterTypes())); 145 } 146 final Set<String> exposed = new HashSet<String>(); 147 for (Method m:ChildMBean.class.getMethods()) { 148 exposed.add(m.getName()+Arrays.asList(m.getParameterTypes())); 149 } 150 declared.retainAll(exposed); 151 OPCOUNT = declared.size(); 152 EXPECTED_TYPES = new HashMap<String,String>(); 153 for (String[] st:type_array) { 154 EXPECTED_TYPES.put(st[0],st[1]); 155 } 156 } catch (Exception x) { 157 throw new ExceptionInInitializerError(x); 158 } 159 } 160 161 private static void test(Object child, String name, boolean mxbean) 162 throws Exception { 163 final ObjectName childName = 164 new ObjectName("test:type=Child,name="+name); 165 final MBeanServer server = 166 ManagementFactory.getPlatformMBeanServer(); 167 server.registerMBean(child,childName); 168 try { 169 final MBeanInfo info = server.getMBeanInfo(childName); 170 System.out.println(name+": " + info.getDescriptor()); 171 final int len = info.getOperations().length; 172 if (len == OPCOUNT) { 173 System.out.println(name+": OK, only "+OPCOUNT+ 174 " operations here..."); 175 } else { 176 final String qual = (len>OPCOUNT)?"many":"few"; 177 System.err.println(name+": Too "+qual+" foos! Found "+ 178 len+", expected "+OPCOUNT); 179 for (MBeanOperationInfo op : info.getOperations()) { 180 System.err.println("public "+op.getReturnType()+" "+ 181 op.getName()+"();"); 182 } 183 throw new RuntimeException("Too " + qual + 184 " foos for "+name); 185 } 186 187 final Descriptor d = info.getDescriptor(); 188 final String mxstr = String.valueOf(d.getFieldValue("mxbean")); 189 final boolean mxb = 190 (mxstr==null)?false:Boolean.valueOf(mxstr).booleanValue(); 191 System.out.println(name+": mxbean="+mxb); 192 if (mxbean && !mxb) 193 throw new AssertionError("MXBean is not OpenMBean?"); 194 195 for (MBeanOperationInfo mboi : info.getOperations()) { 196 197 // Sanity check 198 if (mxbean && !mboi.getName().equals("foo")) { 199 // The spec doesn't guarantee that the MBeanOperationInfo 200 // of an MXBean will be an OpenMBeanOperationInfo, and in 201 // some circumstances in our implementation it will not. 202 // However, in thsi tests, for all methods but foo(), 203 // it should. 204 // 205 if (!(mboi instanceof OpenMBeanOperationInfo)) 206 throw new AssertionError("Operation "+mboi.getName()+ 207 "() is not Open?"); 208 } 209 210 final String exp = EXPECTED_TYPES.get(mboi.getName()); 211 212 // For MXBeans, we need to compare 'exp' with the original 213 // type - because mboi.getReturnType() returns the OpenType 214 // 215 String type = (String)mboi.getDescriptor(). 216 getFieldValue("originalType"); 217 if (type == null) type = mboi.getReturnType(); 218 if (type.equals(exp)) continue; 219 System.err.println("Bad return type for "+ 220 mboi.getName()+"! Found "+type+ 221 ", expected "+exp); 222 throw new RuntimeException("Bad return type for "+ 223 mboi.getName()); 224 } 225 } finally { 226 server.unregisterMBean(childName); 227 } 228 } 229 230 public static void main(String[] args) throws Exception { 231 final Child child = new Child(); 232 test(child,"Child[MBean]",false); 233 final ChildMix childx = new ChildMix(); 234 test(childx,"ChildMix[MXBean]",true); 235 final ChildMixMix childmx = new ChildMixMix(); 236 test(childmx,"ChildMixMix[MXBean]",false); 237 final StandardMBean schild = new StandardMBean(child,ChildMBean.class); 238 test(schild,"Child[StandarMBean(Child)]",false); 239 final StandardMBean schildx = 240 new StandardMBean(childx,ChildMXBean.class,true); 241 test(schildx,"ChildMix[StandarMXBean(ChildMix)]",true); 242 final StandardMBean schildmx = 243 new StandardMBean(childmx,ChildMixMXBean.class,true); 244 test(schildmx,"ChildMixMix[StandarMXBean(ChildMixMix)]",true); 245 } 246 247 }