1 /* 2 * Copyright (c) 2004, 2020, 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 4847959 6191402 27 * @summary Test newly-generified APIs 28 * @author Eamonn McManus 29 * 30 * @run clean GenericTest 31 * @run build GenericTest 32 * @run main GenericTest 33 */ 34 35 import java.lang.management.ManagementFactory; 36 import java.lang.reflect.*; 37 import java.util.*; 38 import java.util.stream.Stream; 39 import javax.management.*; 40 import javax.management.openmbean.*; 41 import javax.management.relation.*; 42 import javax.management.timer.Timer; 43 import javax.management.timer.TimerMBean; 44 45 public class GenericTest { 46 private static int failures; 47 main(String[] args)48 public static void main(String[] args) throws Exception { 49 MBeanServer mbs = ManagementFactory.getPlatformMBeanServer(); 50 51 // Check we are really using the generified version 52 boolean generic; 53 Method findmbs = MBeanServerFactory.class.getMethod("findMBeanServer", 54 String.class); 55 Type findmbstype = findmbs.getGenericReturnType(); 56 if (!(findmbstype instanceof ParameterizedType)) { 57 System.out.println("FAILURE: API NOT GENERIC!"); 58 System.out.println(" MBeanServerFactory.findMBeanServer -> " + 59 findmbstype); 60 failures++; 61 generic = false; 62 } else { 63 System.out.println("OK: this API is generic"); 64 generic = true; 65 } 66 67 ArrayList<MBeanServer> mbsList1 = 68 MBeanServerFactory.findMBeanServer(null); 69 checked(mbsList1, MBeanServer.class); 70 ArrayList mbsList2 = MBeanServerFactory.findMBeanServer(null); 71 check("ArrayList<MBeanServer> findMBeanServer", mbsList1.size() == 1); 72 check("ArrayList findMBeanServer", mbsList1.equals(mbsList2)); 73 74 boolean isSecondAttempt = false; 75 Set<ObjectName> names1 = null; 76 while (true) { 77 names1 = checked(mbs.queryNames(null, null), ObjectName.class); 78 Set names2 = mbs.queryNames(null, null); 79 Set<ObjectName> names3 = 80 checked(((MBeanServerConnection) mbs).queryNames(null, null), 81 ObjectName.class); 82 // If new MBean (e.g. Graal MBean) is registered while the test is running, names1, 83 // names2, and names3 will have different sizes. Repeat the test in this case. 84 if (sameSize(names1, names2, names3) || isSecondAttempt) { 85 check("Set<ObjectName> MBeanServer.queryNames", names1.size() >= 1); 86 check("Set MBeanServer.queryNames", names2.size() >= 1); 87 check("Set<ObjectName> MBeanServerConnection.queryNames", 88 names3.size() >= 1); 89 check("queryNames sets same", 90 names1.equals(names2) && names2.equals(names3)); 91 break; 92 } 93 isSecondAttempt = true; 94 System.out.println("queryNames sets have different size, retrying..."); 95 } 96 97 isSecondAttempt = false; 98 while (true) { 99 Set<ObjectInstance> mbeans1 = 100 checked(mbs.queryMBeans(null, null), ObjectInstance.class); 101 Set mbeans2 = mbs.queryMBeans(null, null); 102 Set<ObjectInstance> mbeans3 = 103 checked(((MBeanServerConnection) mbs).queryMBeans(null, null), 104 ObjectInstance.class); 105 // If new MBean (e.g. Graal MBean) is registered while the test is running, mbeans1, 106 // mbeans2, and mbeans3 will have different sizes. Repeat the test in this case. 107 if (sameSize(mbeans1, mbeans2, mbeans3) || isSecondAttempt) { 108 check("Set<ObjectInstance> MBeanServer.queryMBeans", 109 mbeans1.size() >= 1); 110 check("Set MBeanServer.queryMBeans", mbeans2.size() >= 1); 111 check("Set<ObjectInstance> MBeanServerConnection.queryMBeans", 112 mbeans3.size() >= 1); 113 check("queryMBeans sets same", 114 mbeans1.equals(mbeans2) && mbeans2.equals(mbeans3)); 115 break; 116 } 117 isSecondAttempt = true; 118 System.out.println("queryMBeans sets have different size, retrying..."); 119 } 120 121 AttributeChangeNotificationFilter acnf = 122 new AttributeChangeNotificationFilter(); 123 acnf.enableAttribute("foo"); 124 Vector<String> acnfs = acnf.getEnabledAttributes(); 125 checked(acnfs, String.class); 126 check("Vector<String> AttributeChangeNotificationFilter.getEnabled" + 127 "Attributes", acnfs.equals(Arrays.asList(new String[] {"foo"}))); 128 129 if (generic) { 130 Attribute a = new Attribute("foo", "bar"); 131 AttributeList al1 = new AttributeList(); 132 al1.add(a); 133 AttributeList al2 = 134 new AttributeList(Arrays.asList(new Attribute[] {a})); 135 check("new AttributeList(List<Attribute>)", al1.equals(al2)); 136 List<Attribute> al3 = checked(al1.asList(), Attribute.class); 137 al3.remove(a); 138 check("List<Attribute> AttributeList.asList()", 139 al1.equals(al3) && al1.isEmpty()); 140 } 141 142 List<ObjectName> namelist1 = new ArrayList<ObjectName>(names1); 143 Role role = new Role("rolename", namelist1); 144 List<ObjectName> namelist2 = 145 checked(role.getRoleValue(), ObjectName.class); 146 check("new Role(String,List<ObjectName>).getRoleValue() -> " + 147 "List<ObjectName>", namelist1.equals(namelist2)); 148 149 RoleList rl1 = new RoleList(); 150 rl1.add(role); 151 RoleList rl2 = new RoleList(Arrays.asList(new Role[] {role})); 152 check("new RoleList(List<Role>)", rl1.equals(rl2)); 153 if (generic) { 154 List<Role> rl3 = checked(rl1.asList(), Role.class); 155 rl3.remove(role); 156 check("List<Role> RoleList.asList()", 157 rl1.equals(rl3) && rl1.isEmpty()); 158 } 159 160 RoleUnresolved ru = 161 new RoleUnresolved("rolename", namelist1, 162 RoleStatus.LESS_THAN_MIN_ROLE_DEGREE); 163 List<ObjectName> namelist3 = 164 checked(ru.getRoleValue(), ObjectName.class); 165 check("new RoleUnresolved(...List<ObjectName>...).getRoleValue() -> " + 166 "List<ObjectName>", namelist1.equals(namelist3)); 167 168 RoleUnresolvedList rul1 = new RoleUnresolvedList(); 169 rul1.add(ru); 170 RoleUnresolvedList rul2 = 171 new RoleUnresolvedList(Arrays.asList(new RoleUnresolved[] {ru})); 172 check("new RoleUnresolvedList(List<RoleUnresolved>", rul1.equals(rul2)); 173 if (generic) { 174 List<RoleUnresolved> rul3 = 175 checked(rul1.asList(), RoleUnresolved.class); 176 rul3.remove(ru); 177 check("List<RoleUnresolved> RoleUnresolvedList.asList()", 178 rul1.equals(rul3) && rul1.isEmpty()); 179 } 180 181 // This case basically just tests that we can compile this sort of thing 182 OpenMBeanAttributeInfo ombai1 = 183 new OpenMBeanAttributeInfoSupport("a", "a descr", 184 SimpleType.INTEGER, 185 true, true, false); 186 CompositeType ct = 187 new CompositeType("ct", "ct descr", new String[] {"item1"}, 188 new String[] {"item1 descr"}, 189 new OpenType[] {SimpleType.INTEGER}); 190 OpenMBeanAttributeInfo ombai2 = 191 new OpenMBeanAttributeInfoSupport("a", "a descr", 192 ct, true, true, false); 193 TabularType tt = 194 new TabularType("tt", "tt descr", ct, new String[] {"item1"}); 195 OpenMBeanAttributeInfo ombai3 = 196 new OpenMBeanAttributeInfoSupport("a", "a descr", 197 tt, true, true, false); 198 ArrayType<String[][]> at = 199 new ArrayType<String[][]>(2, SimpleType.STRING); 200 OpenMBeanAttributeInfo ombai4 = 201 new OpenMBeanAttributeInfoSupport("a", "a descr", 202 at, true, true, false); 203 OpenMBeanAttributeInfo ombai4a = 204 new OpenMBeanAttributeInfoSupport("a", "a descr", 205 (ArrayType) at, 206 true, true, false); 207 OpenMBeanAttributeInfo ombai5 = 208 new OpenMBeanAttributeInfoSupport("a", "a descr", 209 SimpleType.INTEGER, 210 true, true, false, 211 5, 1, 9); 212 OpenMBeanAttributeInfo ombai6 = 213 new OpenMBeanAttributeInfoSupport("a", "a descr", 214 SimpleType.INTEGER, 215 true, true, false, 216 5, new Integer[] {1, 5}); 217 218 OpenMBeanInfo ombi = 219 new OpenMBeanInfoSupport("a.a", "a.a descr", 220 new OpenMBeanAttributeInfo[] { 221 ombai1, ombai2, ombai3, ombai4, 222 ombai5, ombai6, 223 }, 224 null, null, null); 225 226 Map<String,Integer> itemMap = 227 checked(singletonMap("item1", 5), 228 String.class, Integer.class); 229 CompositeData cd = 230 new CompositeDataSupport(ct, itemMap); 231 check("CompositeDataSupport(CompositeType, Map<String,?>", 232 cd.get("item1").equals(5)); 233 234 Set<String> ctkeys = checked(ct.keySet(), String.class); 235 check("Set<String> CompositeType.keySet()", 236 ctkeys.equals(singleton("item1"))); 237 238 List<String> ttindex = checked(tt.getIndexNames(), String.class); 239 check("Set<String> TabularType.getIndexNames()", 240 ttindex.equals(singletonList("item1"))); 241 242 TabularData td = new TabularDataSupport(tt); 243 td.putAll(new CompositeData[] {cd}); 244 List<Integer> tdkey = checked(singletonList(5), Integer.class); 245 Set<List<Integer>> tdkeys = checked(singleton(tdkey), 246 (Class<List<Integer>>) tdkey.getClass()); 247 Collection<CompositeData> tdvalues = checked(singleton(cd), 248 CompositeData.class); 249 check("Set<List<?>> TabularDataSupport.keySet()", 250 td.keySet().equals(tdkeys)); 251 check("Collection<CompositeData> TabularDataSupport.values()", 252 td.values().iterator().next().equals(tdvalues.iterator().next())); 253 254 ObjectName stupidName = new ObjectName("stupid:a=b"); 255 mbs.registerMBean(new Stupid(), stupidName); 256 StupidMBean proxy = 257 MBeanServerInvocationHandler.newProxyInstance(mbs, 258 stupidName, 259 StupidMBean.class, 260 false); 261 check("MBeanServerInvocationHandler.newProxyInstance", 262 proxy.getFive() == 5); 263 mbs.unregisterMBean(stupidName); 264 265 mbs.registerMBean(new StandardMBean(new Stupid(), StupidMBean.class), 266 stupidName); 267 check("<T> StandardMBean(T impl, Class<T> intf)", 268 proxy.getFive() == 5); 269 270 // Following is based on the package.html for javax.management.relation 271 // Create the Relation Service MBean 272 ObjectName relSvcName = new ObjectName(":type=RelationService"); 273 RelationService relSvcObject = new RelationService(true); 274 mbs.registerMBean(relSvcObject, relSvcName); 275 276 // Create an MBean proxy for easier access to the Relation Service 277 RelationServiceMBean relSvc = 278 MBeanServerInvocationHandler.newProxyInstance(mbs, relSvcName, 279 RelationServiceMBean.class, 280 false); 281 282 // Define the DependsOn relation type 283 RoleInfo[] dependsOnRoles = { 284 new RoleInfo("dependent", Module.class.getName()), 285 new RoleInfo("dependedOn", Module.class.getName()) 286 }; 287 relSvc.createRelationType("DependsOn", dependsOnRoles); 288 289 // Now define a relation instance "moduleA DependsOn moduleB" 290 291 ObjectName moduleA = new ObjectName(":type=Module,name=A"); 292 ObjectName moduleB = new ObjectName(":type=Module,name=B"); 293 294 // Following two lines added to example: 295 mbs.registerMBean(new Module(), moduleA); 296 mbs.registerMBean(new Module(), moduleB); 297 298 Role dependent = new Role("dependent", singletonList(moduleA)); 299 Role dependedOn = new Role("dependedOn", singletonList(moduleB)); 300 Role[] roleArray = {dependent, dependedOn}; 301 RoleList roles = new RoleList(Arrays.asList(roleArray)); 302 relSvc.createRelation("A-DependsOn-B", "DependsOn", roles); 303 304 // Query the Relation Service to find what modules moduleA depends on 305 Map<ObjectName,List<String>> dependentAMap = 306 relSvc.findAssociatedMBeans(moduleA, "DependsOn", "dependent"); 307 Set<ObjectName> dependentASet = dependentAMap.keySet(); 308 dependentASet = checked(dependentASet, ObjectName.class); 309 // Set of ObjectName containing moduleB 310 check("Map<ObjectName,List<String>> RelationService.findAssociatedMBeans", 311 dependentAMap.size() == 1 && 312 dependentASet.equals(singleton(moduleB))); 313 314 Map<String,List<String>> refRels = 315 relSvc.findReferencingRelations(moduleA, "DependsOn", "dependent"); 316 List<String> refRoles = 317 checked(refRels.get("A-DependsOn-B"), String.class); 318 check("Map<String,List<String>> RelationService.findReferencingRelations", 319 refRoles.equals(singletonList("dependent"))); 320 321 List<String> relsOfType = relSvc.findRelationsOfType("DependsOn"); 322 relsOfType = checked(relsOfType, String.class); 323 check("List<String> RelationService.findRelationsOfType", 324 relsOfType.equals(singletonList("A-DependsOn-B"))); 325 326 List<String> allRelIds = relSvc.getAllRelationIds(); 327 allRelIds = checked(allRelIds, String.class); 328 check("List<String> RelationService.getAllRelationIds()", 329 allRelIds.equals(singletonList("A-DependsOn-B"))); 330 331 List<String> allRelTypes = relSvc.getAllRelationTypeNames(); 332 allRelTypes = checked(allRelTypes, String.class); 333 check("List<String> RelationService.getAllRelationTypeNames", 334 allRelTypes.equals(singletonList("DependsOn"))); 335 336 Map<ObjectName,List<String>> refdMBeans = 337 relSvc.getReferencedMBeans("A-DependsOn-B"); 338 check("Map<ObjectName,List<String>> RelationService.getReferencedMBeans", 339 refdMBeans.get(moduleA).equals(singletonList("dependent")) && 340 refdMBeans.get(moduleB).equals(singletonList("dependedOn"))); 341 342 List<ObjectName> roleContents = 343 checked(relSvc.getRole("A-DependsOn-B", "dependent"), 344 ObjectName.class); 345 check("List<ObjectName> RelationService.getRole", 346 roleContents.equals(singletonList(moduleA))); 347 348 RoleInfo roleInfoDependent = 349 relSvc.getRoleInfo("DependsOn", "dependent"); 350 RoleInfo roleInfoDependedOn = 351 relSvc.getRoleInfo("DependsOn", "dependedOn"); 352 List<RoleInfo> expectedRoleInfos = 353 Arrays.asList(new RoleInfo[] {roleInfoDependent, roleInfoDependedOn}); 354 List<RoleInfo> roleInfos = 355 checked(relSvc.getRoleInfos("DependsOn"), RoleInfo.class); 356 check("List<RoleInfo> RelationService.getRoleInfos", 357 equalListContents(expectedRoleInfos, roleInfos)); 358 359 RelationType relType = 360 new RelationTypeSupport("DependsOn", dependsOnRoles); 361 List<RoleInfo> relTypeRoleInfos = 362 checked(relType.getRoleInfos(), RoleInfo.class); 363 // Since there's no RoleInfo.equals and since the RelationTypeSupport 364 // constructor clones the RoleInfos passed to it, it's tricky to 365 // test equality here so we check type and size and have done with it 366 check("List<RoleInfo> RelationType.getRoleInfos", 367 relTypeRoleInfos.size() == 2); 368 369 MBeanServerNotificationFilter mbsnf = 370 new MBeanServerNotificationFilter(); 371 mbsnf.enableObjectName(moduleA); 372 check("Vector<ObjectName> MBeanServerNotificationFilter." + 373 "getEnabledObjectNames", 374 mbsnf.getEnabledObjectNames().equals(Arrays.asList(moduleA))); 375 mbsnf.enableAllObjectNames(); 376 mbsnf.disableObjectName(moduleB); 377 check("Vector<ObjectName> MBeanServerNotificationFilter." + 378 "getDisabledObjectNames", 379 mbsnf.getDisabledObjectNames().equals(Arrays.asList(moduleB))); 380 381 RelationService unusedRelSvc = new RelationService(false); 382 RelationNotification rn1 = 383 new RelationNotification(RelationNotification.RELATION_MBEAN_REMOVAL, 384 unusedRelSvc, 0L, 0L, "yo!", 385 "A-DependsOn-B", "DependsOn", null, 386 singletonList(moduleA)); 387 List<ObjectName> toUnreg = 388 checked(rn1.getMBeansToUnregister(), ObjectName.class); 389 check("List<ObjectName> RelationNotification.getMBeansToUnregister", 390 toUnreg.equals(singletonList(moduleA))); 391 392 RelationNotification rn2 = 393 new RelationNotification(RelationNotification.RELATION_MBEAN_UPDATE, 394 unusedRelSvc, 0L, 0L, "yo!", 395 "A-DependsOn-B", "DependsOn", null, 396 "dependent", singletonList(moduleA), 397 singletonList(moduleB)); 398 check("List<ObjectName> RelationNotification.getOldRoleValue", 399 checked(rn2.getOldRoleValue(), ObjectName.class) 400 .equals(singletonList(moduleB))); 401 check("List<ObjectName> RelationNotification.getNewRoleValue", 402 checked(rn2.getNewRoleValue(), ObjectName.class) 403 .equals(singletonList(moduleA))); 404 405 ObjectName timerName = new ObjectName(":type=timer"); 406 mbs.registerMBean(new Timer(), timerName); 407 TimerMBean timer = 408 MBeanServerInvocationHandler.newProxyInstance(mbs, 409 timerName, 410 TimerMBean.class, 411 false); 412 Date doomsday = new Date(Long.MAX_VALUE); 413 int timer1 = timer.addNotification("one", "one", null, doomsday); 414 int timer2 = timer.addNotification("two", "two", null, doomsday); 415 Vector<Integer> idsOne = timer.getNotificationIDs("one"); 416 check("Vector<Integer> TimerMBean.getNotificationIDs", 417 idsOne.equals(singletonList(timer1))); 418 Vector<Integer> allIds = timer.getAllNotificationIDs(); 419 check("Vector<Integer> TimerMBean.getAllNotificationIDs", 420 equalListContents(allIds, 421 Arrays.asList(new Integer[]{timer1, timer2}))); 422 423 // ADD NEW TEST CASES ABOVE THIS COMMENT 424 425 if (failures == 0) 426 System.out.println("All tests passed"); 427 else { 428 System.out.println("TEST FAILURES: " + failures); 429 System.exit(1); 430 } 431 432 // DO NOT ADD NEW TEST CASES HERE, ADD THEM ABOVE THE PREVIOUS COMMENT 433 } 434 435 public static interface StupidMBean { getFive()436 public int getFive(); 437 } 438 439 public static class Stupid implements StupidMBean { getFive()440 public int getFive() { 441 return 5; 442 } 443 } 444 445 public static class Module extends StandardMBean implements StupidMBean { Module()446 public Module() throws NotCompliantMBeanException { 447 super(StupidMBean.class); 448 } 449 getFive()450 public int getFive() { 451 return 5; 452 } 453 } 454 singletonList(E value)455 private static <E> List<E> singletonList(E value) { 456 return Collections.singletonList(value); 457 } 458 singleton(E value)459 private static <E> Set<E> singleton(E value) { 460 return Collections.singleton(value); 461 } 462 singletonMap(K key, V value)463 private static <K,V> Map<K,V> singletonMap(K key, V value) { 464 return Collections.singletonMap(key, value); 465 } 466 checked(List<E> c, Class<E> type)467 private static <E> List<E> checked(List<E> c, Class<E> type) { 468 List<E> unchecked = new ArrayList<E>(); 469 List<E> checked = Collections.checkedList(unchecked, type); 470 checked.addAll(c); 471 return Collections.checkedList(c, type); 472 } 473 checked(Set<E> c, Class<E> type)474 private static <E> Set<E> checked(Set<E> c, Class<E> type) { 475 Set<E> unchecked = new HashSet<E>(); 476 Set<E> checked = Collections.checkedSet(unchecked, type); 477 checked.addAll(c); 478 return Collections.checkedSet(c, type); 479 } 480 checked(Map<K,V> m, Class<K> keyType, Class<V> valueType)481 private static <K,V> Map<K,V> checked(Map<K,V> m, 482 Class<K> keyType, 483 Class<V> valueType) { 484 Map<K,V> unchecked = new HashMap<K,V>(); 485 Map<K,V> checked = Collections.checkedMap(unchecked, keyType, valueType); 486 checked.putAll(m); 487 return Collections.checkedMap(m, keyType, valueType); 488 } 489 490 /* The fact that we have to call this method is a clear signal that 491 * the API says List where it means Set. 492 */ equalListContents(List<E> l1, List<E> l2)493 private static <E> boolean equalListContents(List<E> l1, List<E> l2) { 494 return new HashSet<E>(l1).equals(new HashSet<E>(l2)); 495 } 496 check(String what, boolean cond)497 private static void check(String what, boolean cond) { 498 if (cond) 499 System.out.println("OK: " + what); 500 else { 501 System.out.println("FAILED: " + what); 502 failures++; 503 } 504 } 505 sameSize(Set .... sets)506 private static boolean sameSize(Set ... sets) { 507 return Stream.of(sets).map(s -> s.size()).distinct().count() == 1; 508 } 509 } 510