/* * Copyright 2003 Sun Microsystems, Inc. All rights reserved. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. */ package samples.amx; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.util.Map; import java.util.HashMap; import java.util.Set; import java.util.HashSet; import java.util.Collection; import java.util.Collections; import java.util.Iterator; import java.util.List; import javax.management.Attribute; import javax.management.Notification; import javax.management.AttributeChangeNotification; import javax.management.NotificationListener; import javax.management.ListenerNotFoundException; import javax.management.ObjectName; import javax.management.NotificationFilter; import javax.management.MBeanServerConnection; import javax.management.InstanceNotFoundException; import javax.management.MBeanServerNotification; import com.sun.appserv.management.DomainRoot; import com.sun.appserv.management.base.AMX; import com.sun.appserv.management.base.XTypes; import com.sun.appserv.management.base.Container; import com.sun.appserv.management.base.Sample; import com.sun.appserv.management.base.Util; import com.sun.appserv.management.base.Extra; import com.sun.appserv.management.base.StdAttributesAccess; import com.sun.appserv.management.base.QueryMgr; import com.sun.appserv.management.client.AppserverConnectionSource; import com.sun.appserv.management.client.TLSParams; import com.sun.appserv.management.client.HandshakeCompletedListenerImpl; import com.sun.appserv.management.j2ee.J2EEDomain; import com.sun.appserv.management.j2ee.J2EEServer; import com.sun.appserv.management.deploy.DeploymentMgr; import com.sun.appserv.management.deploy.DeploymentStatus; import com.sun.appserv.management.deploy.DeploymentProgress; import com.sun.appserv.management.deploy.DeploymentSupport; import com.sun.appserv.management.monitor.MonitoringDottedNames; import com.sun.appserv.management.monitor.JMXMonitorMgr; import com.sun.appserv.management.monitor.AMXStringMonitor; import com.sun.appserv.management.config.DomainConfig; import com.sun.appserv.management.config.HTTPServiceConfig; import com.sun.appserv.management.config.ConfigConfig; import com.sun.appserv.management.config.ConfigDottedNames; import com.sun.appserv.management.config.StandaloneServerConfig; import com.sun.appserv.management.config.ModuleMonitoringLevelsConfig; import com.sun.appserv.management.config.ModuleMonitoringLevelValues; import com.sun.appserv.management.config.PropertiesAccess; /** Main class demonstrating a variety of MBean API (AMX) usages. */ public final class Samples { private final DomainRoot mDomainRoot; public Samples( final DomainRoot domainRoot ) { mDomainRoot = domainRoot; } public final DomainRoot getDomainRoot() { return( mDomainRoot ); } public DomainConfig getDomainConfig() { return( getDomainRoot().getDomainConfig() ); } public QueryMgr getQueryMgr() { return( getDomainRoot().getQueryMgr() ); } /** Print a message. */ public void println( Object o ) { System.out.println( toString( o ) ); } /** Turn an object into a useful String */ public String toString( Object o ) { return( SampleUtil.toString( o ) ); } /** Display a Map to System.out. */ private void displayMap( final String msg, final Map m) { println( msg + ": " + toString( m.keySet() ) ); } /** Demonstrates how to access various types of {@link AMX} by obtaining a Map and then displaying it. */ public void handleList() { final DomainConfig dcp = getDomainConfig(); // Top-level items println( "\n--- Top-level --- \n" ); displayMap( "ConfigConfig", dcp.getConfigConfigMap() ); displayMap( "ServerConfig", dcp.getServerConfigMap() ); displayMap( "StandaloneServerConfig", dcp.getStandaloneServerConfigMap() ); displayMap( "ClusteredServerConfig", dcp.getClusteredServerConfigMap() ); displayMap( "ClusterConfig", dcp.getClusterConfigMap() ); // deployed items println( "\n--- DeployedItems --- \n" ); displayMap( "J2EEApplicationConfig", dcp.getJ2EEApplicationConfigMap() ); displayMap( "EJBModuleConfig", dcp.getEJBModuleConfigMap() ); displayMap( "WebModuleConfig", dcp.getWebModuleConfigMap() ); displayMap( "RARModuleConfig", dcp.getRARModuleConfigMap() ); displayMap( "AppClientModuleConfig", dcp.getAppClientModuleConfigMap() ); displayMap( "LifecycleModuleConfig", dcp.getLifecycleModuleConfigMap() ); // resources println( "\n--- Resources --- \n" ); displayMap( "CustomResourceConfig", dcp.getCustomResourceConfigMap() ); displayMap( "PersistenceManagerFactoryResourceConfig", dcp.getPersistenceManagerFactoryResourceConfigMap() ); displayMap( "JNDIResourceConfig", dcp.getJNDIResourceConfigMap() ); displayMap( "JMSResourceConfig", dcp.getJMSResourceConfigMap() ); displayMap( "JDBCResourceConfig", dcp.getJDBCResourceConfigMap() ); displayMap( "ConnectorResourceConfig", dcp.getConnectorResourceConfigMap() ); displayMap( "JDBCConnectionPoolConfig", dcp.getJDBCConnectionPoolConfigMap() ); displayMap( "PersistenceManagerFactoryResourceConfig", dcp.getPersistenceManagerFactoryResourceConfigMap() ); displayMap( "ConnectorConnectionPoolConfig", dcp.getConnectorConnectionPoolConfigMap() ); displayMap( "AdminObjectResourceConfig", dcp.getAdminObjectResourceConfigMap() ); displayMap( "ResourceAdapterConfig", dcp.getResourceAdapterConfigMap() ); displayMap( "MailResourceConfig", dcp.getMailResourceConfigMap() ); // get a ConfigConfig final ConfigConfig config = (ConfigConfig)dcp.getConfigConfigMap().get( "server-config" ); // HTTPService println( "\n--- HTTPService --- \n" ); final HTTPServiceConfig httpService = config.getHTTPServiceConfig(); displayMap( "HTTPListeners", httpService.getHTTPListenerConfigMap() ); displayMap( "VirtualServers", httpService.getVirtualServerConfigMap() ); } /** Return a Set of {@link AMX} whose ObjectName has the property <i>property-name</i>=<i>property-value</i>. @param propertyName @param propertyValue @return Set of {@link AMX} */ public Set queryWild( final String propertyName, final String propertyValue) { final String[] propNames = new String[] { propertyName }; final String[] propValues = new String[]{ propertyValue }; final Set amxs = getQueryMgr().queryWildSet( propNames, propValues ); return( amxs ); } /** Call queryWild( propertyName, propertyValue ) and display the result. @param propertyName @param propertyValue */ public void displayWild( final String propertyName, final String propertyValue) { final Set items = queryWild( propertyName, propertyValue ); println( "\n--- Queried for " + propertyName + "=" + propertyValue + " ---" ); final Iterator iter = items.iterator(); while ( iter.hasNext() ) { final AMX item = (AMX)iter.next(); println( "j2eeType=" + item.getJ2EEType() + "," + "name=" + item.getName() ); } } public Set queryForJ2EEType( final String j2eeType ) { final String prop = Util.makeJ2EETypeProp( j2eeType ); final Set items = getQueryMgr().queryPropsSet( prop ); return( items ); } public void displayAvailableChildTypes( final String j2eeType ) { final DomainRoot domainRoot = getDomainRoot(); } private String getIndent( final int num ) { final char[] indent = new char[ num ]; for( int i = 0; i < num; ++i ) { indent[ i ] = ' '; } return( new String( indent ) ); } /** Display the j2eeType and name (if not {@link AMX#NO_NAME}) */ private void displayAMX( final AMX amx, final int indentCount ) { final String indent = getIndent( indentCount ); final String j2eeType = amx.getJ2EEType(); final String name = amx.getName(); if ( name.equals( AMX.NO_NAME ) ) { println( indent + j2eeType ); } else { println( indent + j2eeType + "=" + name ); } } private void displayHierarchy( final Collection amxSet, final int indentCount ) { final Iterator iter = amxSet.iterator(); while ( iter.hasNext() ) { final AMX amx = (AMX)iter.next(); displayHierarchy( amx, indentCount ); } } /** Display the hierarchy of {@link AMX} beginning with the specified one */ public void displayHierarchy( final AMX amx, final int indentCount ) { displayAMX( amx, indentCount ); if ( amx instanceof Container ) { // get Maps of all contained items final Map m = ((Container)amx).getMultiContaineeMap( null ); // for clarity of display, separate out those that are Containers, // and those that are not. final Set deferred = new HashSet(); final Iterator mapsIter = m.values().iterator(); while ( mapsIter.hasNext() ) { final Map instancesMap = (Map)mapsIter.next(); final AMX first = (AMX)instancesMap.values().iterator().next(); if ( first instanceof Container ) { deferred.add( instancesMap ); } else { displayHierarchy( instancesMap.values(), indentCount + 2); } } // display deferred items final Iterator iter = deferred.iterator(); while ( iter.hasNext() ) { final Map instancesMap = (Map)iter.next(); displayHierarchy( instancesMap.values(), indentCount + 2); } } } /** Display the entire MBean hierarchy. */ public void displayHierarchy() { displayHierarchy( getDomainRoot(), 0); } /** Display the MBean hierarchy beginning with j2eeType. */ public void displayHierarchy( final String j2eeType ) { final Set items = getQueryMgr().queryJ2EETypeSet( j2eeType ); if ( items.size() == 0 ) { println( "No {@link AMX} of j2eeType " + SampleUtil.quote( j2eeType ) + " found" ); } else { displayHierarchy( items, 0); } } /** Display all MBeans that have j2eeType=<j2eeType> */ public void displayJ2EEType( final String j2eeType ) { final Set items = queryForJ2EEType( j2eeType ); println( "\n--- Queried for j2eeType=" + j2eeType + " ---" ); final Iterator iter = items.iterator(); while ( iter.hasNext() ) { final AMX item = (AMX)iter.next(); // they may or may not have unique names, so show ObjectNames println( Util.getObjectName( item ) ); } println( "" ); } /** Display all Attributes in the {@link AMX}. */ public void displayAllAttributes( final AMX item ) { println( "\n--- Attributes for " + item.getJ2EEType() + "=" + item.getName() + " ---" ); final Extra extra = Util.getExtra( item ); final Map attrs = extra.getAllAttributes(); final Iterator iter = attrs.keySet().iterator(); while ( iter.hasNext() ) { final String name = (String)iter.next(); final Object value = attrs.get( name ); println( name + "=" + toString( value ) ); } } /** Display all Attributes in the {@link AMX}. */ public void displayAllAttributes( final String j2eeType ) { final Set items = queryForJ2EEType( j2eeType ); if ( items.size() == 0 ) { println( "No {@link AMX} of j2eeType " + SampleUtil.quote( j2eeType ) + " found" ); } else { final Iterator iter = items.iterator(); while ( iter.hasNext() ) { final AMX amx = (AMX)iter.next(); displayAllAttributes( amx ); println( "" ); } } } /** Display all dotted names. */ public void displayDottedNames() { final ConfigDottedNames configDottedNames = getDomainRoot().getConfigDottedNames(); Attribute[] result = (Attribute[])configDottedNames.dottedNameGet( "*" ); println( "--- ConfigDottedNames ---" ); println( SampleUtil.arrayToString( result, "", "\n" ) ); println( "\n--- MonitoringDottedNames ---" ); final MonitoringDottedNames monDottedNames = getDomainRoot().getMonitoringDottedNames(); result = (Attribute[])monDottedNames.dottedNameGet( "*" ); println( SampleUtil.arrayToString( result, "", "\n" ) ); } /** Demonstrate how to use the {@link com.sun.appserv.management.base.QueryMgr} facilities. */ public void demoQuery() { displayWild( AMX.J2EE_TYPE_KEY, "X-*ResourceConfig" ); displayWild( AMX.J2EE_TYPE_KEY, "X-*ServerConfig" ); displayJ2EEType( XTypes.SSL_CONFIG ); displayJ2EEType( XTypes.CLUSTER_CONFIG ); } private Object uploadArchive( final File archive ) throws IOException { final FileInputStream input = new FileInputStream( archive ); final long length = input.available(); final DeploymentMgr mgr = getDomainRoot().getDeploymentMgr(); final Object uploadID = mgr.initiateFileUpload( length ); try { final int chunkSize = 256 * 1024; long remaining = length; while ( remaining != 0 ) { final int actual = remaining < chunkSize ? (int)remaining : chunkSize; final byte[] bytes = new byte[ actual ]; final int num = input.read( bytes ); if ( num != actual ) { throw new IOException(); } mgr.uploadBytes( uploadID, bytes ); remaining -= actual; } } finally { input.close(); } return( uploadID ); } private final String getAppName( final String archiveName ) { String result = archiveName; final int idx = archiveName.lastIndexOf( "." ); if ( idx > 1 ) { result = archiveName.substring( 0, idx ); } return( result ); } /** Deploy an archive. <p> To deploy, you will need an archive to deploy. A recommended sample may be found at: <i>INSTALL_ROOT</i>/samples/ejb/stateless/apps/simple.ear <p> This sample deploys the archive to the domain, but does not create any references to it, so it will not actually be associated with any server. <p> To associate an application with a server, use {@link StandaloneServerConfig#createDeployedItemRefConfig} @see com.sun.appserv.management.config.StandaloneServerConfig @see com.sun.appserv.management.config.DeployedItemRefConfigCR */ public void deploy( final File archive ) throws IOException { final Object uploadID = uploadArchive( archive ); final DeploymentMgr mgr = getDomainRoot().getDeploymentMgr(); final Object deployID = mgr.initDeploy( ); final DeployNotificationListener myListener = new DeployNotificationListener( deployID); mgr.addNotificationListener( myListener, null, null); try { final Map options = new HashMap(); final String archiveName = archive.getName(); final String deployName = getAppName( archiveName ); SampleUtil.println( "Deploying " + archiveName + " as " + deployName ); options.put( DeploymentMgr.DEPLOY_OPTION_NAME_KEY, deployName ); options.put( DeploymentMgr.DEPLOY_OPTION_VERIFY_KEY, Boolean.TRUE.toString() ); options.put( DeploymentMgr.DEPLOY_OPTION_DESCRIPTION_KEY, "description" ); mgr.startDeploy( deployID, uploadID, null, options); while ( ! myListener.isCompleted() ) { try { println( "deploy: waiting for deploy of " + archive); Thread.sleep( 1000 ); } catch( InterruptedException e ) { } } final DeploymentStatus status = myListener.getDeploymentStatus(); final int statusCode = status.getStatusCode(); if ( statusCode == DeploymentStatus.STATUS_CODE_SUCCESS ) { final Map additionalStatus = status.getAdditionalStatus(); final String moduleID = (String)additionalStatus.get( DeploymentStatus.MODULE_ID_KEY ); SampleUtil.println( "Deployed " + quote(archiveName) + " as " + quote(deployName) + ": status=" + status.getStageStatus() + ", moduleID = " + quote(moduleID) + ", AdditionalStatus=" + SampleUtil.mapToString( additionalStatus, " ") ); if ( ! deployName.equals( moduleID ) ) { SampleUtil.println( "WARNING: requested name of " + quote(deployName) + " has not been used, actual name = " + quote(moduleID) + ", see bug #6218714" ); } } else { SampleUtil.println( "Deployment of " + quote( archiveName ) + " FAILED, status code = " + statusCode ); } if ( status.getStageThrowable() != null ) { status.getStageThrowable().printStackTrace(); } } finally { try { mgr.removeNotificationListener( myListener ); } catch( Exception e ) { } } } private String quote( final String s ) { return SampleUtil.quote( s ); } /** Undeploys a deployed module. */ public void undeploy( final String moduleName ) throws IOException { final DeploymentMgr mgr = getDomainRoot().getDeploymentMgr(); final Map statusData = mgr.undeploy( moduleName, null ); final DeploymentStatus status = DeploymentSupport.mapToDeploymentStatus( statusData ); println( "Undeployment result: " + status.getStageStatus() ); if ( status.getStageThrowable() != null ) { status.getStageThrowable().printStackTrace(); } } /** Get a J2EEServer by name. */ public J2EEServer getJ2EEServer( final String serverName ) { final J2EEDomain j2eeDomain = getDomainRoot().getJ2EEDomain(); final Map servers = j2eeDomain.getServerMap(); final J2EEServer server = (J2EEServer)servers.get( serverName ); if ( server == null ) { throw new IllegalArgumentException( serverName ); } return( server ); } /** Create a standalone server. @param configName */ public ConfigConfig createConfig( final String configName ) { final ConfigConfig config = getDomainConfig().createConfigConfig( configName, null ); return( config ); } /** Create a standalone server. @param serverName */ public StandaloneServerConfig createServer( final String serverName, final String configName ) { final String nodeAgentName = null; final StandaloneServerConfig server = (StandaloneServerConfig) getDomainConfig().createStandaloneServerConfig( serverName, nodeAgentName, configName, null ); return( server ); } public StandaloneServerConfig createServer( final String serverName ) { final ConfigConfig config = createConfig( serverName + "-config" ); final StandaloneServerConfig server = createServer( serverName, config.getName() ); return( server ); } /** Start a server. */ public void startServer( final String serverName ) { final J2EEServer server = getJ2EEServer( serverName ); server.start(); } /** Stop a server. */ public void stopServer( final String serverName ) { final J2EEServer server = getJ2EEServer( serverName ); server.stop(); } private static final Set LEGAL_MON = Collections.unmodifiableSet( SampleUtil.newSet( new String[] { ModuleMonitoringLevelValues.HIGH, ModuleMonitoringLevelValues.LOW, ModuleMonitoringLevelValues.OFF, } )); /** Sets the monitoring state for all available modules. @param configName configuration element on which to operate @param state one of HIGH, LOW, OFF */ public void setMonitoring( final String configName, final String state ) { if ( ! LEGAL_MON.contains( state ) ) { throw new IllegalArgumentException( state ); } final ConfigConfig config = (ConfigConfig)getDomainConfig().getConfigConfigMap().get( configName ); final ModuleMonitoringLevelsConfig mon = config.getMonitoringServiceConfig().getModuleMonitoringLevelsConfig(); // set all modules to the same state mon.setConnectorConnectionPool( state ); mon.setThreadPool( state ); mon.setHTTPService( state ); mon.setJDBCConnectionPool( state ); mon.setORB( state ); mon.setTransactionService( state ); mon.setWebContainer( state ); mon.setEJBContainer( state ); } /** Get a Map of <i>property-name</i>=<i>property-value</i>. @param pa a PropertiesAccess */ public Map getProperties( final PropertiesAccess pa ) { final HashMap m = new HashMap(); final String[] names = pa.getPropertyNames(); for( int i = 0; i < names.length; ++i ) { m.put( names[ i ], pa.getPropertyValue( names[ i ] ) ); } return( m ); } /** Display all properties found on all {@link AMX}. @see #getProperties(PropertiesAccess) @see PropertiesAccess#getPropertyNames */ public void displayAllProperties( ) { final Iterator iter = getQueryMgr().queryAllSet().iterator(); while ( iter.hasNext() ) { final AMX amx = (AMX)iter.next(); if ( amx instanceof PropertiesAccess ) { final PropertiesAccess pa = (PropertiesAccess)amx; final Map props = getProperties( pa ); if ( props.keySet().size() != 0 ) { println( "\nProperties for: " + Util.getObjectName( (AMX)pa ) ); println( SampleUtil.mapToString( getProperties( pa ), "\n") ); } } } } private void mySleep( final long millis ) { try { Thread.sleep( millis ); } catch( InterruptedException e ) { } } public final static String MBEAN_SERVER_DELEGATE = "JMImplementation:type=MBeanServerDelegate"; public static ObjectName getMBeanServerDelegateObjectName() { return( Util.newObjectName( MBEAN_SERVER_DELEGATE ) ); } private void waitNumNotifs( final Map notifs, final String type, final int numRequired ) { while ( true ) { final List list = (List)notifs.get( type ); if ( list != null && list.size() >= numRequired ) { break; } mySleep( 50 ); } } private void waitMBeanServerNotification( final SampleListener listener, final String type, final ObjectName objectName ) { List list = null; while ( (list = listener.getNotifsReceived( type )) == null ) { mySleep( 50 ); } boolean waiting = true; while ( waiting ) { final Iterator iter = list.iterator(); while ( iter.hasNext() ) { final MBeanServerNotification notif = (MBeanServerNotification)iter.next(); if ( notif.getMBeanName().equals( objectName ) ) { waiting = false; break; } else { SampleUtil.println( "Unexpected ObjectName: " + objectName + " != " + notif.getMBeanName() ); } } mySleep( 100 ); } } /** Demonstrates the use of a javax.management.monitor MBean to be notified of changes in the value of an Attribute. */ public void demoJMXMonitor() throws InstanceNotFoundException, IOException { final JMXMonitorMgr mgr = getDomainRoot().getJMXMonitorMgr(); final String attrName = "SampleString"; final String attrValue = "hello"; // listen to the MBeanServerDelegate, too, so we can see our sample monitor // get registered. final SampleListener sampleListener = new SampleListener(); final MBeanServerConnection conn = Util.getExtra( mgr ).getConnectionSource().getExistingMBeanServerConnection(); conn.addNotificationListener( getMBeanServerDelegateObjectName(), sampleListener, null, null ); final Sample sample = (Sample)getDomainRoot().getContainee( XTypes.SAMPLE ); final String monitorName = "SampleStringMonitor"; AMXStringMonitor mon = null; try { // cleanup in case it was left around by mistake... try { mgr.remove( monitorName ); } catch( Exception e ) {} // create a new one mon = mgr.createStringMonitor( monitorName ); // observer that we've been notified (not required) waitMBeanServerNotification( sampleListener, MBeanServerNotification.REGISTRATION_NOTIFICATION, Util.getObjectName( mon ) ); // we'll modify this Attribute's value, to force a change sample.addAttribute( attrName, attrValue ); // listen to the monitor mon.addNotificationListener( sampleListener, null, null ); mon.setObservedAttribute( attrName ); mon.setStringToCompare( attrValue ); mon.setNotifyDiffer( true ); mon.setNotifyMatch( true ); // tell the monitor to observe sample mon.addObservedObject( Util.getObjectName( sample ) ); // since the Attribute was added dynamically, there is no // getter method, so we must access the Attribute via JMX final StdAttributesAccess attrs = Util.getExtra( sample ); attrs.setAttribute( new Attribute( attrName, "goodbye" ) ); // set it to original value attrs.setAttribute( new Attribute( attrName, attrValue ) ); // we added it,so we should remove it sample.removeAttribute( attrName ); // let the Notifications arrive... final Map notifs = sampleListener.getNotifsReceived(); waitNumNotifs( notifs, AttributeChangeNotification.ATTRIBUTE_CHANGE, 4 ); } catch( Throwable t ) { t.printStackTrace(); } finally { try { mon.removeNotificationListener( sampleListener ); // don't leave monitors around if ( mon != null ) { mgr.remove( mon.getName() ); // observer that we've been notified (not required) waitMBeanServerNotification( sampleListener, MBeanServerNotification.UNREGISTRATION_NOTIFICATION, Util.getObjectName( mon ) ); } conn.removeNotificationListener( getMBeanServerDelegateObjectName(), sampleListener ); } catch( ListenerNotFoundException e ) { } } } }