/** * Copyright (c) 2007-2009 Alysson Bessani, Eduardo Alchieri, Paulo Sousa, and the authors indicated in the @author tags * * This file is part of SMaRt. * * SMaRt 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. * * SMaRt 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 SMaRt. If not, see <http://www.gnu.org/licenses/>. */ package bftsmart.paxosatwar.messages; import java.io.IOException; import java.io.ObjectInput; import java.io.ObjectOutput; import bftsmart.communication.SystemMessage; /** * This class represents a message used in the paxos protocol. */ public class PaxosMessage extends SystemMessage { private int number; //execution ID for this message TODO: Shouldn't this be called 'eid'? private int round; // Round number to which this message belongs to private int paxosType; // Message type private byte[] value = null; // Value used when message type is PROPOSE private Object macVector; // Proof used when message type is COLLECT /** * Creates a paxos message. Not used. TODO: How about making it private? */ public PaxosMessage(){} /** * Creates a paxos message. Used by the message factory to create a COLLECT or PROPOSE message * TODO: How about removing the modifier, to make it visible just within the package? * @param paxosType This should be MessageFactory.COLLECT or MessageFactory.PROPOSE * @param id Consensus's execution ID * @param round Round number * @param from This should be this process ID * @param value This should be null if its a COLLECT message, or the proposed value if it is a PROPOSE message * @param proof The proof to be sent by the leader for all replicas */ public PaxosMessage(int paxosType, int id,int round,int from, byte[] value, Object proof){ super(from); this.paxosType = paxosType; this.number = id; this.round = round; this.value = value; this.macVector = proof; } /** * Creates a paxos message. Used by the message factory to create a WEAK, STRONG, or DECIDE message * TODO: How about removing the modifier, to make it visible just within the package? * @param paxosType This should be MessageFactory.WEAK, MessageFactory.STRONG or MessageFactory.DECIDE * @param id Consensus's execution ID * @param round Round number * @param from This should be this process ID * @param value The value decided, or strongly/weakly accepted */ public PaxosMessage(int paxosType, int id,int round,int from, byte[] value) { this(paxosType, id, round, from, value, null); } /** * Creates a paxos message. Used by the message factory to create a FREEZE message * TODO: How about removing the modifier, to make it visible just within the package? * @param paxosType This should be MessageFactory.FREEZE * @param id Consensus's execution ID * @param round Round number * @param from This should be this process ID */ public PaxosMessage(int paxosType, int id,int round, int from) { this(paxosType, id, round, from, null, null); } // Implemented method of the Externalizable interface @Override public void writeExternal(ObjectOutput out) throws IOException { super.writeExternal(out); out.writeInt(number); out.writeInt(round); out.writeInt(paxosType); if(value == null) { out.writeInt(-1); } else { out.writeInt(value.length); out.write(value); } if(paxosType == MessageFactory.STRONG || paxosType == MessageFactory.COLLECT) { out.writeObject(macVector); } } // Implemented method of the Externalizable interface @Override public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { super.readExternal(in); number = in.readInt(); round = in.readInt(); paxosType = in.readInt(); int toRead = in.readInt(); if(toRead != -1) { value = new byte[toRead]; do{ toRead -= in.read(value, value.length-toRead, toRead); } while(toRead > 0); } //WEAK, STRONG, DECIDE and FREEZE does not have associated proofs if(paxosType == MessageFactory.STRONG) { macVector = in.readObject(); } } /** * Retrieves the round number to which this message belongs * @return Round number to which this message belongs */ public int getRound() { return round; } /** * Retrieves the weakly accepted, strongly accepted, decided, or proposed value. * @return The value */ public byte[] getValue() { return value; } public void setMACVector(Object proof) { this.macVector = proof; } /** * Returns the proof associated with a PROPOSE or COLLECT message * @return The proof */ public Object getMACVector() { return macVector; } /** * Returns the consensus execution ID of this message * @return Consensus execution ID of this message */ public int getNumber() { return number; } /** * Returns this message type * @return This message type */ public int getPaxosType() { return paxosType; } /** * Returns this message type as a verbose string * @return Message type */ public String getPaxosVerboseType() { if (paxosType==MessageFactory.PROPOSE) return "PROPOSE"; else if (paxosType==MessageFactory.STRONG) return "STRONG"; else if (paxosType==MessageFactory.WEAK) return "WEAK"; else return ""; } @Override public String toString() { return "type="+getPaxosVerboseType()+", number="+getNumber()+", round="+ getRound()+", from="+getSender(); } }