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 4874819
27 * @summary Test that MBeanInfo classes no longer throw an
28 * IllegalArgumentException when attribute names, operation names, and
29 * Java type names do not strictly follow the expected Java syntax.
30 * @author Eamonn McManus, Daniel Fuchs
31 *
32 * @run clean SimpleModelMBeanCommand
33 * @run build SimpleModelMBeanCommand
34 * @run main/othervm/java.security.policy=policy  SimpleModelMBeanCommand
35 */
36
37import java.lang.reflect.*;
38import java.util.*;
39import javax.management.*;
40import javax.management.modelmbean.*;
41
42public class SimpleModelMBeanCommand {
43
44    public static class Resource {
45        public int getNumber() {
46            return number;
47        }
48
49        public void setNumber(int n) {
50            number = n;
51        }
52
53        public int addOne(int x) {
54            return x + 1;
55        }
56
57        public Object[] getArray() {
58            return (Object[]) array.clone();
59        }
60
61        // doesn't look like an attribute so not seen by caching logic
62        public void tweakArray(Object[] array) {
63            this.array = (Object[]) array.clone();
64        }
65
66        private int number = 1234;
67        private Object[] array = {"hello", "world"};
68    }
69
70    public static void main(String[] args) {
71        int errorCount = 0;
72        for (int i = 0; i < NTESTS; i++) {
73            try {
74                System.out.println("Test " + i + ":");
75                test(i);
76            } catch (Throwable e) {
77                errorCount++;
78                boolean first = true;
79                do {
80                    System.err.println(first ? "Exception:" : "Caused by:");
81                    first = false;
82                    e.printStackTrace();
83                    Throwable nexte;
84                    nexte = e.getCause();
85                    if (nexte == null) { // old JMX
86                        if (e instanceof MBeanException)
87                            nexte = ((MBeanException) e).getTargetException();
88                    }
89                    e = nexte;
90                } while (e != null);
91            }
92        }
93        if (errorCount == 0) {
94            System.out.println("All ModelMBean tests successfuly passed");
95            System.out.println("Bye! Bye!");
96            // JTReg doesn't like System.exit(0);
97            return;
98        } else {
99            System.err.println("ERROR: " + errorCount + " tests failed");
100            System.exit(errorCount);
101        }
102
103    }
104
105    private static void test(int testno) throws Exception {
106        // com.sun.jmx.trace.TraceImplementation.init(2);
107        Resource resource = new Resource();
108        Class resourceClass = Resource.class;
109        Class rmmbClass = RequiredModelMBean.class;
110        Method setManagedResource =
111            rmmbClass.getMethod("setManagedResource",
112                                new Class[] {Object.class,
113                                             String.class});
114        Method sendNotification =
115            rmmbClass.getMethod("sendNotification",
116                                new Class[] {Notification.class});
117        Method addAttributeChangeNL =
118            rmmbClass.getMethod("addAttributeChangeNotificationListener",
119                                new Class[] {NotificationListener.class,
120                                             String.class,
121                                             Object.class});
122        Method getArray = resourceClass.getMethod("getArray", new Class[0]);
123        Method getNumber = resourceClass.getMethod("getNumber", new Class[0]);
124        Method setNumber =
125            resourceClass.getMethod("setNumber", new Class[] {Integer.TYPE});
126        Method tweakArray =
127            resourceClass.getMethod("tweakArray",
128                                    new Class[] {Object[].class});
129        Method addOne =
130            resourceClass.getMethod("addOne", new Class[] {Integer.TYPE});
131        MBeanServer mbs = MBeanServerFactory.newMBeanServer();
132        ObjectName on = new ObjectName("a:b=c");
133        Descriptor attrDescr = new DescriptorSupport();
134        attrDescr.setField("name", "Array");
135        attrDescr.setField("descriptorType", "attribute");
136        attrDescr.setField("getMethod", "getArray");
137        ModelMBeanAttributeInfo attrInfo =
138            new ModelMBeanAttributeInfo("Array", "array attr", getArray,
139                                        null, attrDescr);
140        Descriptor attrDescr2 = new DescriptorSupport();
141        attrDescr2.setField("name", "Number");
142        attrDescr2.setField("descriptorType", "attribute");
143        attrDescr2.setField("getMethod", "getNumber");
144        attrDescr2.setField("setMethod", "setNumber");
145        ModelMBeanAttributeInfo attrInfo2 =
146            new ModelMBeanAttributeInfo("Number", "number attr", getNumber,
147                                        setNumber, attrDescr2);
148        Descriptor attrDescr3 = new DescriptorSupport();
149        attrDescr3.setField("name", "Local");
150        attrDescr3.setField("descriptorType", "attribute");
151        attrDescr3.setField("currencyTimeLimit", "" + Integer.MAX_VALUE);
152        ModelMBeanAttributeInfo attrInfo3 =
153            new ModelMBeanAttributeInfo("Local", "java.lang.String",
154                                        "local attr", true, true, false,
155                                        attrDescr3);
156        Descriptor attrDescr4 = new DescriptorSupport();
157        attrDescr4.setField("name", "Local2");
158        attrDescr4.setField("descriptorType", "attribute");
159        ModelMBeanAttributeInfo attrInfo4 =
160            new ModelMBeanAttributeInfo("Local2", "java.lang.String",
161                                        "local attr 2", true, true, false,
162                                        attrDescr4);
163        ModelMBeanAttributeInfo[] attrs =
164            new ModelMBeanAttributeInfo[] {attrInfo, attrInfo2, attrInfo3,
165                                           attrInfo4};
166        ModelMBeanOperationInfo operInfo =
167            new ModelMBeanOperationInfo("getArray descr", getArray);
168        ModelMBeanOperationInfo operInfo2 =
169            new ModelMBeanOperationInfo("getNumber descr", getNumber);
170        ModelMBeanOperationInfo operInfo3 =
171            new ModelMBeanOperationInfo("addOne descr", addOne);
172        ModelMBeanOperationInfo operInfo4 =
173            new ModelMBeanOperationInfo("setNumber descr", setNumber);
174        ModelMBeanOperationInfo operInfo5 =
175            new ModelMBeanOperationInfo("tweakArray descr", tweakArray);
176        ModelMBeanOperationInfo operInfoSetManagedResource =
177            new ModelMBeanOperationInfo("setManagedResource descr",
178                                        setManagedResource);
179        ModelMBeanOperationInfo operInfoSendNotification =
180            new ModelMBeanOperationInfo("sendNotification descr",
181                                        sendNotification);
182        ModelMBeanOperationInfo operInfoAddAttributeChangeNL =
183            new ModelMBeanOperationInfo("AddAttributeChangeNL descr",
184                                        addAttributeChangeNL);
185        ModelMBeanOperationInfo[] opers =
186            new ModelMBeanOperationInfo[] {operInfo, operInfo2, operInfo3,
187                                           operInfo4, operInfo5,
188                                           operInfoSetManagedResource,
189                                           operInfoSendNotification,
190                                           operInfoAddAttributeChangeNL};
191        ModelMBeanInfo info =
192            new ModelMBeanInfoSupport(Resource.class.getName(),
193                                      "Resourcish resource",
194                                      attrs, null, opers, null,
195                                      null);
196        mbs.createMBean(RequiredModelMBean.class.getName(),
197                        on,
198                        new Object[] {info},
199                        new String[] {ModelMBeanInfo.class.getName()});
200        mbs.invoke(on, "setManagedResource",
201                   new Object[] {resource, "objectReference"},
202                   new String[] {"java.lang.Object", "java.lang.String"});
203        switch (testno) {
204        case 0:
205            /* Check that we can get an attribute of type Object[] */
206            Object[] objs = (Object[]) mbs.getAttribute(on, "Array");
207            for (int i = 0; i < objs.length; i++)
208                System.out.println(objs[i]);
209            break;
210        case 1:
211            /* Check that we can get an attribute of type int */
212            Integer n = (Integer) mbs.getAttribute(on, "Number");
213            System.out.println(n);
214            break;
215        case 2:
216            /* Check that we can call an operation that returns int */
217            Integer n1 =
218                (Integer) mbs.invoke(on, "addOne",
219                                     new Integer[] {new Integer(1233)},
220                                     new String[] {"int"});
221            System.out.println(n1);
222            break;
223        case 3:
224            /* Check that we don't get an exception if you sendNotification
225               without any listeners.  */
226            Notification notif = new Notification("type", "source", 123L);
227            mbs.invoke(on, "sendNotification", new Object[] {notif},
228                       new String[] {"javax.management.Notification"});
229            System.out.println("Successfully sent notification");
230            break;
231        case 4:
232            /* Check that we can call addAttributeChangeNotificationListener
233               with null attribute.  */
234            NotificationListener listener = new NotificationListener() {
235                public void handleNotification(Notification notif,
236                                               Object handback) {
237                    System.out.println("Got notif: " + notif +
238                                       " with handback: " + handback);
239                }
240            };
241            mbs.invoke(on, "addAttributeChangeNotificationListener",
242                       new Object[] {listener, null, "the-handback"},
243                       new String[] {
244                           "javax.management.NotificationListener",
245                           "java.lang.String",
246                           "java.lang.Object",
247                       });
248            mbs.setAttribute(on, new Attribute("Number", new Integer(4321)));
249            System.out.println("Attribute value now: " +
250                               mbs.getAttribute(on, "Number"));
251            break;
252        case 5:
253            /* Check that the default caching behaviour is not to cache.  */
254            Object[] firstGot = (Object[]) mbs.getAttribute(on, "Array");
255            System.out.println("First got: " + Arrays.asList(firstGot));
256            ModelMBeanInfo mmbi = (ModelMBeanInfo) mbs.getMBeanInfo(on);
257            System.out.println(mmbi.getDescriptor("Array", "attribute"));
258            mbs.invoke(on, "tweakArray", new Object[] {new Object[] {"x"}},
259                       new String[] {Object[].class.getName()});
260            Object[] secondGot = (Object[]) mbs.getAttribute(on, "Array");
261            System.out.println("Second got: " + Arrays.asList(secondGot));
262            if (secondGot.length != 1)
263                throw new Exception("Got value: " + Arrays.asList(secondGot));
264            break;
265        case 6:
266            /* Check that attributes without getters or setters work.
267               The value is stored in the descriptor.  This test includes
268               an explicit currencyTimeLimit attribute.  */
269            mbs.setAttribute(on, new Attribute("Local", "string value"));
270            ModelMBeanInfo mmbi2 = (ModelMBeanInfo) mbs.getMBeanInfo(on);
271            System.out.println(mmbi2.getDescriptor("Local", "attribute"));
272            Object gotback = mbs.getAttribute(on, "Local");
273            if (!"string value".equals(gotback))
274                throw new Exception("Got value: " + gotback);
275            break;
276        case 7:
277            /* Check that attributes without getters or setters work.
278               The value is stored in the descriptor.  This test does
279               not have an explicit currencyTimeLimit attribute.  */
280            mbs.setAttribute(on, new Attribute("Local2", "thing value"));
281            ModelMBeanInfo mmbi3 = (ModelMBeanInfo) mbs.getMBeanInfo(on);
282            System.out.println(mmbi3.getDescriptor("Local2", "attribute"));
283            Object gotback2 = mbs.getAttribute(on, "Local2");
284            if (!"thing value".equals(gotback2))
285                throw new Exception("Got value: " + gotback2);
286            break;
287        default:
288            System.err.println("UNKNOWN TEST NUMBER " + testno);
289            break;
290        }
291    }
292
293    private static final int NTESTS = 8;
294
295}
296