KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > avalon > phoenix > components > manager > MBeanInfoBuilder


1 /*
2  * Copyright (C) The Apache Software Foundation. All rights reserved.
3  *
4  * This software is published under the terms of the Apache Software License
5  * version 1.1, a copy of which has been included with this distribution in
6  * the LICENSE.txt file.
7  */

8 package org.apache.avalon.phoenix.components.manager;
9
10 import java.beans.BeanInfo JavaDoc;
11 import java.beans.Introspector JavaDoc;
12 import java.beans.MethodDescriptor JavaDoc;
13 import java.beans.PropertyDescriptor JavaDoc;
14 import java.io.InputStream JavaDoc;
15 import java.lang.reflect.Method JavaDoc;
16 import java.util.ArrayList JavaDoc;
17 import javax.management.Descriptor JavaDoc;
18 import javax.management.MBeanParameterInfo JavaDoc;
19 import javax.management.modelmbean.ModelMBeanAttributeInfo JavaDoc;
20 import javax.management.modelmbean.ModelMBeanConstructorInfo JavaDoc;
21 import javax.management.modelmbean.ModelMBeanInfoSupport JavaDoc;
22 import javax.management.modelmbean.ModelMBeanNotificationInfo JavaDoc;
23 import javax.management.modelmbean.ModelMBeanOperationInfo JavaDoc;
24 import javax.management.modelmbean.RequiredModelMBean JavaDoc;
25 import org.apache.avalon.excalibur.i18n.ResourceManager;
26 import org.apache.avalon.excalibur.i18n.Resources;
27 import org.apache.avalon.framework.configuration.Configuration;
28 import org.apache.avalon.framework.configuration.ConfigurationException;
29 import org.apache.avalon.framework.logger.AbstractLogEnabled;
30 import org.apache.avalon.phoenix.tools.configuration.ConfigurationBuilder;
31 import org.xml.sax.InputSource JavaDoc;
32
33 /**
34  * An MBeanInfoBuilder is responsible for building Management Topic
35  * objects from Configuration objects. The format for Configuration object
36  * is specified in the MxInfo specification. The information is loaded into
37  * the Target structure.
38  *
39  * @author <a HREF="mailto:peter at apache.org">Peter Donald</a>
40  * @author <a HREF="mailto:huw@mmlive.com">Huw Roberts</a>
41  * @version $Revision: 1.4 $ $Date: 2002/09/06 11:35:10 $
42  */

43 public final class MBeanInfoBuilder
44     extends AbstractLogEnabled
45 {
46     private static final Resources REZ =
47         ResourceManager.getPackageResources( MBeanInfoBuilder.class );
48     private static final String JavaDoc REQ_MODEL_MBEAN =
49         RequiredModelMBean JavaDoc.class.getName();
50
51     public void build( final Target target,
52                        final Class JavaDoc managedClass,
53                        final Class JavaDoc[] interfaces )
54         throws ConfigurationException
55     {
56         final String JavaDoc notice =
57             REZ.getString( "mxinfo.debug.building", managedClass.getName() );
58         getLogger().debug( notice );
59
60         // if the managed class has an mxinfo file, build the target from it
61
// (this includes any proxies)
62
Configuration config = loadMxInfo( managedClass );
63         if( null != config )
64         {
65             final String JavaDoc message =
66                 REZ.getString( "mxinfo.debug.found.mxinfo",
67                                managedClass.getName() );
68             getLogger().debug( message );
69             buildFromMxInfo( target, managedClass, config );
70         }
71
72         // for each interface, generate a topic from its mxinfo file
73
// or through introspection
74
for( int i = 0, j = interfaces.length; i < j; i++ )
75         {
76             try
77             {
78                 config = loadMxInfo( interfaces[ i ] );
79                 if( config == null )
80                 {
81                     buildFromIntrospection( target, interfaces[ i ] );
82                 }
83                 else
84                 {
85                     buildFromMxInfo( target, managedClass, config );
86                 }
87             }
88             catch( final Exception JavaDoc e )
89             {
90                 final String JavaDoc message =
91                     REZ.getString( "mxinfo.error.target", target.getName() );
92                 getLogger().error( message, e );
93                 throw new ConfigurationException( message );
94             }
95         }
96     }
97
98     /**
99      * Create a {@link ModelMBeanInfoSupport} object for specified classname from
100      * specified configuration data.
101      */

102     private void buildFromMxInfo( final Target target,
103                                   final Class JavaDoc managedClass,
104                                   final Configuration config )
105         throws ConfigurationException
106     {
107         BeanInfo JavaDoc beanInfo;
108         try
109         {
110             beanInfo = Introspector.getBeanInfo( managedClass );
111         }
112         catch( final Exception JavaDoc e )
113         {
114             final String JavaDoc message =
115                 REZ.getString( "mxinfo.error.introspect", managedClass.getName() );
116             throw new ConfigurationException( message, e );
117         }
118
119         // load each topic
120
final Configuration[] topicsConfig = config.getChildren( "topic" );
121         for( int i = 0; i < topicsConfig.length; i++ )
122         {
123             final ModelMBeanInfoSupport JavaDoc topic =
124                 buildTopic( topicsConfig[ i ], beanInfo );
125             target.addTopic( topic );
126         }
127
128         // load each proxy
129
final Configuration[] proxysConfig = config.getChildren( "proxy" );
130         for( int i = 0; i < proxysConfig.length; i++ )
131         {
132             final ModelMBeanInfoSupport JavaDoc topic =
133                 buildProxyTopic( proxysConfig[ i ], managedClass );
134             target.addTopic( topic );
135         }
136
137     }
138
139     /**
140      * Builds a topic based on introspection of the interface
141      */

142     private void buildFromIntrospection( final Target target,
143                                          final Class JavaDoc interfaceClass )
144         throws ConfigurationException
145     {
146         try
147         {
148             final BeanInfo JavaDoc beanInfo =
149                 Introspector.getBeanInfo( interfaceClass );
150
151             // do the methods
152
final MethodDescriptor JavaDoc[] methods = beanInfo.getMethodDescriptors();
153             final ArrayList JavaDoc operations = new ArrayList JavaDoc();
154
155             for( int j = 0; j < methods.length; j++ )
156             {
157                 // skip getters and setters
158
final String JavaDoc name = methods[ j ].getName();
159                 if( !(name.startsWith( "get" ) ||
160                     name.startsWith( "set" ) ||
161                     name.startsWith( "is" )) )
162                 {
163                     operations.add( buildOperationInfo( methods[ j ], null ) );
164                 }
165             }
166
167             final ModelMBeanOperationInfo JavaDoc[] operationList =
168                 (ModelMBeanOperationInfo JavaDoc[])
169                 operations.toArray( new ModelMBeanOperationInfo JavaDoc[ 0 ] );
170
171             // do the attributes
172
final PropertyDescriptor JavaDoc[] propertys = beanInfo.getPropertyDescriptors();
173             final ModelMBeanAttributeInfo JavaDoc[] attributes =
174                 new ModelMBeanAttributeInfo JavaDoc[ propertys.length ];
175
176             for( int j = 0; j < propertys.length; j++ )
177             {
178                 attributes[ j ] = buildAttributeInfo( propertys[ j ], null );
179             }
180
181             final ModelMBeanConstructorInfo JavaDoc[] constructors =
182                 new ModelMBeanConstructorInfo JavaDoc[ 0 ];
183
184             final ModelMBeanNotificationInfo JavaDoc[] notifications =
185                 new ModelMBeanNotificationInfo JavaDoc[ 0 ];
186
187             final String JavaDoc shortName = getShortName( interfaceClass.getName() );
188             final ModelMBeanInfoSupport JavaDoc topic =
189                 new ModelMBeanInfoSupport JavaDoc( REQ_MODEL_MBEAN,
190                                            shortName,
191                                            attributes,
192                                            constructors,
193                                            operationList,
194                                            notifications );
195
196             // add it to target
197
final String JavaDoc message = REZ.getString( "mxinfo.debug.adding.topic", topic.getDescription() );
198             getLogger().debug( message );
199
200             target.addTopic( topic );
201         }
202         catch( final Exception JavaDoc e )
203         {
204             final String JavaDoc message =
205                 REZ.getString( "mxinfo.error.topic", interfaceClass );
206             throw new ConfigurationException( message, e );
207         }
208     }
209
210     /**
211      * A utility method to build a {@link ModelMBeanInfoSupport}
212      * object from specified configuration and BeanInfo.
213      *
214      * @return the created ModelMBeanInfoSupport
215      * @throws ConfigurationException if an error occurs
216      */

217     private ModelMBeanInfoSupport JavaDoc buildTopic( final Configuration config,
218                                               final BeanInfo JavaDoc beanInfo )
219         throws ConfigurationException
220     {
221         final ModelMBeanAttributeInfo JavaDoc[] attributes =
222             buildAttributeInfos( config, beanInfo );
223
224         final ModelMBeanOperationInfo JavaDoc[] operations =
225             buildOperationInfos( config, beanInfo );
226
227         final ModelMBeanConstructorInfo JavaDoc[] constructors =
228             new ModelMBeanConstructorInfo JavaDoc[ 0 ];
229
230         final ModelMBeanNotificationInfo JavaDoc[] notifications =
231             new ModelMBeanNotificationInfo JavaDoc[ 0 ];
232
233         final String JavaDoc name = config.getAttribute( "name" );
234         final ModelMBeanInfoSupport JavaDoc topic =
235             new ModelMBeanInfoSupport JavaDoc( REQ_MODEL_MBEAN,
236                                        name,
237                                        attributes,
238                                        constructors,
239                                        operations,
240                                        notifications );
241
242         return topic;
243     }
244
245     /**
246      * Build a topic for a proxy management class
247      *
248      * @param proxyTagConfig
249      * @param managedClass
250      * @return
251      */

252     private ModelMBeanInfoSupport JavaDoc buildProxyTopic( final Configuration proxyTagConfig,
253                                                    final Class JavaDoc managedClass )
254         throws ConfigurationException
255     {
256         try
257         {
258             final String JavaDoc proxyName = proxyTagConfig.getAttribute( "name" );
259             final String JavaDoc message = REZ.getString( "mxinfo.debug.building.proxy.topic", proxyName );
260             getLogger().debug( message );
261
262             final Class JavaDoc proxyClass = managedClass.getClassLoader().loadClass( proxyName );
263             final Configuration classConfig = loadMxInfo( proxyClass );
264             final Configuration topicConfig = classConfig.getChild( "topic" );
265             final BeanInfo JavaDoc info = Introspector.getBeanInfo( proxyClass );
266             final ModelMBeanInfoSupport JavaDoc topic = buildTopic( topicConfig, info );
267             final Descriptor JavaDoc mBeanDescriptor = topic.getMBeanDescriptor();
268             mBeanDescriptor.setField( "proxyClassName", proxyName );
269             topic.setMBeanDescriptor( mBeanDescriptor );
270
271             return topic;
272         }
273         catch( final Exception JavaDoc e )
274         {
275             if( e instanceof ConfigurationException )
276             {
277                 throw (ConfigurationException)e;
278             }
279             else
280             {
281                 final String JavaDoc message = REZ.getString( "mxinfo.error.proxy", managedClass.getName() );
282                 throw new ConfigurationException( message );
283             }
284         }
285     }
286
287     /**
288      * Builds the management attributes from the configuration
289      *
290      * @param config topic's configuration element
291      * @param info managed class' BeanInfo from introspector
292      * @throws ConfigurationException
293      */

294     private ModelMBeanAttributeInfo JavaDoc[] buildAttributeInfos( final Configuration config,
295                                                            final BeanInfo JavaDoc info )
296         throws ConfigurationException
297     {
298         final Configuration[] attributesConfig = config.getChildren( "attribute" );
299
300         final ModelMBeanAttributeInfo JavaDoc[] attributeList =
301             new ModelMBeanAttributeInfo JavaDoc[ attributesConfig.length ];
302
303         final PropertyDescriptor JavaDoc[] propertys = info.getPropertyDescriptors();
304         for( int i = 0; i < attributesConfig.length; i++ )
305         {
306             final Configuration attribute = attributesConfig[ i ];
307             final String JavaDoc name = attribute.getAttribute( "name" );
308             final PropertyDescriptor JavaDoc property =
309                 getPropertyDescriptor( name, propertys );
310             attributeList[ i ] = buildAttributeInfo( property, attribute );
311         }
312
313         return attributeList;
314     }
315
316     /**
317      * Builds a management config
318      *
319      * @param property from BeanInfo
320      * @param config configuration element - can be null, in which case defaults are used
321      */

322     private ModelMBeanAttributeInfo JavaDoc buildAttributeInfo( final PropertyDescriptor JavaDoc property,
323                                                         final Configuration config )
324     {
325         final String JavaDoc name = property.getName();
326         final Method JavaDoc readMethod = property.getReadMethod();
327         final Method JavaDoc writeMethod = property.getWriteMethod();
328         final String JavaDoc type = property.getPropertyType().getName();
329
330         String JavaDoc description = property.getDisplayName();
331         boolean isReadable = (readMethod != null);
332         boolean isWriteable = (writeMethod != null);
333
334         if( config != null )
335         {
336             // use config info, or BeanInfo if config info is missing
337
description =
338                 config.getAttribute( "description", description );
339
340             // defaults to true if there is a read method, otherwise defaults to false
341
isReadable =
342                 config.getAttributeAsBoolean( "isReadable", true ) && isReadable;
343
344             // defaults to true if there is a write method, otherwise defaults to false
345
isWriteable =
346                 config.getAttributeAsBoolean( "isWriteable", true ) && isWriteable;
347         }
348
349         final boolean isIs =
350             (readMethod != null) && readMethod.getName().startsWith( "is" );
351
352         final ModelMBeanAttributeInfo JavaDoc info =
353             new ModelMBeanAttributeInfo JavaDoc( name, type, description, isReadable, isWriteable, isIs );
354
355         // additional info needed for modelMbean to work
356
final Descriptor JavaDoc descriptor = info.getDescriptor();
357         descriptor.setField( "currencyTimeLimit", new Integer JavaDoc( 1 ) );
358         if( isReadable )
359         {
360             descriptor.setField( "getMethod", readMethod.getName() );
361         }
362         if( isWriteable )
363         {
364             descriptor.setField( "setMethod", writeMethod.getName() );
365         }
366         info.setDescriptor( descriptor );
367
368         return info;
369     }
370
371     /**
372      * Returns the PropertyDescriptor with the specified name from the array
373      */

374     private PropertyDescriptor JavaDoc getPropertyDescriptor( final String JavaDoc name,
375                                                       final PropertyDescriptor JavaDoc[] propertys )
376         throws ConfigurationException
377     {
378         for( int i = 0; i < propertys.length; i++ )
379         {
380             if( propertys[ i ].getName().equals( name ) )
381             {
382                 return propertys[ i ];
383             }
384         }
385
386         final String JavaDoc message =
387             REZ.getString( "mxinfo.error.missing.property", name );
388         throw new ConfigurationException( message );
389     }
390
391     /**
392      * Builds the management operations
393      *
394      * @param config topic configuration element to build from
395      * @param info BeanInfo for managed class from introspector
396      * @throws ConfigurationException
397      */

398     private ModelMBeanOperationInfo JavaDoc[] buildOperationInfos( final Configuration config,
399                                                            final BeanInfo JavaDoc info )
400         throws ConfigurationException
401     {
402         final Configuration[] operationsConfig =
403             config.getChildren( "operation" );
404
405         final ModelMBeanOperationInfo JavaDoc[] operations =
406             new ModelMBeanOperationInfo JavaDoc[ operationsConfig.length ];
407
408         final MethodDescriptor JavaDoc[] methodDescriptors = info.getMethodDescriptors();
409
410         for( int i = 0; i < operationsConfig.length; i++ )
411         {
412             final Configuration operation = operationsConfig[ i ];
413             final String JavaDoc name = operation.getAttribute( "name" );
414             final MethodDescriptor JavaDoc method =
415                 getMethodDescriptor( name, methodDescriptors );
416             operations[ i ] = buildOperationInfo( method, operation );
417         }
418
419         return operations;
420     }
421
422     /**
423      * Builds an operation descriptor from a configuration node
424      *
425      * @param method method as returned from beanInfo
426      * @param config configuration element, can be null
427      * @throws ConfigurationException if the configiration has the wrong elements
428      * @return the operation descriptor based on the configuration
429      */

430     private ModelMBeanOperationInfo JavaDoc buildOperationInfo( final MethodDescriptor JavaDoc method,
431                                                         final Configuration config )
432         throws ConfigurationException
433     {
434         ModelMBeanOperationInfo JavaDoc info;
435
436         if( config == null )
437         {
438             info = new ModelMBeanOperationInfo JavaDoc( method.getDisplayName(),
439                                                 method.getMethod() );
440
441         }
442         else
443         {
444             final String JavaDoc name = method.getName();
445             final String JavaDoc type = method.getMethod().getReturnType().getName();
446             final String JavaDoc description =
447                 config.getAttribute( "description",
448                                      method.getDisplayName() );
449             final int impact =
450                 config.getAttributeAsInteger( "impact",
451                                               ModelMBeanOperationInfo.UNKNOWN );
452
453             final Configuration[] paramConfig =
454                 config.getChildren( "param" );
455             final MBeanParameterInfo JavaDoc[] params =
456                 new MBeanParameterInfo JavaDoc[ paramConfig.length ];
457             for( int i = 0; i < paramConfig.length; i++ )
458             {
459                 params[ i ] = buildParameterInfo( paramConfig[ i ] );
460             }
461
462             info = new ModelMBeanOperationInfo JavaDoc( name, description, params, type, impact );
463         }
464
465         // additional info needed for modelMbean to work
466
final Descriptor JavaDoc descriptor = info.getDescriptor();
467         // TODO: might want to make this configurable. It controls the caching behavior
468
// of the invoke results. MX4J appears to cache this per operation regardless
469
// of what the invoke parameters are *SIGH* - PR
470
descriptor.setField( "currencyTimeLimit", new Integer JavaDoc( 0 ) );
471         info.setDescriptor( descriptor );
472         return info;
473     }
474
475     /**
476      * Returns the MethodDescriptor with the specified name from the array
477      */

478     private MethodDescriptor JavaDoc getMethodDescriptor( final String JavaDoc name,
479                                                   final MethodDescriptor JavaDoc[] methods )
480         throws ConfigurationException
481     {
482
483         for( int i = 0; i < methods.length; i++ )
484         {
485             if( methods[ i ].getName().equals( name ) )
486             {
487                 return methods[ i ];
488             }
489         }
490         final String JavaDoc message = REZ.getString( "mxinfo.error.missing.method", name );
491         throw new ConfigurationException( message );
492     }
493
494     /**
495      * Builds the param descriptor from the configuration data
496      *
497      * @throws ConfigurationException if configuration not structured corretly
498      * @return the descriptor
499      */

500     private MBeanParameterInfo JavaDoc buildParameterInfo( Configuration paramConfig )
501         throws ConfigurationException
502     {
503         final String JavaDoc name = paramConfig.getAttribute( "name" );
504         final String JavaDoc description = paramConfig.getAttribute( "description" );
505         final String JavaDoc type = paramConfig.getAttribute( "type" );
506
507         return new MBeanParameterInfo JavaDoc( name, type, description );
508     }
509
510     /**
511      * Returns the configuration for the class or null if there is no mxinfo
512      * file for it.
513      *
514      * @param clazz the class to load the configuration for
515      * @throws ConfigurationException
516      * @return the configuration file, or null if none exists
517      */

518     private Configuration loadMxInfo( final Class JavaDoc clazz )
519         throws ConfigurationException
520     {
521         final String JavaDoc mxinfoName =
522             "/" + clazz.getName().replace( '.', '/' ) + ".mxinfo";
523         try
524         {
525             InputStream JavaDoc stream = clazz.getResourceAsStream( mxinfoName );
526             if( null == stream )
527             {
528                 return null;
529             }
530
531             final InputSource JavaDoc source = new InputSource JavaDoc( stream );
532
533             // build with validation against DTD
534
return ConfigurationBuilder.build( source, true );
535         }
536         catch( Exception JavaDoc e )
537         {
538             final String JavaDoc message =
539                 REZ.getString( "mxinfo.error.file", mxinfoName );
540             getLogger().error( message, e );
541             throw new ConfigurationException( message );
542         }
543     }
544
545     /**
546      * Returns the class name without the package name
547      */

548     private String JavaDoc getShortName( final String JavaDoc className )
549     {
550         return className.substring( className.lastIndexOf( '.' ) + 1 );
551     }
552 }
553
Popular Tags