URingPaxos-master/src/java/ch/usi/da/paxos/message/Message.java
package ch.usi.da.paxos.message;
/* 
 * Copyright (c) 2013 Università della Svizzera italiana (USI)
 * 
 * This file is part of URingPaxos.
 *
 * URingPaxos is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * URingPaxos is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with URingPaxos.  If not, see <http://www.gnu.org/licenses/>.
 */

import java.io.Serializable;
import java.nio.ByteBuffer;
import java.util.zip.CRC32;

import ch.usi.da.paxos.api.PaxosRole;


/**
 * Name: Message<br>
 * Description: <br>
 * 
 * Creation date: Mar 31, 2012<br>
 * $Id$
 * 
 * @author Samuel Benz benz@geoid.ch
 */
public class Message implements Serializable {

	private static final long serialVersionUID = -4938636847085992695L;
	
	private final long instance;
	
	private final int sender;
	
	private final PaxosRole receiver;
	
	private final MessageType type;
	
	private final int ballot;
	
	private final int value_ballot; // version of the value 
	
	private final Value value;
	
	private int vote_count = 0;

	/**
	 * Public constructor
	 * 
	 * @param instance the instance number
	 * @param sender the sender id
	 * @param receiver the receiver id
	 * @param type the message type
	 * @param ballot the ballot number
	 * @param value the value (can be null)
	 */
	public Message(long instance,int sender,PaxosRole receiver,MessageType type,int ballot,Value value){
		this(instance,sender,receiver,type,ballot,-1,value);
	}

	/**
	 * Public constructor
	 * 
	 * @param instance the instance number
	 * @param sender the sender id
	 * @param receiver the receiver id
	 * @param type the message type
	 * @param ballot the ballot number
	 * @param value_ballot the ballot corresponding to the value
	 * @param value the value (can be null)
	 */
	public Message(long instance,int sender,PaxosRole receiver,MessageType type,int ballot,int value_ballot,Value value){
		this.instance = instance;
		this.sender = sender;
		this.receiver = receiver;
		this.type = type;
		this.ballot = ballot;
		this.value_ballot = value_ballot;
		this.value = value;
	}

	/**
	 * @return the instance
	 */
	public long getInstance() {
		return instance;
	}

	/**
	 * @return the sender
	 */
	public int getSender() {
		return sender;
	}

	/**
	 * @return the receiver
	 */
	public PaxosRole getReceiver() {
		return receiver;
	}

	/**
	 * @return the type
	 */
	public MessageType getType() {
		return type;
	}

	/**
	 * @return the ballot
	 */
	public int getBallot() {
		return ballot;
	}

	/**
	 * @return the value_ballot
	 */
	public int getValueBallot() {
		return value_ballot;
	}

	/**
	 * @return the value
	 */
	public Value getValue() {
		return value;
	}

	/**
	 * @return the vote counter
	 */
	public synchronized int getVoteCount(){
		return vote_count;
	}
	
	/**
	 * @param c set the vote counter
	 */
	public synchronized void setVoteCount(int c){
		vote_count = c;
	}
	
	/**
	 * Increment the vote counter
	 */
	public synchronized void incrementVoteCount(){
		vote_count = vote_count + 1;
	}
	
	public boolean equals(Object obj) {
		if(obj instanceof Message){
			Message m = (Message)obj;
            if(this.instance == m.instance &&
               this.ballot == m.ballot &&
               this.receiver == m.receiver &&
               this.sender == m.sender &&
               this.type == m.type &&
               (this.value != null ? this.value.equals(m.value) : true) &&
               this.value_ballot == m.value_ballot &&
               this.vote_count == m.vote_count){
                    return true;
            }
		}
		return false;
	}
	
	public String toString(){
		if(vote_count > 0){
			return (this.getType() + " from:" + this.getSender() + " to:" + this.getReceiver() + " instance:" + this.instance + " ballot:" + this.getBallot() + " v_ballot:" + this.getValueBallot() + " value:" + this.getValue() + " votes:" + vote_count);
		}else{
			return (this.getType() + " from:" + this.getSender() + " to:" + this.getReceiver() + " instance:" + this.instance + " ballot:" + this.getBallot() + " v_ballot:" + this.getValueBallot() + " value:" + this.getValue());
		}
	}
	
	/**
	 * An convenient way for wire representation 
	 * 
	 * @param m
	 * @return message byte array
	 */
	public static byte[] toWire(Message m){
		ByteBuffer buffer = ByteBuffer.allocate(length(m));
		toBuffer(buffer,m);
		return buffer.array();
		
		/*ByteArrayOutputStream bos = new ByteArrayOutputStream();
		ObjectOutput out = null; 
		try {
			out = new ObjectOutputStream(bos);
			out.writeObject(m);
			return bos.toByteArray();
		} catch (IOException e) {
			return new byte[0];
		} finally {
			try {
				bos.close();
			} catch (IOException e) {
			}
			if(out != null){
				try {
					out.close();
				} catch (IOException e) {
				}
			}
		}*/
	}
	
	/**
	 * This method is not really efficient; but convenient for std. IO
	 * 
	 * @param b
	 * @return Message object
	 */
	public static Message fromWire(byte[] b) {
		ByteBuffer buffer = ByteBuffer.wrap(b);
		try {
			return fromBuffer(buffer);
		} catch (Exception e) {
			return null;
		}
		
		/*ByteArrayInputStream bis = new ByteArrayInputStream(b);
		ObjectInput in = null;
		try {
			in = new ObjectInputStream(bis);
			return (Message) in.readObject();
		} catch (IOException e) {
			return null;
		} catch (ClassNotFoundException e) {
			return null;
		} finally {
			try {
				bis.close();
			} catch (IOException e) {
			}
			if(in != null){
				try {
					in.close();
				} catch (IOException e) {
				}
			}
		}*/
	}

	/**
	 * Get the Message length (without length prefix)
	 * 
	 * @param m
	 * @return length of the message on the wire (without length prefix)
	 */
	public static int length(Message m){
		int length = 32;
		if(m.getValue() != null){
			length = length + m.getValue().getByteID().length + 4 + m.getValue().getValue().length + 1;
		}
		return length;
	}

	/**
	 * Get the CRC32 of the Message (without the Value)
	 * 
	 * @param m
	 * @return crc32 of the message (without the Value)
	 */
	public static long getCRC32(Message m){
		if(m == null) return 0;
		CRC32 crc = new CRC32();
		crc.update((int)m.getInstance());
		crc.update(m.getSender());
		crc.update(m.getReceiver().getId());
		crc.update(m.getType().getId());
		crc.update(m.getBallot());
		crc.update(m.getValueBallot());		
		crc.update(m.getVoteCount());
		return crc.getValue();
	}
	
	/**
	 * This is the recommended way to serialize and send a Message trough NIO
	 * 
	 * @param b
	 * @param m
	 */
	public static void toBuffer(ByteBuffer b,Message m){
		// long  instance
		// int   sender
		// short role
		// short type
		// int   ballot
		// int   value_ballot
		// int   vote count
		// int   ID length (or -1)
		//   byte[]ID
		//   int   value length
		//   byte[]value
		b.putLong(m.getInstance());
		b.putInt(m.getSender());
		b.putShort((short)m.getReceiver().getId());
		b.putShort((short)m.getType().getId());
		b.putInt(m.getBallot());
		b.putInt(m.getValueBallot());		
		b.putInt(m.getVoteCount());
		if(m.getValue() != null){
			b.putInt(m.getValue().getByteID().length);
			b.put(m.getValue().getByteID());
			b.putInt(m.getValue().getValue().length);
			b.put(m.getValue().getValue());
			if(m.getValue().isBatch()){
				b.put((byte) 0x01);
			}else{
				b.put((byte) 0x00);
			}
		}else{
			b.putInt(-1);
		}		
	}

	/**
	 * This is the recommended way de-serialize and receive a Message trough NIO
	 * 
	 * @param buffer
	 * @return Message object
	 */
	public static Message fromBuffer(ByteBuffer buffer) throws Exception {
		long instance = buffer.getLong();
		int sender = buffer.getInt();
		PaxosRole role = PaxosRole.fromId(buffer.getShort());
		MessageType type = MessageType.fromId(buffer.getShort());
		int ballot = buffer.getInt();
		int value_ballot = buffer.getInt();
		int vote_count = buffer.getInt();
		int id_length = buffer.getInt();
		Value value = null;
		if(id_length >= 0){
			byte[] ib = new byte[id_length];
			buffer.get(ib);
			String id = new String(ib);
			int v_length = buffer.getInt();
			byte[] vb = new byte[v_length];
			buffer.get(vb);
			byte[] batch = new byte[1];
			buffer.get(batch);
			if(batch[0] > 0){
				value = new Value(id,vb,true);
			}else{
				value = new Value(id,vb,false);
			}
		}
		Message msg = new Message(instance,sender,role,type,ballot,value_ballot,value);
		msg.setVoteCount(vote_count);
		return msg;
	}
}
