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