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