1 8 package org.apache.avalon.phoenix.tools.verifier; 9 10 import java.util.ArrayList ; 11 import java.util.Stack ; 12 import org.apache.avalon.excalibur.i18n.ResourceManager; 13 import org.apache.avalon.excalibur.i18n.Resources; 14 import org.apache.avalon.framework.activity.Disposable; 15 import org.apache.avalon.framework.activity.Initializable; 16 import org.apache.avalon.framework.activity.Startable; 17 import org.apache.avalon.framework.component.Composable; 18 import org.apache.avalon.framework.configuration.Configurable; 19 import org.apache.avalon.framework.context.Contextualizable; 20 import org.apache.avalon.framework.logger.AbstractLogEnabled; 21 import org.apache.avalon.framework.logger.LogEnabled; 22 import org.apache.avalon.framework.parameters.Parameterizable; 23 import org.apache.avalon.framework.service.Serviceable; 24 import org.apache.avalon.phoenix.Block; 25 import org.apache.avalon.phoenix.BlockListener; 26 import org.apache.avalon.phoenix.metadata.BlockListenerMetaData; 27 import org.apache.avalon.phoenix.metadata.BlockMetaData; 28 import org.apache.avalon.phoenix.metadata.DependencyMetaData; 29 import org.apache.avalon.phoenix.metadata.SarMetaData; 30 import org.apache.avalon.phoenix.metainfo.BlockInfo; 31 import org.apache.avalon.phoenix.metainfo.DependencyDescriptor; 32 import org.apache.avalon.phoenix.metainfo.ServiceDescriptor; 33 34 62 public class SarVerifier 63 extends AbstractLogEnabled 64 { 65 private static final Resources REZ = 66 ResourceManager.getPackageResources( SarVerifier.class ); 67 68 private static final Class [] FRAMEWORK_CLASSES = new Class [] 69 { 70 LogEnabled.class, 71 Contextualizable.class, 72 Composable.class, 73 Serviceable.class, 74 Configurable.class, 75 Parameterizable.class, 76 Initializable.class, 77 Startable.class, 78 Disposable.class 79 }; 80 81 92 public void verifySar( final SarMetaData sar, final ClassLoader classLoader ) 93 throws VerifyException 94 { 95 final BlockMetaData[] blocks = sar.getBlocks(); 96 final BlockListenerMetaData[] listeners = sar.getListeners(); 97 98 String message = null; 99 100 message = REZ.getString( "verify-valid-names" ); 101 getLogger().info( message ); 102 verifySarName( sar.getName() ); 103 verifyValidNames( blocks ); 104 verifyValidNames( listeners ); 105 106 message = REZ.getString( "verify-unique-names" ); 107 getLogger().info( message ); 108 checkNamesUnique( blocks, listeners ); 109 110 message = REZ.getString( "verify-dependencies-mapping" ); 111 getLogger().info( message ); 112 verifyValidDependencies( blocks ); 113 114 message = REZ.getString( "verify-dependency-references" ); 115 getLogger().info( message ); 116 verifyDependencyReferences( blocks ); 117 118 message = REZ.getString( "verify-nocircular-dependencies" ); 119 getLogger().info( message ); 120 verifyNoCircularDependencies( blocks ); 121 122 message = REZ.getString( "verify-block-type" ); 123 getLogger().info( message ); 124 verifyBlocksType( blocks, classLoader ); 125 126 message = REZ.getString( "verify-listener-type" ); 127 getLogger().info( message ); 128 verifyListenersType( listeners, classLoader ); 129 } 130 131 137 private void verifyValidDependencies( final BlockMetaData[] blocks ) 138 throws VerifyException 139 { 140 for( int i = 0; i < blocks.length; i++ ) 141 { 142 verifyDependenciesMap( blocks[ i ] ); 143 } 144 } 145 146 152 private void verifyNoCircularDependencies( final BlockMetaData[] blocks ) 153 throws VerifyException 154 { 155 for( int i = 0; i < blocks.length; i++ ) 156 { 157 final BlockMetaData block = blocks[ i ]; 158 159 final Stack stack = new Stack (); 160 stack.push( block ); 161 verifyNoCircularDependencies( block, blocks, stack ); 162 stack.pop(); 163 } 164 } 165 166 172 private void verifyNoCircularDependencies( final BlockMetaData block, 173 final BlockMetaData[] blocks, 174 final Stack stack ) 175 throws VerifyException 176 { 177 final BlockMetaData[] dependencies = getDependencies( block, blocks ); 178 179 for( int i = 0; i < dependencies.length; i++ ) 180 { 181 final BlockMetaData dependency = dependencies[ i ]; 182 if( stack.contains( dependency ) ) 183 { 184 final String trace = getDependencyTrace( dependency, stack ); 185 final String message = 186 REZ.getString( "dependency-circular", block.getName(), trace ); 187 throw new VerifyException( message ); 188 } 189 190 stack.push( dependency ); 191 verifyNoCircularDependencies( dependency, blocks, stack ); 192 stack.pop(); 193 } 194 } 195 196 203 private String getDependencyTrace( final BlockMetaData block, 204 final Stack stack ) 205 { 206 final StringBuffer sb = new StringBuffer (); 207 sb.append( "[ " ); 208 209 final String name = block.getName(); 210 final int size = stack.size(); 211 final int top = size - 1; 212 for( int i = top; i >= 0; i-- ) 213 { 214 final BlockMetaData other = (BlockMetaData)stack.get( i ); 215 if( top != i ) 216 { 217 sb.append( ", " ); 218 } 219 sb.append( other.getName() ); 220 221 if( other.getName().equals( name ) ) 222 { 223 break; 224 } 225 } 226 227 sb.append( ", " ); 228 sb.append( name ); 229 230 sb.append( " ]" ); 231 return sb.toString(); 232 } 233 234 241 private BlockMetaData[] getDependencies( final BlockMetaData block, 242 final BlockMetaData[] blocks ) 243 { 244 final ArrayList dependencies = new ArrayList (); 245 final DependencyMetaData[] deps = block.getDependencies(); 246 247 for( int i = 0; i < deps.length; i++ ) 248 { 249 final String name = deps[ i ].getName(); 250 final BlockMetaData other = getBlock( name, blocks ); 251 dependencies.add( other ); 252 } 253 254 return (BlockMetaData[])dependencies.toArray( new BlockMetaData[ 0 ] ); 255 } 256 257 263 private void verifyDependencyReferences( final BlockMetaData[] blocks ) 264 throws VerifyException 265 { 266 for( int i = 0; i < blocks.length; i++ ) 267 { 268 verifyDependencyReferences( blocks[ i ], blocks ); 269 } 270 } 271 272 279 private void verifyDependencyReferences( final BlockMetaData block, 280 final BlockMetaData[] others ) 281 throws VerifyException 282 { 283 final BlockInfo info = block.getBlockInfo(); 284 final DependencyMetaData[] roles = block.getDependencies(); 285 286 for( int i = 0; i < roles.length; i++ ) 287 { 288 final String blockName = roles[ i ].getName(); 289 final String roleName = roles[ i ].getRole(); 290 final ServiceDescriptor service = 291 info.getDependency( roleName ).getService(); 292 293 final BlockMetaData other = getBlock( blockName, others ); 295 if( null == other ) 296 { 297 final String message = 298 REZ.getString( "dependency-noblock", blockName, block.getName() ); 299 throw new VerifyException( message ); 300 } 301 302 final ServiceDescriptor[] services = other.getBlockInfo().getServices(); 305 if( !hasMatchingService( service, services ) ) 306 { 307 final String message = 308 REZ.getString( "dependency-noservice", blockName, service, block.getName() ); 309 throw new VerifyException( message ); 310 } 311 } 312 } 313 314 321 private BlockMetaData getBlock( final String name, final BlockMetaData[] blocks ) 322 { 323 for( int i = 0; i < blocks.length; i++ ) 324 { 325 if( blocks[ i ].getName().equals( name ) ) 326 { 327 return blocks[ i ]; 328 } 329 } 330 331 return null; 332 } 333 334 341 private void verifyBlocksType( final BlockMetaData[] blocks, final ClassLoader classLoader ) 342 throws VerifyException 343 { 344 for( int i = 0; i < blocks.length; i++ ) 345 { 346 verifyBlockType( blocks[ i ], classLoader ); 347 } 348 } 349 350 357 private void verifyBlockType( final BlockMetaData block, final ClassLoader classLoader ) 358 throws VerifyException 359 { 360 final String name = block.getName(); 361 final String classname = block.getImplementationKey(); 362 Class clazz = null; 363 try 364 { 365 clazz = classLoader.loadClass( classname ); 366 } 367 catch( final Exception e ) 368 { 369 final String message = REZ.getString( "bad-block-class", 370 name, 371 classname, 372 e.getMessage() ); 373 throw new VerifyException( message ); 374 } 375 376 final Class [] interfaces = 377 getServiceClasses( name, 378 block.getBlockInfo().getServices(), 379 classLoader ); 380 381 for( int i = 0; i < interfaces.length; i++ ) 382 { 383 if( !interfaces[ i ].isAssignableFrom( clazz ) ) 384 { 385 final String message = REZ.getString( "block-noimpl-service", 386 name, 387 classname, 388 interfaces[ i ].getName() ); 389 throw new VerifyException( message ); 390 } 391 } 392 393 if( Block.class.isAssignableFrom( clazz ) ) 394 { 395 final String message = 396 REZ.getString( "verifier.implements-block.error", 397 name, 398 classname ); 399 getLogger().error( message ); 400 System.err.println( message ); 401 } 402 } 403 404 410 private void verifyListenersType( final BlockListenerMetaData[] listeners, 411 final ClassLoader classLoader ) 412 throws VerifyException 413 { 414 for( int i = 0; i < listeners.length; i++ ) 415 { 416 verifyListenerType( listeners[ i ], classLoader ); 417 } 418 } 419 420 426 private void verifyListenerType( final BlockListenerMetaData listener, 427 final ClassLoader classLoader ) 428 throws VerifyException 429 { 430 Class clazz = null; 431 try 432 { 433 clazz = classLoader.loadClass( listener.getClassname() ); 434 } 435 catch( final Exception e ) 436 { 437 final String message = 438 REZ.getString( "bad-listener-class", 439 listener.getName(), 440 listener.getClassname(), 441 e.getMessage() ); 442 throw new VerifyException( message, e ); 443 } 444 445 if( !BlockListener.class.isAssignableFrom( clazz ) ) 446 { 447 final String message = REZ.getString( "listener-noimpl-listener", 448 listener.getName(), 449 listener.getClassname() ); 450 throw new VerifyException( message ); 451 } 452 } 453 454 460 private void verifySarName( final String name ) 461 throws VerifyException 462 { 463 if( !isValidName( name ) ) 464 { 465 final String message = REZ.getString( "invalid-sar-name", name ); 466 throw new VerifyException( message ); 467 } 468 } 469 470 476 private void verifyValidNames( final BlockMetaData[] blocks ) 477 throws VerifyException 478 { 479 for( int i = 0; i < blocks.length; i++ ) 480 { 481 final String name = blocks[ i ].getName(); 482 if( !isValidName( name ) ) 483 { 484 final String message = REZ.getString( "invalid-block-name", name ); 485 throw new VerifyException( message ); 486 } 487 } 488 } 489 490 496 private void verifyValidNames( final BlockListenerMetaData[] listeners ) 497 throws VerifyException 498 { 499 for( int i = 0; i < listeners.length; i++ ) 500 { 501 final String name = listeners[ i ].getName(); 502 if( !isValidName( name ) ) 503 { 504 final String message = REZ.getString( "invalid-listener-name", name ); 505 throw new VerifyException( message ); 506 } 507 } 508 } 509 510 517 private boolean isValidName( final String name ) 518 { 519 final int size = name.length(); 520 for( int i = 0; i < size; i++ ) 521 { 522 final char ch = name.charAt( i ); 523 524 if( !Character.isLetterOrDigit( ch ) && '-' != ch && '.' != ch ) 525 { 526 return false; 527 } 528 } 529 530 return true; 531 } 532 533 542 private void checkNamesUnique( final BlockMetaData[] blocks, 543 final BlockListenerMetaData[] listeners ) 544 throws VerifyException 545 { 546 for( int i = 0; i < blocks.length; i++ ) 547 { 548 final String name = blocks[ i ].getName(); 549 checkNameUnique( name, blocks, listeners, i, -1 ); 550 } 551 552 for( int i = 0; i < listeners.length; i++ ) 553 { 554 final String name = listeners[ i ].getName(); 555 checkNameUnique( name, blocks, listeners, -1, i ); 556 } 557 } 558 559 572 private void checkNameUnique( final String name, 573 final BlockMetaData[] blocks, 574 final BlockListenerMetaData[] listeners, 575 final int blockIndex, 576 final int listenerIndex ) 577 throws VerifyException 578 { 579 for( int i = 0; i < blocks.length; i++ ) 581 { 582 final String other = blocks[ i ].getName(); 583 if( blockIndex != i && name.equals( other ) ) 584 { 585 final String message = REZ.getString( "duplicate-name", name ); 586 throw new VerifyException( message ); 587 } 588 } 589 590 for( int i = 0; i < listeners.length; i++ ) 592 { 593 final String other = listeners[ i ].getName(); 594 if( listenerIndex != i && name.equals( other ) ) 595 { 596 final String message = REZ.getString( "duplicate-name", name ); 597 throw new VerifyException( message ); 598 } 599 } 600 } 601 602 610 private void verifyDependenciesMap( final BlockMetaData block ) 611 throws VerifyException 612 { 613 final DependencyMetaData[] roles = block.getDependencies(); 615 for( int i = 0; i < roles.length; i++ ) 616 { 617 final String roleName = roles[ i ].getRole(); 618 final DependencyDescriptor descriptor = block.getBlockInfo().getDependency( roleName ); 619 620 if( null == descriptor ) 623 { 624 final String message = REZ.getString( "unknown-dependency", 625 roles[ i ].getName(), 626 roleName, 627 block.getName() ); 628 throw new VerifyException( message ); 629 } 630 } 631 632 final DependencyDescriptor[] dependencies = block.getBlockInfo().getDependencies(); 634 for( int i = 0; i < dependencies.length; i++ ) 635 { 636 final DependencyMetaData role = block.getDependency( dependencies[ i ].getRole() ); 637 638 if( null == role ) 641 { 642 final String message = REZ.getString( "unspecified-dependency", 643 dependencies[ i ].getRole(), 644 block.getName() ); 645 throw new VerifyException( message ); 646 } 647 } 648 } 649 650 661 private Class [] getServiceClasses( final String name, 662 final ServiceDescriptor[] services, 663 final ClassLoader classLoader ) 664 throws VerifyException 665 { 666 final Class [] classes = new Class [ services.length ]; 667 668 for( int i = 0; i < services.length; i++ ) 669 { 670 final String classname = services[ i ].getName(); 671 try 672 { 673 classes[ i ] = classLoader.loadClass( classname ); 674 } 675 catch( final Throwable t ) 676 { 677 final String message = 678 REZ.getString( "bad-service-class", name, classname, t.getMessage() ); 679 throw new VerifyException( message, t ); 680 } 681 682 if( !classes[ i ].isInterface() ) 683 { 684 final String message = 685 REZ.getString( "service-not-interface", name, classname ); 686 throw new VerifyException( message ); 687 } 688 689 checkNotFrameworkInterface( name, classname, classes[ i ] ); 690 } 691 692 return classes; 693 } 694 695 703 private void checkNotFrameworkInterface( final String name, 704 final String classname, 705 final Class clazz ) 706 { 707 for( int i = 0; i < FRAMEWORK_CLASSES.length; i++ ) 708 { 709 final Class lifecycle = FRAMEWORK_CLASSES[ i ]; 710 if( lifecycle.isAssignableFrom( clazz ) ) 711 { 712 final String message = 713 REZ.getString( "verifier.service-isa-lifecycle.error", 714 name, 715 classname, 716 clazz.getName(), 717 lifecycle.getName() ); 718 getLogger().warn( message ); 719 System.err.println( message ); 720 } 721 } 722 } 723 724 733 private boolean hasMatchingService( final ServiceDescriptor service, 734 final ServiceDescriptor[] candidates ) 735 { 736 for( int i = 0; i < candidates.length; i++ ) 737 { 738 if( service.matches( candidates[ i ] ) ) 739 { 740 return true; 741 } 742 } 743 744 return false; 745 } 746 } 747 | Popular Tags |