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.simulator;
20
21 import java.net.InetAddress;
22 import java.net.UnknownHostException;
23 import java.rmi.ConnectException;
24 import java.rmi.NotBoundException;
25 import java.rmi.Remote;
26 import java.rmi.RemoteException;
27 import java.util.ArrayList;
28 import java.util.HashMap;
29 import java.util.Iterator;
30 import java.util.List;
31 import java.util.Map;
32 import java.util.Random;
33
34 import jgroup.core.registry.BootstrapRegistry;
35 import jgroup.util.log.Eventlogger;
36 import net.jini.export.Exporter;
37 import net.jini.jeri.BasicILFactory;
38 import net.jini.jeri.BasicJeriExporter;
39 import net.jini.jeri.tcp.TcpServerEndpoint;
40
41 import org.apache.log4j.Logger;
42
43 /**
44 * Implementation of the <code>SocketStatus</code> interface,
45 * allowing an external entity (the simulator) to set the status
46 * of particular links from the JVM hosting this instance of the
47 * SocketStatusImpl. Note that objects within the local JVM may
48 * obtain a reference to a "singlton" instance of this class, and
49 * thus query the link connectivity map through the
50 * <code>isReliable()</code> method.
51 *
52 * @author Alberto Montresor
53 * @author Hein Meling
54 * @since Jgroup 0.5
55 */
56 public class SocketStatusImpl
57 implements SocketStatus
58 {
59
60 ////////////////////////////////////////////////////////////////////////////////////////////
61 // Logger
62 ////////////////////////////////////////////////////////////////////////////////////////////
63
64 /** Obtain logger for this class */
65 private static final Logger log = Logger.getLogger(SocketStatusImpl.class);
66
67
68 ////////////////////////////////////////////////////////////////////////////////////////////
69 // Static fields
70 ////////////////////////////////////////////////////////////////////////////////////////////
71
72 /** Random number generator */
73 private static Random random = new Random();
74
75 /** The local socket status object */
76 private static SocketStatusImpl status = null;
77
78
79 ////////////////////////////////////////////////////////////////////////////////////////////
80 // Fields
81 ////////////////////////////////////////////////////////////////////////////////////////////
82
83 /** Connectivity map */
84 private transient Map<InetAddress,Integer> links = new HashMap<InetAddress, Integer>(20);
85
86 /** Connectivity map */
87 private transient Map<InetAddress,Integer> committedLinks = null;
88
89 /** SocketStatus objects listening for changes in the reachability patteren */
90 private transient List<SocketStatus> listeners = new ArrayList<SocketStatus>(3);
91
92
93 ////////////////////////////////////////////////////////////////////////////////////////////
94 // Constructor
95 ////////////////////////////////////////////////////////////////////////////////////////////
96
97 /**
98 * Constructs an instance of the <code>SocketStatusImpl</code> class.
99 * It is a private constructor to avoid construction from the outside.
100 * Use the <code>instance()</code> method to obtain the local single
101 * instance of the socket status class. This construtor is used when
102 * we know that there is no other <code>SocketStatus</code> instances
103 * on the local machine, and we can safely export and bind this socket
104 * status instance.
105 */
106 private SocketStatusImpl()
107 throws RemoteException
108 {
109 Exporter exporter =
110 new BasicJeriExporter(TcpServerEndpoint.getInstance(0), new BasicILFactory());
111 Remote socketStatusProxy = exporter.export(this);
112 try {
113 BootstrapRegistry.bind(SOCKET_STATUS, socketStatusProxy);
114 if (log.isDebugEnabled())
115 log.debug("Primary SocketStatus exported and bound...");
116 } catch (Exception e) {
117 log.warn("Failed to initialize the SocketStatusImpl class", e);
118 exporter.unexport(true);
119 }
120 }
121
122 /**
123 * This constructor is used when there exists another instance of the
124 * <code>SocketStatus</code>, possibly within another JVM on this machine.
125 * This instance of <code>SocketStatus</code> will export itself and
126 * register with the existing <code>SocketStatus</code> in order to be
127 * notified of changes to the reachability.
128 *
129 * @param st
130 * Reference to the existing <code>SocketStatus</code> remote object.
131 * @throws RemoteException
132 */
133 private SocketStatusImpl(SocketStatus st)
134 throws RemoteException
135 {
136 Exporter exporter =
137 new BasicJeriExporter(TcpServerEndpoint.getInstance(0), new BasicILFactory());
138 Remote ssProxy = exporter.export(this);
139 st.register((SocketStatus) ssProxy);
140 committedLinks = st.getStatus();
141 if (log.isDebugEnabled())
142 log.debug("Secondary SocketStatus object registered with the primary SocketStatus...");
143 }
144
145 /**
146 * Obtain the local instance of the socket status object.
147 */
148 public static SocketStatusImpl instance()
149 {
150 if (status != null) {
151 return status;
152 }
153 try {
154 try {
155 SocketStatus st = (SocketStatus) BootstrapRegistry.lookup(SOCKET_STATUS);
156 status = new SocketStatusImpl(st);
157 } catch (NotBoundException e) {
158 // Since we are the first SocketStatus object available on this host.
159 status = new SocketStatusImpl();
160 }
161 } catch (RemoteException e) {
162 log.info("Partition simulator not available", e);
163 return null;
164 }
165 log.info("Partition simulator activated");
166 return status;
167 }
168
169 ////////////////////////////////////////////////////////////////////////////////////////////
170 // Public access methods for the SocketStatusImpl class
171 ////////////////////////////////////////////////////////////////////////////////////////////
172
173 /**
174 * Check if the link to the given internet address is considered
175 * reliable.
176 */
177 public boolean isReliable(InetAddress address)
178 {
179 if (committedLinks == null) {
180 // no link probabilities have yet been committed
181 return true;
182 }
183 Integer prob = (Integer) committedLinks.get(address);
184 int val = (int) (random.nextFloat() * BASE);
185 return (prob == null || val < prob.intValue());
186 }
187
188
189 /**
190 * Check if the link to the given internet host is considered
191 * reliable.
192 */
193 public boolean isReliable(String hostname)
194 throws UnknownHostException
195 {
196 InetAddress inetAdr = InetAddress.getByName(hostname);
197 return isReliable(inetAdr);
198 }
199
200
201 ////////////////////////////////////////////////////////////////////////////////////////////
202 // Remote methods from the SocketStatus interface
203 ////////////////////////////////////////////////////////////////////////////////////////////
204
205 /* (non-Javadoc)
206 * @see jgroup.relacs.simulator.SocketStatus#register(jgroup.relacs.simulator.SocketStatus)
207 */
208 public void register(SocketStatus sStatus)
209 throws RemoteException
210 {
211 if (!listeners.contains(sStatus))
212 listeners.add(sStatus);
213 }
214
215 /* (non-Javadoc)
216 * @see jgroup.relacs.simulator.SocketStatus#commit()
217 */
218 public void commit()
219 throws RemoteException
220 {
221 if (log.isDebugEnabled())
222 log.debug("commit received");
223 doCommit();
224 }
225
226 private void doCommit()
227 throws RemoteException
228 {
229 committedLinks = new HashMap<InetAddress,Integer>(links);
230 for (Iterator<SocketStatus> iter = listeners.iterator(); iter.hasNext();) {
231 SocketStatus st = iter.next();
232 try {
233 st.notifyStatus(committedLinks);
234 } catch (ConnectException e) {
235 log.warn("Remote SocketStatus object no longer present", e);
236 /*
237 * Since the remote (machine local) socket status object appears
238 * to have crashed, we remove it from the set of listeners.
239 */
240 iter.remove();
241 }
242 }
243 }
244
245 /* (non-Javadoc)
246 * @see jgroup.relacs.simulator.SocketStatus#notifyStatus(java.util.HashMap)
247 */
248 public void notifyStatus(Map<InetAddress,Integer> committedLinks)
249 throws RemoteException
250 {
251 if (log.isDebugEnabled())
252 log.debug("notifyStatus received: " + committedLinks);
253 this.committedLinks = committedLinks;
254 // The following may occur multiple times depending on the number of
255 // listeners registered for link status events.
256 if (Eventlogger.ENABLED)
257 Eventlogger.logEventFlush("LinksCommitted");
258 }
259
260 /* (non-Javadoc)
261 * @see jgroup.relacs.simulator.SocketStatus#getStatus()
262 */
263 public Map<InetAddress,Integer> getStatus()
264 throws RemoteException
265 {
266 if (log.isDebugEnabled())
267 log.debug("getStatus received: " + committedLinks);
268 return committedLinks;
269 }
270
271 /* (non-Javadoc)
272 * @see jgroup.relacs.simulator.SocketStatus#setStatus(java.net.InetAddress, int)
273 */
274 public void setStatus(InetAddress inet, int prob)
275 throws RemoteException
276 {
277 if (log.isDebugEnabled())
278 log.debug("changed the reachability: "+inet+" "+prob);
279 if (prob >= BASE)
280 links.remove(inet);
281 else
282 links.put(inet, prob);
283 }
284
285
286 ////////////////////////////////////////////////////////////////////////////////////////////
287 // Object methods
288 ////////////////////////////////////////////////////////////////////////////////////////////
289
290 public String toString()
291 {
292 StringBuilder buf = new StringBuilder("[SocketStatusImpl: ");
293 buf.append("links.size=" + links.size());
294 if (committedLinks != null) {
295 buf.append(", committedLinks.size=" + committedLinks.size());
296 }
297 buf.append("]");
298 return buf.toString();
299 }
300
301 } // END SocketStatusImpl