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.gm;
20  
21  import java.rmi.NotBoundException;
22  import java.rmi.RemoteException;
23  
24  import jgroup.core.GroupManager;
25  import jgroup.core.IID;
26  import jgroup.core.InternalGMIService;
27  import jgroup.core.JgroupException;
28  import jgroup.core.MemberId;
29  import jgroup.core.MembershipListener;
30  import jgroup.core.MembershipService;
31  import jgroup.core.View;
32  import jgroup.core.registry.RegistryService;
33  import jgroup.util.log.Eventlogger;
34  
35  import org.apache.log4j.Logger;
36  
37  
38  /**
39   *  The <code>NotifyLayer</code> class keeps track of IIDs in 
40   *  the current view, and compares this to the previous. If any
41   *  differences are found, the <code>NotifyLayer</code> will 
42   *  invoke an unbind on the dependable registry.
43   *
44   *  Note that for this layer should occur before the recovery
45   *  layer in the layer stack.  This is since otherwise we may
46   *  introduce a delay in the recovery layer view handling, and
47   *  this may lead this layer to perform IGMI multicasts in such
48   *  a manner that the membership service is unable to conclude
49   *  a new view agreement protocol that has already been started,
50   *  while processing the view in the recovery layer.
51   *
52   *  @author Henning Hommeland
53   *  @author Jo Andreas Lind
54   *  @since Jgroup 2.1
55   */
56  public class NotifyLayer
57    implements NotifyService, MembershipListener, InternalNotification
58  {
59  
60    ////////////////////////////////////////////////////////////////////////////////////////////
61    // Logger
62    ////////////////////////////////////////////////////////////////////////////////////////////
63  
64    /** Obtain logger for this class */
65    private static final Logger log = Logger.getLogger(NotifyLayer.class);
66  
67  
68    //////////////////////////////////////////////////////////////////////////////////////////
69    // Private fields
70    //////////////////////////////////////////////////////////////////////////////////////////
71  
72    /** The IID for this layer */
73    private IID iid;
74  
75    /** The RegistryService for this layer */
76    private RegistryService rs;
77  
78    /** This table contains IIDs from the previous view */
79    private Object[] iidTableOld = null;
80  
81    /** The GroupManager for this layer */
82    private GroupManager gm;
83  
84    /**
85     *  The internalNotifiaction will be used to invoke a internal 
86     *  group method invocation to get the most recent IID of the other
87     *  members so that the leader member can perform the unbind of
88     *  crashed members.
89     */
90    private InternalNotification internalNotification;
91  
92    /** We need the local MemberId to determine its position in the current view */
93    private MemberId id;
94  
95  
96    //////////////////////////////////////////////////////////////////////////////////////////
97    // Constructors
98    //////////////////////////////////////////////////////////////////////////////////////////
99  	
100   /**
101    *  Initializes a NotifyLayer
102    */
103   public NotifyLayer(GroupManager gm, RegistryService rs, MembershipService ms)
104   {
105     this.gm = gm;
106     this.rs = rs;
107     this.id = ms.getMyIdentifier();
108   }
109 	
110 	
111   ////////////////////////////////////////////////////////////////////////////////////////////
112   // Static factory
113   ////////////////////////////////////////////////////////////////////////////////////////////
114 
115   public static NotifyLayer getLayer(GroupManager gm, RegistryService rs, 
116                                      MembershipService ms, InternalGMIService igmi)
117   {
118     return new NotifyLayer(gm, rs, ms);
119   }
120 
121 
122   ////////////////////////////////////////////////////////////////////////////////////////////
123   // Layer methods
124   ////////////////////////////////////////////////////////////////////////////////////////////
125 
126   public void addListener(Object listener) {}
127 
128 
129   ////////////////////////////////////////////////////////////////////////////////////////////
130   // FinalizeLayer interface methods (invoked to complete the group manager construction)
131   ////////////////////////////////////////////////////////////////////////////////////////////
132 
133   /**
134    *  Complete the replica initialization, once all group manager components
135    *  have been initialized.
136    */
137   public void complete(Object server)
138     throws JgroupException
139   {
140     iid = rs.getIID();
141     if (log.isDebugEnabled()) {
142       log.debug("Binding identifier for this group manager: " + iid);
143     }
144     internalNotification = (InternalNotification) gm.getService(InternalNotification.class);
145   }
146 
147 
148   ////////////////////////////////////////////////////////////////////////////////////////////
149   // Methods from InternalNotification
150   ////////////////////////////////////////////////////////////////////////////////////////////	
151 
152   /**
153    *  This method returns the IID for this layer
154    */
155   public Object getIID()
156     throws RemoteException
157   {
158     if (log.isDebugEnabled()) {
159       log.debug("Returning binding identifier for this group manager: " + iid);
160     }
161     return iid;
162   }
163 
164 
165   ////////////////////////////////////////////////////////////////////////////////////////////
166   // Methods from MembershipListener
167   ////////////////////////////////////////////////////////////////////////////////////////////
168 
169   /**
170    *  The viewChange() method is invoked on the whole server
171    *  group when a view change occur.
172    */
173   public void viewChange(View view)
174   {
175     try {
176       Object[] iidTableNew = (Object[]) internalNotification.getIID();
177 
178       if (log.isDebugEnabled()) {
179         for (int i = 0; i < iidTableNew.length; i++) {
180           log.debug("new iids: " + iidTableNew[i]);
181         }
182       }
183 
184       /* The old table needs to be set in the first view change */
185       if (iidTableOld == null)
186         iidTableOld = iidTableNew;
187 
188       /* Compare old table with the new table and check unbind if necessary */
189       if (view.memberHasPosition(-1, id) && iidTableOld.length >= iidTableNew.length) {
190 
191         boolean found = false;
192         try {
193           for (int i = 0; i < iidTableOld.length; i++) {
194             found = false;
195             for (int j = 0; j < iidTableNew.length && found == false; j++) {
196               if (iidTableOld[i].equals(iidTableNew[j]))
197                 found = true;
198             }
199             if (!found) {
200               if (Eventlogger.ENABLED)
201                 Eventlogger.logEventFlush("Unbinding: " + iidTableOld[i]);
202               rs.unbind((IID) iidTableOld[i]);
203               if (Eventlogger.ENABLED)
204                 Eventlogger.logEventFlush("Unbound");
205             }
206           }
207         } catch (JgroupException je) {
208           log.warn("Could not unbind", je);
209         } catch (NotBoundException nbe) {
210           log.warn("Could not unbind; not bound anymore", nbe);
211         }
212 
213       }
214       iidTableOld = iidTableNew;
215     } catch (RemoteException re) {
216       log.warn("Could not obtain iid or unbind", re);
217     } 
218   }
219 
220   public void hasLeft() {}
221 
222   public void prepareChange() {}
223 
224 } // End NotifyLayer