author | dfuchs |
Thu, 02 Feb 2017 16:50:46 +0000 | |
changeset 43503 | bc7f8619ab70 |
parent 33499 | d4f084ec39eb |
permissions | -rw-r--r-- |
2 | 1 |
/* |
30376
2ccf2cf7ea48
8078896: Add @modules as needed to the jdk_svc tests
ykantser
parents:
18805
diff
changeset
|
2 |
* Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. |
2 | 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 |
* |
|
5506 | 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. |
|
2 | 22 |
*/ |
23 |
||
24 |
/* |
|
25 |
* @test |
|
18805
b359f8adc8ad
8010285: Enforce the requirement of Management Interfaces being public
jbachorik
parents:
5506
diff
changeset
|
26 |
* @bug 6175517 6278707 6318827 6305746 6392303 6600709 8010285 |
2 | 27 |
* @summary General MXBean test. |
28 |
* @author Eamonn McManus |
|
18805
b359f8adc8ad
8010285: Enforce the requirement of Management Interfaces being public
jbachorik
parents:
5506
diff
changeset
|
29 |
* @author Jaroslav Bachorik |
43503
bc7f8619ab70
8173607: JMX RMI connector should be in its own module
dfuchs
parents:
33499
diff
changeset
|
30 |
* @modules java.management.rmi |
2 | 31 |
* @run clean MXBeanTest MerlinMXBean TigerMXBean |
32 |
* @run build MXBeanTest MerlinMXBean TigerMXBean |
|
33 |
* @run main MXBeanTest |
|
34 |
*/ |
|
35 |
||
36 |
import java.lang.reflect.Array; |
|
37 |
import java.lang.reflect.Field; |
|
38 |
import java.lang.reflect.InvocationHandler; |
|
39 |
import java.lang.reflect.Method; |
|
40 |
import java.lang.reflect.Proxy; |
|
41 |
import java.util.Arrays; |
|
42 |
import java.util.Collection; |
|
43 |
import java.util.HashMap; |
|
44 |
import java.util.Iterator; |
|
831
50f701930577
6601652: MXBeans: no IllegalArgumentException in the ex. chain for SortedSet/Map with a non-null comparator()
emcmanus
parents:
2
diff
changeset
|
45 |
import java.util.Map; |
50f701930577
6601652: MXBeans: no IllegalArgumentException in the ex. chain for SortedSet/Map with a non-null comparator()
emcmanus
parents:
2
diff
changeset
|
46 |
import java.util.SortedMap; |
2 | 47 |
import javax.management.JMX; |
48 |
import javax.management.MBeanAttributeInfo; |
|
49 |
import javax.management.MBeanInfo; |
|
50 |
import javax.management.MBeanOperationInfo; |
|
51 |
import javax.management.MBeanParameterInfo; |
|
52 |
import javax.management.MBeanServer; |
|
53 |
import javax.management.MBeanServerConnection; |
|
54 |
import javax.management.MBeanServerFactory; |
|
55 |
import javax.management.MBeanServerInvocationHandler; |
|
18805
b359f8adc8ad
8010285: Enforce the requirement of Management Interfaces being public
jbachorik
parents:
5506
diff
changeset
|
56 |
import javax.management.NotCompliantMBeanException; |
2 | 57 |
import javax.management.ObjectName; |
58 |
import javax.management.StandardMBean; |
|
59 |
import javax.management.openmbean.ArrayType; |
|
60 |
import javax.management.openmbean.CompositeData; |
|
61 |
import javax.management.openmbean.CompositeDataInvocationHandler; |
|
62 |
import javax.management.openmbean.OpenType; |
|
63 |
import javax.management.openmbean.SimpleType; |
|
64 |
import javax.management.openmbean.TabularData; |
|
65 |
import javax.management.openmbean.TabularType; |
|
66 |
import javax.management.remote.JMXConnector; |
|
67 |
import javax.management.remote.JMXConnectorFactory; |
|
68 |
import javax.management.remote.JMXConnectorServer; |
|
69 |
import javax.management.remote.JMXConnectorServerFactory; |
|
70 |
import javax.management.remote.JMXServiceURL; |
|
71 |
||
72 |
public class MXBeanTest { |
|
73 |
public static void main(String[] args) throws Exception { |
|
74 |
testInterface(MerlinMXBean.class, false); |
|
75 |
testInterface(TigerMXBean.class, false); |
|
76 |
testInterface(MerlinMXBean.class, true); |
|
77 |
testInterface(TigerMXBean.class, true); |
|
78 |
testExplicitMXBean(); |
|
79 |
testSubclassMXBean(); |
|
80 |
testIndirectMXBean(); |
|
18805
b359f8adc8ad
8010285: Enforce the requirement of Management Interfaces being public
jbachorik
parents:
5506
diff
changeset
|
81 |
testNonCompliantMXBean("Private", new Private()); |
b359f8adc8ad
8010285: Enforce the requirement of Management Interfaces being public
jbachorik
parents:
5506
diff
changeset
|
82 |
testNonCompliantMXBean("NonCompliant", new NonCompliant()); |
2 | 83 |
|
84 |
if (failures == 0) |
|
85 |
System.out.println("Test passed"); |
|
831
50f701930577
6601652: MXBeans: no IllegalArgumentException in the ex. chain for SortedSet/Map with a non-null comparator()
emcmanus
parents:
2
diff
changeset
|
86 |
else |
50f701930577
6601652: MXBeans: no IllegalArgumentException in the ex. chain for SortedSet/Map with a non-null comparator()
emcmanus
parents:
2
diff
changeset
|
87 |
throw new Exception("TEST FAILURES: " + failures); |
2 | 88 |
} |
89 |
||
90 |
private static int failures = 0; |
|
91 |
||
18805
b359f8adc8ad
8010285: Enforce the requirement of Management Interfaces being public
jbachorik
parents:
5506
diff
changeset
|
92 |
private static interface PrivateMXBean { |
b359f8adc8ad
8010285: Enforce the requirement of Management Interfaces being public
jbachorik
parents:
5506
diff
changeset
|
93 |
public int[] getInts(); |
b359f8adc8ad
8010285: Enforce the requirement of Management Interfaces being public
jbachorik
parents:
5506
diff
changeset
|
94 |
} |
b359f8adc8ad
8010285: Enforce the requirement of Management Interfaces being public
jbachorik
parents:
5506
diff
changeset
|
95 |
|
b359f8adc8ad
8010285: Enforce the requirement of Management Interfaces being public
jbachorik
parents:
5506
diff
changeset
|
96 |
public static class Private implements PrivateMXBean { |
b359f8adc8ad
8010285: Enforce the requirement of Management Interfaces being public
jbachorik
parents:
5506
diff
changeset
|
97 |
public int[] getInts() { |
b359f8adc8ad
8010285: Enforce the requirement of Management Interfaces being public
jbachorik
parents:
5506
diff
changeset
|
98 |
return new int[]{1,2,3}; |
b359f8adc8ad
8010285: Enforce the requirement of Management Interfaces being public
jbachorik
parents:
5506
diff
changeset
|
99 |
} |
b359f8adc8ad
8010285: Enforce the requirement of Management Interfaces being public
jbachorik
parents:
5506
diff
changeset
|
100 |
} |
b359f8adc8ad
8010285: Enforce the requirement of Management Interfaces being public
jbachorik
parents:
5506
diff
changeset
|
101 |
|
b359f8adc8ad
8010285: Enforce the requirement of Management Interfaces being public
jbachorik
parents:
5506
diff
changeset
|
102 |
public static interface NonCompliantMXBean { |
b359f8adc8ad
8010285: Enforce the requirement of Management Interfaces being public
jbachorik
parents:
5506
diff
changeset
|
103 |
public boolean getInt(); |
b359f8adc8ad
8010285: Enforce the requirement of Management Interfaces being public
jbachorik
parents:
5506
diff
changeset
|
104 |
public boolean isInt(); |
b359f8adc8ad
8010285: Enforce the requirement of Management Interfaces being public
jbachorik
parents:
5506
diff
changeset
|
105 |
public void setInt(int a); |
b359f8adc8ad
8010285: Enforce the requirement of Management Interfaces being public
jbachorik
parents:
5506
diff
changeset
|
106 |
public void setInt(long b); |
b359f8adc8ad
8010285: Enforce the requirement of Management Interfaces being public
jbachorik
parents:
5506
diff
changeset
|
107 |
} |
b359f8adc8ad
8010285: Enforce the requirement of Management Interfaces being public
jbachorik
parents:
5506
diff
changeset
|
108 |
|
b359f8adc8ad
8010285: Enforce the requirement of Management Interfaces being public
jbachorik
parents:
5506
diff
changeset
|
109 |
public static class NonCompliant implements NonCompliantMXBean { |
b359f8adc8ad
8010285: Enforce the requirement of Management Interfaces being public
jbachorik
parents:
5506
diff
changeset
|
110 |
public boolean getInt() { |
b359f8adc8ad
8010285: Enforce the requirement of Management Interfaces being public
jbachorik
parents:
5506
diff
changeset
|
111 |
return false; |
b359f8adc8ad
8010285: Enforce the requirement of Management Interfaces being public
jbachorik
parents:
5506
diff
changeset
|
112 |
} |
b359f8adc8ad
8010285: Enforce the requirement of Management Interfaces being public
jbachorik
parents:
5506
diff
changeset
|
113 |
|
b359f8adc8ad
8010285: Enforce the requirement of Management Interfaces being public
jbachorik
parents:
5506
diff
changeset
|
114 |
public boolean isInt() { |
b359f8adc8ad
8010285: Enforce the requirement of Management Interfaces being public
jbachorik
parents:
5506
diff
changeset
|
115 |
return true; |
b359f8adc8ad
8010285: Enforce the requirement of Management Interfaces being public
jbachorik
parents:
5506
diff
changeset
|
116 |
} |
b359f8adc8ad
8010285: Enforce the requirement of Management Interfaces being public
jbachorik
parents:
5506
diff
changeset
|
117 |
|
b359f8adc8ad
8010285: Enforce the requirement of Management Interfaces being public
jbachorik
parents:
5506
diff
changeset
|
118 |
public void setInt(int a) { |
b359f8adc8ad
8010285: Enforce the requirement of Management Interfaces being public
jbachorik
parents:
5506
diff
changeset
|
119 |
} |
b359f8adc8ad
8010285: Enforce the requirement of Management Interfaces being public
jbachorik
parents:
5506
diff
changeset
|
120 |
|
b359f8adc8ad
8010285: Enforce the requirement of Management Interfaces being public
jbachorik
parents:
5506
diff
changeset
|
121 |
public void setInt(long b) { |
b359f8adc8ad
8010285: Enforce the requirement of Management Interfaces being public
jbachorik
parents:
5506
diff
changeset
|
122 |
} |
b359f8adc8ad
8010285: Enforce the requirement of Management Interfaces being public
jbachorik
parents:
5506
diff
changeset
|
123 |
} |
b359f8adc8ad
8010285: Enforce the requirement of Management Interfaces being public
jbachorik
parents:
5506
diff
changeset
|
124 |
|
2 | 125 |
public static interface ExplicitMXBean { |
126 |
public int[] getInts(); |
|
127 |
} |
|
128 |
public static class Explicit implements ExplicitMXBean { |
|
129 |
public int[] getInts() { |
|
130 |
return new int[] {1, 2, 3}; |
|
131 |
} |
|
132 |
} |
|
133 |
public static class Subclass |
|
134 |
extends StandardMBean |
|
135 |
implements ExplicitMXBean { |
|
136 |
public Subclass() { |
|
137 |
super(ExplicitMXBean.class, true); |
|
138 |
} |
|
139 |
||
140 |
public int[] getInts() { |
|
141 |
return new int[] {1, 2, 3}; |
|
142 |
} |
|
143 |
} |
|
144 |
public static interface IndirectInterface extends ExplicitMXBean {} |
|
145 |
public static class Indirect implements IndirectInterface { |
|
146 |
public int[] getInts() { |
|
147 |
return new int[] {1, 2, 3}; |
|
148 |
} |
|
149 |
} |
|
150 |
||
18805
b359f8adc8ad
8010285: Enforce the requirement of Management Interfaces being public
jbachorik
parents:
5506
diff
changeset
|
151 |
private static void testNonCompliantMXBean(String type, Object bean) throws Exception { |
b359f8adc8ad
8010285: Enforce the requirement of Management Interfaces being public
jbachorik
parents:
5506
diff
changeset
|
152 |
System.out.println(type + " MXBean test..."); |
b359f8adc8ad
8010285: Enforce the requirement of Management Interfaces being public
jbachorik
parents:
5506
diff
changeset
|
153 |
MBeanServer mbs = MBeanServerFactory.newMBeanServer(); |
b359f8adc8ad
8010285: Enforce the requirement of Management Interfaces being public
jbachorik
parents:
5506
diff
changeset
|
154 |
ObjectName on = new ObjectName("test:type=" + type); |
b359f8adc8ad
8010285: Enforce the requirement of Management Interfaces being public
jbachorik
parents:
5506
diff
changeset
|
155 |
try { |
b359f8adc8ad
8010285: Enforce the requirement of Management Interfaces being public
jbachorik
parents:
5506
diff
changeset
|
156 |
mbs.registerMBean(bean, on); |
b359f8adc8ad
8010285: Enforce the requirement of Management Interfaces being public
jbachorik
parents:
5506
diff
changeset
|
157 |
failure(bean.getClass().getInterfaces()[0].getName() + " is not a compliant " |
b359f8adc8ad
8010285: Enforce the requirement of Management Interfaces being public
jbachorik
parents:
5506
diff
changeset
|
158 |
+ "MXBean interface"); |
b359f8adc8ad
8010285: Enforce the requirement of Management Interfaces being public
jbachorik
parents:
5506
diff
changeset
|
159 |
} catch (NotCompliantMBeanException e) { |
b359f8adc8ad
8010285: Enforce the requirement of Management Interfaces being public
jbachorik
parents:
5506
diff
changeset
|
160 |
success("Non-compliant MXBean not registered"); |
b359f8adc8ad
8010285: Enforce the requirement of Management Interfaces being public
jbachorik
parents:
5506
diff
changeset
|
161 |
} |
b359f8adc8ad
8010285: Enforce the requirement of Management Interfaces being public
jbachorik
parents:
5506
diff
changeset
|
162 |
} |
b359f8adc8ad
8010285: Enforce the requirement of Management Interfaces being public
jbachorik
parents:
5506
diff
changeset
|
163 |
|
2 | 164 |
private static void testExplicitMXBean() throws Exception { |
165 |
System.out.println("Explicit MXBean test..."); |
|
166 |
MBeanServer mbs = MBeanServerFactory.newMBeanServer(); |
|
167 |
ObjectName on = new ObjectName("test:type=Explicit"); |
|
168 |
Explicit explicit = new Explicit(); |
|
169 |
mbs.registerMBean(explicit, on); |
|
170 |
testMXBean(mbs, on); |
|
171 |
} |
|
172 |
||
173 |
private static void testSubclassMXBean() throws Exception { |
|
174 |
System.out.println("Subclass MXBean test..."); |
|
175 |
MBeanServer mbs = MBeanServerFactory.newMBeanServer(); |
|
176 |
ObjectName on = new ObjectName("test:type=Subclass"); |
|
177 |
Subclass subclass = new Subclass(); |
|
178 |
mbs.registerMBean(subclass, on); |
|
179 |
testMXBean(mbs, on); |
|
180 |
} |
|
181 |
||
182 |
private static void testIndirectMXBean() throws Exception { |
|
183 |
System.out.println("Indirect MXBean test..."); |
|
184 |
MBeanServer mbs = MBeanServerFactory.newMBeanServer(); |
|
185 |
ObjectName on = new ObjectName("test:type=Indirect"); |
|
186 |
Indirect indirect = new Indirect(); |
|
187 |
mbs.registerMBean(indirect, on); |
|
188 |
testMXBean(mbs, on); |
|
189 |
} |
|
190 |
||
191 |
private static void testMXBean(MBeanServer mbs, ObjectName on) |
|
192 |
throws Exception { |
|
193 |
MBeanInfo mbi = mbs.getMBeanInfo(on); |
|
194 |
MBeanAttributeInfo[] attrs = mbi.getAttributes(); |
|
195 |
int nattrs = attrs.length; |
|
196 |
if (mbi.getAttributes().length != 1) |
|
197 |
failure("wrong number of attributes: " + attrs); |
|
198 |
else { |
|
199 |
MBeanAttributeInfo mbai = attrs[0]; |
|
200 |
if (mbai.getName().equals("Ints") |
|
201 |
&& mbai.isReadable() && !mbai.isWritable() |
|
202 |
&& mbai.getDescriptor().getFieldValue("openType") |
|
1004 | 203 |
.equals(new ArrayType<int[]>(SimpleType.INTEGER, true)) |
2 | 204 |
&& attrs[0].getType().equals("[I")) |
205 |
success("MBeanAttributeInfo"); |
|
206 |
else |
|
207 |
failure("MBeanAttributeInfo: " + mbai); |
|
208 |
} |
|
209 |
||
210 |
int[] ints = (int[]) mbs.getAttribute(on, "Ints"); |
|
211 |
if (equal(ints, new int[] {1, 2, 3}, null)) |
|
212 |
success("getAttribute"); |
|
213 |
else |
|
214 |
failure("getAttribute: " + Arrays.toString(ints)); |
|
215 |
||
216 |
ExplicitMXBean proxy = |
|
217 |
JMX.newMXBeanProxy(mbs, on, ExplicitMXBean.class); |
|
218 |
int[] pints = proxy.getInts(); |
|
219 |
if (equal(pints, new int[] {1, 2, 3}, null)) |
|
220 |
success("getAttribute through proxy"); |
|
221 |
else |
|
222 |
failure("getAttribute through proxy: " + Arrays.toString(pints)); |
|
223 |
} |
|
224 |
||
225 |
private static class NamedMXBeans extends HashMap<ObjectName, Object> { |
|
226 |
private static final long serialVersionUID = 0; |
|
227 |
||
228 |
NamedMXBeans(MBeanServerConnection mbsc) { |
|
229 |
this.mbsc = mbsc; |
|
230 |
} |
|
231 |
||
232 |
MBeanServerConnection getMBeanServerConnection() { |
|
233 |
return mbsc; |
|
234 |
} |
|
235 |
||
236 |
private final MBeanServerConnection mbsc; |
|
237 |
} |
|
238 |
||
239 |
/* This is the core of the test. Given the MXBean interface c, we |
|
240 |
make an MXBean object that implements that interface by |
|
241 |
constructing a dynamic proxy. If the interface defines an |
|
242 |
attribute Foo (with getFoo and setFoo methods), then it must |
|
243 |
also contain a field (constant) Foo of the same type, and a |
|
244 |
field (constant) FooType that is an OpenType. The field Foo is |
|
245 |
a reference value for this case. We check that the attribute |
|
246 |
does indeed have the given OpenType. The dynamically-created |
|
247 |
MXBean will return the reference value from the getFoo() |
|
248 |
method, and we check that that value survives the mapping to |
|
249 |
open values and back when the attribute is accessed through an |
|
250 |
MXBean proxy. The MXBean will also check in its setFoo method |
|
251 |
that the value being set is equal to the reference value, which |
|
252 |
tests that the mapping and unmapping also works in the other |
|
253 |
direction. The interface should define an operation opFoo with |
|
254 |
two parameters and a return value all of the same type as the |
|
255 |
attribute. The MXBean will check that the two parameters are |
|
256 |
equal to the reference value, and will return that value. The |
|
257 |
test checks that calling the operation through an MXBean proxy |
|
258 |
returns the reference value, again after mapping to and back |
|
259 |
from open values. |
|
260 |
||
261 |
If any field (constant) in the MXBean interface has a name that |
|
262 |
ends with ObjectName, say FooObjectName, then its value must be |
|
263 |
a String containing an ObjectName value. There must be a field |
|
264 |
(constant) called Foo that is a valid MXBean, and that MXBean |
|
265 |
will be registered in the MBean Server with the given name before |
|
266 |
the test starts. This enables us to test that inter-MXBean |
|
267 |
references are correctly converted to ObjectNames and back. |
|
268 |
*/ |
|
269 |
private static <T> void testInterface(Class<T> c, boolean nullTest) |
|
270 |
throws Exception { |
|
271 |
||
272 |
System.out.println("Testing " + c.getName() + |
|
273 |
(nullTest ? " for null values" : "") + "..."); |
|
274 |
||
275 |
MBeanServer mbs = MBeanServerFactory.newMBeanServer(); |
|
276 |
||
277 |
JMXServiceURL url = new JMXServiceURL("rmi", null, 0); |
|
278 |
JMXConnectorServer cs = |
|
279 |
JMXConnectorServerFactory.newJMXConnectorServer(url, null, mbs); |
|
280 |
cs.start(); |
|
281 |
JMXServiceURL addr = cs.getAddress(); |
|
282 |
JMXConnector cc = JMXConnectorFactory.connect(addr); |
|
283 |
MBeanServerConnection mbsc = cc.getMBeanServerConnection(); |
|
284 |
||
285 |
NamedMXBeans namedMXBeans = new NamedMXBeans(mbsc); |
|
286 |
InvocationHandler ih = |
|
287 |
nullTest ? new MXBeanNullImplInvocationHandler(c, namedMXBeans) : |
|
288 |
new MXBeanImplInvocationHandler(c, namedMXBeans); |
|
289 |
T impl = c.cast(Proxy.newProxyInstance(c.getClassLoader(), |
|
290 |
new Class[] {c}, |
|
291 |
ih)); |
|
292 |
ObjectName on = new ObjectName("test:type=" + c.getName()); |
|
293 |
mbs.registerMBean(impl, on); |
|
294 |
||
295 |
System.out.println("Register any MXBeans..."); |
|
296 |
||
297 |
Field[] fields = c.getFields(); |
|
298 |
for (Field field : fields) { |
|
299 |
String n = field.getName(); |
|
300 |
if (n.endsWith("ObjectName")) { |
|
301 |
String objectNameString = (String) field.get(null); |
|
302 |
String base = n.substring(0, n.length() - 10); |
|
303 |
Field f = c.getField(base); |
|
304 |
Object mxbean = f.get(null); |
|
305 |
ObjectName objectName = |
|
306 |
ObjectName.getInstance(objectNameString); |
|
307 |
mbs.registerMBean(mxbean, objectName); |
|
308 |
namedMXBeans.put(objectName, mxbean); |
|
309 |
} |
|
310 |
} |
|
311 |
||
312 |
try { |
|
313 |
testInterface(c, mbsc, on, namedMXBeans, nullTest); |
|
314 |
} finally { |
|
315 |
try { |
|
316 |
cc.close(); |
|
317 |
} finally { |
|
318 |
cs.stop(); |
|
319 |
} |
|
320 |
} |
|
321 |
} |
|
322 |
||
323 |
private static <T> void testInterface(Class<T> c, |
|
324 |
MBeanServerConnection mbsc, |
|
325 |
ObjectName on, |
|
326 |
NamedMXBeans namedMXBeans, |
|
327 |
boolean nullTest) |
|
328 |
throws Exception { |
|
329 |
||
330 |
System.out.println("Type check..."); |
|
331 |
||
332 |
MBeanInfo mbi = mbsc.getMBeanInfo(on); |
|
333 |
MBeanAttributeInfo[] mbais = mbi.getAttributes(); |
|
334 |
for (int i = 0; i < mbais.length; i++) { |
|
335 |
MBeanAttributeInfo mbai = mbais[i]; |
|
336 |
String name = mbai.getName(); |
|
337 |
Field typeField = c.getField(name + "Type"); |
|
338 |
OpenType typeValue = (OpenType) typeField.get(null); |
|
339 |
OpenType openType = |
|
340 |
(OpenType) mbai.getDescriptor().getFieldValue("openType"); |
|
341 |
if (typeValue.equals(openType)) |
|
342 |
success("attribute " + name); |
|
343 |
else { |
|
344 |
final String msg = |
|
345 |
"Wrong type attribute " + name + ": " + |
|
346 |
openType + " should be " + typeValue; |
|
347 |
failure(msg); |
|
348 |
} |
|
349 |
} |
|
350 |
||
351 |
MBeanOperationInfo[] mbois = mbi.getOperations(); |
|
352 |
for (int i = 0; i < mbois.length; i++) { |
|
353 |
MBeanOperationInfo mboi = mbois[i]; |
|
354 |
String oname = mboi.getName(); |
|
355 |
if (!oname.startsWith("op")) |
|
356 |
throw new Error(); |
|
357 |
OpenType retType = |
|
358 |
(OpenType) mboi.getDescriptor().getFieldValue("openType"); |
|
359 |
MBeanParameterInfo[] params = mboi.getSignature(); |
|
360 |
MBeanParameterInfo p1i = params[0]; |
|
361 |
MBeanParameterInfo p2i = params[1]; |
|
362 |
OpenType p1Type = |
|
363 |
(OpenType) p1i.getDescriptor().getFieldValue("openType"); |
|
364 |
OpenType p2Type = |
|
365 |
(OpenType) p2i.getDescriptor().getFieldValue("openType"); |
|
366 |
if (!retType.equals(p1Type) || !p1Type.equals(p2Type)) { |
|
367 |
final String msg = |
|
368 |
"Parameter and return open types should all be same " + |
|
369 |
"but are not: " + retType + " " + oname + "(" + p1Type + |
|
370 |
", " + p2Type + ")"; |
|
371 |
failure(msg); |
|
372 |
continue; |
|
373 |
} |
|
374 |
String name = oname.substring(2); |
|
375 |
Field typeField = c.getField(name + "Type"); |
|
376 |
OpenType typeValue = (OpenType) typeField.get(null); |
|
377 |
if (typeValue.equals(retType)) |
|
378 |
success("operation " + oname); |
|
379 |
else { |
|
380 |
final String msg = |
|
381 |
"Wrong type operation " + oname + ": " + |
|
382 |
retType + " should be " + typeValue; |
|
383 |
failure(msg); |
|
384 |
} |
|
385 |
} |
|
386 |
||
387 |
||
388 |
System.out.println("Mapping check..."); |
|
389 |
||
390 |
Object proxy = |
|
391 |
JMX.newMXBeanProxy(mbsc, on, c); |
|
392 |
||
393 |
Method[] methods = c.getMethods(); |
|
394 |
for (int i = 0; i < methods.length; i++) { |
|
395 |
final Method method = methods[i]; |
|
396 |
if (method.getDeclaringClass() != c) |
|
397 |
continue; // skip hashCode() etc inherited from Object |
|
398 |
final String mname = method.getName(); |
|
399 |
final int what = getType(method); |
|
400 |
final String name = getName(method); |
|
401 |
final Field refField = c.getField(name); |
|
402 |
if (nullTest && refField.getType().isPrimitive()) |
|
403 |
continue; |
|
404 |
final Field openTypeField = c.getField(name + "Type"); |
|
405 |
final OpenType openType = (OpenType) openTypeField.get(null); |
|
406 |
final Object refValue = nullTest ? null : refField.get(null); |
|
407 |
Object setValue = refValue; |
|
408 |
try { |
|
409 |
Field onField = c.getField(name + "ObjectName"); |
|
410 |
String refName = (String) onField.get(null); |
|
411 |
ObjectName refObjName = ObjectName.getInstance(refName); |
|
412 |
Class<?> mxbeanInterface = refField.getType(); |
|
413 |
setValue = nullTest ? null : |
|
414 |
JMX.newMXBeanProxy(mbsc, refObjName, mxbeanInterface); |
|
415 |
} catch (Exception e) { |
|
416 |
// no xObjectName field, setValue == refValue |
|
417 |
} |
|
418 |
boolean ok = true; |
|
419 |
try { |
|
420 |
switch (what) { |
|
421 |
case GET: |
|
422 |
final Object gotOpen = mbsc.getAttribute(on, name); |
|
423 |
if (nullTest) { |
|
424 |
if (gotOpen != null) { |
|
425 |
failure(mname + " got non-null value " + |
|
426 |
gotOpen); |
|
427 |
ok = false; |
|
428 |
} |
|
429 |
} else if (!openType.isValue(gotOpen)) { |
|
430 |
if (gotOpen instanceof TabularData) { |
|
431 |
// detail the mismatch |
|
432 |
TabularData gotTabular = (TabularData) gotOpen; |
|
433 |
compareTabularType((TabularType) openType, |
|
434 |
gotTabular.getTabularType()); |
|
435 |
} |
|
436 |
failure(mname + " got open data " + gotOpen + |
|
437 |
" not valid for open type " + openType); |
|
438 |
ok = false; |
|
439 |
} |
|
440 |
final Object got = method.invoke(proxy, (Object[]) null); |
|
441 |
if (!equal(refValue, got, namedMXBeans)) { |
|
442 |
failure(mname + " got " + string(got) + |
|
443 |
", should be " + string(refValue)); |
|
444 |
ok = false; |
|
445 |
} |
|
446 |
break; |
|
447 |
||
448 |
case SET: |
|
449 |
method.invoke(proxy, new Object[] {setValue}); |
|
450 |
break; |
|
451 |
||
452 |
case OP: |
|
453 |
final Object opped = |
|
454 |
method.invoke(proxy, new Object[] {setValue, setValue}); |
|
455 |
if (!equal(refValue, opped, namedMXBeans)) { |
|
456 |
failure( |
|
457 |
mname + " got " + string(opped) + |
|
458 |
", should be " + string(refValue) |
|
459 |
); |
|
460 |
ok = false; |
|
461 |
} |
|
462 |
break; |
|
463 |
||
464 |
default: |
|
465 |
throw new Error(); |
|
466 |
} |
|
467 |
||
468 |
if (ok) |
|
469 |
success(mname); |
|
470 |
||
471 |
} catch (Exception e) { |
|
472 |
failure(mname, e); |
|
473 |
} |
|
474 |
} |
|
475 |
} |
|
476 |
||
477 |
||
478 |
private static void success(String what) { |
|
479 |
System.out.println("OK: " + what); |
|
480 |
} |
|
481 |
||
482 |
private static void failure(String what) { |
|
483 |
System.out.println("FAILED: " + what); |
|
484 |
failures++; |
|
485 |
} |
|
486 |
||
487 |
private static void failure(String what, Exception e) { |
|
488 |
System.out.println("FAILED WITH EXCEPTION: " + what); |
|
489 |
e.printStackTrace(System.out); |
|
490 |
failures++; |
|
491 |
} |
|
492 |
||
493 |
private static class MXBeanImplInvocationHandler |
|
494 |
implements InvocationHandler { |
|
495 |
MXBeanImplInvocationHandler(Class intf, NamedMXBeans namedMXBeans) { |
|
496 |
this.intf = intf; |
|
497 |
this.namedMXBeans = namedMXBeans; |
|
498 |
} |
|
499 |
||
500 |
public Object invoke(Object proxy, Method method, Object[] args) |
|
501 |
throws Throwable { |
|
502 |
final String mname = method.getName(); |
|
503 |
final int what = getType(method); |
|
504 |
final String name = getName(method); |
|
505 |
final Field refField = intf.getField(name); |
|
506 |
final Object refValue = getRefValue(refField); |
|
507 |
||
508 |
switch (what) { |
|
509 |
case GET: |
|
510 |
assert args == null; |
|
511 |
return refValue; |
|
512 |
||
513 |
case SET: |
|
514 |
assert args.length == 1; |
|
515 |
Object setValue = args[0]; |
|
516 |
if (!equal(refValue, setValue, namedMXBeans)) { |
|
517 |
final String msg = |
|
518 |
mname + "(" + string(setValue) + |
|
519 |
") does not match ref: " + string(refValue); |
|
520 |
throw new IllegalArgumentException(msg); |
|
521 |
} |
|
522 |
return null; |
|
523 |
||
524 |
case OP: |
|
525 |
assert args.length == 2; |
|
526 |
Object arg1 = args[0]; |
|
527 |
Object arg2 = args[1]; |
|
528 |
if (!equal(arg1, arg2, namedMXBeans)) { |
|
529 |
final String msg = |
|
530 |
mname + "(" + string(arg1) + ", " + string(arg2) + |
|
531 |
"): args not equal"; |
|
532 |
throw new IllegalArgumentException(msg); |
|
533 |
} |
|
534 |
if (!equal(refValue, arg1, namedMXBeans)) { |
|
535 |
final String msg = |
|
536 |
mname + "(" + string(arg1) + ", " + string(arg2) + |
|
537 |
"): args do not match ref: " + string(refValue); |
|
538 |
throw new IllegalArgumentException(msg); |
|
539 |
} |
|
540 |
return refValue; |
|
541 |
default: |
|
542 |
throw new Error(); |
|
543 |
} |
|
544 |
} |
|
545 |
||
546 |
Object getRefValue(Field refField) throws Exception { |
|
547 |
return refField.get(null); |
|
548 |
} |
|
549 |
||
550 |
private final Class intf; |
|
551 |
private final NamedMXBeans namedMXBeans; |
|
552 |
} |
|
553 |
||
554 |
private static class MXBeanNullImplInvocationHandler |
|
555 |
extends MXBeanImplInvocationHandler { |
|
556 |
MXBeanNullImplInvocationHandler(Class intf, NamedMXBeans namedMXBeans) { |
|
557 |
super(intf, namedMXBeans); |
|
558 |
} |
|
559 |
||
560 |
@Override |
|
561 |
Object getRefValue(Field refField) throws Exception { |
|
562 |
Class<?> type = refField.getType(); |
|
563 |
if (type.isPrimitive()) |
|
564 |
return super.getRefValue(refField); |
|
565 |
else |
|
566 |
return null; |
|
567 |
} |
|
568 |
} |
|
569 |
||
570 |
||
571 |
private static final String[] prefixes = { |
|
572 |
"get", "set", "op", |
|
573 |
}; |
|
574 |
private static final int GET = 0, SET = 1, OP = 2; |
|
575 |
||
576 |
private static String getName(Method m) { |
|
577 |
return getName(m.getName()); |
|
578 |
} |
|
579 |
||
580 |
private static String getName(String n) { |
|
581 |
for (int i = 0; i < prefixes.length; i++) { |
|
582 |
if (n.startsWith(prefixes[i])) |
|
583 |
return n.substring(prefixes[i].length()); |
|
584 |
} |
|
585 |
throw new Error(); |
|
586 |
} |
|
587 |
||
588 |
private static int getType(Method m) { |
|
589 |
return getType(m.getName()); |
|
590 |
} |
|
591 |
||
592 |
private static int getType(String n) { |
|
593 |
for (int i = 0; i < prefixes.length; i++) { |
|
594 |
if (n.startsWith(prefixes[i])) |
|
595 |
return i; |
|
596 |
} |
|
597 |
throw new Error(); |
|
598 |
} |
|
599 |
||
600 |
static boolean equal(Object o1, Object o2, NamedMXBeans namedMXBeans) { |
|
601 |
if (o1 == o2) |
|
602 |
return true; |
|
603 |
if (o1 == null || o2 == null) |
|
604 |
return false; |
|
605 |
if (o1.getClass().isArray()) { |
|
606 |
if (!o2.getClass().isArray()) |
|
607 |
return false; |
|
608 |
return deepEqual(o1, o2, namedMXBeans); |
|
609 |
} |
|
831
50f701930577
6601652: MXBeans: no IllegalArgumentException in the ex. chain for SortedSet/Map with a non-null comparator()
emcmanus
parents:
2
diff
changeset
|
610 |
if (o1 instanceof Map) { |
50f701930577
6601652: MXBeans: no IllegalArgumentException in the ex. chain for SortedSet/Map with a non-null comparator()
emcmanus
parents:
2
diff
changeset
|
611 |
if (!(o2 instanceof Map)) |
50f701930577
6601652: MXBeans: no IllegalArgumentException in the ex. chain for SortedSet/Map with a non-null comparator()
emcmanus
parents:
2
diff
changeset
|
612 |
return false; |
50f701930577
6601652: MXBeans: no IllegalArgumentException in the ex. chain for SortedSet/Map with a non-null comparator()
emcmanus
parents:
2
diff
changeset
|
613 |
return equalMap((Map) o1, (Map) o2, namedMXBeans); |
50f701930577
6601652: MXBeans: no IllegalArgumentException in the ex. chain for SortedSet/Map with a non-null comparator()
emcmanus
parents:
2
diff
changeset
|
614 |
} |
2 | 615 |
if (o1 instanceof CompositeData && o2 instanceof CompositeData) { |
616 |
return compositeDataEqual((CompositeData) o1, (CompositeData) o2, |
|
617 |
namedMXBeans); |
|
618 |
} |
|
619 |
if (Proxy.isProxyClass(o1.getClass())) { |
|
620 |
if (Proxy.isProxyClass(o2.getClass())) |
|
621 |
return proxyEqual(o1, o2, namedMXBeans); |
|
622 |
InvocationHandler ih = Proxy.getInvocationHandler(o1); |
|
623 |
// if (ih instanceof MXBeanInvocationHandler) { |
|
624 |
// return proxyEqualsObject((MXBeanInvocationHandler) ih, |
|
625 |
// o2, namedMXBeans); |
|
626 |
if (ih instanceof MBeanServerInvocationHandler) { |
|
627 |
return true; |
|
628 |
} else if (ih instanceof CompositeDataInvocationHandler) { |
|
629 |
return o2.equals(o1); |
|
630 |
// We assume the other object has a reasonable equals method |
|
631 |
} |
|
632 |
} else if (Proxy.isProxyClass(o2.getClass())) |
|
633 |
return equal(o2, o1, namedMXBeans); |
|
634 |
return o1.equals(o2); |
|
635 |
} |
|
636 |
||
637 |
// We'd use Arrays.deepEquals except we want the test to work on 1.4 |
|
638 |
// Note this code assumes no selfreferential arrays |
|
639 |
// (as does Arrays.deepEquals) |
|
640 |
private static boolean deepEqual(Object a1, Object a2, |
|
641 |
NamedMXBeans namedMXBeans) { |
|
642 |
int len = Array.getLength(a1); |
|
643 |
if (len != Array.getLength(a2)) |
|
644 |
return false; |
|
645 |
for (int i = 0; i < len; i++) { |
|
646 |
Object e1 = Array.get(a1, i); |
|
647 |
Object e2 = Array.get(a2, i); |
|
648 |
if (!equal(e1, e2, namedMXBeans)) |
|
649 |
return false; |
|
650 |
} |
|
651 |
return true; |
|
652 |
} |
|
653 |
||
831
50f701930577
6601652: MXBeans: no IllegalArgumentException in the ex. chain for SortedSet/Map with a non-null comparator()
emcmanus
parents:
2
diff
changeset
|
654 |
private static boolean equalMap(Map<?,?> m1, Map<?,?> m2, |
50f701930577
6601652: MXBeans: no IllegalArgumentException in the ex. chain for SortedSet/Map with a non-null comparator()
emcmanus
parents:
2
diff
changeset
|
655 |
NamedMXBeans namedMXBeans) { |
50f701930577
6601652: MXBeans: no IllegalArgumentException in the ex. chain for SortedSet/Map with a non-null comparator()
emcmanus
parents:
2
diff
changeset
|
656 |
if (m1.size() != m2.size()) |
50f701930577
6601652: MXBeans: no IllegalArgumentException in the ex. chain for SortedSet/Map with a non-null comparator()
emcmanus
parents:
2
diff
changeset
|
657 |
return false; |
50f701930577
6601652: MXBeans: no IllegalArgumentException in the ex. chain for SortedSet/Map with a non-null comparator()
emcmanus
parents:
2
diff
changeset
|
658 |
if ((m1 instanceof SortedMap) != (m2 instanceof SortedMap)) |
50f701930577
6601652: MXBeans: no IllegalArgumentException in the ex. chain for SortedSet/Map with a non-null comparator()
emcmanus
parents:
2
diff
changeset
|
659 |
return false; |
50f701930577
6601652: MXBeans: no IllegalArgumentException in the ex. chain for SortedSet/Map with a non-null comparator()
emcmanus
parents:
2
diff
changeset
|
660 |
for (Object k1 : m1.keySet()) { |
50f701930577
6601652: MXBeans: no IllegalArgumentException in the ex. chain for SortedSet/Map with a non-null comparator()
emcmanus
parents:
2
diff
changeset
|
661 |
if (!m2.containsKey(k1)) |
50f701930577
6601652: MXBeans: no IllegalArgumentException in the ex. chain for SortedSet/Map with a non-null comparator()
emcmanus
parents:
2
diff
changeset
|
662 |
return false; |
50f701930577
6601652: MXBeans: no IllegalArgumentException in the ex. chain for SortedSet/Map with a non-null comparator()
emcmanus
parents:
2
diff
changeset
|
663 |
if (!equal(m1.get(k1), m2.get(k1), namedMXBeans)) |
50f701930577
6601652: MXBeans: no IllegalArgumentException in the ex. chain for SortedSet/Map with a non-null comparator()
emcmanus
parents:
2
diff
changeset
|
664 |
return false; |
50f701930577
6601652: MXBeans: no IllegalArgumentException in the ex. chain for SortedSet/Map with a non-null comparator()
emcmanus
parents:
2
diff
changeset
|
665 |
} |
50f701930577
6601652: MXBeans: no IllegalArgumentException in the ex. chain for SortedSet/Map with a non-null comparator()
emcmanus
parents:
2
diff
changeset
|
666 |
return true; |
50f701930577
6601652: MXBeans: no IllegalArgumentException in the ex. chain for SortedSet/Map with a non-null comparator()
emcmanus
parents:
2
diff
changeset
|
667 |
} |
50f701930577
6601652: MXBeans: no IllegalArgumentException in the ex. chain for SortedSet/Map with a non-null comparator()
emcmanus
parents:
2
diff
changeset
|
668 |
|
2 | 669 |
// This is needed to work around a bug (5095277) |
670 |
// in CompositeDataSupport.equals |
|
671 |
private static boolean compositeDataEqual(CompositeData cd1, |
|
672 |
CompositeData cd2, |
|
673 |
NamedMXBeans namedMXBeans) { |
|
674 |
if (cd1 == cd2) |
|
675 |
return true; |
|
676 |
if (!cd1.getCompositeType().equals(cd2.getCompositeType())) |
|
677 |
return false; |
|
678 |
Collection v1 = cd1.values(); |
|
679 |
Collection v2 = cd2.values(); |
|
680 |
if (v1.size() != v2.size()) |
|
681 |
return false; // should not happen |
|
682 |
for (Iterator i1 = v1.iterator(), i2 = v2.iterator(); |
|
683 |
i1.hasNext(); ) { |
|
684 |
if (!equal(i1.next(), i2.next(), namedMXBeans)) |
|
685 |
return false; |
|
686 |
} |
|
687 |
return true; |
|
688 |
} |
|
689 |
||
690 |
// Also needed for 5095277 |
|
691 |
private static boolean proxyEqual(Object proxy1, Object proxy2, |
|
692 |
NamedMXBeans namedMXBeans) { |
|
693 |
if (proxy1.getClass() != proxy2.getClass()) |
|
694 |
return proxy1.equals(proxy2); |
|
695 |
InvocationHandler ih1 = Proxy.getInvocationHandler(proxy1); |
|
696 |
InvocationHandler ih2 = Proxy.getInvocationHandler(proxy2); |
|
697 |
if (!(ih1 instanceof CompositeDataInvocationHandler) |
|
698 |
|| !(ih2 instanceof CompositeDataInvocationHandler)) |
|
699 |
return proxy1.equals(proxy2); |
|
700 |
CompositeData cd1 = |
|
701 |
((CompositeDataInvocationHandler) ih1).getCompositeData(); |
|
702 |
CompositeData cd2 = |
|
703 |
((CompositeDataInvocationHandler) ih2).getCompositeData(); |
|
704 |
return compositeDataEqual(cd1, cd2, namedMXBeans); |
|
705 |
} |
|
706 |
||
707 |
// private static boolean proxyEqualsObject(MXBeanInvocationHandler ih, |
|
708 |
// Object o, |
|
709 |
// NamedMXBeans namedMXBeans) { |
|
710 |
// if (namedMXBeans.getMBeanServerConnection() != |
|
711 |
// ih.getMBeanServerConnection()) |
|
712 |
// return false; |
|
713 |
// |
|
714 |
// ObjectName on = ih.getObjectName(); |
|
715 |
// Object named = namedMXBeans.get(on); |
|
716 |
// if (named == null) |
|
717 |
// return false; |
|
718 |
// return (o == named && ih.getMXBeanInterface().isInstance(named)); |
|
719 |
// } |
|
720 |
||
721 |
/* I wanted to call this method toString(Object), but oddly enough |
|
722 |
this meant that I couldn't call it from the inner class |
|
723 |
MXBeanImplInvocationHandler, because the inherited Object.toString() |
|
831
50f701930577
6601652: MXBeans: no IllegalArgumentException in the ex. chain for SortedSet/Map with a non-null comparator()
emcmanus
parents:
2
diff
changeset
|
724 |
prevented that. */ |
2 | 725 |
static String string(Object o) { |
726 |
if (o == null) |
|
727 |
return "null"; |
|
728 |
if (o instanceof String) |
|
729 |
return '"' + (String) o + '"'; |
|
730 |
if (o instanceof Collection) |
|
731 |
return deepToString((Collection) o); |
|
732 |
if (o.getClass().isArray()) |
|
733 |
return deepToString(o); |
|
734 |
return o.toString(); |
|
735 |
} |
|
736 |
||
737 |
private static String deepToString(Object o) { |
|
738 |
StringBuffer buf = new StringBuffer(); |
|
739 |
buf.append("["); |
|
740 |
int len = Array.getLength(o); |
|
741 |
for (int i = 0; i < len; i++) { |
|
742 |
if (i > 0) |
|
743 |
buf.append(", "); |
|
744 |
Object e = Array.get(o, i); |
|
745 |
buf.append(string(e)); |
|
746 |
} |
|
747 |
buf.append("]"); |
|
748 |
return buf.toString(); |
|
749 |
} |
|
750 |
||
751 |
private static String deepToString(Collection c) { |
|
752 |
return deepToString(c.toArray()); |
|
753 |
} |
|
754 |
||
755 |
private static void compareTabularType(TabularType t1, TabularType t2) { |
|
756 |
if (t1.equals(t2)) { |
|
757 |
System.out.println("same tabular type"); |
|
758 |
return; |
|
759 |
} |
|
760 |
if (t1.getClassName().equals(t2.getClassName())) |
|
761 |
System.out.println("same class name"); |
|
762 |
if (t1.getDescription().equals(t2.getDescription())) |
|
763 |
System.out.println("same description"); |
|
764 |
else { |
|
765 |
System.out.println("t1 description: " + t1.getDescription()); |
|
766 |
System.out.println("t2 description: " + t2.getDescription()); |
|
767 |
} |
|
768 |
if (t1.getIndexNames().equals(t2.getIndexNames())) |
|
769 |
System.out.println("same index names"); |
|
770 |
if (t1.getRowType().equals(t2.getRowType())) |
|
771 |
System.out.println("same row type"); |
|
772 |
} |
|
773 |
} |