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