PageRenderTime 56ms CodeModel.GetById 29ms RepoModel.GetById 0ms app.codeStats 1ms

/tags/release_3_2_1/appia/src/org/continuent/appia/protocols/gossipServer/GossipServerSession.java

https://github.com/joninvski/Appia
Java | 425 lines | 314 code | 55 blank | 56 comment | 65 complexity | a7fbae2febe0c3fec1084b02bee6ae0b MD5 | raw file
Possible License(s): Apache-2.0
  1. /**
  2. * Appia: Group communication and protocol composition framework library
  3. * Copyright 2006 University of Lisbon
  4. *
  5. * Licensed under the Apache License, Version 2.0 (the "License");
  6. * you may not use this file except in compliance with the License.
  7. * You may obtain a copy of the License at
  8. *
  9. * http://www.apache.org/licenses/LICENSE-2.0
  10. *
  11. * Unless required by applicable law or agreed to in writing, software
  12. * distributed under the License is distributed on an "AS IS" BASIS,
  13. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. * See the License for the specific language governing permissions and
  15. * limitations under the License.
  16. *
  17. * Initial developer(s): Alexandre Pinto and Hugo Miranda.
  18. * Contributor(s): See Appia web page for a list of contributors.
  19. */
  20. /**
  21. * Title: Apia<p>
  22. * Description: Protocol development and composition framework<p>
  23. * Copyright: Copyright (c) Alexandre Pinto & Hugo Miranda & Luis Rodrigues<p>
  24. * Company: F.C.U.L.<p>
  25. * @author Alexandre Pinto & Hugo Miranda & Luis Rodrigues
  26. * @version 1.0
  27. */
  28. package org.continuent.appia.protocols.gossipServer;
  29. import java.util.Vector;
  30. import java.io.PrintStream;
  31. import java.net.InetSocketAddress;
  32. import org.continuent.appia.core.*;
  33. import org.continuent.appia.core.events.SendableEvent;
  34. import org.continuent.appia.core.events.channel.ChannelInit;
  35. import org.continuent.appia.core.events.channel.Debug;
  36. import org.continuent.appia.core.message.Message;
  37. import org.continuent.appia.protocols.common.FIFOUndeliveredEvent;
  38. import org.continuent.appia.protocols.common.RegisterSocketEvent;
  39. import org.continuent.appia.protocols.group.AppiaGroupException;
  40. import org.continuent.appia.protocols.group.Endpt;
  41. import org.continuent.appia.protocols.group.Group;
  42. import org.continuent.appia.protocols.group.LocalState;
  43. import org.continuent.appia.protocols.group.ViewID;
  44. import org.continuent.appia.protocols.group.ViewState;
  45. import org.continuent.appia.protocols.group.events.GroupInit;
  46. import org.continuent.appia.protocols.group.heal.GossipOutEvent;
  47. import org.continuent.appia.protocols.group.intra.View;
  48. import org.continuent.appia.protocols.group.sync.BlockOk;
  49. import org.continuent.appia.protocols.utils.ParseUtils;
  50. import org.continuent.appia.xml.interfaces.InitializableSession;
  51. import org.continuent.appia.xml.utils.SessionProperties;
  52. public class GossipServerSession extends Session implements InitializableSession {
  53. public static final int DEFAULT_PORT=10000;
  54. public static final long DEFAULT_REMOVE_TIME=20000; // 20 secs
  55. public static final long DEFAULT_TIMER=1000; // 1 sec
  56. public static final String GROUP_NAME="Gossip Group";
  57. public GossipServerSession(Layer layer) {
  58. super(layer);
  59. if (debug != null) {
  60. if (debug instanceof PrintStream)
  61. this.debug=(PrintStream)debug;
  62. else
  63. this.debug=new PrintStream(debug);
  64. }
  65. }
  66. /**
  67. * Initializes the session using the parameters given in the XML configuration.
  68. * Possible parameters:
  69. * <ul>
  70. * <li><b>port</b> the port listening for clients.
  71. * <li><b>remove_time</b> time of inactivity of a client before it is removed. (in milliseconds)
  72. * <li><b>timer</b> the internal timer duration, ie, the heartbeat of the server. (in milliseconds)
  73. * <li><b>gossip</b> other known gossip servers in the format "[host][:port][,[host][:port]]...".
  74. * <li><b>debug</b> boolean indicating whether debug messages should be printed to stderr.
  75. * </ul>
  76. *
  77. * @param params The parameters given in the XML configuration.
  78. */
  79. public void init(SessionProperties params) {
  80. if (params.containsKey("port"))
  81. my_port=params.getInt("port");
  82. if (params.containsKey("remove_time"))
  83. remove_time=params.getLong("remove_time");
  84. if (params.containsKey("timer"))
  85. timer=params.getLong("timer");
  86. if (params.containsKey("gossip")) {
  87. try {
  88. gossips=ParseUtils.parseSocketAddressArray(params.getString("gossip"),null,DEFAULT_PORT);
  89. } catch (Exception ex) {
  90. ex.printStackTrace();
  91. System.exit(1);
  92. }
  93. }
  94. if (params.containsKey("debug")) {
  95. if (params.getBoolean("debug"))
  96. debug=System.err;
  97. }
  98. if (remove_time < timer)
  99. max_idle_count=1;
  100. else
  101. max_idle_count=(int)(remove_time / timer + ((remove_time % timer) > 0 ? 1 : 0));
  102. debug("Initiated:"+params);
  103. }
  104. public void handle(Event event) {
  105. // ChannelInit
  106. if (event instanceof ChannelInit)
  107. handleChannelInit((ChannelInit)event);
  108. // GossipOutEvent
  109. else if (event instanceof GossipOutEvent)
  110. handleGossipOutEvent((GossipOutEvent)event);
  111. // FIFOUndeliveredEvent
  112. else if (event instanceof FIFOUndeliveredEvent)
  113. handleUndelivered((FIFOUndeliveredEvent)event);
  114. // GossipServerTimer
  115. else if (event instanceof GossipServerTimer)
  116. handleTimer((GossipServerTimer)event);
  117. // GossipGroupEvent
  118. else if (event instanceof GossipGroupEvent)
  119. handleGossipGroupEvent((GossipGroupEvent)event);
  120. // BlockOk
  121. else if (event instanceof BlockOk)
  122. handleBlockOk((BlockOk)event);
  123. // View
  124. else if (event instanceof View)
  125. handleView((View)event);
  126. // RegisterSocketEvent
  127. else if (event instanceof RegisterSocketEvent)
  128. handleRegisterSocketEvent((RegisterSocketEvent)event);
  129. else {
  130. debug("Unwanted event (\""+event.getClass().getName()+"\") received. Continued...");
  131. try { event.go(); } catch (AppiaEventException ex) { ex.printStackTrace(); }
  132. }
  133. }
  134. private int my_port=DEFAULT_PORT;
  135. private InetSocketAddress[] gossips=null;
  136. private long remove_time=DEFAULT_REMOVE_TIME;
  137. private long timer=DEFAULT_TIMER;
  138. private int max_idle_count=-1;
  139. private Vector clients=new Vector();
  140. // Auxiliar, so we don't need to create one for every search
  141. private Client aux=new Client(null);
  142. private Channel groupChannel=null;
  143. private ViewState vs;
  144. private LocalState ls;
  145. private void handleChannelInit(ChannelInit ev) {
  146. try { ev.go(); } catch (AppiaEventException ex) { ex.printStackTrace(); }
  147. if (ev.getChannel().getChannelID().equals(GROUP_NAME+" Channel")) {
  148. try {
  149. RegisterSocketEvent rse=new RegisterSocketEvent(ev.getChannel(),Direction.DOWN,this);
  150. rse.go();
  151. } catch (AppiaEventException ex) {
  152. ex.printStackTrace();
  153. throw new AppiaError("GossipServerSession: impossible to register socket for group");
  154. }
  155. System.out.println("GossipServer (group) running");
  156. } else {
  157. try {
  158. RegisterSocketEvent rse=new RegisterSocketEvent(ev.getChannel(),Direction.DOWN,this,my_port);
  159. rse.go();
  160. } catch (AppiaEventException ex) {
  161. ex.printStackTrace();
  162. throw new AppiaError("GossipServerSession: impossible to register socket for clients");
  163. }
  164. try {
  165. GossipServerTimer gst=new GossipServerTimer(timer,ev.getChannel(),this,EventQualifier.ON);
  166. gst.go();
  167. } catch (AppiaException ex) {
  168. ex.printStackTrace();
  169. throw new AppiaError("GossipServerSession: impossible to set timer");
  170. }
  171. if (debug != null) {
  172. try {
  173. Debug d=new Debug(debug,ev.getChannel(),Direction.DOWN,this,EventQualifier.ON);
  174. d.go();
  175. } catch (AppiaEventException ex) {
  176. ex.printStackTrace();
  177. debug("impossible to send Debug");
  178. }
  179. }
  180. System.out.println("GossipServer (client) running");
  181. }
  182. }
  183. private void handleGossipOutEvent(GossipOutEvent ev) {
  184. aux.addr=ev.source;
  185. int i;
  186. if ((i=clients.indexOf(aux)) >= 0) {
  187. Client c=(Client)clients.get(i);
  188. c.idle_count=0;
  189. sendAll(c,ev);
  190. sendGroup(c);
  191. } else {
  192. Client c=new Client(aux.addr);
  193. clients.add(c);
  194. sendAll(c,ev);
  195. sendGroup(c);
  196. }
  197. }
  198. private void handleUndelivered(FIFOUndeliveredEvent ev) {
  199. aux.addr=((SendableEvent)ev.what).dest;
  200. clients.removeElement(aux);
  201. try { ev.go(); } catch (AppiaEventException ex) { ex.printStackTrace(); }
  202. }
  203. private void handleTimer(GossipServerTimer ev) {
  204. try { ev.go(); } catch (AppiaEventException ex) { ex.printStackTrace(); }
  205. int i;
  206. for (i=0 ; i < clients.size() ; i++) {
  207. Client c=(Client)clients.get(i);
  208. if (c.idle_count >= max_idle_count)
  209. clients.removeElementAt(i);
  210. c.idle_count++;
  211. }
  212. debugClients("handleTimer");
  213. }
  214. private void handleRegisterSocketEvent(RegisterSocketEvent ev) {
  215. if (!ev.getChannel().getChannelID().equals(GROUP_NAME+" Channel")) {
  216. try { ev.go(); } catch (AppiaEventException ex) { ex.printStackTrace(); }
  217. return;
  218. }
  219. if (ev.error)
  220. throw new AppiaError("GossipServerSession: error registering socket for group");
  221. try {
  222. if (gossips == null) {
  223. gossips=new InetSocketAddress[] { new InetSocketAddress(ev.localHost,my_port) };
  224. } else {
  225. int i;
  226. for (i=0 ; i < gossips.length ; i++)
  227. if (gossips[i].getAddress().equals(ev.localHost) && (gossips[i].getPort() == my_port))
  228. break;
  229. if (i >= gossips.length) {
  230. InetSocketAddress[] aux=new InetSocketAddress[gossips.length+1];
  231. System.arraycopy(gossips,0,aux,0,gossips.length);
  232. aux[gossips.length]=new InetSocketAddress(ev.localHost,my_port);
  233. gossips=aux;
  234. }
  235. }
  236. if (debug != null) {
  237. for (int i=0 ; i < gossips.length ; i++)
  238. debug("gossips["+i+"]: "+gossips[i]);
  239. }
  240. Endpt[] view=new Endpt[] { new Endpt() };
  241. InetSocketAddress[] addrs=new InetSocketAddress[] { new InetSocketAddress(ev.localHost, ev.port) };
  242. ViewState vs=new ViewState("1",new Group(GROUP_NAME),new ViewID(0,view[0]),new ViewID[0], view, addrs);
  243. GroupInit ginit=new GroupInit(vs,view[0],null,gossips,ev.getChannel(), Direction.DOWN, this);
  244. ginit.go();
  245. } catch (AppiaEventException e) {
  246. e.printStackTrace();
  247. } catch (NullPointerException e) {
  248. e.printStackTrace();
  249. } catch (AppiaGroupException e) {
  250. e.printStackTrace();
  251. }
  252. }
  253. private void handleGossipGroupEvent(GossipGroupEvent ev) {
  254. int naddrs=((Message)ev.getMessage()).popInt();
  255. while (naddrs > 0) {
  256. aux.addr=ev.getMessage().popObject();
  257. int i;
  258. if ((i=clients.indexOf(aux)) >= 0) {
  259. Client c=(Client)clients.get(i);
  260. c.idle_count=0;
  261. } else {
  262. Client c=new Client(aux.addr);
  263. clients.add(c);
  264. }
  265. naddrs--;
  266. }
  267. }
  268. private void handleBlockOk(BlockOk ev) {
  269. groupChannel=null;
  270. try { ev.go(); } catch (AppiaEventException ex) { ex.printStackTrace(); }
  271. }
  272. private void handleView(View ev) {
  273. try { ev.go(); } catch (AppiaEventException ex) { ex.printStackTrace(); }
  274. if ((vs != null) && ls.am_coord && (ev.vs.getNewMembers(vs).length > 0)) {
  275. try {
  276. GossipGroupEvent e=new GossipGroupEvent(ev.getChannel(), Direction.DOWN, this, ev.vs.group, ev.vs.id);
  277. Message emsg=(Message)e.getMessage();
  278. int i;
  279. for (i=0 ; i < clients.size() ; i++) {
  280. emsg.pushObject((InetSocketAddress)((Client)clients.get(i)).addr);
  281. }
  282. emsg.pushInt(clients.size());
  283. e.go();
  284. } catch (AppiaEventException ex) {
  285. ex.printStackTrace();
  286. }
  287. }
  288. vs=ev.vs;
  289. ls=ev.ls;
  290. groupChannel=ev.getChannel();
  291. }
  292. private void sendAll(Client sender, SendableEvent event) {
  293. int i;
  294. for (i=0 ; i < clients.size() ; i++) {
  295. Client c=(Client)clients.get(i);
  296. if (!sender.equals(c)) {
  297. try {
  298. SendableEvent ev=(SendableEvent)event.cloneEvent();
  299. ev.setDir(Direction.DOWN);
  300. ev.setSource(this);
  301. ev.init();
  302. ev.dest=c.addr;
  303. ev.go();
  304. debug("sending to "+((InetSocketAddress)ev.dest).toString());
  305. debug("\t from "+((InetSocketAddress)ev.source).toString());
  306. } catch (AppiaEventException ex) {
  307. ex.printStackTrace();
  308. debug("Unable to send to a client");
  309. } catch (CloneNotSupportedException ex) {
  310. ex.printStackTrace();
  311. debug("Unable to send to a client");
  312. }
  313. }
  314. }
  315. }
  316. private void sendGroup(Client sender) {
  317. if (groupChannel == null) {
  318. debug("Not sending to group because there isn't one.");
  319. return;
  320. }
  321. try {
  322. GossipGroupEvent ev=new GossipGroupEvent(groupChannel, Direction.DOWN, this, vs.group, vs.id);
  323. ev.getMessage().pushObject(sender.addr);
  324. (ev.getMessage()).pushInt(1);
  325. ev.go();
  326. } catch (AppiaEventException ex) {
  327. ex.printStackTrace();
  328. }
  329. }
  330. // DEBUG
  331. private PrintStream debug=null;
  332. private void debug(String s) {
  333. if (debug != null)
  334. debug.println("appia:gossipServer:GossipServerSession: "+s);
  335. }
  336. private void debugClients(String s) {
  337. if (debug != null) {
  338. debug.println("appia:gossipServer:GossipServerSession: "+s);
  339. debug.print("clients={");
  340. int i;
  341. for (i=0 ; i < clients.size() ; i++) {
  342. Client c=(Client)clients.get(i);
  343. debug.print("[("+((InetSocketAddress)c.addr).toString());
  344. debug.print("),"+c.idle_count);
  345. debug.print("] , ");
  346. }
  347. debug.println("}");
  348. }
  349. }
  350. /**
  351. *
  352. * This class defines a Client
  353. *
  354. * @version 1.0
  355. */
  356. private class Client {
  357. public Object addr;
  358. public int idle_count;
  359. public Client(Object addr) {
  360. this.addr=addr;
  361. idle_count=0;
  362. }
  363. public boolean equals(Object obj) {
  364. return (obj instanceof Client) && addr.equals(((Client)obj).addr);
  365. }
  366. public int hashCode() {
  367. return addr.hashCode();
  368. }
  369. }
  370. }