1 8 package org.apache.avalon.phoenix.components.manager; 9 10 import java.beans.BeanInfo ; 11 import java.beans.Introspector ; 12 import java.beans.MethodDescriptor ; 13 import java.beans.PropertyDescriptor ; 14 import java.io.InputStream ; 15 import java.lang.reflect.Method ; 16 import java.util.ArrayList ; 17 import javax.management.Descriptor ; 18 import javax.management.MBeanParameterInfo ; 19 import javax.management.modelmbean.ModelMBeanAttributeInfo ; 20 import javax.management.modelmbean.ModelMBeanConstructorInfo ; 21 import javax.management.modelmbean.ModelMBeanInfoSupport ; 22 import javax.management.modelmbean.ModelMBeanNotificationInfo ; 23 import javax.management.modelmbean.ModelMBeanOperationInfo ; 24 import javax.management.modelmbean.RequiredModelMBean ; 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 ; 32 33 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 REQ_MODEL_MBEAN = 49 RequiredModelMBean .class.getName(); 50 51 public void build( final Target target, 52 final Class managedClass, 53 final Class [] interfaces ) 54 throws ConfigurationException 55 { 56 final String notice = 57 REZ.getString( "mxinfo.debug.building", managedClass.getName() ); 58 getLogger().debug( notice ); 59 60 Configuration config = loadMxInfo( managedClass ); 63 if( null != config ) 64 { 65 final String message = 66 REZ.getString( "mxinfo.debug.found.mxinfo", 67 managedClass.getName() ); 68 getLogger().debug( message ); 69 buildFromMxInfo( target, managedClass, config ); 70 } 71 72 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 e ) 89 { 90 final String message = 91 REZ.getString( "mxinfo.error.target", target.getName() ); 92 getLogger().error( message, e ); 93 throw new ConfigurationException( message ); 94 } 95 } 96 } 97 98 102 private void buildFromMxInfo( final Target target, 103 final Class managedClass, 104 final Configuration config ) 105 throws ConfigurationException 106 { 107 BeanInfo beanInfo; 108 try 109 { 110 beanInfo = Introspector.getBeanInfo( managedClass ); 111 } 112 catch( final Exception e ) 113 { 114 final String message = 115 REZ.getString( "mxinfo.error.introspect", managedClass.getName() ); 116 throw new ConfigurationException( message, e ); 117 } 118 119 final Configuration[] topicsConfig = config.getChildren( "topic" ); 121 for( int i = 0; i < topicsConfig.length; i++ ) 122 { 123 final ModelMBeanInfoSupport topic = 124 buildTopic( topicsConfig[ i ], beanInfo ); 125 target.addTopic( topic ); 126 } 127 128 final Configuration[] proxysConfig = config.getChildren( "proxy" ); 130 for( int i = 0; i < proxysConfig.length; i++ ) 131 { 132 final ModelMBeanInfoSupport topic = 133 buildProxyTopic( proxysConfig[ i ], managedClass ); 134 target.addTopic( topic ); 135 } 136 137 } 138 139 142 private void buildFromIntrospection( final Target target, 143 final Class interfaceClass ) 144 throws ConfigurationException 145 { 146 try 147 { 148 final BeanInfo beanInfo = 149 Introspector.getBeanInfo( interfaceClass ); 150 151 final MethodDescriptor [] methods = beanInfo.getMethodDescriptors(); 153 final ArrayList operations = new ArrayList (); 154 155 for( int j = 0; j < methods.length; j++ ) 156 { 157 final String 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 [] operationList = 168 (ModelMBeanOperationInfo []) 169 operations.toArray( new ModelMBeanOperationInfo [ 0 ] ); 170 171 final PropertyDescriptor [] propertys = beanInfo.getPropertyDescriptors(); 173 final ModelMBeanAttributeInfo [] attributes = 174 new ModelMBeanAttributeInfo [ 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 [] constructors = 182 new ModelMBeanConstructorInfo [ 0 ]; 183 184 final ModelMBeanNotificationInfo [] notifications = 185 new ModelMBeanNotificationInfo [ 0 ]; 186 187 final String shortName = getShortName( interfaceClass.getName() ); 188 final ModelMBeanInfoSupport topic = 189 new ModelMBeanInfoSupport ( REQ_MODEL_MBEAN, 190 shortName, 191 attributes, 192 constructors, 193 operationList, 194 notifications ); 195 196 final String message = REZ.getString( "mxinfo.debug.adding.topic", topic.getDescription() ); 198 getLogger().debug( message ); 199 200 target.addTopic( topic ); 201 } 202 catch( final Exception e ) 203 { 204 final String message = 205 REZ.getString( "mxinfo.error.topic", interfaceClass ); 206 throw new ConfigurationException( message, e ); 207 } 208 } 209 210 217 private ModelMBeanInfoSupport buildTopic( final Configuration config, 218 final BeanInfo beanInfo ) 219 throws ConfigurationException 220 { 221 final ModelMBeanAttributeInfo [] attributes = 222 buildAttributeInfos( config, beanInfo ); 223 224 final ModelMBeanOperationInfo [] operations = 225 buildOperationInfos( config, beanInfo ); 226 227 final ModelMBeanConstructorInfo [] constructors = 228 new ModelMBeanConstructorInfo [ 0 ]; 229 230 final ModelMBeanNotificationInfo [] notifications = 231 new ModelMBeanNotificationInfo [ 0 ]; 232 233 final String name = config.getAttribute( "name" ); 234 final ModelMBeanInfoSupport topic = 235 new ModelMBeanInfoSupport ( REQ_MODEL_MBEAN, 236 name, 237 attributes, 238 constructors, 239 operations, 240 notifications ); 241 242 return topic; 243 } 244 245 252 private ModelMBeanInfoSupport buildProxyTopic( final Configuration proxyTagConfig, 253 final Class managedClass ) 254 throws ConfigurationException 255 { 256 try 257 { 258 final String proxyName = proxyTagConfig.getAttribute( "name" ); 259 final String message = REZ.getString( "mxinfo.debug.building.proxy.topic", proxyName ); 260 getLogger().debug( message ); 261 262 final Class proxyClass = managedClass.getClassLoader().loadClass( proxyName ); 263 final Configuration classConfig = loadMxInfo( proxyClass ); 264 final Configuration topicConfig = classConfig.getChild( "topic" ); 265 final BeanInfo info = Introspector.getBeanInfo( proxyClass ); 266 final ModelMBeanInfoSupport topic = buildTopic( topicConfig, info ); 267 final Descriptor mBeanDescriptor = topic.getMBeanDescriptor(); 268 mBeanDescriptor.setField( "proxyClassName", proxyName ); 269 topic.setMBeanDescriptor( mBeanDescriptor ); 270 271 return topic; 272 } 273 catch( final Exception e ) 274 { 275 if( e instanceof ConfigurationException ) 276 { 277 throw (ConfigurationException)e; 278 } 279 else 280 { 281 final String message = REZ.getString( "mxinfo.error.proxy", managedClass.getName() ); 282 throw new ConfigurationException( message ); 283 } 284 } 285 } 286 287 294 private ModelMBeanAttributeInfo [] buildAttributeInfos( final Configuration config, 295 final BeanInfo info ) 296 throws ConfigurationException 297 { 298 final Configuration[] attributesConfig = config.getChildren( "attribute" ); 299 300 final ModelMBeanAttributeInfo [] attributeList = 301 new ModelMBeanAttributeInfo [ attributesConfig.length ]; 302 303 final PropertyDescriptor [] propertys = info.getPropertyDescriptors(); 304 for( int i = 0; i < attributesConfig.length; i++ ) 305 { 306 final Configuration attribute = attributesConfig[ i ]; 307 final String name = attribute.getAttribute( "name" ); 308 final PropertyDescriptor property = 309 getPropertyDescriptor( name, propertys ); 310 attributeList[ i ] = buildAttributeInfo( property, attribute ); 311 } 312 313 return attributeList; 314 } 315 316 322 private ModelMBeanAttributeInfo buildAttributeInfo( final PropertyDescriptor property, 323 final Configuration config ) 324 { 325 final String name = property.getName(); 326 final Method readMethod = property.getReadMethod(); 327 final Method writeMethod = property.getWriteMethod(); 328 final String type = property.getPropertyType().getName(); 329 330 String description = property.getDisplayName(); 331 boolean isReadable = (readMethod != null); 332 boolean isWriteable = (writeMethod != null); 333 334 if( config != null ) 335 { 336 description = 338 config.getAttribute( "description", description ); 339 340 isReadable = 342 config.getAttributeAsBoolean( "isReadable", true ) && isReadable; 343 344 isWriteable = 346 config.getAttributeAsBoolean( "isWriteable", true ) && isWriteable; 347 } 348 349 final boolean isIs = 350 (readMethod != null) && readMethod.getName().startsWith( "is" ); 351 352 final ModelMBeanAttributeInfo info = 353 new ModelMBeanAttributeInfo ( name, type, description, isReadable, isWriteable, isIs ); 354 355 final Descriptor descriptor = info.getDescriptor(); 357 descriptor.setField( "currencyTimeLimit", new Integer ( 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 374 private PropertyDescriptor getPropertyDescriptor( final String name, 375 final PropertyDescriptor [] 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 message = 387 REZ.getString( "mxinfo.error.missing.property", name ); 388 throw new ConfigurationException( message ); 389 } 390 391 398 private ModelMBeanOperationInfo [] buildOperationInfos( final Configuration config, 399 final BeanInfo info ) 400 throws ConfigurationException 401 { 402 final Configuration[] operationsConfig = 403 config.getChildren( "operation" ); 404 405 final ModelMBeanOperationInfo [] operations = 406 new ModelMBeanOperationInfo [ operationsConfig.length ]; 407 408 final MethodDescriptor [] methodDescriptors = info.getMethodDescriptors(); 409 410 for( int i = 0; i < operationsConfig.length; i++ ) 411 { 412 final Configuration operation = operationsConfig[ i ]; 413 final String name = operation.getAttribute( "name" ); 414 final MethodDescriptor method = 415 getMethodDescriptor( name, methodDescriptors ); 416 operations[ i ] = buildOperationInfo( method, operation ); 417 } 418 419 return operations; 420 } 421 422 430 private ModelMBeanOperationInfo buildOperationInfo( final MethodDescriptor method, 431 final Configuration config ) 432 throws ConfigurationException 433 { 434 ModelMBeanOperationInfo info; 435 436 if( config == null ) 437 { 438 info = new ModelMBeanOperationInfo ( method.getDisplayName(), 439 method.getMethod() ); 440 441 } 442 else 443 { 444 final String name = method.getName(); 445 final String type = method.getMethod().getReturnType().getName(); 446 final String 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 [] params = 456 new MBeanParameterInfo [ paramConfig.length ]; 457 for( int i = 0; i < paramConfig.length; i++ ) 458 { 459 params[ i ] = buildParameterInfo( paramConfig[ i ] ); 460 } 461 462 info = new ModelMBeanOperationInfo ( name, description, params, type, impact ); 463 } 464 465 final Descriptor descriptor = info.getDescriptor(); 467 descriptor.setField( "currencyTimeLimit", new Integer ( 0 ) ); 471 info.setDescriptor( descriptor ); 472 return info; 473 } 474 475 478 private MethodDescriptor getMethodDescriptor( final String name, 479 final MethodDescriptor [] 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 message = REZ.getString( "mxinfo.error.missing.method", name ); 491 throw new ConfigurationException( message ); 492 } 493 494 500 private MBeanParameterInfo buildParameterInfo( Configuration paramConfig ) 501 throws ConfigurationException 502 { 503 final String name = paramConfig.getAttribute( "name" ); 504 final String description = paramConfig.getAttribute( "description" ); 505 final String type = paramConfig.getAttribute( "type" ); 506 507 return new MBeanParameterInfo ( name, type, description ); 508 } 509 510 518 private Configuration loadMxInfo( final Class clazz ) 519 throws ConfigurationException 520 { 521 final String mxinfoName = 522 "/" + clazz.getName().replace( '.', '/' ) + ".mxinfo"; 523 try 524 { 525 InputStream stream = clazz.getResourceAsStream( mxinfoName ); 526 if( null == stream ) 527 { 528 return null; 529 } 530 531 final InputSource source = new InputSource ( stream ); 532 533 return ConfigurationBuilder.build( source, true ); 535 } 536 catch( Exception e ) 537 { 538 final String message = 539 REZ.getString( "mxinfo.error.file", mxinfoName ); 540 getLogger().error( message, e ); 541 throw new ConfigurationException( message ); 542 } 543 } 544 545 548 private String getShortName( final String className ) 549 { 550 return className.substring( className.lastIndexOf( '.' ) + 1 ); 551 } 552 } 553 | Popular Tags |