1 23 24 package com.sun.enterprise.management.monitor; 25 26 import java.util.Map ; 27 import java.util.HashMap ; 28 import java.util.Set ; 29 import java.util.HashSet ; 30 import java.util.Iterator ; 31 import java.util.Collections ; 32 import java.io.Serializable ; 33 34 import java.lang.reflect.Method ; 35 import java.lang.reflect.Proxy ; 36 import java.lang.reflect.InvocationHandler ; 37 38 import javax.management.ObjectName ; 39 import javax.management.MBeanInfo ; 40 import javax.management.MBeanAttributeInfo ; 41 import javax.management.AttributeNotFoundException ; 42 import javax.management.openmbean.CompositeDataSupport ; 43 import javax.management.openmbean.OpenDataException ; 44 import javax.management.InstanceNotFoundException ; 45 46 import javax.management.j2ee.statistics.Statistic ; 47 import javax.management.j2ee.statistics.*; 48 import com.sun.appserv.management.j2ee.statistics.StatsImpl; 49 50 import com.sun.appserv.management.base.AMXDebug; 51 52 import com.sun.appserv.management.monitor.MonitoringStats; 53 54 import com.sun.appserv.management.util.j2ee.J2EEUtil; 55 import com.sun.appserv.management.util.misc.ClassUtil; 56 import com.sun.appserv.management.util.jmx.JMXUtil; 57 import com.sun.appserv.management.util.misc.MapUtil; 58 import com.sun.appserv.management.util.misc.GSetUtil; 59 import com.sun.appserv.management.util.misc.StringUtil; 60 import com.sun.appserv.management.util.misc.ExceptionUtil; 61 import com.sun.appserv.management.util.misc.ArrayUtil; 62 import com.sun.appserv.management.j2ee.statistics.MapStatistic; 63 import com.sun.appserv.management.j2ee.statistics.MapStatisticImpl; 64 import com.sun.appserv.management.j2ee.statistics.StatisticImpl; 65 import com.sun.appserv.management.j2ee.statistics.StatisticFactory; 66 67 import com.sun.appserv.management.util.jmx.AttributeNameMapper; 68 import com.sun.appserv.management.util.jmx.AttributeNameMapperImpl; 69 70 import com.sun.enterprise.management.support.Delegate; 71 import com.sun.enterprise.management.support.DelegateToMBeanDelegate; 72 73 76 public abstract class MonitoringStatsImplBase extends MonitoringImplBase 77 { 78 private MBeanInfo mMBeanInfo; 79 private final AttributeNameMapper mFieldNameMapper; 80 private final AttributeNameMapper mStatisticNameMapper; 81 82 private Set <String > mStatisticNames; 83 84 public 85 MonitoringStatsImplBase( final String j2eeType, final Delegate delegate ) 86 { 87 super( j2eeType, delegate ); 88 89 mMBeanInfo = null; 90 91 mFieldNameMapper = new AttributeNameMapperImpl(); 92 mStatisticNameMapper = new AttributeNameMapperImpl(); 93 94 mStatisticNames = null; 95 } 96 97 public 98 MonitoringStatsImplBase( final String j2eeType ) 99 { 100 this( j2eeType, null ); 101 } 102 103 106 private static interface OldMonitoringMBean 107 { 108 public String [] getStatisticNames(); 109 public Statistic [] getStatistics(); 110 } 111 112 117 protected OldMonitoringMBean 118 getMonitoringMBeanDelegate() 119 { 120 return (OldMonitoringMBean)getDelegateProxy(OldMonitoringMBean.class); 121 } 122 123 126 private static final String GET = "get"; 127 128 132 private static final String STATISTIC_DELIM = "_"; 133 134 135 static private final Set <String > IGNORE_MISSING_SUFFIXES = 136 Collections.unmodifiableSet( GSetUtil.newSet( new String [] 137 { 138 "current", "count", "description", "name", 139 "lowwatermark", "highwatermark", "unit", 140 "lastsampletime", "starttime", 141 "lowerbound", "upperbound", 142 "maxtime", "mintime", "totaltime", "average", 143 144 "children", 145 })); 146 147 150 protected void 151 handleMissingOriginals( final Set <String > missingOriginals ) 152 { 153 final Set <String > stillMissing = new HashSet <String >(); 154 155 for( final String name : missingOriginals ) 156 { 157 final int idx = name.lastIndexOf( '-' ); 158 final String suffix = name.substring( idx + 1, name.length() ); 159 160 if ( ! IGNORE_MISSING_SUFFIXES.contains( suffix ) ) 161 { 162 stillMissing.add( name ); 163 } 164 } 165 166 super.handleMissingOriginals( stillMissing ); 167 } 168 169 170 protected final AttributeNameMapper 171 getFieldNameMapper() 172 { 173 return( mFieldNameMapper ); 174 } 175 protected final AttributeNameMapper 176 getStatisticNameMapper() 177 { 178 return( mStatisticNameMapper ); 179 } 180 181 182 protected final static String [] STD_FIELDS = new String [] 183 { 184 }; 186 187 191 protected void 192 initFieldNameMapper() 193 { 194 final AttributeNameMapper m = getFieldNameMapper(); 195 196 assert( (STD_FIELDS.length % 2) == 0 ); 197 for( int i = 0; i < STD_FIELDS.length - 1; ++i ) 198 { 199 m.addMapping( STD_FIELDS[ i ], STD_FIELDS[ i + 1 ] ); 200 } 201 } 202 203 204 protected final static String [] STD_STATISTICS = new String [] 205 { 206 "id", "ID", 207 "Id", "ID", 208 }; 209 210 214 protected void 215 initStatisticNameMapper() 216 { 217 final AttributeNameMapper m = getStatisticNameMapper(); 218 219 final String [] mappings = STD_STATISTICS; 220 221 for( int i = 0; i < mappings.length -1; ++i ) 222 { 223 m.addMapping( mappings[ i ], mappings[ i + 1 ] ); 224 } 225 } 226 227 233 protected Object 234 getAttributeFromStatistic( 235 final String statisticName, 236 final String fieldName ) 237 throws AttributeNotFoundException 238 { 239 try 240 { 241 final Statistic s = getStatistic( statisticName ); 242 assert( s instanceof MapStatistic ); 243 244 final String methodName = JMXUtil.GET + fieldName; 245 final Method m = s.getClass().getMethod( methodName, (Class [])null); 246 247 final Object result = m.invoke( s, (Object [])null ); 249 return( result ); 250 } 251 catch( Exception e ) 252 { 253 debug( "getAttributeFromStatistic: exception getting statistic " + 254 statisticName + e + "\n" + 255 ExceptionUtil.getStackTrace( ExceptionUtil.getRootCause( e ) ) ); 256 throw new AttributeNotFoundException ( statisticName ); 257 } 258 } 259 260 265 protected Object 266 getAttributeManually( final String name ) 267 throws AttributeNotFoundException 268 { 269 final int idx = name.indexOf( STATISTIC_DELIM ); 270 271 Object result = null; 272 273 if ( idx > 0 ) 274 { 275 final String statisticName = name.substring( 0, idx ); 277 final String fieldName = name.substring( idx + 1, name.length() ); 278 279 result = getAttributeFromStatistic( statisticName, fieldName ); 280 } 281 else 282 { 283 result = super.getAttributeManually( name ); 284 } 285 286 return( result ); 287 } 288 289 292 private static final boolean BUG_STATISTIC_NAMES = true; 293 294 295 private String [] 296 originalToDerivedStatisticNames( final String [] names ) 297 { 298 final String [] derived = new String [ names.length ]; 299 300 for( int i = 0; i < names.length; ++i ) 301 { 302 derived[ i ] = originalToDerivedStatisticName( names[ i ] ); 303 } 304 305 return( derived ); 306 } 307 308 309 private void 310 checkUnderlyingMBean() 311 { 312 assert( BUG_STATISTIC_NAMES ); 313 314 if ( BUG_STATISTIC_NAMES ) 315 { 316 final Delegate delegate = getDelegate(); 317 318 if ( delegate == null) return; 319 320 final String [] claimedNames = getMonitoringMBeanDelegate().getStatisticNames(); 321 if ( claimedNames == null ) 322 { 323 throw new RuntimeException ( "Delegate " + 324 " used by AMX MBean " + getObjectName() + 325 " returned null StatisticNames array" ); 326 } 327 else if ( claimedNames.length == 0 ) 328 { 329 throw new RuntimeException ( "Delegate " + 330 " used by AMX MBean " + getObjectName() + 331 " returned empty StatisticNames array" ); 332 } 333 334 final Statistic [] statistics = getMonitoringMBeanDelegate().getStatistics(); 335 if ( statistics == null ) 336 { 337 throw new RuntimeException ( "Delegate " + 338 " used by AMX MBean " + getObjectName() + 339 " returned null Statistics array" ); 340 } 341 else if ( statistics.length == 0 ) 342 { 343 throw new RuntimeException ( "Delegate " + 344 " used by AMX MBean " + getObjectName() + 345 " returned empty Statistics array" ); 346 } 347 348 try 349 { 350 final Set <String > actualSet = new HashSet <String >(); 351 352 final String [] namesFromGetStatistics = new String [ statistics.length ]; 353 354 for( int i = 0; i < statistics.length; ++i ) 355 { 356 final String name = StringUtil.upperCaseFirstLetter( statistics[ i ].getName() ); 357 namesFromGetStatistics[ i ] = name; 358 359 if ( ! actualSet.contains( name ) ) 360 { 361 actualSet.add( name ); 362 } 363 else 364 { 365 logWarning( "MBean delegate " + 366 " for " + getObjectName() + 367 " returns Statistic with duplicate name: " + name + 368 " from getStatistics() call.\n" ); 369 } 370 } 371 372 final Set <String > claimedSet = GSetUtil.newStringSet( claimedNames ); 373 if ( ! claimedSet.equals( actualSet ) ) 374 { 375 final Set <String > missing = new HashSet <String >( claimedSet ); 376 missing.removeAll( actualSet ); 377 378 final String msg = "\nMBean delegate " + " for " + getObjectName() + 380 " does not provide Statistic(s): " + missing + " from getStatistics() call, " + 381 "\ngetStatisticNames() = " + toString( claimedSet ) + 382 "\nnames from getStatistics() = " + toString( namesFromGetStatistics ) + "\n"; 383 384 AMXDebug.getInstance().getOutput( 385 "MonitoringStatsImplBase.checkUnderlyingMBean" ).println( msg ); 386 logFine( msg ); 387 } 388 } 389 catch( Exception e ) 390 { 391 final Throwable rootCause = ExceptionUtil.getRootCause( e ); 392 logWarning( "MBean delegate " + 393 " doesn't work, used by AMX MBean: " + 394 getObjectName() + "\n" + 395 rootCause.getClass().getName() + "\n" + 396 ExceptionUtil.getStackTrace( rootCause ) ); 397 } 398 } 399 } 400 401 402 private final String [] 403 initStatisticNames() 404 { 405 String [] names = null; 406 407 if ( BUG_STATISTIC_NAMES ) 408 { 409 names = getStats().getStatisticNames(); 410 if ( names == null || names.length == 0 ) 411 { 412 throw new RuntimeException ( "Stats are null or empty for: " + getObjectName()); 413 } 414 } 415 else 416 { 417 names = originalToDerivedStatisticNames( getMonitoringMBeanDelegate().getStatisticNames() ); 418 } 419 420 return( names ); 421 } 422 423 427 public String [] 428 getStatisticNames() 429 { 430 return( GSetUtil.toStringArray( mStatisticNames ) ); 431 } 432 433 public CompositeDataSupport 434 getOpenStatistic(String name) 435 { 436 final Statistic statistic = getStatistic( name ); 437 438 try 439 { 440 return J2EEUtil.statisticToCompositeData(statistic); 441 } 442 catch(OpenDataException e) 443 { 444 throw new RuntimeException (e); 445 } 446 } 447 448 public CompositeDataSupport [] 449 getOpenStatistics( final String [] names) 450 { 451 final CompositeDataSupport [] result = new CompositeDataSupport [names.length]; 452 453 for(int i = 0; i < names.length; i++) 454 { 455 result[ i ] = getOpenStatistic( names[ i ] ); 456 } 457 return result; 458 } 459 460 public CompositeDataSupport 461 getOpenStats() 462 { 463 final Stats stats = getStats(); 464 465 CompositeDataSupport result = null; 466 if ( stats.getStatisticNames().length != 0 ) 468 { 469 try 470 { 471 result = J2EEUtil.statsToCompositeData( stats ); 472 } 473 catch(OpenDataException e) 474 { 475 throw new RuntimeException (e); 476 } 477 } 478 else 479 { 480 logWarning( "No Statistics available for: " + getObjectName() ); 481 } 482 483 return( result ); 484 } 485 486 public Statistic 487 getStatistic( final String name) 488 { 489 final Stats stats = getStats(); 490 491 return stats.getStatistic( name ); 492 } 493 494 public Statistic [] 495 getStatistics(final String [] desiredNames) 496 { 497 final Stats stats = getStats(); 498 final Statistic [] result = new Statistic [ desiredNames.length ]; 499 500 for( int i = 0; i < desiredNames.length; ++i ) 501 { 502 final Statistic statistic = stats.getStatistic( desiredNames[ i ] ); 503 504 result[ i ] = statistic; 506 } 507 508 return( result ); 509 } 510 511 516 protected String 517 originalToDerivedStatisticName( final String underlyingName ) 518 { 519 String result = getStatisticNameMapper().originalToDerived( underlyingName ); 520 result = StringUtil.upperCaseFirstLetter( result ); 521 522 return( result ); 523 } 524 525 protected String 526 derivedToOriginalStatisticName( final String derivedName ) 527 { 528 return( getStatisticNameMapper().derivedToOriginal( derivedName ) ); 529 } 530 531 protected final Statistic [] 532 getStatisticsFromDelegate() 533 { 534 if ( getDelegate() == null ) 535 { 536 throw new NullPointerException (); 537 } 538 return( getStatisticsFromDelegate( getDelegate() ) ); 539 } 540 541 protected final Statistic [] 542 checkDuplicateStatistics( 543 final Delegate d, 544 final Statistic [] statistics) 545 { 546 final Set <String > actualNames = new HashSet <String >(); 548 for ( int i = 0; i < statistics.length; ++i ) 549 { 550 final String name = statistics[ i ].getName(); 551 552 if ( actualNames.contains( name ) ) 553 { 554 throw new RuntimeException ( 555 "MonitoringStatsImplBase.checkDuplicateStatistics: " + 556 getObjectName() + 557 "Statistic " + StringUtil.quote( name ) + " is duplicated in getStatistics(): " + 558 " as supplied from Delegate of " + StringUtil.quote( getObjectName() )+ 559 ", please see bug #6179364" ); 560 } 561 else 562 { 563 actualNames.add( name ); 564 } 565 } 566 567 if ( actualNames.size() != statistics.length ) 568 { 569 final String [] claimedNames = (String [])d.invoke( "getStatisticNames", null, null ); 570 571 final Set <String > missingNames = GSetUtil.newStringSet( claimedNames ); 572 missingNames.removeAll( actualNames ); 573 574 throw new RuntimeException ( 575 "MonitoringStatsImplBase.getStatisticsFromDelegateRaw: " + missingNames.size() + 576 " Statistic names as found in Statistics from getStatistics() are missing: {" + 577 toString( missingNames ) + 578 "} from Delegate of " + StringUtil.quote( getObjectName() ) + ", please see bug #6179364" ); 579 } 580 581 return( statistics ); 582 } 583 584 protected Statistic [] 585 getStatisticsFromDelegateRaw( final Delegate d ) 586 { 587 try 588 { 589 final Statistic [] statistics = (Statistic [])d.invoke( "getStatistics", null, null ); 590 591 checkDuplicateStatistics( d, statistics ); 592 593 return( statistics ); 594 } 595 catch( Exception e ) 596 { 597 final Throwable rootCause = ExceptionUtil.getRootCause( e ); 598 599 logWarning( "MonitoringStatsImplBase: the com.sun.appserv Delegate MBean for AMX MBean " + 600 getObjectName() + " threw an exception: " + rootCause + 601 ", stack = \n" + ExceptionUtil.getStackTrace( rootCause ) ); 602 } 603 return new Statistic [0]; 604 } 605 606 607 private void 608 debug( String s ) 609 { 610 System.out.println( s ); 611 } 612 613 614 618 protected Statistic [] 619 getStatisticsFromDelegate( final Delegate d ) 620 { 621 try 622 { 623 final Statistic [] statistics = getStatisticsFromDelegateRaw( d ); 624 625 for( int i = 0; i < statistics.length; ++i ) 627 { 628 final Statistic origStatistic = statistics[ i ]; 629 630 final MapStatistic m = new MapStatisticImpl( origStatistic ); 631 632 final String convertedName = originalToDerivedStatisticName( origStatistic.getName() ); 633 if ( ! convertedName.equals( origStatistic.getName() ) ) 634 { 635 m.setName( convertedName ); 636 } 637 638 final Class <? extends Statistic > theClass = 639 StatisticFactory.getInterface( origStatistic ); 640 assert( theClass != null ); 641 642 statistics[ i ] = StatisticFactory.create( theClass, m.asMap() ); 644 645 assert( theClass.isAssignableFrom( statistics[ i ].getClass() )); 646 } 647 648 return( statistics ); 649 } 650 catch (Exception e) 651 { 652 final Throwable rootCause = ExceptionUtil.getRootCause( e ); 653 654 if ( ! ( rootCause instanceof InstanceNotFoundException ) ) 655 { 656 logWarning( "Can't get Statistics from delegate for " + getObjectName() + 660 "\n" + rootCause.getMessage() + "\n" + ExceptionUtil.getStackTrace( rootCause ) ); 661 } 662 throw new RuntimeException ( e ); 663 } 664 } 665 666 private final Class [] STATS_IMPL_INTERFACES = new Class [] 668 { 669 Serializable .class, 670 Stats.class, 671 }; 672 673 679 protected abstract Class getStatsInterface(); 680 681 682 protected StatsImpl 683 createStatsImpl() 684 { 685 return new StatsImpl( getStatisticsFromDelegate() ); 686 } 687 688 713 714 715 public String 716 getStatsInterfaceName() 717 { 718 return( getStatsInterface().getName() ); 719 } 720 721 public Stats 722 getStats() 723 { 724 final Class statsInterface = getStatsInterface(); 725 assert( statsInterface == null || Stats.class.isAssignableFrom( statsInterface ) ); 726 727 Class [] implementedInterfaces = null; 728 if ( statsInterface == null ) 729 { 730 implementedInterfaces = STATS_IMPL_INTERFACES; 731 logInfo( "getStats: no Stats interface found for " + getObjectName() ); 732 } 733 else 734 { 735 implementedInterfaces = (Class []) 736 ArrayUtil.newArray( STATS_IMPL_INTERFACES, statsInterface ); 737 } 738 739 final StatsImpl impl = createStatsImpl(); 740 final ClassLoader classLoader = this.getClass().getClassLoader(); 741 742 final Stats stats = (Stats) 743 Proxy.newProxyInstance( classLoader, implementedInterfaces, impl ); 744 745 746 755 756 return( stats ); 757 } 758 759 760 public final boolean 761 refresh() 762 { 763 mMBeanInfo = null; 764 clearAttributeInfos(); 765 766 return( true ); 767 } 768 769 776 private String 777 makeAttributeName( 778 final String statisticName, 779 final String fieldName ) 780 { 781 final String attributeName = statisticName + STATISTIC_DELIM + fieldName; 782 783 return( attributeName ); 784 } 785 786 791 private static final Set <String > LONG_FIELDS = GSetUtil.newUnmodifiableStringSet( 792 "Count", "LastSampleTime", "StartTime", "LowerBound", "UpperBound", 793 "HighWaterMark", "LowWaterMark", "MaxTime", "MinTime", "TotalTime" ); 794 795 798 private Class 799 determineFieldType( 800 final String fieldName, 801 final Object value ) 802 { 803 Class theClass = String .class; 804 805 if ( value != null ) 806 { 807 theClass = ClassUtil.ObjectClassToPrimitiveClass( value.getClass() ); 808 } 809 else if ( LONG_FIELDS.contains( fieldName ) ) 810 { 811 theClass = long.class; 812 } 813 814 return( theClass ); 815 } 816 817 822 private Map <String ,MBeanAttributeInfo > 823 statisticToMBeanAttributeInfos( final Statistic s ) 824 { 825 final Map <String ,Object > src = new MapStatisticImpl( s ).asMap(); 826 827 final String statisticName = s.getName(); 828 829 final Map <String ,MBeanAttributeInfo > result = new HashMap <String ,MBeanAttributeInfo >(); 830 for( final String fieldName : src.keySet() ) 831 { 832 final Object value = src.get( fieldName ); 833 final String type = determineFieldType( fieldName, value ).getName(); 835 836 final String attributeName = makeAttributeName( statisticName, fieldName ); 837 838 final MBeanAttributeInfo attributeInfo = new MBeanAttributeInfo ( attributeName, type, "", 839 true, false, false ); 840 result.put( attributeName, attributeInfo ); 841 } 842 return( result ); 843 } 844 845 849 private synchronized MBeanInfo 850 createMBeanInfo() 851 { 852 final MBeanInfo baseMBeanInfo = super.getMBeanInfo(); 853 854 MBeanInfo mbeanInfo = baseMBeanInfo; 855 856 if ( getMBeanServer() != null && getDelegate() != null ) 857 { 858 assert( getDelegate() != null ) : "null delegate for: " + getObjectName(); 859 860 final Map <String ,MBeanAttributeInfo > 861 newAttrs = new HashMap <String ,MBeanAttributeInfo >(); 862 863 final Statistic [] statistics = getStats().getStatistics(); 864 for( int i = 0; i < statistics.length; ++i ) 865 { 866 final Map <String ,MBeanAttributeInfo > attrInfos = 867 statisticToMBeanAttributeInfos( statistics[ i ] ); 868 869 newAttrs.putAll( attrInfos ); 870 } 871 872 final MBeanAttributeInfo [] dynamicAttrInfos = 873 new MBeanAttributeInfo [ newAttrs.keySet().size() ]; 874 newAttrs.values().toArray( dynamicAttrInfos ); 875 876 final MBeanAttributeInfo [] attrInfos = 877 JMXUtil.mergeMBeanAttributeInfos( dynamicAttrInfos, baseMBeanInfo.getAttributes() ); 878 879 mbeanInfo = JMXUtil.newMBeanInfo( baseMBeanInfo, attrInfos ); 880 } 881 882 return( mbeanInfo ); 883 } 884 885 protected ObjectName 886 preRegisterHook( final ObjectName objectName ) 887 { 888 initFieldNameMapper(); 889 initStatisticNameMapper(); 890 891 refresh(); 893 894 assert( MonitoringStats.class.isAssignableFrom( getInterface() ) ) : 895 "MBean extends MonitoringStatsImpl but does not have MonitoringStats interface: " + getObjectName(); 896 897 if ( BUG_STATISTIC_NAMES ) 898 { 899 checkUnderlyingMBean(); 900 } 901 902 mStatisticNames = GSetUtil.newUnmodifiableStringSet( initStatisticNames() ); 903 904 return objectName; 905 } 906 907 private static final MBeanInfo EMPTY_MBEAN_INFO = 908 new MBeanInfo ( "Empty", "Failed to create MBeanInfo", null, null, null, null); 909 910 public synchronized MBeanInfo 911 getMBeanInfo() 912 { 913 if ( mMBeanInfo == null ) 914 { 915 try 916 { 917 mMBeanInfo = createMBeanInfo(); 918 } 919 catch( Throwable t ) 920 { 921 final Throwable rootCause = ExceptionUtil.getRootCause( t ); 924 925 if ( ! ( rootCause instanceof InstanceNotFoundException ) ) 930 { 931 getMBeanLogger().warning( "can't create MBeanInfo for: " + getObjectName() + 932 "\n" + rootCause.getClass() + ": " + rootCause.getMessage() + ":\n" + 933 ExceptionUtil.getStackTrace( rootCause ) ); 934 } 935 936 mMBeanInfo = EMPTY_MBEAN_INFO; 937 } 938 } 939 940 return( mMBeanInfo ); 941 } 942 } 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 | Popular Tags |