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