A JMX Monitoring API

This appendix describes the Java Management Extensions (JMX) Monitoring API in Oracle Service Bus, which provides external access to Service Bus monitoring data. The primary purpose of the JMX Monitoring API is to provide efficient, lower-level APIs that support bulk operations. It does this using JMX as a transport. This API is not a high-level API compatible with JMX-based tools. However, if you are developing client software, you may want to develop high-level JMX APIs that support JMX-based tooling.

This appendix includes the following sections:

A.1 Introduction to the JMX Monitoring API

The JMX monitoring API makes use of JMX as a transport only. It exposes a public MBean to provide all the required operations to get monitoring data (statistical information) for any monitored service and its components. It also exposes a set of public POJO objects required to carry out operations provided by the MBean. There is no need for third-party client software to know the intricacies of the hierarchy inherent in the statistical information stored in the Service Bus monitoring system.

Using these APIs, customers can integrate their monitoring/management systems with Service Bus to do the following:

  • Identify services enabled for monitoring.

  • Get detailed statistical information for a specific service, for its components, or for both.

  • Reset statistics accumulated since the last reset.

A.2 Using the JMX Monitoring API

The public JMX API is modeled by a single instance of ServiceDomainMBean, which has operations to check for monitored services and retrieve data from them. A public set of POJOs provides additional objects and methods that, along with ServiceDomainMbean, provide a complete API for monitoring statistics.

The following sections provide brief descriptions of the POJOs and MBean, along with description of the statistics that are reported for Service Bus resources. The Java API Reference for Oracle Service Bus provides detailed descriptions of the POJOs and MBean.

Please be sure to read the important notes at the end of this chapter.

A.2.1 Public POJO Objects

The following POJO objects are exposed as part the JMX monitoring API.

A.2.1.1 ResourceType

This object represents all types of resources that are enabled for service monitoring. There are four enum constants representing types: SERVICE, FLOW_COMPONENT, URI, and WEBSERVICE_OPERATION.

See com.bea.wli.monitoring.ResourceType in the Java API Reference for Oracle Service Bus.

A.2.1.2 ServiceResourceStatistic

This object represents all business and proxy service resource types and the statistics associated with them. There are methods to get statistics for all resources or for a specific resource.

See com.bea.wli.monitoring.ServiceResourceStatistic in the Java API Reference for Oracle Service Bus.

A.2.1.3 ResourceStatistic

This object represents a resource for which statistics collection is supported. There are methods to get the name of the resource, the type, and the statistics.

See com.bea.wli.monitoring.ResourceStatistic in the Java API Reference for Oracle Service Bus.

A.2.1.4 StatisticValue

This object represents a statistic value for a resource. The monitoring system currently supports the following types of statistic values, all nested classes:

  • CountStatistic

  • IntervalStatistic

  • StatusStatistic

StatisticValue is an abstract class so concrete objects representing count and interval statistic values can be derived from it. It includes getName() and getType() methods.

See com.bea.wli.monitoring.StatisticValue in the Java API Reference for Oracle Service Bus.

A.2.1.5 StatisticType

This object represents predefined types of statistics. There are three enum types: STATUS, COUNT, and INTERVAL.

See com.bea.wli.monitoring.StatisticValue in the Java API Reference for Oracle Service Bus.

A.2.2 ServiceDomainMBean

This MBean represents the service domain. It provides methods to find monitored services, get and reset statistics, and to mark business service endpoint URIs offline. For more information, see com.bea.wli.monitoring.ServiceDomainMBean in the Java API Reference for Oracle Service Bus.

A.2.3 MonitoringConfigurationMBean

This MBean provides methods to enable and disable monitoring and alerting. Subinterfaces provide methods for managing different types of services in the runtime. For more information, see com.bea.wli.sb.management.configuration.MonitoringConfigurationMBean in the Java API Reference for Oracle Service Bus.

A.2.4 Statistics Collected for Oracle Service Bus

The following sections describe the statistics reported for each resource type.

A.2.4.1 Statistics Details for Resource Type - SERVICE

Service resource types include the inbound and outbound endpoints (proxy and business services) as well as pipelines and split-joins, which transform and route messages. These resources may have associated WSDL files, security settings, and so on.

The following statistics are reported for this resource type. Note that certain statistics only apply to certain services, as noted in the table.

Table A-1 SERVICE Statistics

Statistic Name Type Service Types

Alert.pipeline-severity-all

count

Pipelines

Alert.pipeline-severity-critical

count

Pipelines

Alert.pipeline-severity-fatal

count

Pipelines

Alert.pipeline-severity-major

count

Pipelines

Alert.pipeline-severity-minor

count

Pipelines

Alert.pipeline-severity-normal

count

Pipelines

Alert.pipeline-severity-warning

count

Pipelines

Alert.severity-all

count

All

Alert.sla-severity-all

count

All

Alert.sla-severity-critical

count

All

Alert.sla-severity-fatal

count

All

Alert.sla-severity-minor

count

All

Alert.sla-severity-normal

count

All

Alert.sla-severity-major

count

All

Alert.sla-severity-warning

count

All

Router.elapsed-time

interval

Pipelines

Router.error-count

count

Pipelines

Router.failure-rate

derived

Pipelines

Router.message-count

count

Pipelines

Router.success-rate

derived

Pipelines

Router.validation-errors

count

Pipeline

Security.WebService Security.wss-errors

count

Business and proxy services

SplitJoin.elapsed-time

interval

SplitJoins

SplitJoin.error-count

count

SplitJoins

SplitJoin.failure-rate

derived

SplitJoins

SplitJoin.message-count

count

SplitJoins

SplitJoin.success-rate

derived

SplitJoins

Transport.cache-hit-count

count

Business services

Transport.error-count

count

Business and proxy services

Transport.failover-count

count

Business services

Transport.failure-rate

derived

Business and proxy services

Transport.message-count

count

Business and proxy services

Transport.response-time

interval

Business and proxy services

Transport.success-rate

derived

Business and proxy services

Transport.throttling-time

interval

Business services

Transport.uri-offline-count

count

Business services


Note:

  • The wss-error statistic provides Web Service Security violations counts.

  • When the statistics of a Managed Server are retrieved from a cluster domain using the ServiceDomainMBean the statistics for proxy services will not contain sla-severity-normal, sla-severity-minor, sla-severity-major, sla-severity-warning, sla-severity-critical, sla-severity-fatal, sla-severity-all.

  • Only the names of the statistics are displayed in Fusion Middleware Control.

  • Success ratio (*.success-rate statistics) is the percentage ratio of successful messages to total number of messages. Failure ratio (*.failure-rate statistics) is the percentage ratio of failed messages to total number of messages.

  • The name of statistics are linked to component of the service for which they are collected using '.'.

A.2.4.2 Statistics for Resource Type–FLOW_COMPONENT

Statistics are collected for pipelines on the pipeline pair and routing nodes. They are collected for split-joins on the branch nodes.

Pipelines are one-way processing paths consisting of stages that are executed sequentially against the current message. Stages are used to perform activities such as transformation, logging and publishing. There are three categories of pipelines: request, response, and error. The pipeline-pair node ties together a single request and a single response pipeline into one top-level element.

A routing node consists of a set of routes. A route identifies a target service and includes some additional configuration options that determine how the message will be packaged and sent to that service. A routing node will result in at most one route being selected as part of request processing.

Split-joins let you split a service payload, such as an order, into individual messages that are sent to multiple services concurrently, as opposed to standard sequential processing. Processing is defined within branches.

The following statistics are reported for the flow component of these resources.

Table A-2 FLOW_COMPONENT Statistics

Statistic Name Type Service Types

Router.Pipeline.name.elapsed-time

interval

Pipelines

Router.Pipeline.name.error-count

count

Pipelines

Router.Pipeline.name.message-count

count

Pipelines

Router.Route Node.name.elapsed-time

interval

Pipelines

Router.Route Node.name.error-count

count

Pipelines

Router.Route Node.name.message-count

count

Pipelines

SplitJoin.Branch.name.elapsed-time

interval

SplitJoins

SplitJoin.Branch.name.error-count

count

SplitJoins

SplitJoin.Branch.name.message-count

count

SplitJoins


Note:

Statistics for pipeline-pairs, route nodes, and split-join branches are returned as statistics for flow components. enum value ResourceType.FLOW_COMPONENT represents both pipeline and split-join components. Thus there is no way for a client to check if the returned flow component is a pipeline-pair, route node, or split-join branch. The name of the flow component, however, may suggest the type.

A.2.4.3 Statistics details for Resource Type – WEBSERVICE_OPERATION

This resource type provides statistical information pertaining to WSDL operations. Statistics are reported for each defined operation. The following statistics are reported.

Table A-3 WEBSERVICE_OPERATION Statistics

Statistic Name Type Service Type

Operation.name.elapsed-time

interval

Business services, proxy services, and pipelines

Operation.name.error-count

count

Business services, proxy services, and pipelines

Operation.name.message-count

count

Business services, proxy services, and pipelines


A.2.4.4 Statistics details for Resource Type – URI

This resource type provides statistical information pertaining to endpoint URI for a business service. Statistics are reported for each defined Endpoint URI. The following statistics are reported.

Table A-4 Statistics for Endpoint URI

Statistic Name Type

Transport.uri.name.error-count

count

Transport.uri.name.message-count

count

Transport.uri.name.response-time

interval

Transport.uri.name.status

status


Note:

You cannot obtain any statistic of the type status for a cluster using the JMX Monitoring APIs.

A.2.5 Caveats

Please be aware of the following when working with the JMX monitoring API:

  • A client program will not know about newly added services that have monitoring turned on, or services modified to turn on monitoring, unless it periodically checks for such changes.

  • Reset operations should not be performed too frequently. Oracle recommends that reset intervals be greater than 15 minutes.

  • If statistics are reset while proxy or business services are running, the following TransactionConflictException can occur. This is most likely to occur if statistics are reset at system startup.

    <OSB-382016> <Failed to instantiate router for service...>
    
  • Oracle strongly discourages using this API in a concurrent manner with more than one thread or process because a reset performed in one thread or process is not visible to another threads or processes. This caveat also applies to resets performed from Fusion Middleware Control, as such resets are not visible to this API.

A.2.6 Performance

Performance should be better than or equivalent to that observed in Fusion Middleware Control.

A.3 API Usage Example

The sample program in this section demonstrates how to use the JMX Monitoring API.

The following steps describe how statistics can be retrieved for a proxy service that is enabled for monitoring.

  1. Get ServiceDomainMBean from the MBean Server.

  2. Get the references for monitored services using the getMonitoredRefs operation of the ServiceDomainMBean.

  3. Get ServiceResourceStatistics using the getStatistics operation of the ServiceDomainMBean of the desired service.

  4. Get all ResourceStatistic objects using the operations of getAllResourceStatistics.

  5. For each retrieved ResourceStatistic object, get StatisticValue objects using the getStatistics operation and save the statistical information to a file.

  6. Repeat process as necessary.

A.3.1 Sample Program

The following sample program illustrates how to:

  1. Find business and proxy services enabled for monitoring.

  2. Retrieve statistics for one or more services.

  3. Reset statistics for one or more services.

  4. Handle exceptions.

  5. Save retrieved statistics in the proper format.

To run this program, include the following JAR files in the classpath: 

  • weblogic.jar

  • oracle.servicebus.kernel-api.jar

  • oracle.servicebus.configfwk.jar

  • com.bea.core.management.core_version.jar

  • com.bea.core.management.jmx_version.jar

You may need to reset the default values for SERVER_NAME, HOSTNAME, PORT, USERNAME, and PASSWORD in the code below for your environment.

Note:

If you need to get the Status statistics for each endpoint of a business service, set the SERVER_NAME attribute in a cluster environment. If you are running on a single node, Status statistics are returned even if you do not set this property.

For performance reasons, avoid extracting and resetting statistics for a large number of services too often. See Section A.2.5, "Caveats." See Example A-1 for a sample program.

Example A-1 Sample Program to Retrieve Statistics for a Proxy Service that is Enabled for Monitoring

Note that some lines in the sample below have been wrapped and reformatted for better readability.

package tests.monitoring;
 
import com.bea.wli.config.Ref;
import com.bea.wli.monitoring.*;
import com.bea.wli.sb.util.Refs;
import weblogic.management.jmx.MBeanServerInvocationHandler;
 
import javax.management.MBeanServerConnection;
import javax.management.MalformedObjectNameException;
import javax.management.ObjectName;
import javax.management.remote.JMXConnector;
import javax.management.remote.JMXConnectorFactory;
import javax.management.remote.JMXServiceURL;
import javax.naming.Context;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.net.MalformedURLException;
import java.util.*;
import java.text.SimpleDateFormat;
 
 
public class ServiceStatisticsRetriever
{
    private ServiceDomainMBean serviceDomainMbean = null;
    private String serverName = null;
 
    /**
     * Retrieve statistics for all business services being monitored in the
     * domain and reset statistics for the same.
     */
    void getAndResetStatsForAllMonitoredBizServices() throws Exception  
    {
        getAndResetStatsForMonitoredServices(
                new String[] {Refs.BUSINESS_SERVICE_TYPE},
                new ResourceType[]{ResourceType.SERVICE, ResourceType.WEBSERVICE_OPERATION,
                                   ResourceType.URI},
                serverName, "BizStatistics");
    }
 
    /**
     * Retrieve statistics for all proxy services being monitored in the
     * domain and reset statistics for the same.
     */
    void getAndResetStatsForAllMonitoredProxyServices() throws Exception
    {
        getAndResetStatsForMonitoredServices(
                new String[]  {Refs.PROXY_SERVICE_TYPE},
                new ResourceType[]{ResourceType.SERVICE, ResourceType.FLOW_COMPONENT,
                                   ResourceType.WEBSERVICE_OPERATION},
                null,
                "ProxyStatistics");
    }
 
    /**
     * Retrieve statistics for all business services being monitored in the
     * domain and reset statistics for the same.
     */
    void getAndResetStatsForMonitoredServices(String[] typeIds, ResourceType[] resourceTypes,
                 String serverName, String filePrefix) throws Exception
    {
        Ref[] serviceRefs = serviceDomainMbean.getMonitoredRefs(typeIds);
 
        try
        {
            // Get statistics for a specific server.
            System.out.println("Now trying to get statistics for -" + serviceRefs.length + "
                                services...");
            HashMap<Ref, ServiceResourceStatistic> resourcesMap =
                                                   serviceDomainMbean.getStatistics(
                    serviceRefs,
                    resourceTypes,
                    serverName);
 
            // Reset statistics.
            long resetRequestTime = serviceDomainMbean.resetStatistics(serviceRefs);
 
            // Save retrieved statistics.
            String fileName = filePrefix +
                              "_" +
                              new SimpleDateFormat("yyyy_MM_dd_HH_mm").format(new
                                  Date(System.currentTimeMillis())) +
                              ".txt";
            saveStatisticsToFile(resourcesMap, resetRequestTime, fileName);
        }
        catch (IllegalArgumentException iae)
        {
            System.out.println("===============================\n");
            System.out.println("Encountered IllegalArgumentException...Details:");
            System.out.println(iae.getMessage());
            System.out.println("Check if proxy ref was passed OR flowComp " +
                               "resource was passed OR bitmap is invalid..." +
                               "\nIf so correct it and try again!!!");
            System.out.println("==================================\n");
            throw iae;
        }
        catch (DomainMonitoringDisabledException dmde)
        {
            // Statistics not available as monitoring is turned off at domain level.
            System.out.println("==================================\n");
            System.out.println("Statistics not available as monitoring " +
                               "is turned off at domain level.");
            System.out.println("==============================\n");
            throw dmde;
        }
        catch (MonitoringException me)
        {
            // Internal problem... May be aggregation server is crashed...
            System.out.println("================================\n");
            System.out.println("ERROR: Statistics is not available..." +
                               "Check if aggregation server is crashed...");
            System.out.println("=================================\n");
            throw me;
        }
    }
 
    /**
     * Saves statistics of all services from the specified map.
     *
     * @param statsMap     Map containing statistics for one or more services
     *                     of the same type; i.e., business or proxy.
     * @param resetReqTime Reset request time. This information will be
     *                     written at the end of the file, provided it is not zero.
     * @param fileName     Statistics will be saved in a file with this name.
     */
    private void saveStatisticsToFile(
            HashMap<Ref, ServiceResourceStatistic> statsMap,
            long resetReqTime,
            String fileName) throws Exception
    {
        if (statsMap == null)
        {
            System.out.println("\nService statistics map is null...Nothing to save.\n");
            return;
        }
 
        if (statsMap.size() == 0)
        {
            System.out.println("\nService statistics map is empty...Nothing to save.\n");
            return;
        }
 
        FileWriter out = new FileWriter(new File(fileName));
 
        out.write("*********************************************\n");
        out.write("This file contains statistics for " + statsMap.size() + " services.\n");
        out.write("***********************************************\n");
 
        Set<Map.Entry<Ref, ServiceResourceStatistic>> set = statsMap.entrySet();
 
        System.out.println("\nWriting stats to the file - " + fileName +"\n");
 
        // Print statistical information of each service
        for (Map.Entry<Ref, ServiceResourceStatistic> mapEntry : set)
        {
            out.write("\n\n======= Printing statistics for service " + 
                       mapEntry.getKey().getFullName() + "=======\n");
 
            ServiceResourceStatistic serviceStats = mapEntry.getValue();
            out.write("Statistic collection time is - " + new
                       Date(serviceStats.getCollectionTimestamp()) + "\n");
 
            try
            {
                ResourceStatistic[] resStatsArray = serviceStats.getAllResourceStatistics();
 
                for (ResourceStatistic resStats : resStatsArray)
                {
                    // Print resource information
                    out.write("\nResource name: " + resStats.getName());
                    out.write("\tResource type: " + resStats.getResourceType().toString());
 
                    // Now get and print statistics for this resource
                    StatisticValue[] statValues = resStats.getStatistics();
                    for (StatisticValue value : statValues)
                    {
                        out.write("\n\t\tStatistic Name - " + value.getName());
                        out.write("\n\t\tStatistic Type - " + value.getType());
 
                        // Determine statistics type
                        if (value.getType() == StatisticType.INTERVAL)
                        {
                            StatisticValue.IntervalStatistic is =
                                 (StatisticValue.IntervalStatistic) value;
 
                            // Print interval statistics values
                            out.write("\n\t\t\t\tCount Value - " + is.getCount());
                            out.write("\n\t\t\t\tMin Value - " + is.getMin());
                            out.write("\n\t\t\t\tMax Value - " + is.getMax());
                            out.write("\n\t\t\t\tSum Value - " + is.getSum());
                            out.write("\n\t\t\t\tAve Value - " + is.getAverage());
                        }
                        else if (value.getType() == StatisticType.COUNT)
                        {
                            StatisticValue.CountStatistic cs =(StatisticValue.CountStatistic) 
                               value;
 
                            // Print count statistics value
                            out.write("\n\t\t\t\tCount Value - " + cs.getCount());
                        }
                        else if (value.getType() == StatisticType.STATUS)
                        {
                            StatisticValue.StatusStatistic ss = (StatisticValue.StatusStatistic)
                               value;
                            // Print count statistics value
                            out.write("\n\t\t\t\t Initial Status - " + ss.getInitialStatus());
                            out.write("\n\t\t\t\t Current Status - " + ss.getCurrentStatus());
                        }
                    }
                }
 
                out.write("\n=========================================\n");
            }
            catch (MonitoringNotEnabledException mnee)
            {
                // Statistics not available
                out.write("WARNING: Monitoring is not enabled for this service... Do 
                           something...");
                out.write("=====================================\n");
            }
            catch (InvalidServiceRefException isre)
            {
                // Invalid service
                out.write("ERROR: Invlaid Ref. May be this service is deleted. Do something...");
                out.write("======================================\n");
            }
            catch (MonitoringException me)
            {
                // Statistics not available
                out.write("ERROR: Failed to get statistics for this service...Details: " +
                           me.getMessage());
                me.printStackTrace();
                out.write("======================================\n");
            }
        }
 
        if (resetReqTime > 0)
        {
            // Save reset request time.
            out.write("\n*****************************************\n");
            out.write("Statistics for all these services are RESET.\n");
            out.write("RESET request time is " 
                   + new SimpleDateFormat("MM/dd/yyyy HH:mm:ss").format(new Date(resetReqTime)));
            out.write("\n****************************************\n");
        }
 
        // Flush and close file.
        out.flush();
        out.close();
    }
 
    /**
     * Init method.
     *
     * @param props Properties required for initialization.
     */
    private void init(HashMap props) throws Exception
    {
        Properties properties = new Properties();
        properties.putAll(props);
        
        initServiceDomainMBean(properties.getProperty("HOSTNAME"),
                              Integer.parseInt(properties.getProperty("PORT", "7001")),
                              properties.getProperty("USERNAME"),
                              properties.getProperty("PASSWORD"));
        
        serverName = properties.getProperty("SERVER_NAME");
    }
 
 
    /**
     * Gets an instance of ServiceDomainMBean from the weblogic server.
     */
    private void initServiceDomainMBean(String host, int port, String username, String password)
                                        throws Exception
    {
        InvocationHandler handler = new ServiceDomainMBeanInvocationHandler(host, port, username,
           password);
        
        Object proxy = Proxy.newProxyInstance(
                ServiceDomainMBean.class.getClassLoader(),
                new Class[]{ServiceDomainMBean.class}, handler);
        
        serviceDomainMbean = (ServiceDomainMBean) proxy;
    }
 
    /**
     * Invocation handler class for ServiceDomainMBean class.
     */
    public static class ServiceDomainMBeanInvocationHandler implements InvocationHandler
    {
        private String jndiURL = "weblogic.management.mbeanservers.domainruntime";
        private String mbeanName = ServiceDomainMBean.NAME;
        private String type = ServiceDomainMBean.TYPE;
 
        private String protocol = "t3";
        private String hostname = "localhost";
        private int port = 7001;
        private String jndiRoot = "/jndi/";
 
        private String username = "weblogic";
        private String password = "weblogic";
 
        private JMXConnector conn = null;
        private Object actualMBean = null;
 
        public ServiceDomainMBeanInvocationHandler(String hostName, int port, String userName,
                   String password)
        {
            this.hostname = hostName;
            this.port = port;
            this.username = userName;
            this.password = password;
        }
 
        /**
         * Gets JMX connection
         */
        public JMXConnector initConnection() throws IOException, MalformedURLException
        {
            JMXServiceURL serviceURL = new JMXServiceURL(protocol, hostname, port, jndiRoot +
                                       jndiURL);
            Hashtable<String, String> h = new Hashtable<String, String>();
 
            if (username != null)
                h.put(Context.SECURITY_PRINCIPAL, username);
            if (password != null)
                h.put(Context.SECURITY_CREDENTIALS, password);
 
            h.put(JMXConnectorFactory.PROTOCOL_PROVIDER_PACKAGES, "weblogic.management.remote");
 
            return JMXConnectorFactory.connect(serviceURL, h);
        }
 
        /**
         * Invokes specified method with specified params on specified
         * object.
         */
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
        {
            if (conn == null)
                conn = initConnection();
 
            if (actualMBean == null)
                actualMBean = findServiceDomain(conn.getMBeanServerConnection(), mbeanName, type,
                              null);
            
            return method.invoke(actualMBean, args);
        }
 
        /**
         * Finds the specified MBean object
         *
         * @param connection - A connection to the MBeanServer.
         * @param mbeanName  - The name of the MBean instance.
         * @param mbeanType  - The type of the MBean.
         * @param parent     - The name of the parent Service. Can be NULL.
         * @return Object - The MBean or null if the MBean was not found.
         */
        public Object findServiceDomain(MBeanServerConnection connection,
                                        String mbeanName,
                                        String mbeanType,
                                        String parent)
        {
            try
            {
                ObjectName on = new ObjectName(ServiceDomainMBean.OBJECT_NAME);
                return (ServiceDomainMBean)
                       MBeanServerInvocationHandler.newProxyInstance(connection, on);
            }
            catch (MalformedObjectNameException e)
            {
                e.printStackTrace();
                return null;
            }
        }
    }
 
    /**
     * Timer task to keep retrieving and resetting service statistics.
     */
    static class GetAndResetStatisticsTask extends TimerTask
    {
        private ServiceStatisticsRetriever collector;
 
        public GetAndResetStatisticsTask(ServiceStatisticsRetriever col)
        {
            collector = col;
        }
 
        public void run()
        {
            System.out.println("\n**********************************");
            System.out.println("Retrieving statistics for all monitored" + "business services.");
 
            try
            {
                collector.getAndResetStatsForAllMonitoredBizServices();
                System.out.println("Successfully retrieved and reset statistics for " +
                                   "all monitored \n business services at " +
                                   new SimpleDateFormat("MM/dd/yyyy HH:mm:ss").format(new
                                    Date(System.currentTimeMillis())));
            }
            catch (Exception e)
            {
                System.out.println("Failed to retrieve and reset statistics for all monitored
                                    business services...");
                e.printStackTrace();
            }
            System.out.println("**********************************\n");
            System.out.println("\n**********************************");
            System.out.println("Retrieving statistics for all monitored proxy services.");
 
            try
            {
                collector.getAndResetStatsForAllMonitoredProxyServices();
                System.out.println("Successfully retrieved and reset statistics " +
                                   "for all monitored \nproxy services at " +
                                   new SimpleDateFormat("MM/dd/yyyy HH:mm:ss").format(new
                                    Date(System.currentTimeMillis())));
            }
            catch (Exception e)
            {
                System.out.println("Failed to retrieve and reset statistics " + 
                                   "for all monitored proxy services...");
                e.printStackTrace();
            }
 
            System.out.println("*********************************\n");
        }
    }
 
    /**
     * The main method to start the timer task to extract, save, and reset
     * statistics for all monitored business and proxy services. It uses
     * the following system properties.
     * 1. hostname - Hostname of admin server
     * 2. port - Listening port of admin server
     * 3. username - Login username
     * 4. password - Login password
     * 5. period - Frequency in hours. This will be used by the timer
     * to determine the time gap between two executions.
     *
     * @param args Not used.
     */
    public static void main(String[] args)
    {
        try
        {
            Properties p = System.getProperties();
 
            HashMap<String, String> map = new HashMap<String, String>();
 
            map.put("HOSTNAME", p.getProperty("hostname", "localhost"));
            map.put("PORT", p.getProperty("port", "7001"));
            map.put("USERNAME", p.getProperty("username", "weblogic"));
            map.put("PASSWORD", p.getProperty("password", "weblogic"));
 
            //set a server name if you want to get the uri status statistics in a cluster
            map.put("SERVER_NAME", p.getProperty("server_name", "AdminServer"));
 
            String periodStr = p.getProperty("period", "1");
            int periodInHour = Integer.parseInt(periodStr);
            long periodInMilliSec = periodInHour * 60 * 60 * 1000;
 
            ServiceStatisticsRetriever collector = new ServiceStatisticsRetriever();
            collector.init(map);
 
            // Start timer.
            Timer timer = new Timer();
            timer.scheduleAtFixedRate(new GetAndResetStatisticsTask(collector),
                                          0, periodInMilliSec);
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }
    }
}