package eu.hgross.blaubot.admin;
import com.google.gson.Gson;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import eu.hgross.blaubot.messaging.BlaubotMessage;
/**
* Abstract class for AdminMessages. The admin messages are identified by their classifiers encoded as one byte.
* AdminMessages should be created using the {@link AdminMessageFactory}.
*
* @author Henning Gross {@literal (mail.to@henning-gross.de)}
*
*/
public abstract class AbstractAdminMessage {
/**
* The admin message header length in bytes.
* It is actually just a one byte discriminator.
*/
public static int HEADER_LENGTH = 1;
protected static final Gson gson = new Gson();
private static final ByteOrder BYTE_ORDER = ByteOrder.BIG_ENDIAN;
public static final byte CLASSIFIER_CENSUS_MESSAGE = 1;
public static final byte CLASSIFIER_NEW_PRINCE_MESSAGE = 2;
public static final byte CLASSIFIER_KEEP_ALIVE_MESSAGE = 3;
public static final byte CLASSIFIER_PRINCE_FOUND_A_KING_MESSAGE = 4;
public static final byte CLASSIFIER_BOW_DOWN_TO_NEW_KING = 5;
public static final byte CLASSIFIER_PRINCE_ACK = 6;
public static final byte CLASSIFIER_ADD_SUBSCRIPTION = 7;
public static final byte CLASSIFIER_REMOVE_SUBSCRIPTION = 8;
public static final byte CLASSIFIER_STRING_MESSAGE = 9;
public static final byte CLASSIFIER_SERVER_CONNECTION_AVAILABLE = 10;
public static final byte CLASSIFIER_SERVER_CONNECTION_DOWN = 11;
public static final byte CLASSIFIER_SERVER_CONNECTION_RELAY_PAYLOAD = 12;
public static final byte CLASSIFIER_CLOSE_SERVER_CONNECTION = 13;
public static final byte CLASSIFIER_DISCOVERED_DEVICE = 14;
public static final byte CLASSIFIER_FINISHED_HANDSHAKE = 15;
private byte classifier;
protected AbstractAdminMessage(BlaubotMessage message) {
ByteBuffer bb = ByteBuffer.wrap(message.getPayload());
bb.order(BYTE_ORDER);
classifier = bb.get();
AdminMessageFactory.validateClassifier(classifier);
this.setUpFromBytes(bb);
}
public AbstractAdminMessage(byte classifier) {
setClassifier(classifier);
}
protected void setClassifier(byte classifier) {
this.classifier = classifier;
};
public byte getClassifier() {
return classifier;
};
/**
* Gets this message's byte representation (NOT including the classifier)
* @return the payload as byte array
*/
protected abstract byte[] payloadToBytes();
/**
* Get this message's byte representation including the classifier bytes
*
* @return the serialized classifier and payload bytes
*/
protected byte[] classifierAndPayloadBytes() {
byte[] payloadBytes = payloadToBytes();
ByteBuffer bb = ByteBuffer.allocate(payloadBytes.length + 1);
bb.order(BYTE_ORDER);
bb.put(classifier);
bb.put(payloadBytes);
bb.flip();
return bb.array();
};
/**
* Should set the message's attributes based on the message's payload.
* The {@link ByteBuffer} contains the classifier bytes but it's current
* index will be set beyond that.
* @param messagePayloadAsBytes a ByteBuffer wrapped around the message's payload with it's current index set beyond the classifier bytes
*/
protected abstract void setUpFromBytes(ByteBuffer messagePayloadAsBytes);
/**
* Creates a {@link BlaubotMessage} representing this {@link AbstractAdminMessage}
* @return the {@link BlaubotMessage} representation
*/
public BlaubotMessage toBlaubotMessage() {
byte[] payload = classifierAndPayloadBytes();
BlaubotMessage r = new BlaubotMessage();
r.setPayload(payload);
r.getMessageType().setIsAdminMessage(true).setContainsPayload(true).setIsKeepAliveMessage(false).setIsFirstHop(false);
r.setPriority(BlaubotMessage.Priority.ADMIN);
return r;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + classifier;
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
AbstractAdminMessage other = (AbstractAdminMessage) obj;
if (classifier != other.classifier)
return false;
return true;
}
}