package lsr.paxos.messages;
import java.io.DataInputStream;
import java.io.IOException;
import java.io.Serializable;
import java.nio.ByteBuffer;
/**
* Base class for all messages. Every message requires to know the view number
* of the sender.
* <p>
* To implement new message, it is required to override the
* <code>byteSize()</code> method and implement <code>write()</code> method. See
* subclasses implementation for details how they should be implemented.
*/
public abstract class Message implements Serializable {
private static final long serialVersionUID = 1L;
protected final int view;
private long sentTime;
/**
* Creates message from specified view number and current time.
*
* @param view - current view number
*/
protected Message(int view) {
this(view, System.currentTimeMillis());
}
/**
* Creates new message from specified view number and sent time.
*
* @param view - current view number
* @param sentTime - time when the message was sent
*/
protected Message(int view, long sentTime) {
this.view = view;
this.sentTime = sentTime;
}
/**
* Creates new message from input stream with serialized message inside.
*
* @param input - the input stream with serialized message
* @throws IOException if I/O error occurs
*/
protected Message(DataInputStream input) throws IOException {
view = input.readInt();
sentTime = input.readLong();
}
/**
* Sets the time when the message was sent.
*
* @param sentTime - the time when the message was sent in milliseconds
*/
public void setSentTime(long sentTime) {
this.sentTime = sentTime;
}
/**
* Returns the time when the message was sent.
*
* @return the time when the message was sent in milliseconds.
*/
public long getSentTime() {
return sentTime;
}
/**
* Sets the sent time to the current time.
*/
public void setSentTime() {
sentTime = System.currentTimeMillis();
}
/**
* Returns the view number stored in this message.
*
* @return the view number
*/
public int getView() {
return view;
}
/**
* The size of the message after serialization in bytes.
*
* @return the size of the message in bytes
*/
public int byteSize() {
return 1 + 4 + 8;
}
/**
* Returns a message as byte array. The size of the array is equal to
* <code>byteSize()</code>.
*
* @return serialized message to byte array
*/
public final byte[] toByteArray() {
// Create with the byte array of the exact size,
// to prevent internal resizes
ByteBuffer bb = ByteBuffer.allocate(byteSize());
bb.put((byte) getType().ordinal());
bb.putInt(view);
bb.putLong(sentTime);
write(bb);
assert bb.remaining() == 0 : "Wrong sizes. Limit=" + bb.limit() + ",capacity=" +
bb.capacity() + ",position=" + bb.position();
return bb.array();
}
public final void writeTo(ByteBuffer bb) {
bb.put((byte) getType().ordinal());
bb.putInt(view);
bb.putLong(sentTime);
write(bb);
}
/**
* Returns the type of the message. This method is implemented by subclasses
* and should return correct message type.
*
* @return the type of the message
*/
public abstract MessageType getType();
public String toString() {
return "v:" + getView();
}
/**
* When serializing message to byte array, this function is called on the
* message. Implementation of message-specific fields serialization must go
* there.
*
* @param bb - the byte buffer to serialize fields to
*/
protected abstract void write(ByteBuffer bb);
}