/*
* 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.message;
import java.io.IOException;
import java.io.ObjectOutputStream;
import com.slamd.asn1.ASN1Element;
import com.slamd.asn1.ASN1Exception;
import com.slamd.asn1.ASN1Sequence;
import com.slamd.common.SLAMDException;
/**
* This class defines a generic message that can be sent between the client and
* the server to request some operation or provide information. Subclasses will
* define the actual messages that may be sent.
*
*
* @author Neil A. Wilson
*/
public abstract class Message
{
/**
* The ASN.1 type for a client hello message.
*/
public static final byte ASN1_TYPE_CLIENT_HELLO = 0x60;
/**
* The ASN.1 type for a server hello message.
*/
public static final byte ASN1_TYPE_SERVER_HELLO = 0x61;
/**
* The ASN.1 type for a hello response message.
*/
public static final byte ASN1_TYPE_HELLO_RESPONSE = 0x62;
/**
* The ASN.1 type for a job request messages.
*/
public static final byte ASN1_TYPE_JOB_REQUEST = 0x63;
/**
* The ASN.1 type for a job response message.
*/
public static final byte ASN1_TYPE_JOB_RESPONSE = 0x64;
/**
* The ASN.1 type for a job control request message.
*/
public static final byte ASN1_TYPE_JOB_CONTROL_REQUEST = 0x65;
/**
* The ASN.1 type for a job control response message.
*/
public static final byte ASN1_TYPE_JOB_CONTROL_RESPONSE = 0x66;
/**
* The ASN.1 type for a job completed message.
*/
public static final byte ASN1_TYPE_JOB_COMPLETED = 0x67;
/**
* The ASN.1 type for a status request message.
*/
public static final byte ASN1_TYPE_STATUS_REQUEST = 0x68;
/**
* The ASN.1 type for a status response message.
*/
public static final byte ASN1_TYPE_STATUS_RESPONSE = 0x69;
/**
* The ASN.1 type for a server shutdown message.
*/
public static final byte ASN1_TYPE_SERVER_SHUTDOWN = 0x4A;
/**
* The ASN.1 type for a keepalive message.
*/
public static final byte ASN1_TYPE_KEEPALIVE = 0x4B;
/**
* The ASN.1 type for a file transfer request message.
*/
public static final byte ASN1_TYPE_CLASS_TRANSFER_REQUEST = 0x4C;
/**
* The ASN.1 type for a file transfer response message.
*/
public static final byte ASN1_TYPE_CLASS_TRANSFER_RESPONSE = 0x6D;
/**
* The ASN.1 type for a client manager hello message.
*/
public static final byte ASN1_TYPE_CLIENT_MANAGER_HELLO = 0x6E;
/**
* The ASN.1 type for a start client request.
*/
public static final byte ASN1_TYPE_START_CLIENT_REQUEST = 0x6F;
/**
* The ASN.1 type for a start client response.
*/
public static final byte ASN1_TYPE_START_CLIENT_RESPONSE = 0x70;
/**
* The ASN.1 type for a stop client request.
*/
public static final byte ASN1_TYPE_STOP_CLIENT_REQUEST = 0x51;
/**
* The ASN.1 type for a stop client response.
*/
public static final byte ASN1_TYPE_STOP_CLIENT_RESPONSE = 0x72;
/**
* The ASN.1 type for a register stat message.
*/
public static final byte ASN1_TYPE_REGISTER_STAT = 0x73;
/**
* The ASN.1 type for a report stat message.
*/
public static final byte ASN1_TYPE_REPORT_STAT = 0x74;
/**
* A unique (per connection) identifier that is included in both a request and
* a response to help determine which responses are associated with which
* requests.
*/
protected final int messageID;
// An indicator that allows the client and server to determine what kind of
// message this is.
private final int messageType;
/**
* Creates a new generic message of the specified type.
*
* @param messageID The message ID for this message.
* @param messageType The message type.
*/
protected Message(int messageID, int messageType)
{
this.messageID = messageID;
this.messageType = messageType;
}
/**
* Retrieves the message ID for this message.
*
* @return The message ID for this message.
*/
public int getMessageID()
{
return messageID;
}
/**
* Retrieves the message type for this message.
*
* @return The message type for this message.
*/
public int getMessageType()
{
return messageType;
}
/**
* Sends this message over the provided output stream. This can be used by
* either the client or the server to send the message to the other side.
*
* @param objectOutputStream The output stream over which to send the
* message.
*
* @throws IOException If there is a problem sending the message over the
* output stream.
*/
public void send(ObjectOutputStream objectOutputStream)
throws IOException
{
objectOutputStream.writeObject(this);
objectOutputStream.flush();
}
/**
* Retrieves a string representation of this message.
*
* @return A string representation of this message.
*/
@Override()
public String toString()
{
String eol = System.getProperty("line.separator");
return "SLAMD Message" + eol +
" Message Type: " + messageType + eol +
" Message ID: " + messageID + eol;
}
/**
* Encodes this message into an ASN.1 element.
*
* @return An ASN.1 encoded representation of this message.
*/
public abstract ASN1Element encode();
/**
* Decodes the provided ASN.1 element as a message.
*
* @param element The ASN.1 element to be decoded.
*
* @return The decoded version of the ASN.1 element.
*
* @throws SLAMDException If the provided element cannot be decoded to a
* valid message.
*/
public static Message decode(ASN1Element element)
throws SLAMDException
{
ASN1Sequence messageSequence = null;
try
{
messageSequence = element.decodeAsSequence();
}
catch (ASN1Exception ae)
{
throw new SLAMDException("Could not decode the provided ASN.1 element " +
"as a sequence: " + ae, ae);
}
ASN1Element[] elements = messageSequence.getElements();
if (elements.length != 2)
{
throw new SLAMDException("There must be 2 elements in a SLAMD message " +
"sequence -- got " + elements.length +
" elements");
}
int messageID = 0;
try
{
messageID = elements[0].decodeAsInteger().getIntValue();
}
catch (ASN1Exception ae)
{
throw new SLAMDException("Could not decode the message ID element as " +
"an integer", ae);
}
switch (elements[1].getType())
{
case ASN1_TYPE_CLIENT_HELLO:
return ClientHelloMessage.decodeClientHello(messageID,
elements[1]);
case ASN1_TYPE_SERVER_HELLO:
return ServerHelloMessage.decodeServerHello(messageID,
elements[1]);
case ASN1_TYPE_HELLO_RESPONSE:
return HelloResponseMessage.decodeHelloResponse(messageID,
elements[1]);
case ASN1_TYPE_JOB_REQUEST:
return JobRequestMessage.decodeJobRequest(messageID,
elements[1]);
case ASN1_TYPE_JOB_RESPONSE:
return JobResponseMessage.decodeJobResponse(messageID,
elements[1]);
case ASN1_TYPE_JOB_CONTROL_REQUEST:
return
JobControlRequestMessage.decodeJobControlRequest(
messageID, elements[1]);
case ASN1_TYPE_JOB_CONTROL_RESPONSE:
return
JobControlResponseMessage.decodeJobControResponse(
messageID, elements[1]);
case ASN1_TYPE_JOB_COMPLETED:
return JobCompletedMessage.decodeJobCompleted(messageID,
elements[1]);
case ASN1_TYPE_STATUS_REQUEST:
return StatusRequestMessage.decodeStatusRequest(messageID,
elements[1]);
case ASN1_TYPE_STATUS_RESPONSE:
return StatusResponseMessage.decodeStatusResponse(messageID,
elements[1]);
case ASN1_TYPE_SERVER_SHUTDOWN:
return ServerShutdownMessage.decodeShutdown(messageID,
elements[1]);
case ASN1_TYPE_KEEPALIVE:
return KeepAliveMessage.decodeKeepAlive(messageID, elements[1]);
case ASN1_TYPE_CLASS_TRANSFER_REQUEST:
return
ClassTransferRequestMessage.decodeTransferRequest(messageID,
elements[1]);
case ASN1_TYPE_CLASS_TRANSFER_RESPONSE:
return ClassTransferResponseMessage.
decodeTransferResponse(messageID, elements[1]);
case ASN1_TYPE_CLIENT_MANAGER_HELLO:
return
ClientManagerHelloMessage.decodeClientManagerHello(messageID,
elements[1]);
case ASN1_TYPE_START_CLIENT_REQUEST:
return StartClientRequestMessage.decodeStartClient(messageID,
elements[1]);
case ASN1_TYPE_START_CLIENT_RESPONSE:
return StartClientResponseMessage.
decodeStartClientResponse(messageID, elements[1]);
case ASN1_TYPE_STOP_CLIENT_REQUEST:
return StopClientRequestMessage.decodeStopClient(messageID,
elements[1]);
case ASN1_TYPE_STOP_CLIENT_RESPONSE:
return
StopClientResponseMessage.decodeStopClientResponse(messageID,
elements[1]);
case ASN1_TYPE_REGISTER_STAT:
return RegisterStatisticMessage.
decodeRegisterStatMessage(messageID, elements[1]);
case ASN1_TYPE_REPORT_STAT:
return ReportStatisticMessage.decodeReportStatMessage(messageID,
elements[1]);
default:
throw new SLAMDException("Unknown message body element type: " +
elements[1].getType());
}
}
}