1 | /** |
2 | * Class <code>ModelMBeanIntegrator<code>. |
3 | */ |
4 | package org.jsesoft.mmbi; |
5 | |
6 | import java.lang.annotation.Annotation; |
7 | import java.lang.reflect.Constructor; |
8 | import java.lang.reflect.Field; |
9 | import java.lang.reflect.InvocationTargetException; |
10 | import java.lang.reflect.Method; |
11 | import java.lang.reflect.Modifier; |
12 | import java.beans.*; |
13 | import java.util.Vector; |
14 | import javax.management.Descriptor; |
15 | import javax.management.MBeanException; |
16 | import javax.management.MBeanOperationInfo; |
17 | import javax.management.MBeanParameterInfo; |
18 | import javax.management.MBeanServer; |
19 | import javax.management.ObjectName; |
20 | import javax.management.modelmbean.DescriptorSupport; |
21 | import javax.management.modelmbean.ModelMBeanAttributeInfo; |
22 | import javax.management.modelmbean.ModelMBeanConstructorInfo; |
23 | import javax.management.modelmbean.ModelMBeanInfo; |
24 | import javax.management.modelmbean.ModelMBeanInfoSupport; |
25 | import javax.management.modelmbean.ModelMBeanOperationInfo; |
26 | import javax.management.modelmbean.XMLParseException; |
27 | import javax.management.modelmbean.ModelMBeanNotificationInfo; |
28 | |
29 | import org.jsesoft.ri.InspectorSupport; |
30 | import org.jsesoft.ri.ReflectionInspector; |
31 | |
32 | /** |
33 | * Instruments (an registers) an arbitrary object as Model MBean. |
34 | * |
35 | * <p> |
36 | * This class provides JMX Model MBean instrumentation and registration |
37 | * for objects of arbitrary classes. It is implemented as a strategy for the |
38 | * {@link org.jsesoft.ri.ReflectionInspector <code>ReflectionInspector</code>} |
39 | * class. |
40 | * </p> |
41 | * <p> |
42 | * <b>Example:</b> |
43 | * <code> |
44 | * <pre> |
45 | * ModelMBeanInstrumentor instrumentor = new ModelMBeanInstrumentor(); |
46 | * SampleResource resource = new SampleResource(); |
47 | * NamedModelMBean mbean = instrumentor.instrument( resource, "sampleResource" ); |
48 | * System.out.println( "Stop JConsole " + mbean.getName().getCanonicalName() ); |
49 | * MBeanServer server = |
50 | * java.lang.management.ManagementFactory.getPlatformMBeanServer(); |
51 | * int count = 300; |
52 | * while( ! resource.isStopped() ) { |
53 | * Thread.sleep( 100 ); |
54 | * count--; |
55 | * if( (count <= 0) && (! resource.isControlled()) ) { |
56 | * resource.setStopped( true ); |
57 | * } |
58 | * } |
59 | * server.unregisterMBean( mbean.getName() ); |
60 | * </pre> |
61 | * </code> |
62 | * </p> |
63 | * |
64 | * @author JSESoft |
65 | * @version $Revision: 1.6 $ |
66 | */ |
67 | public class ModelMBeanInstrumentor |
68 | extends InspectorSupport |
69 | { |
70 | /** The mbean's descriptor. */ |
71 | private Descriptor mbeanDescriptor; |
72 | /** The mbean's ModelMBeanInfo. */ |
73 | private ModelMBeanInfo mbeanInfo; |
74 | /** The actually insepted classes JavaBean BeanInfo */ |
75 | BeanInfo beanInfo; |
76 | /** The mbean's construcotr infos. */ |
77 | private Vector<ModelMBeanConstructorInfo> constructorInfos; |
78 | /** The mbean's operation infos. */ |
79 | private Vector<ModelMBeanOperationInfo> operationInfos; |
80 | /** The mbean's attribuye infos. */ |
81 | private Vector<ModelMBeanAttributeInfo> attributeInfos; |
82 | /** The mbean's attribuye infos. */ |
83 | private Vector<ModelMBeanNotificationInfo> notificationInfos; |
84 | /** A type specifier for Vector.toArray() */ |
85 | private static final ModelMBeanConstructorInfo[] constructors |
86 | = new ModelMBeanConstructorInfo[0]; |
87 | /** A type specifier for Vector.toArray() */ |
88 | private static final ModelMBeanOperationInfo[] operations |
89 | = new ModelMBeanOperationInfo[0]; |
90 | /** A type specifier for Vector.toArray() */ |
91 | private static final ModelMBeanAttributeInfo[] attributes |
92 | = new ModelMBeanAttributeInfo[0]; |
93 | /** A type specifier for Vector.toArray() */ |
94 | private static final ModelMBeanNotificationInfo[] notifications |
95 | = new ModelMBeanNotificationInfo[0]; |
96 | /** The class where to stop reflection recursion. */ |
97 | private Class sentinel; |
98 | /** Whether or not to produce debug info. */ |
99 | private static final boolean debug = true; |
100 | /** The mbean itself. */ |
101 | private NamedModelMBean mbean = null; |
102 | /** The inspector uesed. */ |
103 | private ReflectionInspector inspector; |
104 | |
105 | /** |
106 | * Constructs an instance with <code>Object.class</code> |
107 | * as sentinel. |
108 | * |
109 | * @see #ModelMBeanInstrumentor(Class) |
110 | */ |
111 | public ModelMBeanInstrumentor() |
112 | { |
113 | this( Object.class ); |
114 | } |
115 | |
116 | /** |
117 | * Constructs an instance with the specified class as sentinel. |
118 | * |
119 | * <p> |
120 | * Traversal of the reflection tree is recusrsive with respect |
121 | * to inheritance. The <b>sentinel</b> specifies where recursion stops. |
122 | * Default is <code>Object.class</code> (see |
123 | * {@link #ModelMBeanInstrumentor() non-parameter constructor}). |
124 | * </p> |
125 | * @param sentinel Class where recursive traversal stops |
126 | */ |
127 | public ModelMBeanInstrumentor( Class sentinel ) |
128 | { |
129 | super(); |
130 | this.sentinel = sentinel; |
131 | } |
132 | |
133 | /** |
134 | * Creates a <code>ModelMBean</code> for a managed resource. |
135 | * |
136 | * @param managedResource the resource to be managed as Model MBean |
137 | * @return the created NamedModelMBean |
138 | * @throws Exception if instrumentation fails |
139 | */ |
140 | public NamedModelMBean instrument( Object managedResource ) |
141 | throws Exception |
142 | { |
143 | return instrument( managedResource, null ); |
144 | } |
145 | |
146 | /** |
147 | * Creates a <code>ModelMBean</code> for a managed resource |
148 | * and registers it as JMX MBean. |
149 | * |
150 | * <p> |
151 | * This function is the workhorse of this class. It |
152 | * <ol> |
153 | * <li> |
154 | * It creates a {@link NamedModelMBean <code>NamedModelMBean</code>} |
155 | * instance. |
156 | * </li> |
157 | * <li> |
158 | * It internally creates an |
159 | * {@link org.jsesoft.ri.ReflectionInspector ReflectionInspector} for |
160 | * traversing the reflection tree. |
161 | * </li> |
162 | * <li> |
163 | * It inspects the managed resource. |
164 | * </li> |
165 | * <li> |
166 | * if the <code>nickName</code> parameter is null, thats it. Otherqwise |
167 | * </li> |
168 | * <li> |
169 | * It creates an object name like this |
170 | * <code> |
171 | * <pre> |
172 | * classnameOfManagedResource:id=nickName-hashCode |
173 | * </pre> |
174 | * </code> |
175 | * </li> |
176 | * <li> |
177 | * registers the MBean at the platform MBean server |
178 | * </li> |
179 | * <li> |
180 | * sets the instance of the mbean |
181 | * </li> |
182 | * </ol> |
183 | * </p> |
184 | * |
185 | * @param managedResource the resource to be managed as Model MBean |
186 | * @param nickName part of the object name (if null then don't register) |
187 | * @return the created NamedModelMBean |
188 | * @throws Exception if instrumentation fails |
189 | */ |
190 | public NamedModelMBean instrument( Object managedResource, String nickName ) |
191 | throws Exception |
192 | { |
193 | mbeanInfo = null; |
194 | attributeInfos = null; |
195 | constructorInfos = null; |
196 | operationInfos = null; |
197 | notificationInfos = null; |
198 | mbean = new NamedModelMBean(); |
199 | mbean.setManagedResource( managedResource, "ObjectReference" ); |
200 | inspector = new ReflectionInspector(); |
201 | beanInfo = |
202 | Introspector.getBeanInfo( managedResource.getClass(), sentinel ); |
203 | inspector.setInspectee( managedResource.getClass() ); |
204 | inspector.setStrategy( this ); |
205 | boolean reply = inspector.inspect(); |
206 | assert reply:"inspection failed"; |
207 | if( nickName == null ) { |
208 | return mbean; |
209 | } |
210 | StringBuilder name = |
211 | new StringBuilder( managedResource.getClass().getName() ); |
212 | name.append( ":id=" ).append( nickName ).append( "-" ).append( managedResource. |
213 | hashCode() ); |
214 | ObjectName objectName = new ObjectName( name.toString() ); |
215 | MBeanServer server = java.lang.management.ManagementFactory. |
216 | getPlatformMBeanServer(); |
217 | mbean.setInstance( server.registerMBean( mbean, objectName ) ); |
218 | return mbean; |
219 | } |
220 | |
221 | /** |
222 | * This override sets the mbean's MBeanInfo after inspection. |
223 | * |
224 | * <p> |
225 | * <b>Note:</b> This function is not intended to be called |
226 | * by customers. Instead, it is called by the inspector. |
227 | * </p> |
228 | * @param inspected the inspected class |
229 | * @throws Exception if inspection fails |
230 | */ |
231 | @Override public void postInspect( Class inspected ) |
232 | throws Exception |
233 | { |
234 | mbean.setModelMBeanInfo( getMBeanInfo() ); |
235 | } |
236 | |
237 | /** |
238 | * This override creates a JMX descriptor for the inspected class. |
239 | * |
240 | * <p> |
241 | * <b>Note:</b> This function is not intended to be called |
242 | * by customers. Instead, it is called by the inspector. |
243 | * </p> |
244 | * @param inspected the inspected class |
245 | * @throws Exception if inspection fails |
246 | * @return true if inspection complete |
247 | */ |
248 | @Override public boolean inspect( Class inspected ) |
249 | throws Exception |
250 | { |
251 | if( inspected.equals( sentinel ) ) { |
252 | return true; |
253 | } |
254 | BeanInfo oldBeanInfo = beanInfo; |
255 | beanInfo = Introspector.getBeanInfo( inspected, sentinel ); |
256 | handleJMXNotificationAnnotations( inspected.getAnnotations() ); |
257 | JMX annotation = |
258 | ( JMX )inspected.getAnnotation( org.jsesoft.mmbi.JMX.class ); |
259 | |
260 | Descriptor descriptor = |
261 | getDescriptor( |
262 | annotation, |
263 | beanInfo.getBeanDescriptor(), |
264 | inspected.getName(), |
265 | inspected.getSimpleName(), |
266 | inspected.getCanonicalName(), |
267 | "MBean" ); |
268 | mbeanDescriptor = descriptor; |
269 | if( debug ) { |
270 | System.out.println( ( ( DescriptorSupport )descriptor ).toXMLString() ); |
271 | } |
272 | beanInfo = oldBeanInfo; |
273 | return false; |
274 | } |
275 | |
276 | /** |
277 | * This override creates a constructor info for the inspected constructor. |
278 | * |
279 | * <p> |
280 | * <b>Note:</b> This function is not intended to be called |
281 | * by customers. Instead, it is called by the inspector. |
282 | * </p> |
283 | * @param inspected the inspected class |
284 | * @param constructor the inspected constructor |
285 | * @throws Exception if inspection fails |
286 | * @return true if inspection complete |
287 | */ |
288 | @Override |
289 | public boolean inspectConstructor( Class inspected, Constructor constructor ) |
290 | throws Exception |
291 | { |
292 | if( !Modifier.isPublic( constructor.getModifiers() ) ) { |
293 | return false; |
294 | } |
295 | handleJMXNotificationAnnotations( constructor.getAnnotations() ); |
296 | JMX annotation = |
297 | constructor.getAnnotation( org.jsesoft.mmbi.JMX.class ); |
298 | if( ( annotation != null ) |
299 | && ( annotation.hide() ) ) { |
300 | return false; |
301 | } |
302 | MBeanParameterInfo[] parameterInfos = |
303 | getParameterInfos( |
304 | constructor.getParameterTypes(), |
305 | constructor.getParameterAnnotations(), |
306 | null ); |
307 | String name = constructor.getName(); |
308 | Descriptor descriptor = |
309 | getDescriptor( |
310 | annotation, |
311 | null, |
312 | name, |
313 | name, |
314 | name, |
315 | "operation" ); |
316 | descriptor.setField( "role", "constructor" ); |
317 | if( constructorInfos == null ) { |
318 | constructorInfos = new Vector<ModelMBeanConstructorInfo>(); |
319 | } |
320 | constructorInfos.add( |
321 | new ModelMBeanConstructorInfo( |
322 | ( String )descriptor.getFieldValue( "name" ), |
323 | ( String )descriptor.getFieldValue( "description" ), |
324 | parameterInfos, |
325 | descriptor ) ); |
326 | if( debug ) { |
327 | System.out.println( ( ( DescriptorSupport )descriptor ).toXMLString() ); |
328 | } |
329 | return false; |
330 | } |
331 | |
332 | /** |
333 | * This override creates a operation info for the inspected method. |
334 | * |
335 | * <p> |
336 | * <b>Note:</b> This function is not intended to be called |
337 | * by customers. Instead, it is called by the inspector. |
338 | * </p> |
339 | * @param inspected the inspected class |
340 | * @param operation the inspected method |
341 | * @throws Exception if inspection fails |
342 | * @return true if inspection complete |
343 | */ |
344 | @Override public boolean inspectMethod( Class inspected, Method operation ) |
345 | throws Exception |
346 | { |
347 | if( !Modifier.isPublic( operation.getModifiers() ) ) { |
348 | return false; |
349 | } |
350 | handleJMXNotificationAnnotations( operation.getAnnotations() ); |
351 | JMX annotation = |
352 | operation.getAnnotation( org.jsesoft.mmbi.JMX.class ); |
353 | if( ( annotation != null ) |
354 | && ( annotation.hide() ) ) { |
355 | return false; |
356 | } |
357 | MethodDescriptor methodDescriptor = |
358 | getMethodDescriptor( |
359 | beanInfo.getMethodDescriptors(), |
360 | operation ); |
361 | ParameterDescriptor[] parameterDescriptors = |
362 | ( methodDescriptor == null ) ? null |
363 | : methodDescriptor.getParameterDescriptors(); |
364 | MBeanParameterInfo[] parameterInfos = |
365 | getParameterInfos( |
366 | operation.getParameterTypes(), |
367 | operation.getParameterAnnotations(), |
368 | parameterDescriptors ); |
369 | String name = operation.getName(); |
370 | Descriptor descriptor = |
371 | getDescriptor( |
372 | annotation, |
373 | methodDescriptor, |
374 | name, |
375 | name, |
376 | name, |
377 | "operation" ); |
378 | descriptor.setField( "class", inspected.getName() ); |
379 | descriptor.setField( "displayName", descriptor.getFieldValue( "name" ) ); |
380 | if( ( operation.getName().startsWith( "get" ) |
381 | && ( operation.getParameterTypes().length == 0 ) |
382 | && ( operation.getReturnType() != null ) ) |
383 | || ( operation.getName().startsWith( "is" ) |
384 | && ( operation.getParameterTypes().length == 0 ) |
385 | && boolean.class.equals( operation.getReturnType() ) ) ) { |
386 | descriptor.setField( "role", "getter" ); |
387 | } else |
388 | if( operation.getName().startsWith( "set" ) |
389 | && ( void.class.equals( operation.getReturnType() ) ) |
390 | && ( operation.getParameterTypes().length == 1 ) ) { |
391 | descriptor.setField( "role", "setter" ); |
392 | } else { |
393 | descriptor.setField( "role", "operation" ); |
394 | } |
395 | int impact = |
396 | ( annotation == null ) ? MBeanOperationInfo.ACTION_INFO : annotation.impact(); |
397 | if( impact == MBeanOperationInfo.UNKNOWN ) { |
398 | impact = MBeanOperationInfo.ACTION_INFO; |
399 | } |
400 | if( operationInfos == null ) { |
401 | operationInfos = new Vector<ModelMBeanOperationInfo>(); |
402 | } |
403 | operationInfos.add( |
404 | new ModelMBeanOperationInfo( |
405 | ( String )descriptor.getFieldValue( "name" ), |
406 | ( String )descriptor.getFieldValue( "description" ), |
407 | parameterInfos, |
408 | operation.getReturnType().getName(), |
409 | impact, |
410 | descriptor ) ); |
411 | if( debug ) { |
412 | System.out.println( ( ( DescriptorSupport )descriptor ).toXMLString() ); |
413 | } |
414 | |
415 | return false; |
416 | } |
417 | |
418 | private MBeanParameterInfo[] getParameterInfos( |
419 | Class<? >[] types, |
420 | Annotation[][] annotations, |
421 | ParameterDescriptor[] features ) |
422 | throws |
423 | NoSuchMethodException, |
424 | InvocationTargetException, |
425 | IllegalAccessException |
426 | { |
427 | if( types.length == 0 ) { |
428 | return new MBeanParameterInfo[0]; |
429 | } |
430 | MBeanParameterInfo[] parameterInfos |
431 | = new MBeanParameterInfo[types.length]; |
432 | for( int iX = 0; iX < types.length; iX++ ) { |
433 | Class<? > type = types[iX]; |
434 | JMX annotation = getJMXAnnotation( annotations[iX] ); |
435 | String name = ( features == null ) ? null : features[iX].getName(); |
436 | if( name == null ) { |
437 | name = "p" + iX; |
438 | } |
439 | String description = |
440 | ( features == null ) ? null : features[iX].getShortDescription(); |
441 | if( description == null ) { |
442 | description = ( annotation == null ) ? "" : annotation.description(); |
443 | } |
444 | if( "".equals( description ) ) { |
445 | description = name; |
446 | } |
447 | parameterInfos[iX] = |
448 | new MBeanParameterInfo( name, type.getName(), description ); |
449 | } |
450 | return parameterInfos; |
451 | } |
452 | |
453 | /** |
454 | * Gets the JavaBeans method descriptor for the method. |
455 | * |
456 | * @param features the BeanInfo MethodDescriptors |
457 | * @param method the Method |
458 | * @return the MethodDescriptor, null if none |
459 | */ |
460 | public MethodDescriptor getMethodDescriptor( MethodDescriptor[] features, |
461 | Method method ) |
462 | { |
463 | for( MethodDescriptor feature : features ) { |
464 | if( feature.getMethod().equals( method ) ) { |
465 | return feature; |
466 | } |
467 | } |
468 | return null; |
469 | } |
470 | |
471 | /** |
472 | * This override creates a attribute info for the inspected field. |
473 | * |
474 | * <p> |
475 | * <b>Note:</b> This function is not intended to be called |
476 | * by customers. Instead, it is called by the inspector. |
477 | * </p> |
478 | * @param inspected the inspected class |
479 | * @param field the inspected field |
480 | * @throws Exception if inspection fails |
481 | * @return true if inspection complete |
482 | */ |
483 | @Override public boolean inspectField( Class inspected, Field field ) |
484 | throws Exception |
485 | { |
486 | JMX annotation = |
487 | field.getAnnotation( org.jsesoft.mmbi.JMX.class ); |
488 | if( ( annotation != null ) |
489 | && ( annotation.hide() ) ) { |
490 | return false; |
491 | } |
492 | PropertyDescriptor propertyDescriptor = |
493 | getPropertyDescriptor( beanInfo.getPropertyDescriptors(), field ); |
494 | Method getter = null; |
495 | if( propertyDescriptor != null ) { |
496 | getter = propertyDescriptor.getReadMethod(); |
497 | } |
498 | if( getter == null ) { |
499 | getter = getGetter( inspected, field ); |
500 | } |
501 | Method setter = null; |
502 | if( propertyDescriptor != null ) { |
503 | setter = propertyDescriptor.getWriteMethod(); |
504 | } |
505 | if( setter == null ) { |
506 | setter = getSetter( inspected, field ); |
507 | } |
508 | if( ( setter == null ) && ( getter == null ) ) { |
509 | return false; |
510 | } |
511 | String name = field.getName(); |
512 | Descriptor descriptor = |
513 | getDescriptor( |
514 | annotation, |
515 | propertyDescriptor, |
516 | name, |
517 | name, |
518 | name, |
519 | "attribute" ); |
520 | if( getter != null ) { |
521 | descriptor.setField( "getMethod", getter.getName() ); |
522 | } |
523 | if( setter != null ) { |
524 | descriptor.setField( "setMethod", setter.getName() ); |
525 | } |
526 | if( attributeInfos == null ) { |
527 | attributeInfos = new Vector<ModelMBeanAttributeInfo>(); |
528 | } |
529 | attributeInfos.add( |
530 | new ModelMBeanAttributeInfo( |
531 | ( String )descriptor.getFieldValue( "name" ), |
532 | ( String )descriptor.getFieldValue( "description" ), |
533 | getter, |
534 | setter, |
535 | descriptor ) ); |
536 | if( debug ) { |
537 | System.out.println( ( ( DescriptorSupport )descriptor ).toXMLString() ); |
538 | } |
539 | return false; |
540 | } |
541 | |
542 | /** |
543 | * Gets the BeanInfe PropertyDescriptor for the field. |
544 | * |
545 | * @param features the BeanInfo PropertyDescriptors |
546 | * @param field the Field |
547 | * @return the PropertyDescriptor, null if none |
548 | */ |
549 | public PropertyDescriptor getPropertyDescriptor( |
550 | PropertyDescriptor[] features, |
551 | Field field ) |
552 | { |
553 | for( PropertyDescriptor feature : features ) { |
554 | if( feature.getName().equals( field.getName() ) ) { |
555 | return feature; |
556 | } |
557 | } |
558 | return null; |
559 | } |
560 | |
561 | /** |
562 | * Inquires the getter method for a field. |
563 | * |
564 | * @param inspected the inspected Class |
565 | * @param field the inspected Field |
566 | * @return getter, null if none defined |
567 | */ |
568 | public static Method getGetter( Class inspected, Field field ) |
569 | { |
570 | String name = field.getName(); |
571 | String upper = |
572 | Character.toUpperCase( name.charAt( 0 ) ) + name.substring( 1 ); |
573 | Method methods[] = inspected.getDeclaredMethods(); |
574 | for( Method method : methods ) { |
575 | if( !Modifier.isPublic( method.getModifiers() ) ) { |
576 | continue; |
577 | } |
578 | if( boolean.class.equals( field.getType() ) |
579 | && boolean.class.equals( method.getReturnType() ) |
580 | && ( method.getParameterTypes().length == 0 ) |
581 | && ( "is" + upper ).equals( method.getName() ) ) { |
582 | return method; |
583 | } |
584 | if( field.getType().equals( method.getReturnType() ) |
585 | && ( method.getParameterTypes().length == 0 ) |
586 | && ( "get" + upper ).equals( method.getName() ) ) { |
587 | return method; |
588 | } |
589 | } |
590 | return null; |
591 | } |
592 | |
593 | /** |
594 | * Inquires the setter method for a field. |
595 | * |
596 | * @param inspected the inspected Class |
597 | * @param field the inspected Field |
598 | * @return setter, null if none defined |
599 | */ |
600 | public static Method getSetter( Class inspected, Field field ) |
601 | { |
602 | String name = field.getName(); |
603 | String upper = |
604 | Character.toUpperCase( name.charAt( 0 ) ) + name.substring( 1 ); |
605 | Method methods[] = inspected.getDeclaredMethods(); |
606 | for( Method method : methods ) { |
607 | if( !Modifier.isPublic( method.getModifiers() ) ) { |
608 | continue; |
609 | } |
610 | Class[] types = method.getParameterTypes(); |
611 | if( types.length != 1 ) { |
612 | continue; |
613 | } |
614 | if( field.getType().equals( types[0] ) |
615 | && ( "set" + upper ).equals( method.getName() ) ) { |
616 | return method; |
617 | } |
618 | } |
619 | return null; |
620 | } |
621 | |
622 | /** |
623 | * Inquires the JMX annotation. |
624 | * |
625 | * @param annotations the annotations to be looked up for the JMX annotation |
626 | * @return JMX |
627 | */ |
628 | public static JMX getJMXAnnotation( Annotation[] annotations ) |
629 | { |
630 | for( Annotation annotation : annotations ) { |
631 | if( annotation.annotationType().isAssignableFrom( |
632 | org.jsesoft.mmbi.JMX.class ) ) { |
633 | return( JMX )annotation; |
634 | } |
635 | } |
636 | return null; |
637 | } |
638 | |
639 | /** |
640 | * Handles the JMXNotification annotations. |
641 | * |
642 | * @param annotations the annotations to be looked up for the JMX annotation |
643 | * @throws Exception if descriptor cannot be created |
644 | */ |
645 | public void handleJMXNotificationAnnotations( Annotation[] annotations ) |
646 | throws Exception |
647 | { |
648 | for( Annotation annotation : annotations ) { |
649 | if( annotation.annotationType().isAssignableFrom( |
650 | org.jsesoft.mmbi.JMXNotification.class ) ) { |
651 | JMXNotification notification = ( JMXNotification )annotation; |
652 | String[] types = notification.types(); |
653 | Descriptor descriptor; |
654 | descriptor = new DescriptorSupport(); |
655 | descriptor.setField( "name", notification.name() ); |
656 | descriptor.setField( "displayName", notification.displayName() ); |
657 | descriptor.setField( "description", notification.description() ); |
658 | descriptor.setField( "severity", notification.severity() ); |
659 | descriptor.setField( "descriptorType", "notification" ); |
660 | if( notificationInfos == null ) { |
661 | notificationInfos = new Vector<ModelMBeanNotificationInfo>(); |
662 | } |
663 | notificationInfos.add( |
664 | new ModelMBeanNotificationInfo( |
665 | notification.types(), |
666 | notification.name(), |
667 | notification.description(), |
668 | descriptor ) ); |
669 | if( debug ) { |
670 | System.out.println( ( ( DescriptorSupport )descriptor ).toXMLString() ); |
671 | } |
672 | } |
673 | } |
674 | } |
675 | |
676 | /** |
677 | * Creates a JMX descriptor from the specified information. |
678 | * |
679 | * <p> |
680 | * Default information can be overruled by annotation information |
681 | * </p> |
682 | * <p> |
683 | * <b>Note:</b> Though this was designed as a helper function, |
684 | * it might be useful for customers, too. |
685 | * </p> |
686 | * |
687 | * @param annotation the JMX annotation containing overriding info |
688 | * @param feature the Javabeans feature descriptor containing overriding info |
689 | * @param defaultName the default name |
690 | * @param defaultDisplayName the default display name |
691 | * @param defaultDescription the default description |
692 | * @param descriptorType the type of the descriptor to create |
693 | * @return the created descriptor |
694 | * @throws MBeanException if descriptor cannot be created |
695 | * @throws XMLParseException if the annotation's XML is not valid |
696 | */ |
697 | public static Descriptor getDescriptor( |
698 | JMX annotation, |
699 | FeatureDescriptor feature, |
700 | String defaultName, |
701 | String defaultDisplayName, |
702 | String defaultDescription, |
703 | String descriptorType ) |
704 | throws |
705 | MBeanException, |
706 | XMLParseException |
707 | { |
708 | Descriptor descriptor; |
709 | if( annotation != null ) { |
710 | String xml = annotation.xml(); |
711 | if( "".equals( xml ) ) { |
712 | descriptor = new DescriptorSupport(); |
713 | descriptor.setField( "name", defaultName ); |
714 | } else { |
715 | descriptor = new DescriptorSupport( xml ); |
716 | } |
717 | } else { |
718 | descriptor = new DescriptorSupport(); |
719 | descriptor.setField( "name", defaultName ); |
720 | } |
721 | descriptor.setField( "descriptorType", descriptorType ); |
722 | String name = ( String )descriptor.getFieldValue( "name" ); |
723 | if( ( feature != null ) && ( feature.getName() != null ) ) { |
724 | name = feature.getName(); |
725 | } |
726 | if( ( annotation != null ) |
727 | && ( !"".equals( annotation.name() ) ) ) { |
728 | name = annotation.name(); |
729 | } |
730 | String displayName = ( String )descriptor.getFieldValue( "displayName" ); |
731 | if( ( feature != null ) && ( feature.getDisplayName() != null ) ) { |
732 | displayName = feature.getDisplayName(); |
733 | } |
734 | if( ( annotation != null ) |
735 | && ( !"".equals( annotation.displayName() ) ) ) { |
736 | displayName = annotation.displayName(); |
737 | } |
738 | if( ( displayName == null ) || "".equals( displayName ) ) { |
739 | displayName = defaultDisplayName; |
740 | } |
741 | String description = ( String )descriptor.getFieldValue( "description" ); |
742 | if( ( feature != null ) && ( feature.getShortDescription() != null ) ) { |
743 | description = feature.getShortDescription(); |
744 | } |
745 | if( ( annotation != null ) |
746 | && ( !"".equals( annotation.description() ) ) ) { |
747 | description = annotation.description(); |
748 | } |
749 | if( ( description == null ) || "".equals( description ) ) { |
750 | description = defaultDescription; |
751 | } |
752 | descriptor.setField( "name", name ); |
753 | descriptor.setField( "displayName", displayName ); |
754 | descriptor.setField( "description", description ); |
755 | return descriptor; |
756 | } |
757 | |
758 | /** |
759 | * Gets the created constructor infos. |
760 | * |
761 | * @return ModelMBeanConstructorInfo[] |
762 | */ |
763 | public ModelMBeanConstructorInfo[] getConstructorInfos() |
764 | { |
765 | if( constructorInfos == null ) { |
766 | return null; |
767 | } |
768 | return constructorInfos.toArray( constructors ); |
769 | } |
770 | |
771 | /** |
772 | * Gets the created operation info. |
773 | * |
774 | * @return ModelMBeanOperationInfo[] |
775 | */ |
776 | public ModelMBeanOperationInfo[] getOperationInfos() |
777 | { |
778 | if( operationInfos == null ) { |
779 | return null; |
780 | } |
781 | return operationInfos.toArray( operations ); |
782 | } |
783 | |
784 | /** |
785 | * Gets the created attribute info. |
786 | * |
787 | * @return ModelMBeanAttributeInfo[] |
788 | */ |
789 | public ModelMBeanAttributeInfo[] getAttributeInfos() |
790 | { |
791 | if( attributeInfos == null ) { |
792 | return null; |
793 | } |
794 | return attributeInfos.toArray( attributes ); |
795 | } |
796 | |
797 | /** |
798 | * Gets the created attribute info. |
799 | * |
800 | * @return ModelMBeanAttributeInfo[] |
801 | */ |
802 | public ModelMBeanNotificationInfo[] getNotificationInfos() |
803 | { |
804 | if( notificationInfos == null ) { |
805 | return null; |
806 | } |
807 | return notificationInfos.toArray( notifications ); |
808 | } |
809 | |
810 | /** |
811 | * Gets the created MBeanInfo. |
812 | * |
813 | * <p> |
814 | * This function creates the MBean Info, if not already done. |
815 | * </p> |
816 | * @return ModelMBeanInfo |
817 | */ |
818 | public ModelMBeanInfo getMBeanInfo() |
819 | { |
820 | if( mbeanInfo != null ) { |
821 | return mbeanInfo; |
822 | } |
823 | return mbeanInfo = |
824 | new ModelMBeanInfoSupport( |
825 | ( String )mbeanDescriptor.getFieldValue( "name" ), |
826 | ( String )mbeanDescriptor.getFieldValue( "description" ), |
827 | getAttributeInfos(), |
828 | getConstructorInfos(), |
829 | getOperationInfos(), |
830 | getNotificationInfos(), |
831 | mbeanDescriptor ); |
832 | } |
833 | |
834 | /** |
835 | * Inquires the inspector used for reflection traversal. |
836 | * |
837 | * @return the used <code>ReflectionInspector</code> |
838 | */ |
839 | public ReflectionInspector getInspector() |
840 | { |
841 | return inspector; |
842 | } |
843 | } |