package org.jgroups;
import org.jgroups.util.Util;
import java.io.*;
import java.util.ArrayList;
import java.util.List;
/**
* A view that is sent as a result of a cluster merge. Whenever a group splits into subgroups, e.g., due to
* a network partition, and later the subgroups merge back together, a MergeView instead of a View
* will be received by the application. The MergeView class is a subclass of View and contains as
* additional instance variable: the list of views that were merged. For example, if the group
* denoted by view V1:(p,q,r,s,t) splits into subgroups V2:(p,q,r) and V2:(s,t), the merged view
* might be V3:(p,q,r,s,t). In this case the MergeView would contain a list of 2 views: V2:(p,q,r)
* and V2:(s,t).
*
* @since 2.0
* @author Bela Ban
*/
public class MergeView extends View {
protected List<View> subgroups=null; // subgroups that merged into this single view (a list of Views)
/**
* Used by externalization
*/
public MergeView() {
}
/**
* 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.
* @param subgroups
* A list of Views representing the former subgroups
*/
public MergeView(ViewId vid, List<Address> members, List<View> subgroups) {
super(vid, members);
this.subgroups=subgroups;
}
/**
* 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.
* @param subgroups
* A list of Views representing the former subgroups
*/
public MergeView(Address creator, long id, List<Address> members, List<View> subgroups) {
super(creator, id, members);
this.subgroups=subgroups;
}
public List<View> getSubgroups() {
return subgroups;
}
public View copy() {
ViewId vid2=vid.copy();
List<Address> members2=members != null ? new ArrayList<Address>(members) : null;
List<View> subgroups2=subgroups != null ? new ArrayList<View>(subgroups) : null;
return new MergeView(vid2, members2, subgroups2);
}
public String toString() {
StringBuilder sb=new StringBuilder();
sb.append("MergeView::").append(super.toString());
if(subgroups != null && !subgroups.isEmpty()) {
sb.append(", subgroups=");
sb.append(Util.printListWithDelimiter(subgroups, ", ", Util.MAX_LIST_PRINT_SIZE));
}
return sb.toString();
}
public void writeTo(DataOutput out) throws Exception {
super.writeTo(out);
// write subgroups
int len=subgroups != null? subgroups.size() : 0;
out.writeShort(len);
if(len == 0)
return;
for(View v: subgroups) {
if(v instanceof MergeView)
out.writeBoolean(true);
else
out.writeBoolean(false);
v.writeTo(out);
}
}
public void readFrom(DataInput in) throws Exception {
super.readFrom(in);
short len=in.readShort();
if(len > 0) {
View v;
subgroups=new ArrayList<View>(len);
for(int i=0; i < len; i++) {
boolean is_merge_view=in.readBoolean();
v=is_merge_view? new MergeView() : new View();
v.readFrom(in);
subgroups.add(v);
}
}
}
public int serializedSize() {
int retval=super.serializedSize();
retval+=Global.SHORT_SIZE; // for size of subgroups vector
if(subgroups == null)
return retval;
for(View v: subgroups) {
retval+=Global.BYTE_SIZE; // boolean for View or MergeView
retval+=v.serializedSize();
}
return retval;
}
}