1 /* 2 * Copyright (c) 2003, 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 4950756 27 * @summary Test that RequiredModelMBean.invoke will not invoke methods 28 * from the RequiredModelMBean class itself if they are not in the 29 * ModelMBeanInfo 30 * @author Eamonn McManus 31 * @modules java.management 32 * @run clean RequiredModelMBeanMethodTest 33 * @run build RequiredModelMBeanMethodTest 34 * @run main RequiredModelMBeanMethodTest 35 */ 36 37 import java.lang.reflect.*; 38 import javax.management.*; 39 import javax.management.modelmbean.*; 40 41 /* 42 * We do the same test with a number of different operations: 43 * 44 * - A plain operation that is directed to the managed resource in the 45 * usual way. We give it some parameters so we can test that the 46 * class loading logic for signature parameters is reasonable. 47 * 48 * - An operation (removeNotificationListener) that is directed to the 49 * RequiredModelMBean itself. We use this particular operation because 50 * it will throw an exception, which allows us to check that it did in 51 * fact execute. 52 * 53 * - An operation (load()) that has the same signature as a 54 * RequiredModelMBean operation but is directed to the resource 55 * because of a "class" field in the descriptor. 56 * 57 * - An operation (store()) that has the same signature as a 58 * RequiredModelMBean operation but is directed to the resource 59 * because of a "targetObject" field in the descriptor. 60 * 61 * In each case we check that the operation does not work if it is not 62 * in the ModelMBeanInfo, and does work if it is. 63 */ 64 public class RequiredModelMBeanMethodTest { 65 public static void main(String[] args) throws Exception { 66 boolean ok = true; 67 MBeanServer mbs = MBeanServerFactory.createMBeanServer(); 68 69 Descriptor tralalaDescriptor = 70 new DescriptorSupport(new String[] { 71 "name=tralala", 72 "descriptorType=operation", 73 "role=operation", 74 "targetType=ObjectReference", 75 }); 76 Method tralalaMethod = 77 Resource.class.getMethod("tralala", 78 new Class[] {int.class, Resource.class}); 79 ModelMBeanOperationInfo tralalaInfo = 80 new ModelMBeanOperationInfo("tralala descr", tralalaMethod, 81 tralalaDescriptor); 82 83 Method remACNLMethod = 84 RequiredModelMBean.class.getMethod("removeAttributeChangeNotificationListener", 85 new Class[] { 86 NotificationListener.class, 87 String.class 88 }); 89 ModelMBeanOperationInfo remACNLInfo = 90 new ModelMBeanOperationInfo("remACNL descr", remACNLMethod); 91 92 Descriptor loadDescriptor = 93 new DescriptorSupport(new String[] { 94 "name=load", 95 "descriptorType=operation", 96 "role=operation", 97 "targetType=ObjectReference", 98 "class=" + Resource.class.getName(), 99 }); 100 ModelMBeanOperationInfo loadInfo = 101 new ModelMBeanOperationInfo("load", "load descr", 102 new MBeanParameterInfo[0], 103 "void", ModelMBeanOperationInfo.ACTION, 104 loadDescriptor); 105 106 Descriptor storeDescriptor = 107 new DescriptorSupport(new String[] { 108 "name=store", 109 "descriptorType=operation", 110 "role=operation", 111 "targetType=ObjectReference", 112 }); 113 storeDescriptor.setField("targetObject", resource); 114 ModelMBeanOperationInfo storeInfo = 115 new ModelMBeanOperationInfo("store", "store descr", 116 new MBeanParameterInfo[0], 117 "void", ModelMBeanOperationInfo.ACTION, 118 storeDescriptor); 119 120 ModelMBeanInfo emptyMMBI = 121 new ModelMBeanInfoSupport(Resource.class.getName(), 122 "empty descr", 123 null, null, null, null); 124 ModelMBean emptyMMB = new RequiredModelMBean(emptyMMBI); 125 emptyMMB.setManagedResource(resource, "ObjectReference"); 126 ObjectName emptyMMBName = new ObjectName("test:type=Empty"); 127 mbs.registerMBean(emptyMMB, emptyMMBName); 128 129 System.out.println("Testing that we cannot call methods not in the " + 130 "ModelMBeanInfo"); 131 try { 132 boolean thisok = test(mbs, emptyMMBName, false); 133 if (thisok) 134 System.out.println("...OK"); 135 else 136 ok = false; 137 } catch (Exception e) { 138 System.out.println("TEST FAILED: Caught exception:"); 139 e.printStackTrace(System.out); 140 ok = false; 141 } 142 143 ModelMBeanOperationInfo[] opInfos = { 144 tralalaInfo, remACNLInfo, loadInfo, storeInfo, 145 }; 146 ModelMBeanInfo fullMMBI = 147 new ModelMBeanInfoSupport(Resource.class.getName(), 148 "full descr", 149 null, null, opInfos, null); 150 ModelMBean fullMMB = new RequiredModelMBean(fullMMBI); 151 fullMMB.setManagedResource(resource, "ObjectReference"); 152 ObjectName fullMMBName = new ObjectName("test:type=Full"); 153 mbs.registerMBean(fullMMB, fullMMBName); 154 155 156 System.out.println(); 157 System.out.println("Testing that we can call methods in the " + 158 "ModelMBeanInfo"); 159 System.out.println(" and that \"class\" or \"targetObject\" in " + 160 "descriptor directs methods to resource"); 161 try { 162 boolean thisok = test(mbs, fullMMBName, true); 163 if (thisok) 164 System.out.println("...OK"); 165 else 166 ok = false; 167 } catch (Exception e) { 168 System.out.println("TEST FAILED: Caught exception:"); 169 e.printStackTrace(System.out); 170 ok = false; 171 } 172 173 if (ok) { 174 if (!resource.loadCalled || !resource.storeCalled) { 175 System.out.println("TEST FAILED: not called:" + 176 (resource.loadCalled ? "" : " load") + 177 (resource.storeCalled ? "" : " store")); 178 ok = false; 179 } 180 } 181 182 // Test the invoke("class.method") form 183 if (ok) { 184 System.out.println("Testing invoke(\"class.method\")"); 185 resource.loadCalled = false; 186 mbs.invoke(fullMMBName, Resource.class.getName() + ".load", 187 null, null); 188 if (!resource.loadCalled) { 189 System.out.println("TEST FAILED: load not called"); 190 ok = false; 191 } 192 try { 193 mbs.invoke(fullMMBName, 194 RequiredModelMBean.class.getName() + 195 ".removeAttributeChangeNotificationListener", 196 new Object[] {boringListener, null}, 197 new String[] { 198 NotificationListener.class.getName(), 199 String.class.getName(), 200 }); 201 System.out.println("TEST FAILED: removeNotificationListener" + 202 " returned successfully but " + 203 "should not have"); 204 ok = false; 205 } catch (MBeanException e) { 206 final Exception target = e.getTargetException(); 207 if (target instanceof ListenerNotFoundException) { 208 // OK: there is no such listener 209 } else 210 throw e; 211 } 212 } 213 214 if (ok) 215 System.out.println("Test passed"); 216 else { 217 System.out.println("TEST FAILED"); 218 System.exit(1); 219 } 220 } 221 222 private static boolean test(MBeanServer mbs, ObjectName name, 223 boolean shouldWork) 224 throws Exception { 225 226 boolean ok = true; 227 228 final String[] names = { 229 "tralala", 230 "removeAttributeChangeNotificationListener", 231 "load", 232 "store", 233 }; 234 235 for (int i = 0; i < 4; i++) { 236 boolean thisok = true; 237 try { 238 switch (i) { 239 case 0: 240 String tralala = (String) 241 mbs.invoke(name, names[i], 242 new Object[] {new Integer(5), resource}, 243 new String[] {"int", 244 Resource.class.getName()}); 245 if (!"tralala".equals(tralala)) { 246 System.out.println("TEST FAILED: tralala returned: " + 247 tralala); 248 thisok = false; 249 } 250 break; 251 case 1: 252 try { 253 mbs.invoke(name, 254 names[i], 255 new Object[] {boringListener, null}, 256 new String[] { 257 NotificationListener.class.getName(), 258 String.class.getName(), 259 }); 260 System.out.println("TEST FAILED: " + names[i] + 261 " returned successfully but " + 262 "should not have"); 263 thisok = false; 264 } catch (MBeanException e) { 265 final Exception target = e.getTargetException(); 266 if (target instanceof ListenerNotFoundException) { 267 // OK: there is no such listener 268 } else 269 throw e; 270 } 271 break; 272 case 2: 273 case 3: 274 mbs.invoke(name, 275 names[i], 276 new Object[0], 277 new String[0]); 278 break; 279 default: 280 throw new AssertionError(); 281 } 282 283 thisok = shouldWork; 284 if (!shouldWork) { 285 System.out.println("TEST FAILED: " + names[i] + 286 " worked but should not"); 287 } 288 } catch (MBeanException e) { 289 if (shouldWork) { 290 System.out.println("TEST FAILED: " + names[i] + ": " + e); 291 e.printStackTrace(System.out); 292 thisok = false; 293 } else { 294 Exception target = e.getTargetException(); 295 if (!(target instanceof ServiceNotFoundException)) { 296 System.out.println("TEST FAILED: " + names[i] + 297 ": wrong exception: " + target); 298 thisok = false; 299 } 300 } 301 } catch (Exception e) { 302 System.out.println("TEST FAILED: " + names[i] + ": " + e); 303 e.printStackTrace(System.out); 304 thisok = false; 305 } 306 307 if (thisok) 308 System.out.println("OK: " + names[i]); 309 else 310 ok = false; 311 } 312 313 return ok; 314 } 315 316 public static class Resource { 317 public String tralala(int x, Resource y) { 318 if (x != 5 || y != this) 319 return "wrong params: " + x + " " + y; 320 return "tralala"; 321 } 322 323 public void load() { 324 loadCalled = true; 325 } 326 327 public void store() { 328 storeCalled = true; 329 } 330 331 boolean loadCalled, storeCalled; 332 } 333 334 private static Resource resource = new Resource(); 335 336 private static NotificationListener boringListener = 337 new NotificationListener() { 338 public void handleNotification(Notification n, Object h) { 339 } 340 }; 341 }