1 8 package org.codehaus.loom.components.util.verifier; 9 10 import java.lang.reflect.Constructor ; 11 import java.lang.reflect.Modifier ; 12 13 import org.apache.avalon.framework.activity.Disposable; 14 import org.apache.avalon.framework.activity.Initializable; 15 import org.apache.avalon.framework.activity.Startable; 16 import org.apache.avalon.framework.activity.Suspendable; 17 import org.apache.avalon.framework.component.Composable; 18 import org.apache.avalon.framework.component.Recomposable; 19 import org.apache.avalon.framework.configuration.Configurable; 20 import org.apache.avalon.framework.configuration.Reconfigurable; 21 import org.apache.avalon.framework.context.Contextualizable; 22 import org.apache.avalon.framework.context.Recontextualizable; 23 import org.apache.avalon.framework.logger.LogEnabled; 24 import org.apache.avalon.framework.parameters.Parameterizable; 25 import org.apache.avalon.framework.parameters.Reparameterizable; 26 import org.apache.avalon.framework.service.Serviceable; 27 28 import org.codehaus.spice.salt.i18n.ResourceManager; 29 import org.codehaus.spice.salt.i18n.Resources; 30 import org.codehaus.dna.AbstractLogEnabled; 31 import org.codehaus.metaclass.Attributes; 32 import org.codehaus.metaclass.model.Attribute; 33 34 40 public class ComponentVerifier extends AbstractLogEnabled 41 { 42 45 private static final Resources REZ = 46 ResourceManager.getPackageResources( ComponentVerifier.class ); 47 48 51 private static final Class [] EMPTY_TYPES = new Class [0]; 52 53 56 private static final Class [] FRAMEWORK_CLASSES = new Class [] 57 { 58 LogEnabled.class, 59 Contextualizable.class, 60 Recontextualizable.class, 61 Composable.class, 62 Recomposable.class, 63 Serviceable.class, 64 Configurable.class, 65 Reconfigurable.class, 66 Parameterizable.class, 67 Reparameterizable.class, 68 Initializable.class, 69 Startable.class, 70 Suspendable.class, 71 Disposable.class 72 }; 73 74 82 public void verifyType( final String name, final Class type ) 83 throws Exception 84 { 85 final Attribute attribute = 86 Attributes.getAttribute( type, "dna.component" ); 87 if( null == attribute ) 88 { 89 final String msg = "Legacy? component " + name 90 + " does not specify correct metadata. Skipping type verification"; 91 92 getLogger().warn( msg ); 93 94 } 98 final Class [] interfaces = getServiceClasses( name, type ); 99 verifyComponent( name, type, interfaces, false ); 100 } 101 102 113 public void verifyComponent( final String name, 114 final Class implementation, 115 final Class [] services, 116 final boolean buildable ) 117 throws Exception 118 { 119 if( buildable ) 120 { 121 verifyClass( name, implementation ); 122 } 123 verifyLifecycles( name, implementation ); 124 verifyServices( name, services ); 125 verifyImplementsServices( name, implementation, services ); 126 } 127 128 137 public void verifyImplementsServices( final String name, 138 final Class implementation, 139 final Class [] services ) 140 throws Exception 141 { 142 for( int i = 0; i < services.length; i++ ) 143 { 144 if( !services[i].isAssignableFrom( implementation ) ) 145 { 146 final String message = 147 REZ.format( "verifier.noimpl-service.error", 148 name, 149 implementation.getName(), 150 services[i].getName() ); 151 throw new Exception ( message ); 152 } 153 } 154 } 155 156 164 public void verifyClass( final String name, 165 final Class clazz ) 166 throws Exception 167 { 168 verifyNoArgConstructor( name, clazz ); 169 verifyNonAbstract( name, clazz ); 170 verifyNonArray( name, clazz ); 171 verifyNonInterface( name, clazz ); 172 verifyNonPrimitive( name, clazz ); 173 verifyPublic( name, clazz ); 174 } 175 176 184 public void verifyServices( final String name, 185 final Class [] classes ) 186 throws Exception 187 { 188 for( int i = 0; i < classes.length; i++ ) 189 { 190 verifyService( name, classes[i] ); 191 } 192 } 193 194 202 public void verifyService( final String name, 203 final Class clazz ) 204 throws Exception 205 { 206 verifyServiceIsaInterface( name, clazz ); 207 verifyServiceIsPublic( name, clazz ); 208 verifyServiceNotALifecycle( name, clazz ); 209 } 210 211 219 public void verifyLifecycles( final String name, 220 final Class implementation ) 221 throws Exception 222 { 223 final boolean composable = 224 Composable.class.isAssignableFrom( implementation ) || 225 Recomposable.class.isAssignableFrom( implementation ); 226 final boolean serviceable = Serviceable.class.isAssignableFrom( implementation ); 227 if( serviceable && composable ) 228 { 229 final String message = 230 REZ.format( "verifier.incompat-serviceable.error", 231 name, 232 implementation.getName() ); 233 throw new Exception ( message ); 234 } 235 236 final boolean configurable = 237 Configurable.class.isAssignableFrom( implementation ) || 238 Reconfigurable.class.isAssignableFrom( implementation ); 239 final boolean parameterizable = 240 Parameterizable.class.isAssignableFrom( implementation ) || 241 Reparameterizable.class.isAssignableFrom( implementation ); 242 if( parameterizable && configurable ) 243 { 244 final String message = 245 REZ.format( "verifier.incompat-config.error", 246 name, 247 implementation.getName() ); 248 throw new Exception ( message ); 249 } 250 } 251 252 260 public void verifyServiceIsaInterface( final String name, 261 final Class clazz ) 262 throws Exception 263 { 264 if( !clazz.isInterface() ) 265 { 266 final String message = 267 REZ.format( "verifier.non-interface-service.error", 268 name, 269 clazz.getName() ); 270 throw new Exception ( message ); 271 } 272 } 273 274 282 public void verifyServiceIsPublic( final String name, 283 final Class clazz ) 284 throws Exception 285 { 286 final boolean isPublic = 287 Modifier.isPublic( clazz.getModifiers() ); 288 if( !isPublic ) 289 { 290 final String message = 291 REZ.format( "verifier.non-public-service.error", 292 name, 293 clazz.getName() ); 294 throw new Exception ( message ); 295 } 296 } 297 298 306 public void verifyServiceNotALifecycle( final String name, 307 final Class clazz ) 308 throws Exception 309 { 310 for( int i = 0; i < FRAMEWORK_CLASSES.length; i++ ) 311 { 312 final Class lifecycle = FRAMEWORK_CLASSES[i]; 313 if( lifecycle.isAssignableFrom( clazz ) ) 314 { 315 final String message = 316 REZ.format( "verifier.service-isa-lifecycle.error", 317 name, 318 clazz.getName(), 319 lifecycle.getName() ); 320 throw new Exception ( message ); 321 } 322 } 323 } 324 325 333 public void verifyNoArgConstructor( final String name, 334 final Class clazz ) 335 throws Exception 336 { 337 try 338 { 339 final Constructor ctor = clazz.getConstructor( EMPTY_TYPES ); 340 if( !Modifier.isPublic( ctor.getModifiers() ) ) 341 { 342 final String message = 343 REZ.format( "verifier.non-public-ctor.error", 344 name, 345 clazz.getName() ); 346 throw new Exception ( message ); 347 } 348 } 349 catch( final NoSuchMethodException nsme ) 350 { 351 final String message = 352 REZ.format( "verifier.missing-noargs-ctor.error", 353 name, 354 clazz.getName() ); 355 throw new Exception ( message ); 356 } 357 } 358 359 367 public void verifyNonAbstract( final String name, 368 final Class clazz ) 369 throws Exception 370 { 371 final boolean isAbstract = 372 Modifier.isAbstract( clazz.getModifiers() ); 373 if( isAbstract ) 374 { 375 final String message = 376 REZ.format( "verifier.abstract-class.error", 377 name, 378 clazz.getName() ); 379 throw new Exception ( message ); 380 } 381 } 382 383 391 public void verifyPublic( final String name, 392 final Class clazz ) 393 throws Exception 394 { 395 final boolean isPublic = 396 Modifier.isPublic( clazz.getModifiers() ); 397 if( !isPublic ) 398 { 399 final String message = 400 REZ.format( "verifier.nonpublic-class.error", 401 name, 402 clazz.getName() ); 403 throw new Exception ( message ); 404 } 405 } 406 407 415 public void verifyNonPrimitive( final String name, 416 final Class clazz ) 417 throws Exception 418 { 419 if( clazz.isPrimitive() ) 420 { 421 final String message = 422 REZ.format( "verifier.primitive-class.error", 423 name, 424 clazz.getName() ); 425 throw new Exception ( message ); 426 } 427 } 428 429 437 public void verifyNonInterface( final String name, 438 final Class clazz ) 439 throws Exception 440 { 441 if( clazz.isInterface() ) 442 { 443 final String message = 444 REZ.format( "verifier.interface-class.error", 445 name, 446 clazz.getName() ); 447 throw new Exception ( message ); 448 } 449 } 450 451 459 public void verifyNonArray( final String name, 460 final Class clazz ) 461 throws Exception 462 { 463 if( clazz.isArray() ) 464 { 465 final String message = 466 REZ.format( "verifier.array-class.error", 467 name, 468 clazz.getName() ); 469 throw new Exception ( message ); 470 } 471 } 472 473 484 protected Class [] getServiceClasses( final String name, 485 final Class type ) 486 throws Exception 487 { 488 final ClassLoader classLoader = type.getClassLoader(); 489 final Attribute[] attributes = 490 Attributes.getAttributes( type, "dna.service" ); 491 final Class [] classes = new Class [attributes.length]; 492 for( int i = 0; i < attributes.length; i++ ) 493 { 494 final String classname = attributes[i].getParameter( "type" ); 495 try 496 { 497 classes[i] = classLoader.loadClass( classname ); 498 } 499 catch( final Throwable t ) 500 { 501 final String message = 502 "Unable to load service class \"" + 503 classname + 504 "\" for Component named \"" + 505 name + "\". (Reason: " + t + ")."; 506 throw new Exception ( message ); 507 } 508 } 509 510 return classes; 511 } 512 } 513 | Popular Tags |