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