bboss.org.jgroups.View Maven / Gradle / Ivy
The newest version!
package bboss.org.jgroups;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.Externalizable;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Vector;
import bboss.org.jgroups.util.Streamable;
import bboss.org.jgroups.util.Util;
/**
* A view is a local representation of the current membership of a group.
* Only one view is installed in a channel at a time.
* Views contain the address of its creator, an ID and a list of member addresses.
* These adresses are ordered, and the first address is always the coordinator of the view.
* This way, each member of the group knows who the new coordinator will be if the current one
* crashes or leaves the group.
* The views are sent between members using the VIEW_CHANGE event
* @author Bela Ban
* @version $Id: View.java,v 1.24 2009/12/17 16:37:19 belaban Exp $
*/
public class View implements Externalizable, Cloneable, Streamable {
/* A view is uniquely identified by its ViewID
* The view id contains the creator address and a Lamport time.
* The Lamport time is the highest timestamp seen or sent from a view.
* if a view change comes in with a lower Lamport time, the event is discarded.
*/
protected ViewId vid=null;
/**
* A list containing all the members of the view
* This list is always ordered, with the coordinator being the first member.
* the second member will be the new coordinator if the current one disappears
* or leaves the group.
*/
protected Vector members=null;
@Deprecated
protected Map payload=null;
private static final long serialVersionUID=7027860705519930293L;
/**
* creates an empty view, should not be used
*/
public View() {
}
/**
* Creates a new view
*
* @param vid The view id of this view (can not be null)
* @param members Contains a list of all the members in the view, can be empty but not null.
*/
public View(ViewId vid, Vector members) {
this.vid=vid;
this.members=members;
}
public View(ViewId vid, Collection members) {
this.vid=vid;
this.members=new Vector(members);
}
/**
* Creates a new view
*
* @param creator The creator of this view (can not be null)
* @param id The lamport timestamp of this view
* @param members Contains a list of all the members in the view, can be empty but not null.
*/
public View(Address creator, long id, Vector members) {
this(new ViewId(creator, id), members);
}
/**
* returns the view ID of this view
* if this view was created with the empty constructur, null will be returned
*
* @return the view ID of this view
*/
public ViewId getVid() {
return vid;
}
public ViewId getViewId() {return vid;}
/**
* returns the creator of this view
* if this view was created with the empty constructur, null will be returned
*
* @return the creator of this view in form of an Address object
*/
public Address getCreator() {
return vid != null ? vid.getCoordAddress() : null;
}
/**
* Returns a reference to the List of members (ordered)
* Do NOT change this list, hence your will invalidate the view
* Make a copy if you have to modify it.
*
* @return a reference to the ordered list of members in this view
*/
public Vector getMembers() {
return Util.unmodifiableVector(members);
}
/**
* returns true, if this view contains a certain member
*
* @param mbr - the address of the member,
* @return true if this view contains the member, false if it doesn't
* if the argument mbr is null, this operation returns false
*/
public boolean containsMember(Address mbr) {
return !(mbr == null || members == null) && members.contains(mbr);
}
public boolean equals(Object obj) {
if(!(obj instanceof View))
return false;
if(vid != null) {
int rc=vid.compareTo(((View)obj).vid);
if(rc != 0)
return false;
if(members != null && ((View)obj).members != null) {
return members.equals(((View)obj).members);
}
}
else {
if(((View)obj).vid == null)
return true;
}
return false;
}
public int hashCode() {
return vid != null? vid.hashCode() : 0;
}
/**
* returns the number of members in this view
*
* @return the number of members in this view 0..n
*/
public int size() {
return members == null ? 0 : members.size();
}
/**
* creates a copy of this view
*
* @return a copy of this view
*/
public Object clone() {
ViewId vid2=vid != null ? (ViewId)vid.clone() : null;
Vector members2=members != null ? new Vector(members) : null;
return new View(vid2, members2);
}
/**
* debug only
*/
public String printDetails() {
StringBuilder ret=new StringBuilder();
ret.append(vid).append("\n\t");
if(members != null) {
for(int i=0; i < members.size(); i++) {
ret.append(members.elementAt(i)).append("\n\t");
}
ret.append('\n');
}
return ret.toString();
}
/**
* Adds a key and value to the view. Since the payloads will be shipped around *with* the view, so the keys and
* values need to be serializable. Note that the total serialized size of all keys and values cannot
* exceed 65000 bytes !
* @param key
* @param value
* @deprecated Will be removed in 3.0
*/
public void addPayload(String key, Object value) {
if(payload == null) {
payload=new HashMap(7);
}
payload.put(key, value);
}
/**
*
* @param key
* @return
* @deprecated Will be removed in 3.0
*/
public Object removePayload(String key) {
return payload != null? payload.remove(key) : null;
}
/**
*
* @param key
* @return
* @deprecated Will be removed in 3.0
*/
public Object getPayload(String key) {
if(payload != null)
return payload.get(key);
return null;
}
public String toString() {
StringBuilder ret=new StringBuilder(64);
ret.append(vid).append(" ").append(members);
return ret.toString();
}
public void writeExternal(ObjectOutput out) throws IOException {
out.writeObject(vid);
out.writeObject(members);
if(payload != null && !payload.isEmpty()) {
out.writeBoolean(true);
out.writeObject(payload);
}
else {
out.writeBoolean(false);
}
}
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
vid=(ViewId)in.readObject();
members=(Vector)in.readObject();
if(in.readBoolean()) {
payload=(Map)in.readObject();
}
}
public void writeTo(DataOutputStream out) throws IOException {
// vid
if(vid != null) {
out.writeBoolean(true);
vid.writeTo(out);
}
else
out.writeBoolean(false);
// members:
Util.writeAddresses(members, out);
if(payload != null && !payload.isEmpty()) {
try {
byte buffer[]=Util.objectToByteBuffer(payload);
out.writeShort(buffer.length);
out.write(buffer, 0, buffer.length);
}
catch(Exception e) {
throw new IOException("could not write View payload");
}
}
else {
out.writeShort(0);
}
}
public void readFrom(DataInputStream in) throws IOException, IllegalAccessException, InstantiationException {
boolean b;
// vid:
b=in.readBoolean();
if(b) {
vid=new ViewId();
vid.readFrom(in);
}
// members:
members=(Vector)Util.readAddresses(in, Vector.class);
short payloadLength=in.readShort();
if(payloadLength > 0) {
byte[] buffer=new byte[payloadLength];
in.readFully(buffer);
try {
payload=(Map)Util.objectFromByteBuffer(buffer);
}
catch(Exception e) {
throw new IOException("Could not read View payload " + buffer.length);
}
}
}
public int serializedSize() {
int retval=Global.BYTE_SIZE; // presence for vid
if(vid != null)
retval+=vid.serializedSize();
retval+=Util.size(members);
retval+=Global.SHORT_SIZE; // presence for payload
if(payload != null) {
retval+=Util.sizeOf(payload);
}
return retval;
}
}