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