View Javadoc

1   /*
2    * Copyright (c) 1998-2002 The Jgroup Team.
3    *
4    * This program is free software; you can redistribute it and/or modify
5    * it under the terms of the GNU Lesser General Public License version 2 as
6    * published by the Free Software Foundation.
7    *
8    * This program is distributed in the hope that it will be useful,
9    * but WITHOUT ANY WARRANTY; without even the implied warranty of
10   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11   * GNU Lesser General Public License for more details.
12   *
13   * You should have received a copy of the GNU Lesser General Public License
14   * along with this program; if not, write to the Free Software
15   * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
16   *
17   */
18  
19  package jgroup.relacs.types;
20  
21  import java.io.Externalizable;
22  import java.io.IOException;
23  import java.io.ObjectInput;
24  import java.io.ObjectOutput;
25  import java.util.HashSet;
26  import java.util.Set;
27  
28  import jgroup.core.MemberId;
29  import jgroup.core.View;
30  
31  
32  /**
33   *  This class implements the <code>jgroup.core.View</code> interface.
34   *
35   *  @author Alberto Montresor
36   *  @author Hein Meling
37   *  @since Jgroup 0.1
38   */
39  public class ViewImpl
40    implements View, Externalizable
41  {
42  
43    private static final long serialVersionUID = 5806351416950303803L;
44  
45    ////////////////////////////////////////////////////////////////////////////////////////////
46    // Fields
47    ////////////////////////////////////////////////////////////////////////////////////////////
48  
49    /** Group identifier */
50    private int gid;
51    
52    /** View identifier (unique and increasing for each new view) */
53    private long vid;
54  
55    /** The number of views merging into this one */
56    private int mergingViews;
57  
58    /** View composition */
59    private MemberId[] members;
60  
61  
62    ////////////////////////////////////////////////////////////////////////////////////////////
63    // Constructors
64    ////////////////////////////////////////////////////////////////////////////////////////////
65  
66    /**
67     *  Default constructor for externalization
68     */
69    public ViewImpl() { }
70  
71    /**
72     * Creates a view that contains no members; this kind of view is
73     * used only to detect group failures (failure of a single last member).
74     */
75    public ViewImpl(int gid)
76    {
77      this.gid = gid;
78      this.vid = 0;
79      this.mergingViews = 0;
80      members  = new MemberId[0];
81    }
82  
83    /**
84     * Creates a view composed by a single member and a single host; used
85     * to initialize members joining to a group.
86     */
87    public ViewImpl(int gid, long vid, MemberId me)
88    {
89      this.gid     = gid;
90      this.vid     = vid;
91      this.mergingViews = 0;
92      members = new MemberId[1];
93      members[0] = me;
94    }
95  
96    /**
97     * Creates a view composed by a set of hosts and members; used to create
98     * new view after receiving view messages.
99     * 
100    * @param mergingViews 
101    *   The number of views merging into this one.
102    */
103   public ViewImpl(int gid, long vid, int mergingViews, MemberId[] members)
104   {
105     this.gid     = gid;
106     this.vid     = vid;
107     this.mergingViews = mergingViews;
108     this.members = members;
109   }
110 
111   /**
112    * Clones a view.
113    */
114   public ViewImpl(View v)
115   {
116     this.gid     = v.getGid();
117     this.vid     = v.getVid();
118     this.mergingViews = v.mergingViews();
119     this.members = v.getMembers();
120   }
121 
122 
123   ////////////////////////////////////////////////////////////////////////////////////////////
124   // View interface methods
125   ////////////////////////////////////////////////////////////////////////////////////////////
126 
127   /**
128    *  Returns the identifier of the group for which this view has been
129    *  generated.
130    */
131   public int getGid()
132   {
133     return gid;
134   }
135 
136 
137   /**
138    *  Returns the identifier of this view
139    */
140   public long getVid()
141   {
142     return vid;
143   }
144 
145   /**
146    *  Returns the number of views (or partitions) merging into this view.
147    */
148   public int mergingViews()
149   {
150     return mergingViews;
151   }
152 
153   /**
154    *  Returns an array of <code>MemberId</code>s identifying the members
155    *  included in this view.
156    */
157   public MemberId[] getMembers()
158   {
159     return members.clone();
160   }
161 
162   /* (non-Javadoc)
163    * @see jgroup.core.View#getLeader()
164    */
165   public MemberId getLeader()
166   {
167     return members[0];
168   }
169 
170   /* (non-Javadoc)
171    * @see jgroup.core.View#isLeader(jgroup.core.MemberId)
172    */
173   public boolean isLeader(MemberId member)
174   {
175     /* If there is only one member, it is the leader. */
176     return members.length == 1 || member.equals(members[0]);
177   }
178 
179   /* (non-Javadoc)
180    * @see jgroup.core.View#commonMembers(jgroup.core.MemberId[])
181    */
182   public MemberId[] commonMembers(MemberId[] otherMembers)
183   {
184     if (otherMembers == null)
185       return getMembers();
186     Set<MemberId> commonMembers = new HashSet<MemberId>();
187     for (int i = 0; i < members.length; i++)
188       for (int j = 0; j < otherMembers.length; j++)
189         if (members[i].equals(otherMembers[j]))
190           commonMembers.add(members[i]);
191     return (MemberId[]) commonMembers.toArray(new MemberId[commonMembers.size()]);
192   }
193 
194   /* (non-Javadoc)
195    * @see jgroup.core.View#commonMembers(jgroup.core.View)
196    */
197   public MemberId[] commonMembers(View view)
198   {
199     if (this.equals(view))
200       return getMembers();
201     return commonMembers(((ViewImpl) view).members);
202   }
203 
204   /* (non-Javadoc)
205    * @see jgroup.core.View#newMembers(jgroup.core.View)
206    */
207   public MemberId[] newMembers(View previousView)
208   {
209     if (previousView == null)
210       return getMembers();
211     if (this.equals(previousView))
212       return new MemberId[0];
213     Set<MemberId> newMembers = new HashSet<MemberId>();
214     MemberId[] previousMembers = previousView.getMembers();
215     for (int i = 0; i < members.length; i++) {
216       boolean found = false;
217       for (int j = 0; !found && j < previousMembers.length; j++) {
218         if (members[i].equals(previousMembers[j])) {
219           found = true;
220         }
221       }
222       if (!found)
223         newMembers.add(members[i]);
224     }
225     return (MemberId[]) newMembers.toArray(new MemberId[newMembers.size()]);
226   }
227 
228   /* (non-Javadoc)
229    * @see jgroup.core.View#oldMembers(jgroup.core.View)
230    */
231   public MemberId[] oldMembers(View previousView)
232   {
233     if (previousView == null) {
234       // There are no old members, since the previous view is null
235       return new MemberId[0];
236     }
237     // This is the reverse case of newMembers()
238     return previousView.newMembers(this);
239   }
240 
241   /* (non-Javadoc)
242    *  @see jgroup.core.View#contains(jgroup.core.MemberId)
243    */
244   public boolean contains(MemberId memberId)
245   {
246     boolean found = false;
247     for (int i = 0; !found && i < members.length; i++) {
248       found = members[i].equals(memberId);
249     }
250     return found;
251   }
252   
253 
254   /* (non-Javadoc)
255    * @see jgroup.core.View#containsAll(jgroup.core.View)
256    */
257   public boolean containsAll(View view)
258   {
259     if (view == null)
260       return false;
261     // This is to avoid cloning, when using getMembers()
262     MemberId[] viewMembers = ((ViewImpl) view).members;
263     /*
264      * Check if the current view contains all members of the
265      * new view.
266      */ 
267     for (int i = 0; i < viewMembers.length; i++) {
268       if (!contains(viewMembers[i])) {
269         return false;
270       }
271     }
272     return true;
273   }
274 
275 
276   /* (non-Javadoc)
277    * @see jgroup.core.View#hasSameMembers(jgroup.core.View)
278    */
279   public boolean hasSameMembers(View prevView)
280   {
281     if (prevView == null || this.size() != prevView.size())
282       return false;
283     MemberId[] commonMembers = this.commonMembers(prevView);
284     if (commonMembers.length != prevView.size())
285       return false;
286     else
287       return true;
288   }
289 
290 
291   /**
292    *  Returns the number of members in this view.
293    */
294   public int size()
295   {
296     return members.length;
297   }
298 
299 
300   /* (non-Javadoc)
301    * @see jgroup.core.View#getMemberPosition(jgroup.core.MemberId)
302    */
303   public int getMemberPosition(MemberId id)
304   {
305     for (int i = 0; i < members.length; i++)
306       if (members[i].equals(id))
307         return i;
308     return -1;
309   }
310 
311 
312   /**
313    *  Returns true if the specified member is the member at the given
314    *  position; otherwise false is returned.
315    *
316    *  @param pos
317    *    The position in the view to check for equality with the given
318    *    member.  A negative position value is considered to indicate
319    *    a position from the end of the view array, while a positive
320    *    value indicate a position from the beginning of the view
321    *    array.  A position value outside the range of the view, will
322    *    always return false.
323    *  @param member
324    *    The member whose position to check.
325    *  @return 
326    *    True if the given member is at the specified position in this
327    *    view; false otherwise.
328    */
329   public boolean memberHasPosition(int pos, MemberId member)
330   {
331     /* A negative position runs from the end of the array. */
332     if (pos < 0)
333       pos = members.length + pos;
334 
335     /* Check if the given (or computed) position is possible. */
336     if (pos >= 0 && pos < members.length)
337       return members[pos].equals(member);
338     else 
339       return false;
340   }
341 
342   ////////////////////////////////////////////////////////////////////////////////////////////
343   // Methods from Object
344   ////////////////////////////////////////////////////////////////////////////////////////////
345 
346   /**
347    *  Compares two <code>View</code>s for content equality.
348    *
349    *  @param obj the Object to compare with
350    *  @return  true if these Objects are equal; false otherwise.
351    */
352   public boolean equals(Object obj)
353   {
354     if (obj == null)
355       return false;
356     if (obj == this)
357       return true;
358     if (obj instanceof ViewImpl) {
359       ViewImpl view = (ViewImpl) obj;
360       return (gid == view.gid && vid == view.vid);
361     }
362     return false;
363   }
364 
365 
366   /**
367    *  Prints the content of this view.
368    */
369   public String toString()
370   {
371     StringBuilder buf = new StringBuilder("\n  [GroupId: ");
372     buf.append(gid);
373     buf.append(", ViewId: ");
374     buf.append(vid);
375     buf.append(", Partitions: ");
376     buf.append(mergingViews);
377     buf.append("]\n  ");
378     for (int i = 0; i < members.length; i++) {
379       buf.append(members[i]);
380       if (i == 0)
381         buf.append(" [leader]\n  ");
382       else
383         buf.append("\n  ");
384     }
385     return buf.toString();
386   }
387 
388 
389   ////////////////////////////////////////////////////////////////////////////////////////////
390   // Methods from Externalizable
391   ////////////////////////////////////////////////////////////////////////////////////////////
392   
393   /**
394    *  Restores the content of this object from the marshalled data contained
395    *  in the specified input stream.
396    * 
397    *  @param in the stream to be read
398    */
399   public void readExternal(ObjectInput in)
400     throws IOException, ClassNotFoundException
401   {
402     gid = GroupId.unmarshal(in);
403     vid = ViewId.unmarshal(in);
404     mergingViews = in.readInt();
405     int len = GroupIndex.unmarshal(in);
406     members = new MemberId[len];
407     for (int i=0; i < len; i++) {
408       members[i] = new MemberIdImpl();
409       members[i].readExternal(in);
410     }
411   }
412 
413   /**
414    *  Marshals the content of this object to the specified output stream.
415    * 
416    *  @param out the stream to be written
417    */
418   public void writeExternal(ObjectOutput out)
419     throws IOException
420   {
421     GroupId.marshal(out, gid);
422     ViewId.marshal(out, vid);
423     out.writeInt(mergingViews);
424     GroupIndex.marshal(out, members.length);
425     for (int i=0; i < members.length; i++) {
426       members[i].writeExternal(out);
427     }
428   }
429   
430   public Object clone()
431   {
432     ViewImpl v = new ViewImpl();
433     v.gid = gid;
434     v.vid = vid;
435     v.members = members.clone();
436     v.mergingViews = mergingViews;
437     return v;    
438   }
439 
440 } // END ViewImpl