package org.jgroups.protocols.tom;
import org.jgroups.Address;
import org.jgroups.Global;
import org.jgroups.Header;
import org.jgroups.util.Util;
import java.io.DataInput;
import java.io.DataOutput;
import java.util.ArrayList;
import java.util.Collection;
/**
* The header for the Total Order Anycast (TOA) protocol
*
* @author Pedro Ruivo
* @since 3.1
*/
public class ToaHeader extends Header {
//type
public static final byte DATA_MESSAGE = 1 << 0;
public static final byte PROPOSE_MESSAGE = 1 << 1;
public static final byte FINAL_MESSAGE = 1 << 2;
public static final byte SINGLE_DESTINATION_MESSAGE = 1 << 3;
private byte type = 0;
private MessageID messageID; //address and sequence number
private long sequencerNumber;
private Collection<Address> destinations= new ArrayList<Address>();
public ToaHeader() {
messageID = new MessageID();
}
public MessageID getMessageID() {
return messageID;
}
public Address getOrigin() {
return messageID.getAddress();
}
public void addDestinations(Collection<Address> addresses) {
if(addresses != null && !addresses.isEmpty())
for(Address address: addresses)
if(!destinations.contains(address))
destinations.add(address);
}
public Collection<Address> getDestinations() {
return destinations;
}
public long getSequencerNumber() {
return sequencerNumber;
}
public void setSequencerNumber(long sequencerNumber) {
this.sequencerNumber = sequencerNumber;
}
public byte getType() {
return type;
}
@Override
public int size() {
return (int) (Global.BYTE_SIZE + messageID.serializedSize() + Util.size(sequencerNumber) +
Util.size(destinations));
}
@Override
public void writeTo(DataOutput out) throws Exception {
out.writeByte(type);
messageID.writeTo(out);
Util.writeLong(sequencerNumber, out);
Util.writeAddresses(destinations, out);
}
@Override
public void readFrom(DataInput in) throws Exception {
type = in.readByte();
messageID.readFrom(in);
sequencerNumber = Util.readLong(in);
destinations= (Collection<Address>) Util.readAddresses(in, ArrayList.class);
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("ToaHeader [")
.append("type=").append(type2String(type))
.append(", message_id=").append(messageID)
.append(", sequence_number=").append(sequencerNumber)
.append(", destinations=").append(destinations)
.append("]");
return sb.toString();
}
public static String type2String(byte type) {
switch(type) {
case DATA_MESSAGE: return "DATA_MESSAGE";
case PROPOSE_MESSAGE: return "PROPOSE_MESSAGE";
case FINAL_MESSAGE: return "FINAL_MESSAGE";
case SINGLE_DESTINATION_MESSAGE: return "SINGLE_DESTINATION_MESSAGE";
default: return "UNKNOWN";
}
}
public static ToaHeader createNewHeader(byte type, MessageID messageID) {
if (messageID == null) {
throw new NullPointerException("The message ID can't be null");
}
ToaHeader header = new ToaHeader();
header.setType(type);
header.setMessageID(messageID);
return header;
}
public static ToaHeader createSingleDestinationHeader() {
ToaHeader header = new ToaHeader();
header.setType(SINGLE_DESTINATION_MESSAGE);
return header;
}
private void setType(byte type) {
this.type = type;
}
private void setMessageID(MessageID messageID) {
this.messageID = messageID;
}
}