/* * Sun Public License * * The contents of this file are subject to the Sun Public License Version * 1.0 (the "License"). You may not use this file except in compliance with * the License. A copy of the License is available at http://www.sun.com/ * * The Original Code is the SLAMD Distributed Load Generation Engine. * The Initial Developer of the Original Code is Neil A. Wilson. * Portions created by Neil A. Wilson are Copyright (C) 2004-2010. * Some preexisting portions Copyright (C) 2002-2006 Sun Microsystems, Inc. * All Rights Reserved. * * Contributor(s): Neil A. Wilson */ package com.slamd.resourcemonitor; import java.util.ArrayList; import java.util.Properties; import com.slamd.job.JobClass; import com.slamd.common.Constants; import com.slamd.common.SLAMDException; import com.slamd.stat.StatTracker; /** * This class defines a set of methods that must be implemented by any class * that is to be used as a SLAMD resource monitor. * * * @author Neil A. Wilson */ public abstract class ResourceMonitor extends Thread { /** * The value that will be returned from the <CODE>getClientOS</CODE> method * if the client is running an unknown or unrecognized operating system. */ public static final int OS_TYPE_UNKNOWN = Constants.OS_TYPE_UNKNOWN; /** * The value that will be returned from the <CODE>getClientOS</CODE> method * if the client is running Solaris. */ public static final int OS_TYPE_SOLARIS = Constants.OS_TYPE_SOLARIS; /** * The value that will be returned from the <CODE>getClientOS</CODE> method * if the client is running Linux. */ public static final int OS_TYPE_LINUX = Constants.OS_TYPE_LINUX; /** * The value that will be returned from the <CODE>getClientOS</CODE> method * if the client is running HP-UX. */ public static final int OS_TYPE_HPUX = Constants.OS_TYPE_HPUX; /** * The value that will be returned from the <CODE>getClientOS</CODE> method * if the client is running AIX. */ public static final int OS_TYPE_AIX = Constants.OS_TYPE_AIX; /** * The value that will be returned from the <CODE>getClientOS</CODE> method * if the client is running Windows. */ public static final int OS_TYPE_WINDOWS = Constants.OS_TYPE_WINDOWS; /** * The value that will be returned from the <CODE>getClientOS</CODE> method * if the client is running Mac OS X. */ public static final int OS_TYPE_OSX = Constants.OS_TYPE_OSX; // The list of log messages associated with this monitor thread. private ArrayList<String> logMessages; // Indicates whether this resource monitor has stopped collecting statistics. private boolean hasStopped; // Indicates whether this resource monitor should stop collecting statistics. private volatile boolean shouldStop; // The time that this resource monitor should start collecting statistics. private long startTime; // The time that this resource monitor should stop collecting statistics. private long stopTime; // The set of properties that indicate how this monitor thread should operate. private Properties monitorProperties; // The reference to the resource monitor client being used to capture // statistics. protected ResourceMonitorClient monitorClient; // The resource monitor job that is currently running. private ResourceMonitorJob monitorJob; // A reference to the resource monitor thread that is currently running. private volatile Thread monitorThread; /** * Initializes this resource monitor implementation. This method will be * called before any other methods in this interface are invoked. * * @param monitorClient The reference to the resource monitor client * being used to capture statistics. * @param monitorProperties A set of properties that indicate how this * monitor thread should operate. * * @throws SLAMDException If a problem occurs while initializing the * resource monitor. */ public final void initialize(ResourceMonitorClient monitorClient, Properties monitorProperties) throws SLAMDException { this.monitorClient = monitorClient; this.monitorProperties = monitorProperties; this.monitorJob = null; shouldStop = false; hasStopped = false; monitorThread = null; initializeMonitor(); } /** * Performs any initialization specific to this resource monitor. * * @throws SLAMDException If a problem occurs while performing the * initialization. */ public abstract void initializeMonitor() throws SLAMDException; /** * Retrieves the reference to the resource monitor client with which this * monitor thread is associated. * * @return The reference to the resource monitor client with which this * monitor thread is associated. */ public final ResourceMonitorClient getMonitorClient() { return monitorClient; } /** * Retrieves the configuration properties associated with this resource * monitor thread. * * @return The configuration properties associated with this resource monitor * thread. */ public final Properties getMonitorProperties() { return monitorProperties; } /** * Retrieves the resource monitor job that is currently running. * * @return The resource monitor job that is currently running, or * <CODE>null</CODE> if there is none. */ public final ResourceMonitorJob getMonitorJob() { return monitorJob; } /** * Retrieves the configuration property with the specified name. * * @param propertyName The name of the property for which to retrieve the * value. * * @return The configuration property with the specified name, or * <CODE>null</CODE> if no property exists with that name. */ public final String getProperty(String propertyName) { return monitorProperties.getProperty(propertyName); } /** * Retrieves the configuration property with the specified name. * * @param propertyName The name of the property for which to retrieve the * value. * @param defaultValue The value to return if no property exists with the * given name. * * @return The configuration property with the specified name, or the given * default value if no property exists with that name. */ public final String getProperty(String propertyName, String defaultValue) { return monitorProperties.getProperty(propertyName, defaultValue); } /** * Retrieves the integer representation of the configuration property with the * specified name. * * @param propertyName The name of the property for which to retrieve the * value. * @param defaultValue The value to return if no property exists with the * given name, or if its value cannot be parsed as an * integer. * * @return The integer representation of the configuration property with the * specified name. */ public final int getProperty(String propertyName, int defaultValue) { String propertyValue = monitorProperties.getProperty(propertyName, String.valueOf(defaultValue)); try { return Integer.parseInt(propertyValue); } catch (NumberFormatException nfe) { return defaultValue; } } /** * Retrieves the Boolean representation of the configuration property with the * specified name. * * @param propertyName The name of the property for which to retrieve the * value. * @param defaultValue The value to return if no property exists with the * given name, or if its value cannot be parsed as a * Boolean. * * @return The Boolean representation of the configuration property with the * specified name. */ public final boolean getProperty(String propertyName, boolean defaultValue) { String propertyValue = monitorProperties.getProperty(propertyName, String.valueOf(defaultValue)); if (propertyValue.equalsIgnoreCase("true") || propertyValue.equalsIgnoreCase("yes") || propertyValue.equalsIgnoreCase("on") || propertyValue.equalsIgnoreCase("1")) { return true; } else if (propertyValue.equalsIgnoreCase("false") || propertyValue.equalsIgnoreCase("no") || propertyValue.equalsIgnoreCase("off") || propertyValue.equalsIgnoreCase("0")) { return false; } else { return defaultValue; } } /** * Retrieves the name to use for this resource monitor. * * @return The name to use for this resource monitor. */ public abstract String getMonitorName(); /** * Indicates whether the current client system is supported for this resource * monitor. * * @return <CODE>true</CODE> if the current client system is supported for * this resource monitor, or <CODE>false</CODE> if not. */ public abstract boolean clientSupported(); /** * Creates a new instance of this resource monitor thread. Note that the * <CODE>initialize()</CODE> method should have been called on the new * instance before it is returned. * * @return A new instance of this resource monitor thread. * * @throws SLAMDException If a problem occurs while creating or initializing * the resource monitor. */ public abstract ResourceMonitor newInstance() throws SLAMDException; /** * Initializes the stat trackers maintained by this resource monitor. * * @param clientID The client ID to use for the stubs. * @param threadID The thread ID to use for the stubs. * @param collectionInterval The collection interval to use for the stubs. */ public abstract void initializeStatistics(String clientID, String threadID, int collectionInterval); /** * Retrieves the statistical data collected by this resource monitor. * * @return The statistical data collected by this resource monitor. */ public abstract StatTracker[] getResourceStatistics(); /** * Indicates that this resource monitor should start collecting statistics. * * @param monitorJob The resource monitor job with which the statistics will * be associated. */ public final void startCollecting(ResourceMonitorJob monitorJob) { this.monitorJob = monitorJob; this.startTime = monitorJob.getStartTime(); this.stopTime = monitorJob.getShouldStopTime(); logMessages = new ArrayList<String>(); initializeStatistics(monitorClient.getClientHostname(), getMonitorName(), monitorJob.getCollectionInterval()); start(); } /** * Indicates that this resource monitor should stop collecting statistics. */ public final void stopCollecting() { shouldStop = true; } /** * Indicates that this resource monitor should stop collecting statistics. It * will not return until the monitor has indicated that it has actually * stopped. */ public final void stopAndWait() { shouldStop = true; long requestTime = System.currentTimeMillis(); while (! hasStopped) { long now = System.currentTimeMillis(); if (((now - requestTime) > 5000) && (monitorThread != null)) { monitorThread.interrupt(); requestTime = now; } try { Thread.sleep(10); } catch (InterruptedException ie) {} } } /** * Indicates whether this monitor thread should stop collecting statistics. * * @return <CODE>true</CODE> if this monitor thread should stop collecting * statistics, or <CODE>false</CODE> if not. */ public final boolean shouldStop() { if ((stopTime > 0) && (System.currentTimeMillis() > stopTime)) { shouldStop = true; } return shouldStop; } /** * Run the monitor. Upon exiting, it will set a flag indicating that the * thread has stopped. */ @Override() public final void run() { // Sleep until the start time arrives. long sleepTime = startTime - System.currentTimeMillis(); while ((! shouldStop) && (sleepTime > 0)) { long loopSleepTime; if (sleepTime > 1000) { loopSleepTime = 1000; } else { loopSleepTime = sleepTime; } try { Thread.sleep(loopSleepTime); } catch (InterruptedException ie) {} sleepTime = startTime - System.currentTimeMillis(); } // Actually run the monitor thread. if (! shouldStop) { monitorThread = Thread.currentThread(); try { runMonitor(); } catch (Exception e) { String message = "Uncaught exception while processing resource " + "monitor: " + JobClass.stackTraceToString(e); monitorClient.logVerbose(message); logMessages.add(message); } monitorThread = null; } // Indicate that the thread is now done. hasStopped = true; monitorJob.monitorDone(this); monitorJob = null; logMessages = null; } /** * Performs the work of actually collecting resource statistics. This method * should periodically call the <CODE>shouldStop()</CODE> method to determine * whether to stop collecting statistics. * * @return A value that indicates the status of the monitor when it * completed. */ public abstract int runMonitor(); /** * Retrieves the value indicating the operating system on which this resource * monitor is running. * * @return The value indicating the operating system on which this resource * monitor is running. */ public final int getClientOS() { return monitorClient.getClientOS(); } /** * Retrieves the hostname of the system on which this resource monitor is * running. * * @return The hostname of the system on which this resource monitor is * running. */ public final String getClientHostname() { return monitorClient.getClientHostname(); } /** * Writes the specified message to the log associated with this resource * monitor. * * @param message The message to be written to the log associated with this * resource monitor. */ public final void logMessage(String message) { monitorClient.logVerbose(message); logMessages.add(message); } /** * Writes the specified message to the client message writer if it is * operating in verbose mode. * * @param message The message to be written. */ public final void writeVerbose(String message) { monitorClient.logVerbose(message); } /** * Retrieves the set of messages that have been logged by this monitor. * * @return The set of messages that have been logged by this monitor. */ public final String[] getLogMessages() { String[] messages = new String[logMessages.size()]; for (int i=0; i < messages.length; i++) { messages[i] = getMonitorName() + " -- " + logMessages.get(i); } return messages; } }