1 23 24 29 package com.sun.enterprise.management.base; 30 31 import java.util.Set ; 32 import java.util.Arrays ; 33 import java.util.HashSet ; 34 import java.util.Map ; 35 import java.util.HashMap ; 36 import java.util.Iterator ; 37 import java.io.IOException ; 38 import java.io.NotSerializableException ; 39 40 import javax.management.ObjectName ; 41 import javax.management.MBeanServerConnection ; 42 import javax.management.MBeanOperationInfo ; 43 import javax.management.InstanceNotFoundException ; 44 import javax.management.JMException ; 45 import javax.management.ReflectionException ; 46 import javax.management.AttributeNotFoundException ; 47 import javax.management.MBeanException ; 48 import javax.management.MBeanInfo ; 49 import javax.management.MBeanAttributeInfo ; 50 import javax.management.Attribute ; 51 import javax.management.AttributeList ; 52 53 54 import com.sun.appserv.management.j2ee.J2EEDomain; 55 56 import com.sun.appserv.management.client.ProxyFactory; 57 import com.sun.appserv.management.base.AMX; 58 import com.sun.appserv.management.config.ResourceRefConfig; 59 import com.sun.appserv.management.config.DeployedItemRefConfig; 60 import com.sun.appserv.management.config.ResourceConfig; 61 62 import com.sun.appserv.management.util.misc.ExceptionUtil; 63 import com.sun.appserv.management.util.misc.ArrayUtil; 64 import com.sun.appserv.management.util.misc.ArrayConversion; 65 import com.sun.appserv.management.util.misc.ClassUtil; 66 import com.sun.appserv.management.util.jmx.JMXUtil; 67 import com.sun.appserv.management.util.jmx.ReadWriteAttributeFilter; 68 69 import com.sun.appserv.management.util.stringifier.ArrayStringifier; 70 71 72 73 import com.sun.enterprise.management.AMXTestBase; 74 import com.sun.enterprise.management.Capabilities; 75 76 78 public final class GenericTest extends AMXTestBase 79 { 80 final boolean mDoInfo; 81 final boolean mDoAttributes; 82 final boolean mDoOperations; 83 final boolean mwarnings; 84 85 public 86 GenericTest() 87 throws IOException 88 { 89 mDoInfo = true; 90 mDoAttributes = true; 91 mDoOperations = true; 92 mwarnings = true; 93 } 94 95 public static Capabilities 96 getCapabilities() 97 { 98 return getOfflineCapableCapabilities( true ); 99 } 100 private Map <String ,Throwable > 101 validateAttributesSingly( 102 final ObjectName objectName, 103 final String [] attrNames, 104 Map <String ,Throwable > failures, 105 Map <String ,Throwable > warnings ) 106 throws Exception 107 { 108 MBeanServerConnection conn = getConnection(); 109 110 for( int i = 0; i < attrNames.length; ++i ) 111 { 112 final String attrName = attrNames[ i ]; 113 114 try 115 { 116 final Object a = conn.getAttribute( objectName, attrName ); 117 118 if ( a == null ) 119 { 120 } 122 } 123 catch( NotSerializableException e ) 124 { 125 warnings.put( attrName, e ); 126 } 127 catch( IOException e ) 128 { 129 failures.put( attrName, e ); 130 } 131 catch( Exception e ) 132 { 133 failures.put( attrName, e ); 134 } 135 } 136 137 return( failures ); 138 } 139 140 141 private String 142 getExceptionMsg( final Throwable e ) 143 { 144 String msg = null; 145 146 if ( e instanceof IOException ) 147 { 148 msg = "received an exception of class " + e.getClass().getName(); 149 150 if ( shouldPrintStackTraces() ) 151 { 152 msg = msg + "Stack trace = \n" + 153 ExceptionUtil.getStackTrace( ExceptionUtil.getRootCause( e ) ); 154 } 155 } 156 else 157 { 158 msg = "threw an Exception of type " + 159 e.getClass().getName() + ", message = " + e.getMessage(); 160 161 if ( shouldPrintStackTraces() ) 162 { 163 msg = msg + "\n" + ExceptionUtil.getStackTrace( e ); 164 } 165 } 166 167 final Throwable rootCause = ExceptionUtil.getRootCause( e ); 168 169 if ( rootCause != e ) 170 { 171 msg = msg + "...\nRoot cause was exception of type " + e.getClass().getName() + ", message = " + 172 rootCause.getMessage(); 173 174 175 if ( shouldPrintStackTraces() ) 176 { 177 msg = msg + "\n" + ExceptionUtil.getStackTrace( rootCause ); 178 } 179 } 180 181 return( msg ); 182 } 183 184 MBeanAttributeInfo 185 findAttributeInfo( 186 final MBeanAttributeInfo [] infos, 187 String attrName ) 188 { 189 MBeanAttributeInfo info = null; 190 191 for( int i = 0; i < infos.length; ++i ) 192 { 193 if ( infos[ i ] != null && infos[ i ].getName().equals( attrName ) ) 194 { 195 info = infos[ i ]; 196 break; 197 } 198 } 199 200 assert( info != null ); 201 return( info ); 202 } 203 204 private void 205 displayAttributeFailuresOrWarnings( 206 final boolean failure, 207 final ObjectName objectName, 208 final MBeanAttributeInfo [] infos, 209 final Map <String ,Throwable > problems ) 210 throws Exception 211 { 212 trace( "" ); 213 trace( problems.keySet().size() + (failure ? " Failures: " : " Warnings: ") + objectName ); 214 215 int i = 0; 216 for( final String attrName : problems.keySet() ) 217 { 218 final Throwable t = problems.get( attrName ); 219 220 final MBeanAttributeInfo info = findAttributeInfo( infos, attrName ); 221 222 final String prefix = "(" + (i+1) + ")" + " getting Attribute \"" + attrName + "\" of type " + 223 info.getType() + " "; 224 225 if ( t == null ) 226 { 227 trace( prefix + "returned null" ); 228 } 229 else 230 { 231 trace( prefix + getExceptionMsg( t ) ); 232 } 233 ++i; 234 } 235 } 236 237 238 239 private boolean 240 validateMBeanInfo( final ObjectName objectName, final MBeanInfo info) 241 { 242 boolean valid = true; 243 244 if ( ArrayUtil.arrayContainsNulls( info.getAttributes() ) ) 245 { 246 warning( "MBean has nulls in its MBeanAttributeInfo[]: " + objectName ); 247 valid = false; 248 } 249 250 if ( ArrayUtil.arrayContainsNulls( info.getConstructors() ) ) 251 { 252 warning( "MBean has nulls in its MBeanConstructorInfo[]: " + objectName ); 253 valid = false; 254 } 255 256 if ( ArrayUtil.arrayContainsNulls( info.getOperations() ) ) 257 { 258 warning( "MBean has nulls in its MBeanOperationInfo[]: " + objectName ); 259 valid = false; 260 } 261 262 if ( ArrayUtil.arrayContainsNulls( info.getNotifications() ) ) 263 { 264 warning( "MBean has nulls in its MBeanNotificationInfo[]: " + objectName ); 265 valid = false; 266 } 267 268 return( valid ); 269 } 270 271 static final private String SECTION_LINE = 272 "--------------------------------------------------------------------------------"; 273 274 275 276 private void 277 printDuplicateAttributes( final ObjectName objectName, MBeanAttributeInfo [] attrInfos, String name) 278 { 279 String msg = "MBean " + quote( objectName ) + " has the same Attribute listed more than once:\n"; 280 281 for( int i = 0; i < attrInfos.length; ++i ) 282 { 283 final MBeanAttributeInfo a = attrInfos[ i ]; 284 285 if ( a.getName().equals( name ) ) 286 { 287 msg = msg + name + ": " + a.getType() + ", " + quote( a.getDescription() ); 288 } 289 } 290 291 warning( msg ); 292 } 293 294 private boolean 295 validateUniqueAttributeNames( final ObjectName objectName, MBeanAttributeInfo [] attrInfos ) 296 { 297 boolean valid = true; 298 final MBeanAttributeInfo [] infos = 299 JMXUtil.filterAttributeInfos( attrInfos, ReadWriteAttributeFilter.READABLE_FILTER ); 300 final String [] names = JMXUtil.getAttributeNames( infos ); 301 302 if ( ArrayConversion.arrayToSet( names ).size() != attrInfos.length ) 303 { 304 final Set <String > set = new HashSet <String >(); 305 306 for( int i = 0; i < names.length; ++i ) 307 { 308 final String name = names[ i ]; 309 310 if ( set.contains( name ) ) 311 { 312 valid = false; 313 314 printDuplicateAttributes( objectName, attrInfos, name ); 315 } 316 else 317 { 318 set.add( name ); 319 } 320 } 321 set.clear(); 322 } 323 324 return( valid ); 325 } 326 327 private boolean 328 validateMissingAndEmptyAttributeNames( final ObjectName objectName ) 329 { 330 boolean valid = true; 331 final MBeanServerConnection conn = getConnection(); 332 333 AttributeList attrs = null; 334 try 335 { 336 attrs = conn.getAttributes( objectName, new String [0] ); 337 if ( attrs == null ) 338 { 339 warning( "MBean " + quote( objectName ) + 340 " returned NULL for an empty AttributeList" ); 341 valid = false; 342 } 343 else if ( attrs.size() != 0 ) 344 { 345 warning( "MBean " + quote( objectName ) + 346 " returned attributes for an empty AttributeList" ); 347 valid = false; 348 } 349 } 350 catch( Exception e ) 351 { 352 valid = false; 353 354 warning( "MBean " + quote( objectName ) + 355 " threw an exception getting an empty attribute list" ); 356 } 357 358 try 359 { 360 final String notFoundName = "bogus." + System.currentTimeMillis(); 361 attrs = conn.getAttributes( objectName, new String [] { notFoundName }); 362 if ( attrs == null ) 363 { 364 warning( "MBean " + quote( objectName ) + 365 " returned NULL for a missing Attribute" ); 366 valid = false; 367 } 368 else if ( attrs.size() != 0 ) 369 { 370 warning( "MBean " + quote( objectName ) + 371 " returned attributes for a non-existent name" ); 372 valid = false; 373 } 374 } 375 catch( Exception e ) 376 { 377 valid = false; 378 379 warning( "MBean " + quote( objectName ) + 380 " threw an exception when getAttributes() was called with a " + 381 "non-existent Attribute, exception class = " + 382 e.getClass().getName() ); 383 } 384 385 return( valid ); 386 } 387 388 private boolean 389 validateAttributeTypes( 390 final ObjectName objectName, 391 final AttributeList attrs, 392 final MBeanAttributeInfo [] attrInfos) 393 throws Exception 394 { 395 boolean valid = true; 396 397 final Map <String ,MBeanAttributeInfo > attrInfosMap = JMXUtil.attributeInfosToMap( attrInfos ); 398 399 final Iterator iter = attrs.iterator(); 400 while ( iter.hasNext() ) 401 { 402 final Attribute attr = (Attribute )iter.next(); 403 404 final String name = attr.getName(); 405 final Object value = attr.getValue(); 406 final MBeanAttributeInfo attrInfo = (MBeanAttributeInfo )attrInfosMap.get( name ); 407 if ( attrInfo == null ) 408 { 409 valid = false; 410 warning( "MBean " + objectName + " returned an Attribute not " + 411 "declared in its MBeanInfo: " + name ); 412 } 413 else if ( value != null ) 414 { 415 final String typeName = attrInfo.getType(); 416 final Class <?> infoClass = ClassUtil.getClassFromName( typeName ); 417 final Class <?> valueClass = value.getClass(); 418 419 if ( infoClass == null ) 420 { 421 valid = false; 422 warning( "Can't find class for: " + typeName ); 423 } 424 else if ( ! infoClass.isAssignableFrom( valueClass ) ) 425 { 426 final Class <?> objectClass = ClassUtil.PrimitiveClassToObjectClass( infoClass ); 427 428 if ( ! objectClass.isAssignableFrom( valueClass ) ) 429 { 430 valid = false; 431 warning( "MBean " + objectName + " returned Attribute " + 432 name + "=" + value + 433 " of class " + value.getClass().getName() + 434 " not matching its MBeanInfo: " + infoClass.getName() ); 435 } 436 } 437 } 438 } 439 440 return( valid ); 441 } 442 443 private boolean 444 validateAttributes( 445 final ObjectName objectName, 446 final MBeanAttributeInfo [] attrInfos) 447 throws Exception 448 { 449 boolean valid = true; 450 451 final MBeanAttributeInfo [] readableInfos = JMXUtil.filterAttributeInfos( attrInfos, 452 ReadWriteAttributeFilter.READABLE_FILTER ); 453 final String [] attrNames = JMXUtil.getAttributeNames( readableInfos ); 454 Arrays.sort( attrNames ); 455 456 if ( attrNames.length != 0 ) 457 { 458 try 461 { 462 final AttributeList attrs = getConnection().getAttributes( objectName, attrNames ); 464 465 if ( attrs == null ) 466 { 467 warning( "MBean " + quote( objectName ) + " returned NULL for its AttributeList" ); 468 valid = false; 469 } 470 else if ( attrs.size() != readableInfos.length ) 471 { 472 final ArrayStringifier as = new ArrayStringifier( ", ", true ); 474 final String claimedString = as.stringify( attrNames ); 475 476 final Set <String > actualSet = JMXUtil.attributeListToValueMap( attrs ).keySet(); 477 final Set <String > missingSet = ArrayConversion.arrayToSet( attrNames ); 478 missingSet.removeAll( actualSet ); 479 480 final String [] missingNames = (String [])ArrayConversion.setToArray( missingSet, true ); 481 Arrays.sort( missingNames ); 482 final String missingString = as.stringify( missingNames ); 483 484 warning( "MBean " + quote( objectName ) + 485 " did not supply the " + 486 missingNames.length + " attributes " + missingString ); 487 } 488 489 valid = validateAttributeTypes( objectName, attrs, readableInfos ); 490 } 491 catch( Exception e ) 492 { 493 trace( SECTION_LINE ); 494 final String msg = "getAttributes() failed on " + quote( objectName ) + ", exception =\n" + e; 495 496 if ( e instanceof NotSerializableException ) 497 { 498 warning( msg ); 499 } 500 else 501 { 502 warning( msg ); 503 valid = false; 504 } 505 final Map <String ,Throwable > failures = new HashMap <String ,Throwable >(); 507 final Map <String ,Throwable > warnings = new HashMap <String ,Throwable >(); 508 509 validateAttributesSingly( objectName, attrNames, failures, warnings ); 510 511 trace( "Validating attributes one-at-a-time using getAttribute() for " + quote( objectName )); 512 if ( failures.size() == 0 && warnings.size() == 0 ) 513 { 514 warning( " during getAttributes(" + 515 ArrayStringifier.stringify( attrNames, "," ) + ") for: " + objectName + 516 " (but Attributes work when queried one-at-a-time).\nIt " + 517 getExceptionMsg( e ) ); 518 } 519 520 if ( failures.size() != 0 ) 521 { 522 displayAttributeFailuresOrWarnings( true, objectName, readableInfos, failures ); 523 } 524 525 if ( warnings.size() != 0 ) 526 { 527 displayAttributeFailuresOrWarnings( false, objectName, readableInfos, warnings ); 528 } 529 530 trace( SECTION_LINE ); 531 } 532 } 533 else 534 { 535 valid = true; 536 } 537 538 if ( ! validateUniqueAttributeNames( objectName, attrInfos ) ) 539 { 540 valid = false; 541 } 542 543 if ( ! validateMissingAndEmptyAttributeNames( objectName ) ) 544 { 545 valid = false; 546 } 547 548 return( valid ); 549 } 550 551 void 552 checkObjectNameReturnValue( 553 MBeanServerConnection conn, 554 ObjectName callee, 555 MBeanOperationInfo operationInfo, 556 ObjectName resultOfCall ) 557 throws Exception 558 { 559 try 560 { 561 printVerbose( "checking MBean info for: " + resultOfCall ); 562 final MBeanInfo mbeanInfo = conn.getMBeanInfo( resultOfCall ); 563 } 564 catch( InstanceNotFoundException e ) 565 { 566 trace( "WARNING: MBean " + resultOfCall + " returned from " + 567 operationInfo.getReturnType() + " " + operationInfo.getName() + "() does not exist" ); 568 569 } 570 catch( Exception e ) 571 { 572 trace( "WARNING: MBean " + resultOfCall + " returned from " + 573 operationInfo.getReturnType() + " " + operationInfo.getName() + 574 "() can't supply MBeanInfo: " + getExceptionMsg( e ) 575 ); 576 577 if ( e instanceof IOException ) 578 { 579 throw (IOException )e; 580 } 581 } 582 } 583 584 void 585 checkGetterResult( 586 MBeanServerConnection conn, 587 ObjectName callee, 588 MBeanOperationInfo operationInfo, 589 Object resultOfCall ) 590 throws Exception 591 { 592 if ( resultOfCall instanceof ObjectName ) 593 { 594 final ObjectName name = (ObjectName )resultOfCall; 595 596 checkObjectNameReturnValue( conn, callee, operationInfo, name ); 597 } 598 else if ( resultOfCall instanceof ObjectName [] ) 599 { 600 final ObjectName [] names = (ObjectName [])resultOfCall; 601 602 for( int i = 0; i < names.length; ++i ) 603 { 604 checkObjectNameReturnValue( conn, callee, operationInfo, names[ i ]); 605 } 606 } 607 } 608 609 private boolean 610 validateGetters( 611 final ObjectName objectName, 612 final MBeanOperationInfo [] operationInfos ) 613 throws Exception 614 { 615 boolean valid = true; 616 MBeanServerConnection conn = getConnection(); 617 618 for( int i = 0; i < operationInfos.length; ++i ) 619 { 620 final MBeanOperationInfo info = operationInfos[ i ]; 621 622 if ( JMXUtil.isGetter( info ) ) 623 { 624 boolean opValid = false; 625 626 try 627 { 628 printVerbose( "invoking getter: " + info.getName() + "()" ); 629 final Object result = conn.invoke( objectName, info.getName(), null, null ); 630 631 checkGetterResult( conn, 632 objectName, info, result ); 633 } 634 catch( Exception e ) 635 { 636 warning( "Failure: calling " + info.getName() + "() on " + objectName + 637 ": " + getExceptionMsg( e ) ); 638 639 if ( e instanceof IOException ) 640 { 641 throw( (IOException )e ); 642 } 643 valid = false; 644 } 645 } 646 } 647 648 return( valid ); 649 } 650 651 652 653 boolean 654 shouldPrintStackTraces() 655 { 656 return( true ); 657 } 658 659 660 private boolean 661 validate( final ObjectName objectName ) 662 throws Exception 663 { 664 boolean valid = true; 665 666 MBeanServerConnection conn = getConnection(); 667 668 MBeanInfo info = null; 669 try 670 { 671 info = conn.getMBeanInfo( objectName ); 672 } 673 catch( Exception e ) 674 { 675 valid = false; 676 warning( " during getMBeanInfo() for: " + objectName + "\n" + 677 " message = " + e.getMessage() ); 678 throw e; 680 } 681 682 if ( mDoInfo && ! validateMBeanInfo( objectName, info ) ) 683 { 684 trace( "validateMBeanInfo failed for: " + objectName ); 685 valid = false; 686 } 687 688 689 if ( mDoAttributes && 690 ! validateAttributes( objectName, info.getAttributes() ) ) 691 { 692 trace( "validateAttributes failed for: " + objectName ); 693 valid = false; 694 } 695 696 if ( mDoOperations && 697 ! validateGetters( objectName, info.getOperations() ) ) 698 { 699 trace( "validateGetters failed for: " + objectName ); 700 valid = false; 701 } 702 703 return( valid ); 704 } 705 706 707 private void 708 validate( final ObjectName [] objectNames ) 709 throws Exception 710 { 711 int failureCount = 0; 712 713 trace( "Validating: " ); 714 if ( mDoInfo ) 715 { 716 trace( "- MBeanInfo" ); 717 } 718 if ( mDoAttributes ) 719 { 720 trace( "- Attributes" ); 721 } 722 if ( mDoOperations ) 723 { 724 trace( "- Operations (getters)" ); 725 } 726 727 trace( "" ); 728 729 for( int i = 0; i < objectNames.length; ++i ) 730 { 731 final ObjectName objectName = objectNames[ i ]; 732 733 printVerbose( "Validating: " + objectName ); 734 735 if ( ! shouldTest( objectName ) ) 736 { 737 notTested( objectName ); 738 continue; 739 } 740 741 final boolean valid = validate( objectName ); 742 if ( ! valid ) 743 { 744 ++failureCount; 745 } 746 } 747 748 trace( "Total mbeans failing: " + failureCount ); 749 } 750 751 752 753 public void 754 testGenerically() 755 throws Exception 756 { 757 final Set <ObjectName > all = getTestUtil().getAllObjectNames(); 758 759 final ObjectName [] allObjectNames = new ObjectName [ all.size() ]; 760 all.toArray( allObjectNames ); 761 validate( allObjectNames ); 762 } 763 764 } 765 766 767 | Popular Tags |