1 /* 2 * Copyright (c) 2005, 2016, 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 8058865 27 * @summary Checks correct collection of MXBean's class after unregistration 28 * @author Olivier Lagneau 29 * 30 * @library /lib/testlibrary 31 * 32 * @run main/othervm/timeout=300 MXBeanLoadingTest1 33 */ 34 35 import java.lang.ref.WeakReference; 36 import java.net.URL; 37 import java.util.Arrays; 38 import java.util.Map; 39 import javax.management.Attribute; 40 import javax.management.JMX; 41 import javax.management.MBeanAttributeInfo; 42 import javax.management.MBeanInfo; 43 import javax.management.MBeanOperationInfo; 44 import javax.management.MBeanServer; 45 import javax.management.MBeanServerFactory; 46 import javax.management.MXBean; 47 import javax.management.ObjectName; 48 import javax.management.loading.PrivateMLet; 49 import javax.management.openmbean.CompositeData; 50 import javax.management.openmbean.CompositeDataSupport; 51 import javax.management.openmbean.CompositeType; 52 import javax.management.openmbean.OpenType; 53 import javax.management.openmbean.SimpleType; 54 55 public class MXBeanLoadingTest1 { 56 57 public static void main(String[] args) throws Exception { 58 MXBeanLoadingTest1 test = new MXBeanLoadingTest1(); 59 test.run((Map<String, Object>)null); 60 } 61 62 63 public void run(Map<String, Object> args) { 64 65 System.out.println("MXBeanLoadingTest1::run: Start") ; 66 67 try { 68 System.out.println("We ensure no reference is retained on MXBean class" 69 + " after it is unregistered. We take time to perform" 70 + " some little extra check of Descriptors, MBean*Info."); 71 72 ClassLoader myClassLoader = MXBeanLoadingTest1.class.getClassLoader(); 73 if(myClassLoader == null) 74 throw new RuntimeException("Test Failed : Null Classloader for test"); 75 URL url = myClassLoader.getResource( 76 MXBeanLoadingTest1.class.getCanonicalName() 77 .replace(".", "/") + ".class"); 78 String clsLoadPath = url.toURI().toString(). 79 replaceAll(MXBeanLoadingTest1.class.getSimpleName() 80 + ".class", ""); 81 82 URL[] urls = new URL[]{new URL(clsLoadPath)}; 83 PrivateMLet mlet = new PrivateMLet(urls, null, false); 84 Class<?> shadowClass = mlet.loadClass(TestMXBean.class.getName()); 85 86 if (shadowClass == TestMXBean.class) { 87 String message = "(ERROR) MLet got original TestMXBean, not shadow"; 88 System.out.println(message); 89 throw new RuntimeException(message); 90 } 91 shadowClass = null; 92 93 MBeanServer mbs = MBeanServerFactory.createMBeanServer(); 94 ObjectName mletName = new ObjectName("x:type=mlet"); 95 mbs.registerMBean(mlet, mletName); 96 97 ObjectName testName = new ObjectName("x:type=test"); 98 mbs.createMBean(Test.class.getName(), testName, mletName); 99 100 // That test fails because the MXBean instance is accessed via 101 // a delegate OpenMBean which has 102 ClassLoader testLoader = mbs.getClassLoaderFor(testName); 103 104 if (testLoader != mlet) { 105 System.out.println("MLet " + mlet); 106 String message = "(ERROR) MXBean's class loader is not MLet: " 107 + testLoader; 108 System.out.println(message); 109 throw new RuntimeException(message); 110 } 111 testLoader = null; 112 113 114 // Cycle get/set/get of the attribute of type Luis. 115 // We check the set is effective. 116 CompositeData cd_B = (CompositeData)mbs.getAttribute(testName, "B"); 117 CompositeType compType_B = cd_B.getCompositeType(); 118 119 CompositeDataSupport cds_B = 120 new CompositeDataSupport(compType_B, 121 new String[]{"something"}, 122 new Object[]{Integer.valueOf(13)}); 123 Attribute myAtt = new Attribute("B", cds_B); 124 mbs.setAttribute(testName, myAtt); 125 126 CompositeData cd_B2 = (CompositeData)mbs.getAttribute(testName, "B"); 127 128 if ( ((Integer)cd_B2.get("something")).intValue() != 13 ) { 129 String message = "(ERROR) The setAttribute of att B did not work;" 130 + " expect Luis.something = 13 but got " 131 + cd_B2.get("something"); 132 System.out.println(message); 133 throw new RuntimeException(message); 134 } 135 136 MBeanInfo info = mbs.getMBeanInfo(testName); 137 String mxbeanField = 138 (String)info.getDescriptor().getFieldValue(JMX.MXBEAN_FIELD); 139 140 if ( mxbeanField == null || ! mxbeanField.equals("true")) { 141 String message = "(ERROR) Improper mxbean field value " 142 + mxbeanField; 143 System.out.println(message); 144 throw new RuntimeException(message); 145 } 146 147 // Check the 2 attributes. 148 MBeanAttributeInfo[] attrs = info.getAttributes(); 149 150 if ( attrs.length == 2 ) { 151 for (MBeanAttributeInfo mbai : attrs) { 152 String originalTypeFieldValue = 153 (String)mbai.getDescriptor().getFieldValue(JMX.ORIGINAL_TYPE_FIELD); 154 OpenType<?> openTypeFieldValue = 155 (OpenType<?>)mbai.getDescriptor().getFieldValue(JMX.OPEN_TYPE_FIELD); 156 157 if ( mbai.getName().equals("A") ) { 158 if ( !mbai.isReadable() || !mbai.isWritable() 159 || mbai.isIs() 160 || !mbai.getType().equals("int") ) { 161 String message = "(ERROR) Unexpected MBeanAttributeInfo for A " 162 + mbai; 163 System.out.println(message); 164 throw new RuntimeException(message); 165 } 166 167 if ( ! originalTypeFieldValue.equals("int") ) { 168 String message = "(ERROR) Unexpected originalType in Descriptor for A " 169 + originalTypeFieldValue; 170 System.out.println(message); 171 throw new RuntimeException(message); 172 } 173 174 if ( ! openTypeFieldValue.equals(SimpleType.INTEGER) ) { 175 String message = "(ERROR) Unexpected openType in Descriptor for A " 176 + originalTypeFieldValue; 177 System.out.println(message); 178 throw new RuntimeException(message); 179 } 180 } else if ( mbai.getName().equals("B") ) { 181 if ( !mbai.isReadable() || !mbai.isWritable() 182 || mbai.isIs() 183 || !mbai.getType().equals("javax.management.openmbean.CompositeData") ) { 184 String message = "(ERROR) Unexpected MBeanAttributeInfo for B " 185 + mbai; 186 System.out.println(message); 187 throw new RuntimeException(message); 188 } 189 190 if ( ! originalTypeFieldValue.equals(Luis.class.getName()) ) { 191 String message = "(ERROR) Unexpected originalType in Descriptor for B " 192 + originalTypeFieldValue; 193 System.out.println(message); 194 throw new RuntimeException(message); 195 } 196 197 if ( ! openTypeFieldValue.equals(compType_B) ) { 198 String message = "(ERROR) Unexpected openType in Descriptor for B " 199 + compType_B; 200 System.out.println(message); 201 throw new RuntimeException(message); 202 } 203 } else { 204 String message = "(ERROR) Unknown attribute name"; 205 System.out.println(message); 206 throw new RuntimeException(message); 207 } 208 } 209 } else { 210 String message = "(ERROR) Unexpected MBeanAttributeInfo array" 211 + Arrays.deepToString(attrs); 212 System.out.println(message); 213 throw new RuntimeException(message); 214 } 215 216 // Check the MXBean operation. 217 MBeanOperationInfo[] ops = info.getOperations(); 218 // The impact is ACTION_INFO as for a standard MBean it is UNKNOWN, 219 // logged 6320104. 220 if (ops.length != 1 || !ops[0].getName().equals("bogus") 221 || ops[0].getSignature().length > 0 222 || !ops[0].getReturnType().equals("void")) { 223 String message = "(ERROR) Unexpected MBeanOperationInfo array " 224 + Arrays.deepToString(ops); 225 System.out.println(message); 226 throw new RuntimeException(message); 227 } 228 229 String originalTypeFieldValue = 230 (String)ops[0].getDescriptor().getFieldValue(JMX.ORIGINAL_TYPE_FIELD); 231 OpenType<?> openTypeFieldValue = 232 (OpenType<?>)ops[0].getDescriptor().getFieldValue(JMX.OPEN_TYPE_FIELD); 233 234 if ( ! originalTypeFieldValue.equals("void") ) { 235 String message = "(ERROR) Unexpected originalType in Descriptor for bogus " 236 + originalTypeFieldValue; 237 System.out.println(message); 238 throw new RuntimeException(message); 239 } 240 241 if ( ! openTypeFieldValue.equals(SimpleType.VOID) ) { 242 String message = "(ERROR) Unexpected openType in Descriptor for bogus " 243 + originalTypeFieldValue; 244 System.out.println(message); 245 throw new RuntimeException(message); 246 } 247 248 // Check there is 2 constructors. 249 if (info.getConstructors().length != 2) { 250 String message = "(ERROR) Wrong number of constructors " + 251 "in introspected bean: " + 252 Arrays.asList(info.getConstructors()); 253 System.out.println(message); 254 throw new RuntimeException(message); 255 } 256 257 // Check MXBean class name. 258 if (!info.getClassName().endsWith("Test")) { 259 String message = "(ERROR) Wrong info class name: " + 260 info.getClassName(); 261 System.out.println(message); 262 throw new RuntimeException(message); 263 } 264 265 mbs.unregisterMBean(testName); 266 mbs.unregisterMBean(mletName); 267 268 WeakReference<PrivateMLet> mletRef = 269 new WeakReference<PrivateMLet>(mlet); 270 mlet = null; 271 272 System.out.println("MXBean registered and unregistered, waiting for " + 273 "garbage collector to collect class loader"); 274 275 for (int i = 0; i < 10000 && mletRef.get() != null; i++) { 276 System.gc(); 277 Thread.sleep(1); 278 } 279 280 if (mletRef.get() == null) 281 System.out.println("(OK) class loader was GC'd"); 282 else { 283 String message = "(ERROR) Class loader was not GC'd"; 284 System.out.println(message); 285 throw new RuntimeException(message); 286 } 287 } catch(Exception e) { 288 Utils.printThrowable(e, true) ; 289 throw new RuntimeException(e); 290 } 291 292 System.out.println("MXBeanLoadingTest1::run: Done without any error") ; 293 } 294 295 296 // I agree the use of the MXBean annotation and the MXBean suffix for the 297 // interface name are redundant but however harmless. 298 // 299 @MXBean(true) 300 public static interface TestMXBean { 301 public void bogus(); 302 public int getA(); 303 public void setA(int a); 304 public Luis getB(); 305 public void setB(Luis mi); 306 } 307 308 309 public static class Test implements TestMXBean { 310 private Luis luis = new Luis() ; 311 public Test() {} 312 public Test(int x) {} 313 314 public void bogus() {} 315 public int getA() {return 0;} 316 public void setA(int a) {} 317 public Luis getB() {return this.luis;} 318 public void setB(Luis luis) {this.luis = luis;} 319 } 320 321 322 public static class Luis { 323 private int something = 0; 324 public Luis() {} 325 public int getSomething() {return something;} 326 public void setSomething(int v) {something = v;} 327 public void doNothing() {} 328 } 329 }