/* * 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.protocol; import java.util.ArrayList; import java.util.Date; import java.util.HashMap; import com.slamd.asn1.ASN1Boolean; import com.slamd.asn1.ASN1Element; import com.slamd.asn1.ASN1Integer; import com.slamd.asn1.ASN1OctetString; import com.slamd.asn1.ASN1Sequence; import com.slamd.common.Constants; import com.slamd.common.SLAMDException; import com.slamd.parameter.Parameter; import com.slamd.parameter.ParameterList; /** * This class defines a SLAMD message that will be sent from the server to the * client to provide it with information about a job that is to be processed. * * * @author Neil A. Wilson */ public class JobRequest extends SLAMDMessage { // Indicates whether the client should report in-progress statistics for the // job. private boolean reportInProgressStats; // The time that job processing should start. private Date startTime; // The time that job processing should end. private Date stopTime; // The client number assigned to the client being given this request. private int clientNumber; // The statistics collection interval in seconds for the job. private int collectionInterval; // The maximum length of time in seconds that the job should run. private int duration; // The interval to use when reporting in-progress statistics. private int inProgressReportInterval; // The version of the job class to use when running the job. private int jobClassVersion; // The number of clients to use to process the job. private int numClients; // The number of threads per client to use to process the job. private int threadsPerClient; // The delay in milliseconds between the startups for each of the threads. private int threadStartupDelay; // The list of parameters to use when running the job. private ParameterList parameterList; // The fully-qualified name of the job class to use for the job. private String jobClassName; // The job ID for the job to process. private String jobID; /** * Creates a new instance of this job request message which is intended for * use in decoding a message transmitted between the server and the client. * It is not intended for general use. */ public JobRequest() { super(); reportInProgressStats = false; startTime = null; stopTime = null; clientNumber = -1; collectionInterval = -1; duration = -1; inProgressReportInterval = -1; jobClassVersion = -1; numClients = -1; threadsPerClient = -1; threadStartupDelay = -1; parameterList = new ParameterList(); jobClassName = null; jobID = null; } /** * Creates a new instance of this job request message with the provided * information. * * @param messageID The message ID for this SLAMD message. * @param extraProperties The "extra" properties for this SLAMD * message. Both the names and values for * the properties must be strings. * @param jobID The job ID for the job to process. * @param jobClassName The fully-qualified name of the job class * for the job to process. * @param jobClassVersion The job class version for the job to * process. * @param numClients The number of clients that should be used * to process the job. * @param threadsPerClient The number of threads per client that * should be used to process the job. * @param startTime The time that processing should begin for * the job. * @param stopTime The time that processing should stop for * the job. * @param duration The maximum length of time in seconds * that the job should run. * @param collectionInterval The statistics collection interval for * the job. * @param threadStartupDelay The delay in milliseconds that should be * used between the startup for each job * thread. * @param parameterList The list of parameters to use when * processing the job. * @param reportInProgressStats Indicates whether the client should * periodically report its in-progress * statistics to the server. * @param inProgressReportInterval The interval to use when reporting * in-progress statistics to the server. */ public JobRequest(int messageID, HashMap<String,String> extraProperties, String jobID, String jobClassName, int jobClassVersion, int numClients, int threadsPerClient, Date startTime, Date stopTime, int duration, int collectionInterval, int threadStartupDelay, ParameterList parameterList, boolean reportInProgressStats, int inProgressReportInterval) { super(messageID, extraProperties); this.jobID = jobID; this.jobClassName = jobClassName; this.jobClassVersion = jobClassVersion; this.numClients = numClients; this.threadsPerClient = threadsPerClient; this.startTime = startTime; this.stopTime = stopTime; this.duration = duration; this.collectionInterval = collectionInterval; this.threadStartupDelay = threadStartupDelay; this.parameterList = parameterList; this.reportInProgressStats = reportInProgressStats; this.inProgressReportInterval = inProgressReportInterval; clientNumber = -1; } /** * Retrieves the job ID for the job to process. * * @return The job ID for the job to process. */ public String getJobID() { return jobID; } /** * Specifies the job ID for the job to process. * * @param jobID The job ID for the job to process. */ public void setJobID(String jobID) { this.jobID = jobID; } /** * Retrieves the fully-qualified name of the job class for the job to process. * * @return The fully-qualified name of the job class for the job to process. */ public String getJobClassName() { return jobClassName; } /** * Specifies the fully-qualified name of the job class for the job to process. * * @param jobClassName The fully-qualified name of the job class for the job * to process. */ public void setJobClassName(String jobClassName) { this.jobClassName = jobClassName; } /** * Retrieves the job class version for the job to process. * * @return The job class version for the job to process, or -1 if no version * information is available. */ public int getJobClassVersion() { return jobClassVersion; } /** * Specifies the job class version for the job to process. * * @param jobClassVersion The job class version for the job to process. */ public void setJobClassVersion(int jobClassVersion) { this.jobClassVersion = jobClassVersion; } /** * Retrieves the number of clients that should be used to process the job. * * @return The number of clients that should be used to process the job. */ public int getNumClients() { return numClients; } /** * Specifies the number of clients that should be used to process the job. * * @param numClients The number of clients that should be used to process * the job. */ public void setNumClients(int numClients) { this.numClients = numClients; } /** * Retrieves the number of threads per client that should be used to process * the job. * * @return The number of threads per client that should be used to process * the job. */ public int getThreadsPerClient() { return threadsPerClient; } /** * Specifies the number of threads per client that should be used to process * the job. * * @param threadsPerClient The number of threads per client that should be * used to process the job. */ public void setThreadsPerClient(int threadsPerClient) { this.threadsPerClient = threadsPerClient; } /** * Retrieves the time at which processing should start for the job. * * @return The time at which processing should start for the job. */ public Date getStartTime() { return startTime; } /** * Specifies the time at which processing should start for the job. * * @param startTime The time at which processing should start for the job. */ public void setStartTime(Date startTime) { this.startTime = startTime; } /** * Retrieves the time at which processing should stop for the job. * * @return The time at which processing should stop for the job, or * <CODE>null</CODE> if no stop time has been specified. */ public Date getStopTime() { return stopTime; } /** * Specifies the time at which processing should stop for the job. * * @param stopTime The time at which processing should stop for the job. */ public void setStopTime(Date stopTime) { this.stopTime = stopTime; } /** * Retrieves the maximum length of time in seconds that the job should run. * * @return The maximum length of time in seconds that the job should run, or * a value less than or equal to zero if there is no duration. */ public int getDuration() { return duration; } /** * Specifies the maximum length of time in seconds that the job should run. * * @param duration The maximum length of time in seconds that the job should * run. */ public void setDuration(int duration) { this.duration = duration; } /** * Retrieves the statistics collection interval for the job. * * @return The statistics collection interval for the job. */ public int getCollectionInterval() { return collectionInterval; } /** * Specifies the statistics collection interval for the job. * * @param collectionInterval The statistics collection interval for the job. */ public void setCollectionInterval(int collectionInterval) { this.collectionInterval = collectionInterval; } /** * Retrieves the delay in milliseconds that should be used when starting the * individual threads for the job. * * @return The delay in milliseconds that should be used when starting the * individual threads for the job, or a value less than or equal to * zero to indicate that there should not be any delay. */ public int getThreadStartupDelay() { return threadStartupDelay; } /** * Speifies the delay in milliseconds that should be used when starting the * individual threads for the job. * * @param threadStartupDelay The delay in milliseconds that should be used * when starting the individual threads for the * job. */ public void setThreadStartupDelay(int threadStartupDelay) { this.threadStartupDelay = threadStartupDelay; } /** * Retrieves the set of parameters that should be used to process the job. * * @return The set of parameters that should be used to process the job. */ public ParameterList getParameterList() { return parameterList; } /** * Specifies the set of parameters that should be used to process the job. * * @param parameterList The set of parameters that should be used to process * the job. */ public void setParameterList(ParameterList parameterList) { this.parameterList = parameterList; } /** * Indicates whether the client should periodically report the collected * results to the server. * * @return <CODE>true</CODE> if the client should periodically report the * collected results to the server, or <CODE>false</CODE> if not. */ public boolean reportInProgressStats() { return reportInProgressStats; } /** * Specifies whether the client should periodically report the collected * results to the server. * * @param reportInProgressStats Specifies whether the client should * periodically report the collected results to * the server. */ public void setReportInProgressStats(boolean reportInProgressStats) { this.reportInProgressStats = reportInProgressStats; } /** * Retrieves the interval that the client should use to report the in-progress * results to the server. This is irrelevant for cases in which real-time * reporting is not enabled. * * @return The interval that the client should use to report the in-progress * results to the server. */ public int getInProgressResportInterval() { return inProgressReportInterval; } /** * Specifies the interval that the client should use to report the in-progress * results to the server. * * @param inProgressReportInterval The interval that the client should use * to report the in-progress results to the * server. */ public void setInProgressReportInterval(int inProgressReportInterval) { this.inProgressReportInterval = inProgressReportInterval; } /** * Retrieves the client number for the client to which this request is being * sent. This value should be different for each client that receives this * job request, with the first client number being zero and subsequent clients * increasing this value by one. * * @return The client number for the client to which this request is being * sent. */ public int getClientNumber() { return clientNumber; } /** * Specifies the client number for the client to which this request is being * sent. This method must be called to set the client number before sending * the job request message to that client. The first client should receive a * client number of zero, with the value incrementing sequentially for each * subsequent client. * * @param clientNumber The client number for the client to which this * request is being sent. */ public void setClientNumber(int clientNumber) { this.clientNumber = clientNumber; } /** * Encodes the payload component of this SLAMD message to an ASN.1 element for * inclusion in the message envelope. * * @return The ASN.1 element containing the encoded message payload. */ @Override() public ASN1Element encodeMessagePayload() { ArrayList<ASN1Element> elementList = new ArrayList<ASN1Element>(); elementList.add(encodeNameValuePair(ProtocolConstants.PROPERTY_JOB_ID, new ASN1OctetString(jobID))); elementList.add(encodeNameValuePair( ProtocolConstants.PROPERTY_JOB_CLASS_NAME, new ASN1OctetString(jobClassName))); if (jobClassVersion > 0) { elementList.add(encodeNameValuePair( ProtocolConstants.PROPERTY_JOB_CLASS_VERSION, new ASN1Integer(jobClassVersion))); } elementList.add(encodeNameValuePair( ProtocolConstants.PROPERTY_NUM_CLIENTS, new ASN1Integer(numClients))); elementList.add(encodeNameValuePair( ProtocolConstants.PROPERTY_THREADS_PER_CLIENT, new ASN1Integer(threadsPerClient))); elementList.add(encodeNameValuePair(ProtocolConstants.PROPERTY_START_TIME, new ASN1OctetString(String.valueOf(startTime.getTime())))); if (stopTime != null) { elementList.add(encodeNameValuePair(ProtocolConstants.PROPERTY_STOP_TIME, new ASN1OctetString(String.valueOf(stopTime.getTime())))); } if (duration > 0) { elementList.add(encodeNameValuePair(ProtocolConstants.PROPERTY_DURATION, new ASN1Integer(duration))); } elementList.add(encodeNameValuePair( ProtocolConstants.PROPERTY_COLLECTION_INTERVAL, new ASN1Integer(collectionInterval))); if (threadStartupDelay > 0) { elementList.add(encodeNameValuePair( ProtocolConstants.PROPERTY_THREAD_STARTUP_DELAY, new ASN1Integer(threadStartupDelay))); } elementList.add(encodeNameValuePair( ProtocolConstants.PROPERTY_PARAMETER_LIST, parameterList.encode())); elementList.add(encodeNameValuePair( ProtocolConstants.PROPERTY_REPORT_IN_PROGRESS_STATS, new ASN1Boolean(reportInProgressStats))); if (reportInProgressStats) { elementList.add(encodeNameValuePair( ProtocolConstants.PROPERTY_IN_PROGRESS_REPORT_INTERVAL, new ASN1Integer(inProgressReportInterval))); } elementList.add(encodeNameValuePair( ProtocolConstants.PROPERTY_CLIENT_NUMBER, new ASN1Integer(clientNumber))); return new ASN1Sequence(elementList); } /** * Decodes the provided ASN.1 element and uses it as the payload for this * SLAMD message. * * @param payloadElement The ASN.1 element to decode as the payload for this * SLAMD message. * * @throws SLAMDException If a problem occurs while attempting to decode the * provided ASN.1 element as the payload for this * SLAMD message. */ @Override() public void decodeMessagePayload(ASN1Element payloadElement) throws SLAMDException { HashMap<String,ASN1Element> propertyMap = decodeNameValuePairSequence(payloadElement); ASN1Element valueElement = propertyMap.get(ProtocolConstants.PROPERTY_JOB_ID); if (valueElement == null) { throw new SLAMDException("Job request message does not include the job " + "ID."); } else { try { jobID = valueElement.decodeAsOctetString().getStringValue(); } catch (Exception e) { throw new SLAMDException("Unable to decode the job ID: " + e, e); } } valueElement = propertyMap.get(ProtocolConstants.PROPERTY_JOB_CLASS_NAME); if (valueElement == null) { throw new SLAMDException("Job request message does not include the job " + "class name."); } else { try { jobClassName = valueElement.decodeAsOctetString().getStringValue(); } catch (Exception e) { throw new SLAMDException("Unable to decode the job class name: " + e, e); } } valueElement = propertyMap.get(ProtocolConstants.PROPERTY_JOB_CLASS_VERSION); if (valueElement != null) { try { jobClassVersion = valueElement.decodeAsInteger().getIntValue(); } catch (Exception e) { throw new SLAMDException("Unable to decode the job class version: " + e, e); } } valueElement = propertyMap.get(ProtocolConstants.PROPERTY_NUM_CLIENTS); if (valueElement == null) { throw new SLAMDException("Job request message does not include the " + "number of clients."); } else { try { numClients = valueElement.decodeAsInteger().getIntValue(); } catch (Exception e) { throw new SLAMDException("Unable to decode the number of clients: " + e, e); } } valueElement = propertyMap.get(ProtocolConstants.PROPERTY_THREADS_PER_CLIENT); if (valueElement == null) { throw new SLAMDException("Job request message does not include the " + "number of threads per client."); } else { try { numClients = valueElement.decodeAsInteger().getIntValue(); } catch (Exception e) { throw new SLAMDException("Unable to decode the number of threads per " + "client: " + e, e); } } valueElement = propertyMap.get(ProtocolConstants.PROPERTY_START_TIME); if (valueElement == null) { throw new SLAMDException("Job request message does not include the " + "start time."); } else { try { String startTimeStr = valueElement.decodeAsOctetString().getStringValue(); startTime = new Date(Long.parseLong(startTimeStr)); } catch (Exception e) { throw new SLAMDException("Unable to decode the start time: " + e, e); } } valueElement = propertyMap.get(ProtocolConstants.PROPERTY_STOP_TIME); if (valueElement != null) { try { String stopTimeStr = valueElement.decodeAsOctetString().getStringValue(); stopTime = new Date(Long.parseLong(stopTimeStr)); } catch (Exception e) { throw new SLAMDException("Unable to decode the stop time: " + e, e); } } valueElement = propertyMap.get(ProtocolConstants.PROPERTY_DURATION); if (valueElement != null) { try { duration = valueElement.decodeAsInteger().getIntValue(); } catch (Exception e) { throw new SLAMDException("Unable to decode the duration: " + e, e); } } valueElement = propertyMap.get(ProtocolConstants.PROPERTY_COLLECTION_INTERVAL); if (valueElement == null) { throw new SLAMDException("Job request message does not include the " + "statistics collection interval."); } else { try { collectionInterval = valueElement.decodeAsInteger().getIntValue(); } catch (Exception e) { throw new SLAMDException("Unable to decode the statistics collection " + "interval: " + e, e); } } valueElement = propertyMap.get(ProtocolConstants.PROPERTY_THREAD_STARTUP_DELAY); if (valueElement != null) { try { threadStartupDelay = valueElement.decodeAsInteger().getIntValue(); } catch (Exception e) { throw new SLAMDException("Unable to decode the thread startup " + "delay: " + e, e); } } valueElement = propertyMap.get(ProtocolConstants.PROPERTY_PARAMETER_LIST); if (valueElement == null) { throw new SLAMDException("Job request message does not include the " + "job parameter list."); } else { try { parameterList = ParameterList.decode(valueElement); } catch (Exception e) { throw new SLAMDException("Unable to decode the job parameter list: " + e, e); } } valueElement = propertyMap.get(ProtocolConstants.PROPERTY_REPORT_IN_PROGRESS_STATS); if (valueElement != null) { try { reportInProgressStats = valueElement.decodeAsBoolean().getBooleanValue(); } catch (Exception e) { throw new SLAMDException("Unable to decode the reportInProgressStats " + "flag: " + e, e); } } valueElement = propertyMap.get( ProtocolConstants.PROPERTY_IN_PROGRESS_REPORT_INTERVAL); if (valueElement != null) { try { inProgressReportInterval = valueElement.decodeAsInteger().getIntValue(); } catch (Exception e) { throw new SLAMDException("Unable to decode the in progress report " + "interval: " + e, e); } } valueElement = propertyMap.get(ProtocolConstants.PROPERTY_CLIENT_NUMBER); if (valueElement == null) { throw new SLAMDException("Job request message does not include the " + "client number."); } else { try { clientNumber = valueElement.decodeAsInteger().getIntValue(); } catch (Exception e) { throw new SLAMDException("Unable to decode the client number: " + e, e); } } } /** * Appends a string representation of the payload for this SLAMD message to * the provided buffer. The string representation may contain multiple lines, * but the last line should not end with an end-of-line marker. * * @param buffer The buffer to which the string representation is to be * appended. * @param indent The number of spaces to indent the payload content. */ @Override() public void payloadToString(StringBuilder buffer, int indent) { StringBuilder indentBuf = new StringBuilder(indent); for (int i=0; i < indent; i++) { indentBuf.append(' '); } buffer.append(indentBuf); buffer.append("jobID = "); buffer.append(jobID); buffer.append(Constants.EOL); buffer.append(indentBuf); buffer.append("jobClassName = "); buffer.append(jobClassName); buffer.append(Constants.EOL); if (jobClassVersion > 0) { buffer.append(indentBuf); buffer.append("jobClassVersion = "); buffer.append(jobClassVersion); buffer.append(Constants.EOL); } buffer.append(indentBuf); buffer.append("numClients = "); buffer.append(numClients); buffer.append(Constants.EOL); buffer.append(indentBuf); buffer.append("threadsPerClient = "); buffer.append(threadsPerClient); buffer.append(Constants.EOL); buffer.append(indentBuf); buffer.append("startTime = "); buffer.append(startTime); buffer.append(Constants.EOL); if (stopTime != null) { buffer.append(indentBuf); buffer.append("stopTime = "); buffer.append(stopTime); buffer.append(Constants.EOL); } if (duration > 0) { buffer.append(indentBuf); buffer.append("duration = "); buffer.append(duration); buffer.append(Constants.EOL); } buffer.append(indentBuf); buffer.append("collectionInterval = "); buffer.append(collectionInterval); buffer.append(Constants.EOL); buffer.append(indentBuf); buffer.append("threadStartupDelay = "); buffer.append(threadStartupDelay); buffer.append(Constants.EOL); buffer.append(indentBuf); buffer.append("parameterList ="); buffer.append(Constants.EOL); Parameter[] params = parameterList.getParameters(); for (int i=0; i < params.length; i++) { buffer.append(indentBuf); buffer.append(" "); buffer.append(params[i].getDisplayName()); buffer.append(" = "); buffer.append(params[i].getDisplayValue()); buffer.append(Constants.EOL); } buffer.append(indentBuf); buffer.append("reportInProgressStats = "); buffer.append(reportInProgressStats); buffer.append(Constants.EOL); if (reportInProgressStats) { buffer.append(indentBuf); buffer.append("inProgressResportInterval = "); buffer.append(inProgressReportInterval); buffer.append(Constants.EOL); } buffer.append(indentBuf); buffer.append("clientNumber = "); buffer.append(clientNumber); } }