blob: 018a22ea1d1ef97f6a750bb9a417cb922a9e8f1b [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
2 * Copyright 2003 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
20 * CA 95054 USA or visit www.sun.com if you need additional information or
21 * have any questions.
22 */
23
24/*
25 * @test
26 * @bug 4719923
27 * @summary Test that MBeanInfo.equals works even for mutable subclasses
28 * @author Eamonn McManus
29 * @run clean MBeanInfoEqualsTest
30 * @run build MBeanInfoEqualsTest
31 * @run main MBeanInfoEqualsTest
32 */
33
34/* Test that MBeanInfo and its referenced classes implement the equals
35 and hashCode methods correctly. These classes include some magic
36 to improve performance based on the classes' immutability. The
37 logic checks that any subclasses encountered remain immutable, and
38 falls back on less performant code if not. */
39
40import javax.management.*;
41import java.lang.reflect.*;
42
43public class MBeanInfoEqualsTest {
44 // Class just used for reflection
45 private static class Toy {
46 public Toy() {}
47 public Toy(int a, String b) {}
48 public int getA() {return 0;}
49 public void setA(int a) {}
50 public boolean isB() {return false;}
51 public void setB(boolean b) {}
52 public void run() {}
53 public void blah(int a, String b) {}
54 }
55
56 static final Class toy = Toy.class;
57 static final Constructor con1, con2;
58 static final Method getA, setA, isB, setB, run, blah;
59 static {
60 try {
61 con1 = toy.getConstructor(new Class[] {});
62 con2 = toy.getConstructor(new Class[] {Integer.TYPE,
63 String.class});
64 getA = toy.getMethod("getA", new Class[] {});
65 setA = toy.getMethod("setA", new Class[] {Integer.TYPE});
66 isB = toy.getMethod("isB", new Class[] {});
67 setB = toy.getMethod("setB", new Class[] {Boolean.TYPE});
68 run = toy.getMethod("run", new Class[] {});
69 blah = toy.getMethod("blah", new Class[] {Integer.TYPE,
70 String.class});
71 } catch (Exception e) {
72 throw new Error(e.getMessage());
73 }
74 }
75
76 private static final MBeanAttributeInfo
77 newMBeanAttributeInfo(String name, String description,
78 Method getter, Method setter) {
79 try {
80 return new MBeanAttributeInfo(name, description, getter, setter);
81 } catch (IntrospectionException e) {
82 throw new Error(e.getMessage());
83 }
84 }
85
86 static final MBeanAttributeInfo
87 a1a = new MBeanAttributeInfo("thing", "java.foo.bar", "an attribute",
88 true, true, false),
89 a1b = new MBeanAttributeInfo("thing", "java.foo.bar", "an attribute",
90 true, true, false),
91 a2a = new MBeanAttributeInfo("splob", "java.foo.bar", "an attribute",
92 true, true, false),
93 a2b = new MBeanAttributeInfo(a2a.getName(), a2a.getType(),
94 a2a.getDescription(), a2a.isReadable(),
95 a2a.isWritable(), a2a.isIs()),
96 a3 = new MBeanAttributeInfo("splob", "java.foo.bar", "a whatsit",
97 true, true, false),
98 a4 = new MBeanAttributeInfo("splob", "java.foo.bar", "a whatsit",
99 false, true, false),
100 a5a = newMBeanAttributeInfo("a", "an attribute", getA, setA),
101 a5b = new MBeanAttributeInfo("a", "int", "an attribute",
102 true, true, false),
103 a6a = newMBeanAttributeInfo("a", "an attribute", getA, null),
104 a6b = new MBeanAttributeInfo("a", "int", "an attribute",
105 true, false, false),
106 a7a = newMBeanAttributeInfo("a", "an attribute", null, setA),
107 a7b = new MBeanAttributeInfo("a", "int", "an attribute",
108 false, true, false),
109 a8a = newMBeanAttributeInfo("b", "an attribute", isB, setB),
110 a8b = new MBeanAttributeInfo("b", "boolean", "an attribute",
111 true, true, true),
112 a9a = newMBeanAttributeInfo("b", "an attribute", isB, null),
113 a9b = new MBeanAttributeInfo("b", "boolean", "an attribute",
114 true, false, true);
115
116 static final MBeanParameterInfo
117 p1a = new MBeanParameterInfo("thing", "java.foo.bar", "a parameter"),
118 p1b = new MBeanParameterInfo("thing", "java.foo.bar", "a parameter"),
119 p2 = new MBeanParameterInfo("splob", "java.foo.bar", "a parameter"),
120 p3 = new MBeanParameterInfo("thing", "java.foo.bax", "a parameter"),
121 p4 = new MBeanParameterInfo("thing", "java.foo.bar", "a whatsit");
122
123 static final MBeanConstructorInfo
124 c1a = new MBeanConstructorInfo("a constructor", con1),
125 c1b = new MBeanConstructorInfo(c1a.getName(), "a constructor",
126 new MBeanParameterInfo[0]),
127 c1c = new MBeanConstructorInfo(c1a.getName(), c1a.getDescription(),
128 c1a.getSignature()),
129 c1d = new MBeanConstructorInfo(c1a.getName(), c1a.getDescription(),
130 null),
131 c2a = new MBeanConstructorInfo("another constructor", con2),
132 c2b = new MBeanConstructorInfo(c2a.getName(),
133 c2a.getDescription(),
134 c2a.getSignature()),
135 c3a = new MBeanConstructorInfo("conName", "a constructor",
136 new MBeanParameterInfo[] {p2, p3}),
137 c3b = new MBeanConstructorInfo("conName", "a constructor",
138 new MBeanParameterInfo[] {p2, p3}),
139 c4 = new MBeanConstructorInfo("conName", "a constructor",
140 new MBeanParameterInfo[] {p3, p2}),
141 c5 = new MBeanConstructorInfo("otherName", "a constructor",
142 new MBeanParameterInfo[] {p3, p2}),
143 c6 = new MBeanConstructorInfo("otherName", "another constructor",
144 new MBeanParameterInfo[] {p3, p2});
145
146 static final MBeanOperationInfo
147 o1a = new MBeanOperationInfo("an operation", run),
148 o1b = new MBeanOperationInfo("an operation", run),
149 o1c = new MBeanOperationInfo("run", "an operation",
150 o1a.getSignature(), "void",
151 o1a.getImpact()),
152 o1d = new MBeanOperationInfo("run", "an operation",
153 new MBeanParameterInfo[0], "void",
154 o1a.getImpact()),
155 o1e = new MBeanOperationInfo("run", "an operation",
156 null, "void",
157 o1a.getImpact()),
158 o2a = new MBeanOperationInfo("another operation", blah),
159 o2b = new MBeanOperationInfo(o2a.getName(), o2a.getDescription(),
160 o2a.getSignature(), o2a.getReturnType(),
161 o2a.getImpact());
162
163 static final MBeanNotificationInfo
164 n1a = new MBeanNotificationInfo(new String[] {"a.b", "c.d"},
165 "x.y.z",
166 "a notification info"),
167 n1b = new MBeanNotificationInfo(new String[] {"a.b", "c.d"},
168 "x.y.z",
169 "a notification info"),
170 n2a = new MBeanNotificationInfo(new String[] {"a.b", "c.d"},
171 "x.y.z",
172 "another notification info"),
173 n2b = new MBeanNotificationInfo(n2a.getNotifTypes(),
174 n2a.getName(),
175 n2a.getDescription()),
176 n3 = new MBeanNotificationInfo(new String[] {"a.b", "c.d"},
177 "x.y.zz",
178 "a notification info"),
179 n4 = new MBeanNotificationInfo(new String[] {"c.d", "a.b"},
180 "x.y.z",
181 "a notification info");
182
183 static final MBeanAttributeInfo[]
184 xa1a = {a1a, a2a},
185 xa1b = {a1b, a2b},
186 xa2a = {a2a, a1a};
187
188 static final MBeanConstructorInfo[]
189 xc1a = {c1a, c2a},
190 xc1b = {c1b, c2b},
191 xc2a = {c2a, c1a};
192
193 static final MBeanOperationInfo[]
194 xo1a = {o1a, o2a},
195 xo1b = {o1b, o2b},
196 xo2a = {o2a, o1a};
197
198 static final MBeanNotificationInfo[]
199 xn1a = {n1a, n2a},
200 xn1b = {n1b, n2b},
201 xn2a = {n2a, n1a};
202
203 static final MBeanInfo
204 i1a = new MBeanInfo("a.b.c", "an MBean info", xa1a, xc1a, xo1a, xn1a),
205 i1b = new MBeanInfo("a.b.c", "an MBean info", xa1a, xc1a, xo1a, xn1a),
206 i1c = new MBeanInfo("a.b.c", "an MBean info", xa1b, xc1b, xo1b, xn1b),
207 i1d = new MutableMBeanInfo("a.b.c", "an MBean info", xa1b, xc1b, xo1b,
208 xn1b),
209 i1e = new ImmutableMBeanInfo("a.b.c", "an MBean info", xa1b, xc1b,
210 xo1b, xn1b),
211 i1f = new ImmutableMBeanInfo("a.b.c", "an MBean info", xa1b, xc1b,
212 xo1b, xn1b),
213 i2a = new MBeanInfo("a.b.cc", "an MBean info", xa1a, xc1a, xo1a, xn1a),
214 i2b = new MBeanInfo(i2a.getClassName(), i2a.getDescription(),
215 i2a.getAttributes(), i2a.getConstructors(),
216 i2a.getOperations(), i2a.getNotifications()),
217 i3 = new MBeanInfo("a.b.c", "another MBean info", xa1a, xc1a, xo1a,
218 xn1a),
219 i4 = new MBeanInfo("a.b.c", "an MBean info", xa2a, xc1a, xo1a, xn1a),
220 i5 = new MBeanInfo("a.b.c", "an MBean info", xa1a, xc2a, xo1a, xn1a),
221 i6 = new MBeanInfo("a.b.c", "an MBean info", xa1a, xc1a, xo2a, xn1a),
222 i7 = new MBeanInfo("a.b.c", "an MBean info", xa1a, xc1a, xo1a, xn2a);
223
224 static final Object[][] equivalenceClasses = {
225 {a1a, a1b}, {a2a, a2b}, {a3}, {a4}, {a5a, a5b}, {a6a, a6b}, {a7a, a7b},
226 {a8a, a8b}, {a9a, a9b},
227 {c1a, c1b, c1c, c1d}, {c2a, c2b}, {c3a, c3b}, {c4}, {c5}, {c6},
228 {o1a, o1b, o1c, o1d, o1e}, {o2a, o2b},
229 {p1a, p1b}, {p2}, {p3}, {p4},
230 {n1a, n1b}, {n2a, n2b}, {n3}, {n4},
231 {i1a, i1b, i1c, i1d, i1e, i1f}, {i2a, i2b}, {i3}, {i4}, {i5}, {i6},
232 {i7},
233 };
234
235 private static class ImmutableMBeanInfo extends MBeanInfo {
236 ImmutableMBeanInfo(String className,
237 String description,
238 MBeanAttributeInfo[] attributes,
239 MBeanConstructorInfo[] constructors,
240 MBeanOperationInfo[] operations,
241 MBeanNotificationInfo[] notifications) {
242 super(className, description, attributes, constructors, operations,
243 notifications);
244 }
245 }
246
247 /* This class checks that the MBeanInfo.equals() method really
248 does call getClassName() etc rather than referring to its
249 private fields. */
250 private static class MutableMBeanInfo extends MBeanInfo {
251 private final String className;
252 private final String description;
253 private final MBeanAttributeInfo[] attributes;
254 private final MBeanOperationInfo[] operations;
255 private final MBeanConstructorInfo[] constructors;
256 private final MBeanNotificationInfo[] notifications;
257
258 MutableMBeanInfo(String className,
259 String description,
260 MBeanAttributeInfo[] attributes,
261 MBeanConstructorInfo[] constructors,
262 MBeanOperationInfo[] operations,
263 MBeanNotificationInfo[] notifications) {
264 super("bogus", null, null, null, null, null);
265 this.className = className;
266 this.description = description;
267 this.attributes = attributes;
268 this.constructors = constructors;
269 this.operations = operations;
270 this.notifications = notifications;
271 }
272
273 public String getClassName() {
274 return className;
275 }
276
277 public String getDescription() {
278 return description;
279 }
280
281 public MBeanAttributeInfo[] getAttributes() {
282 return attributes;
283 }
284
285 public MBeanOperationInfo[] getOperations() {
286 return operations;
287 }
288
289 public MBeanConstructorInfo[] getConstructors() {
290 return constructors;
291 }
292
293 public MBeanNotificationInfo[] getNotifications() {
294 return notifications;
295 }
296 }
297
298 private static boolean checkEquals(String what, Object[][] equivs) {
299 boolean ok = true;
300 /* The equivs array is an array of equivalence classes. The members
301 of each equivalence class must be equal among themselves.
302 Each member of each equivalence class must be different from
303 each member of each other equivalence class. */
304 for (int ei = 0; ei < equivs.length; ei++) {
305 Object[] ec1 = equivs[ei];
306 ok &= checkSame(what + " equivalence class " + ei, ec1);
307 for (int ej = 0; ej < equivs.length; ej++) {
308 if (ei == ej)
309 continue;
310 Object[] ec2 = equivs[ej];
311 ok &= checkDifferent(what + " equivalence classes " +
312 ei + " and " + ej, ec1, ec2);
313 }
314 }
315 if (ok)
316 System.out.println("equals test for " + what + " passed");
317 return ok;
318 }
319
320 /* We could simplify this test to compare every element with every
321 other and choose whether they are supposed to be the same based
322 on whether they are in the same equivalence class. A bit
323 simpler, but so what. */
324
325 private static boolean checkSame(String what, Object[] equiv) {
326 boolean ok = true;
327 for (int i = 0; i < equiv.length; i++) {
328 final Object o1 = equiv[i];
329 for (int j = 0; j < equiv.length; j++) {
330 final Object o2 = equiv[j];
331 if (!o1.equals(o2)) {
332 System.out.println("equals test: " + what +
333 ": !obj[" + i +
334 "].equals(obj[" + j + "])");
335 System.out.println("..." + o1 + " " + o2);
336 ok = false;
337 }
338 if (o1.hashCode() != o2.hashCode()) {
339 System.out.println("equals test: " + what +
340 ": obj[" + i +
341 "].hashCode() != obj[" + j +
342 "].hashCode()");
343 System.out.println("..." + o1 + " " + o2);
344 ok = false;
345 }
346 }
347 }
348 return ok;
349 }
350
351 private static boolean checkDifferent(String what, Object[] equiv1,
352 Object[] equiv2) {
353 boolean ok = true;
354 for (int i = 0; i < equiv1.length; i++) {
355 final Object o1 = equiv1[i];
356 for (int j = 0; j < equiv2.length; j++) {
357 final Object o2 = equiv2[j];
358 if (o1.equals(o2)) {
359 System.out.println("equals test " + what + ": obj[" +
360 i + "].equals(obj[" + j + "])");
361 System.out.println("..." + o1 + " " + o2);
362 ok = false;
363 }
364 }
365 }
366 return ok;
367 }
368
369 public static void main(String[] args) throws Exception {
370 boolean ok = true;
371 ok &= checkEquals("equivalence", equivalenceClasses);
372 if (ok) {
373 System.out.println("all tests passed");
374 } else {
375 System.out.println("at least one test failed");
376 System.exit(1);
377 }
378 }
379}