/* * 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 java.util.StringTokenizer; import com.slamd.asn1.ASN1Element; import com.slamd.asn1.ASN1Enumerated; 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.stat.ResourceMonitorStatTracker; import com.slamd.stat.StatEncoder; import com.slamd.stat.StatTracker; /** * This class defines a SLAMD message that will be sent from the client to the * server whenever processing has been completed for a job. It will primarily * contain statistical information for the job. * * * @author Neil A. Wilson */ public class JobCompleted extends SLAMDMessage { // Information about any data files that might have been generated during job // processing that should be sent back to the server. private FileData[] fileData; // The actual length of time in seconds that the job was active. private int actualDuration; // The state of the job when processing was complete. private int jobState; // The time that the job actually started processing. private long actualStartTime; // The time that the job actually finished processing. private long actualStopTime; // The set of resource monitor statistics collected by the job. private ResourceMonitorStatTracker[] monitorStatTrackers; // The status counters maintained by the job. private StatTracker[] statTrackers; // The ID for the job being processed. private String jobID; // The set of messages that have been logged by the client. private String[] logMessages; /** * Creates a new instance of this job completed 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 JobCompleted() { super(); jobID = null; jobState = Constants.JOB_STATE_UNKNOWN; actualStartTime = -1; actualStopTime = -1; actualDuration = -1; statTrackers = new StatTracker[0]; monitorStatTrackers = new ResourceMonitorStatTracker[0]; fileData = new FileData[0]; logMessages = new String[0]; } /** * Creates a new instance of this job completed 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 associated job. * @param jobState The final state for the job. * @param actualStartTime The time that the job actually started processing. * @param actualStopTime The time that the job actually stopped processing. * @param actualDuration The length of time in seconds the job was active. * @param statTrackers The set of statistical information collected while * the job was running. * @param logMessages The set of log messages for the job. */ public JobCompleted(int messageID, HashMap<String,String> extraProperties, String jobID, int jobState, long actualStartTime, long actualStopTime, int actualDuration, StatTracker[] statTrackers, String[] logMessages) { super(messageID, extraProperties); this.jobID = jobID; this.jobState = jobState; this.actualStartTime = actualStartTime; this.actualStopTime = actualStopTime; this.actualDuration = actualDuration; if (statTrackers == null) { this.statTrackers = new StatTracker[0]; } else { this.statTrackers = statTrackers; } if (logMessages == null) { this.logMessages = new String[0]; } else { this.logMessages = logMessages; } monitorStatTrackers = new ResourceMonitorStatTracker[0]; fileData = new FileData[0]; } /** * Retrieves the job ID for the associated job. * * @return The job ID for the associated job. */ public String getJobID() { return jobID; } /** * Specifies the job ID for the associated job. * * @param jobID The job ID for the associated job. */ public void setJobID(String jobID) { this.jobID = jobID; } /** * Returns the final job state code for the job. * * @return The final job state code for the job. */ public int getJobState() { return jobState; } /** * Specifies the final job state code for the job. * * @param jobState The final job state code for the job. */ public void setJobState(int jobState) { this.jobState = jobState; } /** * Retrieves the time that the job actually started processing. * * @return The time that the job actually started processing. */ public long getActualStartTime() { return actualStartTime; } /** * Specifies the time that the job actually started processing. * * @param actualStartTime The time that the job actually started processing. */ public void setActualStartTime(long actualStartTime) { this.actualStartTime = actualStartTime; } /** * Retrieves the time that the job actually stopped processing. * * @return The time that the job actually stopped processing. */ public long getActualStopTime() { return actualStopTime; } /** * Specifies the time that the job actually stopped processing. * * @param actualStopTime The time that the job actually stopped processing. */ public void setActualStopTime(long actualStopTime) { this.actualStopTime = actualStopTime; } /** * Retrieves the length of time in seconds that the job was active. * * @return The length of time in seconds that the job was active. */ public int getActualDuration() { return actualDuration; } /** * Specifies the length of time in seconds that the job was active. * * @param actualDuration The length of time in seconds that the job was * active. */ public void setActualDuration(int actualDuration) { this.actualDuration = actualDuration; } /** * Retrieves the set of job statistics collected by the job. * * @return The set of job statistics collected by the job. */ public StatTracker[] getStatTrackers() { return statTrackers; } /** * Specifies the set of job statistics collected by the job. * * @param statTrackers The set of job statistics collected by the job. */ public void setStatTrackers(StatTracker[] statTrackers) { if (statTrackers == null) { this.statTrackers = new StatTracker[0]; } else { this.statTrackers = statTrackers; } } /** * Retrieves the set of resource monitor statistics collected by the job. * * @return The set of resource monitor statistics collected by the job. */ public ResourceMonitorStatTracker[] getResourceMonitorStatTrackers() { return monitorStatTrackers; } /** * Specifies the set of resource monitor statistics collected by the job. * * @param monitorStatTrackers The set of resource monitor statistics * collected by the job. */ public void setResourceMonitorStatTrackers(ResourceMonitorStatTracker[] monitorStatTrackers) { if (monitorStatTrackers == null) { this.monitorStatTrackers = new ResourceMonitorStatTracker[0]; } else { this.monitorStatTrackers = monitorStatTrackers; } } /** * Retrieves a set of information about any files generated during job * processing that should be uploaded to the server. * * @return A set of information about any files generated during job * processing that should be uploaded to the server. */ public FileData[] getFileData() { return fileData; } /** * Specifies a set of information about any files generated during job * processing that should be uploaded to the server. * * @param fileData A set of information about any files generated during * job processing that should be uploaded to the server. */ public void setFileData(FileData[] fileData) { if (fileData == null) { this.fileData = new FileData[0]; } else { this.fileData = fileData; } } /** * Retrieves the set of log messages generated during job processing. * * @return The set of log messages generated during job processing. */ public String[] getLogMessages() { return logMessages; } /** * Specifies the set of log messages generated during job processing. * * @param logMessages The set of log messages generated during job * processing. */ public void setLogMessages(String[] logMessages) { if (logMessages == null) { this.logMessages = new String[0]; } else { this.logMessages = logMessages; } } /** * 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_STATE, new ASN1Enumerated(jobState))); elementList.add(encodeNameValuePair( ProtocolConstants.PROPERTY_ACTUAL_START_TIME, new ASN1OctetString(String.valueOf(actualStartTime)))); elementList.add(encodeNameValuePair( ProtocolConstants.PROPERTY_ACTUAL_STOP_TIME, new ASN1OctetString(String.valueOf(actualStopTime)))); elementList.add(encodeNameValuePair( ProtocolConstants.PROPERTY_ACTUAL_DURATION, new ASN1Integer(actualDuration))); if ((statTrackers != null) && (statTrackers.length > 0)) { elementList.add(encodeNameValuePair( ProtocolConstants.PROPERTY_JOB_STATISTICS, StatEncoder.trackersToSequence(statTrackers))); } if ((monitorStatTrackers != null) && (monitorStatTrackers.length > 0)) { elementList.add(encodeNameValuePair( ProtocolConstants.PROPERTY_MONITOR_STATISTICS, ResourceMonitorStatTracker.trackersToSequence(monitorStatTrackers))); } if ((fileData != null) && (fileData.length > 0)) { elementList.add(encodeNameValuePair(ProtocolConstants.PROPERTY_FILE_DATA, FileData.encodeArray(fileData))); } if ((logMessages != null) && (logMessages.length > 0)) { // Although we could encode each message individually, that can cause a // very large performance hit for jobs with lots of log messages. // Instead, we'll concatenate it into a big string that we can decode // later. StringBuilder buffer = new StringBuilder(); for (int i=0; i < logMessages.length; i++) { buffer.append(logMessages[i]); buffer.append('\n'); } elementList.add(encodeNameValuePair( ProtocolConstants.PROPERTY_LOG_MESSAGES, new ASN1OctetString(buffer.toString()))); } 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 completed message does not include a 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_STATE); if (valueElement == null) { throw new SLAMDException("Job completed message does not include the " + "job state."); } else { try { jobState = valueElement.decodeAsEnumerated().getIntValue(); } catch (Exception e) { throw new SLAMDException("Unable to decode the job state: " + e, e); } } valueElement = propertyMap.get(ProtocolConstants.PROPERTY_ACTUAL_START_TIME); if (valueElement == null) { throw new SLAMDException("Job completed message does not include the " + "actual start time."); } else { try { actualStartTime = Long.parseLong(valueElement.decodeAsOctetString(). getStringValue()); } catch (Exception e) { throw new SLAMDException("Unable to decode the actual start time: " + e, e); } } valueElement = propertyMap.get(ProtocolConstants.PROPERTY_ACTUAL_STOP_TIME); if (valueElement == null) { throw new SLAMDException("Job completed message does not include the " + "actual stop time."); } else { try { actualStopTime = Long.parseLong(valueElement.decodeAsOctetString(). getStringValue()); } catch (Exception e) { throw new SLAMDException("Unable to decode the actual stop time: " + e, e); } } valueElement = propertyMap.get(ProtocolConstants.PROPERTY_ACTUAL_DURATION); if (valueElement == null) { throw new SLAMDException("Job completed message does not include the " + "actual duration."); } else { try { actualDuration = Integer.parseInt(valueElement.decodeAsOctetString(). getStringValue()); } catch (Exception e) { throw new SLAMDException("Unable to decode the actual duration: " + e, e); } } valueElement = propertyMap.get(ProtocolConstants.PROPERTY_JOB_STATISTICS); if (valueElement != null) { try { statTrackers = StatEncoder.sequenceToTrackers(valueElement.decodeAsSequence()); } catch (Exception e) { throw new SLAMDException("Unable to decode the job statistics: " + e, e); } } valueElement = propertyMap.get(ProtocolConstants.PROPERTY_MONITOR_STATISTICS); if (valueElement != null) { try { monitorStatTrackers = ResourceMonitorStatTracker.sequenceToTrackers( valueElement.decodeAsSequence()); } catch (Exception e) { throw new SLAMDException("Unable to decode the resource monitor " + "statistics: " + e, e); } } valueElement = propertyMap.get(ProtocolConstants.PROPERTY_FILE_DATA); if (valueElement != null) { try { fileData = FileData.decodeArray(valueElement); } catch (Exception e) { throw new SLAMDException("Unable to decode the file data: " + e, e); } } valueElement = propertyMap.get(ProtocolConstants.PROPERTY_LOG_MESSAGES); if (valueElement != null) { try { String messagesString = valueElement.decodeAsOctetString().getStringValue(); StringTokenizer tokenizer = new StringTokenizer(messagesString, "\r\n"); ArrayList<String> messageList = new ArrayList<String>(); while (tokenizer.hasMoreTokens()) { messageList.add(tokenizer.nextToken()); } logMessages = new String[messageList.size()]; messageList.toArray(logMessages); } catch (Exception e) { throw new SLAMDException("Unable to decode the file data: " + 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("jobState = "); buffer.append(jobState); buffer.append(" ("); buffer.append(Constants.jobStateToString(jobState)); buffer.append(')'); buffer.append(Constants.EOL); buffer.append(indentBuf); buffer.append("actualStartTime = "); buffer.append(new Date(actualStartTime)); buffer.append(Constants.EOL); buffer.append(indentBuf); buffer.append("actualStopTime = "); buffer.append(new Date(actualStopTime)); buffer.append(Constants.EOL); buffer.append(indentBuf); buffer.append("actualDuration = "); buffer.append(actualDuration); if ((statTrackers != null) && (statTrackers.length > 0)) { buffer.append(Constants.EOL); buffer.append(indentBuf); buffer.append("jobStatistics ="); for (int i=0; i < statTrackers.length; i++) { buffer.append(Constants.EOL); buffer.append(indentBuf); buffer.append(" "); buffer.append(statTrackers[i].getSummaryString()); } } if ((monitorStatTrackers != null) && (monitorStatTrackers.length > 0)) { buffer.append(Constants.EOL); buffer.append(indentBuf); buffer.append("monitorStatistics ="); for (int i=0; i < monitorStatTrackers.length; i++) { buffer.append(Constants.EOL); buffer.append(indentBuf); buffer.append(" "); buffer.append( monitorStatTrackers[i].getStatTracker().getSummaryString()); } } if ((fileData != null) && (fileData.length > 0)) { buffer.append(Constants.EOL); buffer.append(indentBuf); buffer.append("fileData ="); for (int i=0; i < fileData.length; i++) { buffer.append(Constants.EOL); fileData[i].toString(buffer, indent+5); } } if ((logMessages != null) && (logMessages.length > 0)) { buffer.append(Constants.EOL); buffer.append(indentBuf); buffer.append("logMessages ="); for (int i=0; i < logMessages.length; i++) { buffer.append(Constants.EOL); buffer.append(indentBuf); buffer.append(" "); buffer.append(logMessages[i]); } } } }