2
|
1 |
/*
|
|
2 |
* Copyright 2005-2006 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. Sun designates this
|
|
8 |
* particular file as subject to the "Classpath" exception as provided
|
|
9 |
* by Sun in the LICENSE file that accompanied this code.
|
|
10 |
*
|
|
11 |
* This code is distributed in the hope that it will be useful, but WITHOUT
|
|
12 |
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
13 |
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
14 |
* version 2 for more details (a copy is included in the LICENSE file that
|
|
15 |
* accompanied this code).
|
|
16 |
*
|
|
17 |
* You should have received a copy of the GNU General Public License version
|
|
18 |
* 2 along with this work; if not, write to the Free Software Foundation,
|
|
19 |
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
20 |
*
|
|
21 |
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
|
|
22 |
* CA 95054 USA or visit www.sun.com if you need additional information or
|
|
23 |
* have any questions.
|
|
24 |
*/
|
|
25 |
|
|
26 |
package com.sun.jmx.mbeanserver;
|
|
27 |
|
|
28 |
|
|
29 |
import static com.sun.jmx.mbeanserver.Util.*;
|
|
30 |
|
|
31 |
import java.lang.ref.WeakReference;
|
|
32 |
import java.lang.reflect.Array;
|
|
33 |
import java.lang.reflect.Constructor;
|
|
34 |
import java.lang.reflect.InvocationTargetException;
|
|
35 |
import java.lang.reflect.Method;
|
|
36 |
import java.lang.reflect.Type;
|
287
|
37 |
import java.util.Arrays;
|
2
|
38 |
import java.util.List;
|
|
39 |
import java.util.WeakHashMap;
|
|
40 |
|
|
41 |
import javax.management.Descriptor;
|
|
42 |
import javax.management.ImmutableDescriptor;
|
687
|
43 |
import javax.management.IntrospectionException;
|
2
|
44 |
import javax.management.InvalidAttributeValueException;
|
|
45 |
import javax.management.MBeanAttributeInfo;
|
|
46 |
import javax.management.MBeanConstructorInfo;
|
|
47 |
import javax.management.MBeanException;
|
|
48 |
import javax.management.MBeanInfo;
|
|
49 |
import javax.management.MBeanNotificationInfo;
|
|
50 |
import javax.management.MBeanOperationInfo;
|
|
51 |
import javax.management.NotCompliantMBeanException;
|
|
52 |
import javax.management.NotificationBroadcaster;
|
|
53 |
import javax.management.ReflectionException;
|
|
54 |
|
|
55 |
/**
|
|
56 |
* An introspector for MBeans of a certain type. There is one instance
|
687
|
57 |
* of this class for Standard MBeans, and one for every MXBeanMappingFactory;
|
|
58 |
* these two cases correspond to the two concrete subclasses of this abstract
|
|
59 |
* class.
|
2
|
60 |
*
|
|
61 |
* @param <M> the representation of methods for this kind of MBean:
|
|
62 |
* Method for Standard MBeans, ConvertingMethod for MXBeans.
|
|
63 |
*
|
|
64 |
* @since 1.6
|
|
65 |
*/
|
|
66 |
/*
|
|
67 |
* Using a type parameter <M> allows us to deal with the fact that
|
|
68 |
* Method and ConvertingMethod have no useful common ancestor, on
|
|
69 |
* which we could call getName, getGenericReturnType, etc. A simpler approach
|
|
70 |
* would be to wrap every Method in an object that does have a common
|
|
71 |
* ancestor with ConvertingMethod. But that would mean an extra object
|
|
72 |
* for every Method in every Standard MBean interface.
|
|
73 |
*/
|
|
74 |
abstract class MBeanIntrospector<M> {
|
|
75 |
static final class PerInterfaceMap<M>
|
|
76 |
extends WeakHashMap<Class<?>, WeakReference<PerInterface<M>>> {}
|
|
77 |
|
|
78 |
/** The map from interface to PerInterface for this type of MBean. */
|
|
79 |
abstract PerInterfaceMap<M> getPerInterfaceMap();
|
|
80 |
/**
|
|
81 |
* The map from concrete implementation class and interface to
|
|
82 |
* MBeanInfo for this type of MBean.
|
|
83 |
*/
|
|
84 |
abstract MBeanInfoMap getMBeanInfoMap();
|
|
85 |
|
|
86 |
/** Make an interface analyzer for this type of MBean. */
|
|
87 |
abstract MBeanAnalyzer<M> getAnalyzer(Class<?> mbeanInterface)
|
|
88 |
throws NotCompliantMBeanException;
|
|
89 |
|
|
90 |
/** True if MBeans with this kind of introspector are MXBeans. */
|
|
91 |
abstract boolean isMXBean();
|
|
92 |
|
|
93 |
/** Find the M corresponding to the given Method. */
|
|
94 |
abstract M mFrom(Method m);
|
|
95 |
|
|
96 |
/** Get the name of this method. */
|
|
97 |
abstract String getName(M m);
|
|
98 |
|
|
99 |
/**
|
|
100 |
* Get the return type of this method. This is the return type
|
|
101 |
* of a method in a Java interface, so for MXBeans it is the
|
|
102 |
* declared Java type, not the mapped Open Type.
|
|
103 |
*/
|
|
104 |
abstract Type getGenericReturnType(M m);
|
|
105 |
|
|
106 |
/**
|
|
107 |
* Get the parameter types of this method in the Java interface
|
|
108 |
* it came from.
|
|
109 |
*/
|
|
110 |
abstract Type[] getGenericParameterTypes(M m);
|
|
111 |
|
|
112 |
/**
|
|
113 |
* Get the signature of this method as a caller would have to supply
|
|
114 |
* it in MBeanServer.invoke. For MXBeans, the named types will be
|
|
115 |
* the mapped Open Types for the parameters.
|
|
116 |
*/
|
|
117 |
abstract String[] getSignature(M m);
|
|
118 |
|
|
119 |
/**
|
|
120 |
* Check that this method is valid. For example, a method in an
|
|
121 |
* MXBean interface is not valid if one of its parameters cannot be
|
|
122 |
* mapped to an Open Type.
|
|
123 |
*/
|
687
|
124 |
abstract void checkMethod(M m);
|
2
|
125 |
|
|
126 |
/**
|
|
127 |
* Invoke the method with the given target and arguments.
|
|
128 |
*
|
|
129 |
* @param cookie Additional information about the target. For an
|
|
130 |
* MXBean, this is the MXBeanLookup associated with the MXBean.
|
|
131 |
*/
|
|
132 |
/*
|
|
133 |
* It would be cleaner if the type of the cookie were a
|
|
134 |
* type parameter to this class, but that would involve a lot of
|
|
135 |
* messy type parameter propagation just to avoid a couple of casts.
|
|
136 |
*/
|
|
137 |
abstract Object invokeM2(M m, Object target, Object[] args, Object cookie)
|
|
138 |
throws InvocationTargetException, IllegalAccessException,
|
|
139 |
MBeanException;
|
|
140 |
|
|
141 |
/**
|
|
142 |
* Test whether the given value is valid for the given parameter of this
|
|
143 |
* M.
|
|
144 |
*/
|
|
145 |
abstract boolean validParameter(M m, Object value, int paramNo,
|
|
146 |
Object cookie);
|
|
147 |
|
|
148 |
/**
|
|
149 |
* Construct an MBeanAttributeInfo for the given attribute based on the
|
|
150 |
* given getter and setter. One but not both of the getter and setter
|
|
151 |
* may be null.
|
|
152 |
*/
|
|
153 |
abstract MBeanAttributeInfo getMBeanAttributeInfo(String attributeName,
|
687
|
154 |
M getter, M setter) throws IntrospectionException;
|
|
155 |
|
2
|
156 |
/**
|
|
157 |
* Construct an MBeanOperationInfo for the given operation based on
|
|
158 |
* the M it was derived from.
|
|
159 |
*/
|
|
160 |
abstract MBeanOperationInfo getMBeanOperationInfo(String operationName,
|
|
161 |
M operation);
|
|
162 |
|
|
163 |
/**
|
|
164 |
* Get a Descriptor containing fields that MBeans of this kind will
|
|
165 |
* always have. For example, MXBeans will always have "mxbean=true".
|
|
166 |
*/
|
|
167 |
abstract Descriptor getBasicMBeanDescriptor();
|
|
168 |
|
|
169 |
/**
|
|
170 |
* Get a Descriptor containing additional fields beyond the ones
|
|
171 |
* from getBasicMBeanDescriptor that MBeans whose concrete class
|
|
172 |
* is resourceClass will always have.
|
|
173 |
*/
|
|
174 |
abstract Descriptor getMBeanDescriptor(Class<?> resourceClass);
|
|
175 |
|
687
|
176 |
/**
|
|
177 |
* Get any additional Descriptor entries for this introspector instance.
|
|
178 |
* If there is a non-default MXBeanMappingFactory, it will appear in
|
|
179 |
* this Descriptor.
|
|
180 |
* @return Additional Descriptor entries, or an empty Descriptor if none.
|
|
181 |
*/
|
|
182 |
Descriptor getSpecificMBeanDescriptor() {
|
|
183 |
return ImmutableDescriptor.EMPTY_DESCRIPTOR;
|
|
184 |
}
|
|
185 |
|
287
|
186 |
void checkCompliance(Class<?> mbeanType) throws NotCompliantMBeanException {
|
|
187 |
if (!mbeanType.isInterface()) {
|
|
188 |
throw new NotCompliantMBeanException("Not an interface: " +
|
|
189 |
mbeanType.getName());
|
|
190 |
}
|
|
191 |
}
|
|
192 |
|
|
193 |
/**
|
|
194 |
* Get the methods to be analyzed to build the MBean interface.
|
|
195 |
*/
|
|
196 |
List<Method> getMethods(final Class<?> mbeanType) throws Exception {
|
|
197 |
return Arrays.asList(mbeanType.getMethods());
|
|
198 |
}
|
2
|
199 |
|
|
200 |
final PerInterface<M> getPerInterface(Class<?> mbeanInterface)
|
|
201 |
throws NotCompliantMBeanException {
|
|
202 |
PerInterfaceMap<M> map = getPerInterfaceMap();
|
|
203 |
synchronized (map) {
|
|
204 |
WeakReference<PerInterface<M>> wr = map.get(mbeanInterface);
|
|
205 |
PerInterface<M> pi = (wr == null) ? null : wr.get();
|
|
206 |
if (pi == null) {
|
|
207 |
try {
|
|
208 |
MBeanAnalyzer<M> analyzer = getAnalyzer(mbeanInterface);
|
|
209 |
MBeanInfo mbeanInfo =
|
|
210 |
makeInterfaceMBeanInfo(mbeanInterface, analyzer);
|
|
211 |
pi = new PerInterface<M>(mbeanInterface, this, analyzer,
|
|
212 |
mbeanInfo);
|
|
213 |
wr = new WeakReference<PerInterface<M>>(pi);
|
|
214 |
map.put(mbeanInterface, wr);
|
|
215 |
} catch (Exception x) {
|
|
216 |
throw Introspector.throwException(mbeanInterface,x);
|
|
217 |
}
|
|
218 |
}
|
|
219 |
return pi;
|
|
220 |
}
|
|
221 |
}
|
|
222 |
|
|
223 |
/**
|
|
224 |
* Make the MBeanInfo skeleton for the given MBean interface using
|
|
225 |
* the given analyzer. This will never be the MBeanInfo of any real
|
|
226 |
* MBean (because the getClassName() must be a concrete class), but
|
|
227 |
* its MBeanAttributeInfo[] and MBeanOperationInfo[] can be inserted
|
|
228 |
* into such an MBeanInfo, and its Descriptor can be the basis for
|
|
229 |
* the MBeanInfo's Descriptor.
|
|
230 |
*/
|
|
231 |
private MBeanInfo makeInterfaceMBeanInfo(Class<?> mbeanInterface,
|
687
|
232 |
MBeanAnalyzer<M> analyzer) throws IntrospectionException {
|
2
|
233 |
final MBeanInfoMaker maker = new MBeanInfoMaker();
|
|
234 |
analyzer.visit(maker);
|
|
235 |
final String description =
|
|
236 |
"Information on the management interface of the MBean";
|
|
237 |
return maker.makeMBeanInfo(mbeanInterface, description);
|
|
238 |
}
|
|
239 |
|
|
240 |
/** True if the given getter and setter are consistent. */
|
|
241 |
final boolean consistent(M getter, M setter) {
|
|
242 |
return (getter == null || setter == null ||
|
|
243 |
getGenericReturnType(getter).equals(getGenericParameterTypes(setter)[0]));
|
|
244 |
}
|
|
245 |
|
|
246 |
/**
|
|
247 |
* Invoke the given M on the given target with the given args and cookie.
|
|
248 |
* Wrap exceptions appropriately.
|
|
249 |
*/
|
|
250 |
final Object invokeM(M m, Object target, Object[] args, Object cookie)
|
|
251 |
throws MBeanException, ReflectionException {
|
|
252 |
try {
|
|
253 |
return invokeM2(m, target, args, cookie);
|
|
254 |
} catch (InvocationTargetException e) {
|
|
255 |
unwrapInvocationTargetException(e);
|
|
256 |
throw new RuntimeException(e); // not reached
|
|
257 |
} catch (IllegalAccessException e) {
|
|
258 |
throw new ReflectionException(e, e.toString());
|
|
259 |
}
|
|
260 |
/* We do not catch and wrap RuntimeException or Error,
|
|
261 |
* because we're in a DynamicMBean, so the logic for DynamicMBeans
|
|
262 |
* will do the wrapping.
|
|
263 |
*/
|
|
264 |
}
|
|
265 |
|
|
266 |
/**
|
|
267 |
* Invoke the given setter on the given target with the given argument
|
|
268 |
* and cookie. Wrap exceptions appropriately.
|
|
269 |
*/
|
|
270 |
/* If the value is of the wrong type for the method we are about to
|
|
271 |
* invoke, we are supposed to throw an InvalidAttributeValueException.
|
|
272 |
* Rather than making the check always, we invoke the method, then
|
|
273 |
* if it throws an exception we check the type to see if that was
|
|
274 |
* what caused the exception. The assumption is that an exception
|
|
275 |
* from an invalid type will arise before any user method is ever
|
|
276 |
* called (either in reflection or in OpenConverter).
|
|
277 |
*/
|
|
278 |
final void invokeSetter(String name, M setter, Object target, Object arg,
|
|
279 |
Object cookie)
|
|
280 |
throws MBeanException, ReflectionException,
|
|
281 |
InvalidAttributeValueException {
|
|
282 |
try {
|
|
283 |
invokeM2(setter, target, new Object[] {arg}, cookie);
|
|
284 |
} catch (IllegalAccessException e) {
|
|
285 |
throw new ReflectionException(e, e.toString());
|
|
286 |
} catch (RuntimeException e) {
|
|
287 |
maybeInvalidParameter(name, setter, arg, cookie);
|
|
288 |
throw e;
|
|
289 |
} catch (InvocationTargetException e) {
|
|
290 |
maybeInvalidParameter(name, setter, arg, cookie);
|
|
291 |
unwrapInvocationTargetException(e);
|
|
292 |
}
|
|
293 |
}
|
|
294 |
|
|
295 |
private void maybeInvalidParameter(String name, M setter, Object arg,
|
|
296 |
Object cookie)
|
|
297 |
throws InvalidAttributeValueException {
|
|
298 |
if (!validParameter(setter, arg, 0, cookie)) {
|
|
299 |
final String msg =
|
|
300 |
"Invalid value for attribute " + name + ": " + arg;
|
|
301 |
throw new InvalidAttributeValueException(msg);
|
|
302 |
}
|
|
303 |
}
|
|
304 |
|
|
305 |
static boolean isValidParameter(Method m, Object value, int paramNo) {
|
|
306 |
Class<?> c = m.getParameterTypes()[paramNo];
|
|
307 |
try {
|
|
308 |
// Following is expensive but we only call this method to determine
|
|
309 |
// if an exception is due to an incompatible parameter type.
|
|
310 |
// Plain old c.isInstance doesn't work for primitive types.
|
|
311 |
Object a = Array.newInstance(c, 1);
|
|
312 |
Array.set(a, 0, value);
|
|
313 |
return true;
|
|
314 |
} catch (IllegalArgumentException e) {
|
|
315 |
return false;
|
|
316 |
}
|
|
317 |
}
|
|
318 |
|
|
319 |
private static void
|
|
320 |
unwrapInvocationTargetException(InvocationTargetException e)
|
|
321 |
throws MBeanException {
|
|
322 |
Throwable t = e.getCause();
|
|
323 |
if (t instanceof RuntimeException)
|
|
324 |
throw (RuntimeException) t;
|
|
325 |
else if (t instanceof Error)
|
|
326 |
throw (Error) t;
|
|
327 |
else
|
|
328 |
throw new MBeanException((Exception) t,
|
|
329 |
(t == null ? null : t.toString()));
|
|
330 |
}
|
|
331 |
|
|
332 |
/** A visitor that constructs the per-interface MBeanInfo. */
|
687
|
333 |
private class MBeanInfoMaker
|
|
334 |
implements MBeanAnalyzer.MBeanVisitor<M, IntrospectionException> {
|
2
|
335 |
|
|
336 |
public void visitAttribute(String attributeName,
|
|
337 |
M getter,
|
687
|
338 |
M setter) throws IntrospectionException {
|
2
|
339 |
MBeanAttributeInfo mbai =
|
|
340 |
getMBeanAttributeInfo(attributeName, getter, setter);
|
|
341 |
|
|
342 |
attrs.add(mbai);
|
|
343 |
}
|
|
344 |
|
|
345 |
public void visitOperation(String operationName,
|
|
346 |
M operation) {
|
|
347 |
MBeanOperationInfo mboi =
|
|
348 |
getMBeanOperationInfo(operationName, operation);
|
|
349 |
|
|
350 |
ops.add(mboi);
|
|
351 |
}
|
|
352 |
|
|
353 |
/** Make an MBeanInfo based on the attributes and operations
|
|
354 |
* found in the interface. */
|
|
355 |
MBeanInfo makeMBeanInfo(Class<?> mbeanInterface,
|
|
356 |
String description) {
|
|
357 |
final MBeanAttributeInfo[] attrArray =
|
|
358 |
attrs.toArray(new MBeanAttributeInfo[0]);
|
|
359 |
final MBeanOperationInfo[] opArray =
|
|
360 |
ops.toArray(new MBeanOperationInfo[0]);
|
|
361 |
final String interfaceClassName =
|
|
362 |
"interfaceClassName=" + mbeanInterface.getName();
|
687
|
363 |
final Descriptor classNameDescriptor =
|
2
|
364 |
new ImmutableDescriptor(interfaceClassName);
|
|
365 |
final Descriptor mbeanDescriptor = getBasicMBeanDescriptor();
|
|
366 |
final Descriptor annotatedDescriptor =
|
|
367 |
Introspector.descriptorForElement(mbeanInterface);
|
|
368 |
final Descriptor descriptor =
|
687
|
369 |
DescriptorCache.getInstance().union(
|
|
370 |
classNameDescriptor,
|
2
|
371 |
mbeanDescriptor,
|
|
372 |
annotatedDescriptor);
|
|
373 |
|
|
374 |
return new MBeanInfo(mbeanInterface.getName(),
|
|
375 |
description,
|
|
376 |
attrArray,
|
|
377 |
null,
|
|
378 |
opArray,
|
|
379 |
null,
|
|
380 |
descriptor);
|
|
381 |
}
|
|
382 |
|
|
383 |
private final List<MBeanAttributeInfo> attrs = newList();
|
|
384 |
private final List<MBeanOperationInfo> ops = newList();
|
|
385 |
}
|
|
386 |
|
|
387 |
/*
|
|
388 |
* Looking up the MBeanInfo for a given base class (implementation class)
|
|
389 |
* is complicated by the fact that we may use the same base class with
|
|
390 |
* several different explicit MBean interfaces via the
|
|
391 |
* javax.management.StandardMBean class. It is further complicated
|
|
392 |
* by the fact that we have to be careful not to retain a strong reference
|
|
393 |
* to any Class object for fear we would prevent a ClassLoader from being
|
|
394 |
* garbage-collected. So we have a first lookup from the base class
|
|
395 |
* to a map for each interface that base class might specify giving
|
|
396 |
* the MBeanInfo constructed for that base class and interface.
|
|
397 |
*/
|
|
398 |
static class MBeanInfoMap
|
|
399 |
extends WeakHashMap<Class<?>, WeakHashMap<Class<?>, MBeanInfo>> {
|
|
400 |
}
|
|
401 |
|
|
402 |
/**
|
|
403 |
* Return the MBeanInfo for the given resource, based on the given
|
|
404 |
* per-interface data.
|
|
405 |
*/
|
687
|
406 |
final MBeanInfo getMBeanInfo(Object resource, PerInterface<M> perInterface)
|
|
407 |
throws NotCompliantMBeanException {
|
2
|
408 |
MBeanInfo mbi =
|
|
409 |
getClassMBeanInfo(resource.getClass(), perInterface);
|
|
410 |
MBeanNotificationInfo[] notifs = findNotifications(resource);
|
687
|
411 |
Descriptor d = getSpecificMBeanDescriptor();
|
|
412 |
boolean anyNotifs = (notifs != null && notifs.length > 0);
|
|
413 |
if (!anyNotifs && ImmutableDescriptor.EMPTY_DESCRIPTOR.equals(d))
|
2
|
414 |
return mbi;
|
|
415 |
else {
|
687
|
416 |
d = ImmutableDescriptor.union(d, mbi.getDescriptor());
|
2
|
417 |
return new MBeanInfo(mbi.getClassName(),
|
|
418 |
mbi.getDescription(),
|
|
419 |
mbi.getAttributes(),
|
|
420 |
mbi.getConstructors(),
|
|
421 |
mbi.getOperations(),
|
|
422 |
notifs,
|
687
|
423 |
d);
|
2
|
424 |
}
|
|
425 |
}
|
|
426 |
|
|
427 |
/**
|
|
428 |
* Return the basic MBeanInfo for resources of the given class and
|
|
429 |
* per-interface data. This MBeanInfo might not be the final MBeanInfo
|
|
430 |
* for instances of the class, because if the class is a
|
|
431 |
* NotificationBroadcaster then each instance gets to decide what
|
|
432 |
* MBeanNotificationInfo[] to put in its own MBeanInfo.
|
|
433 |
*/
|
|
434 |
final MBeanInfo getClassMBeanInfo(Class<?> resourceClass,
|
|
435 |
PerInterface<M> perInterface) {
|
|
436 |
MBeanInfoMap map = getMBeanInfoMap();
|
|
437 |
synchronized (map) {
|
|
438 |
WeakHashMap<Class<?>, MBeanInfo> intfMap = map.get(resourceClass);
|
|
439 |
if (intfMap == null) {
|
|
440 |
intfMap = new WeakHashMap<Class<?>, MBeanInfo>();
|
|
441 |
map.put(resourceClass, intfMap);
|
|
442 |
}
|
|
443 |
Class<?> intfClass = perInterface.getMBeanInterface();
|
|
444 |
MBeanInfo mbi = intfMap.get(intfClass);
|
|
445 |
if (mbi == null) {
|
|
446 |
MBeanInfo imbi = perInterface.getMBeanInfo();
|
|
447 |
Descriptor descriptor =
|
|
448 |
ImmutableDescriptor.union(imbi.getDescriptor(),
|
|
449 |
getMBeanDescriptor(resourceClass));
|
|
450 |
mbi = new MBeanInfo(resourceClass.getName(),
|
|
451 |
imbi.getDescription(),
|
|
452 |
imbi.getAttributes(),
|
|
453 |
findConstructors(resourceClass),
|
|
454 |
imbi.getOperations(),
|
|
455 |
(MBeanNotificationInfo[]) null,
|
|
456 |
descriptor);
|
|
457 |
intfMap.put(intfClass, mbi);
|
|
458 |
}
|
|
459 |
return mbi;
|
|
460 |
}
|
|
461 |
}
|
|
462 |
|
|
463 |
static MBeanNotificationInfo[] findNotifications(Object moi) {
|
|
464 |
if (!(moi instanceof NotificationBroadcaster))
|
|
465 |
return null;
|
|
466 |
MBeanNotificationInfo[] mbn =
|
|
467 |
((NotificationBroadcaster) moi).getNotificationInfo();
|
687
|
468 |
if (mbn == null || mbn.length == 0)
|
2
|
469 |
return null;
|
|
470 |
MBeanNotificationInfo[] result =
|
|
471 |
new MBeanNotificationInfo[mbn.length];
|
|
472 |
for (int i = 0; i < mbn.length; i++) {
|
|
473 |
MBeanNotificationInfo ni = mbn[i];
|
|
474 |
if (ni.getClass() != MBeanNotificationInfo.class)
|
|
475 |
ni = (MBeanNotificationInfo) ni.clone();
|
|
476 |
result[i] = ni;
|
|
477 |
}
|
|
478 |
return result;
|
|
479 |
}
|
|
480 |
|
|
481 |
private static MBeanConstructorInfo[] findConstructors(Class<?> c) {
|
|
482 |
Constructor[] cons = c.getConstructors();
|
|
483 |
MBeanConstructorInfo[] mbc = new MBeanConstructorInfo[cons.length];
|
|
484 |
for (int i = 0; i < cons.length; i++) {
|
|
485 |
final String descr = "Public constructor of the MBean";
|
|
486 |
mbc[i] = new MBeanConstructorInfo(descr, cons[i]);
|
|
487 |
}
|
|
488 |
return mbc;
|
|
489 |
}
|
|
490 |
|
|
491 |
}
|