PageRenderTime 148ms CodeModel.GetById 45ms RepoModel.GetById 1ms app.codeStats 0ms

/BetAndUin/src/server/ConnectionWithServerManager.java

https://github.com/jpbarbosa/BetAndUin
Java | 393 lines | 228 code | 61 blank | 104 comment | 36 complexity | bd75001eac58a02eb6418b51e928874b MD5 | raw file
  1. package server;
  2. import java.io.IOException;
  3. import java.net.DatagramPacket;
  4. import java.net.DatagramSocket;
  5. import java.net.InetAddress;
  6. import java.net.Socket;
  7. import java.net.SocketException;
  8. import common.Constants;
  9. import messages.MessagesRepository;
  10. import messages.ReceiveServerMessages;
  11. /* Message types and their definitions:
  12. * I_WILL_BE_PRIMARY_SERVER:
  13. * -> This is the first message sent when the server is up, informing
  14. * the other server that it desires to be the primary server.
  15. * Then, it waits for a response from the other server, indicating
  16. * whether it is already the primary server or not.
  17. *
  18. * I_M_ALREADY_PRIMARY_SERVER:
  19. * -> Upon receiving a I_WILL_BE_PRIMARY_SERVER message, if it is
  20. * already primary server, it will send this message.
  21. *
  22. * OK:
  23. * -> Upon receiving a I_WILL_BE_PRIMARY_SERVER message, if it isn't
  24. * already the primary server, it will send this message. The use
  25. * of this message is unlikely.
  26. *
  27. * KEEP_ALIVE:
  28. * -> Message used by the main server to inform the secondary server
  29. * that it is functioning.
  30. */
  31. public class ConnectionWithServerManager extends Thread{
  32. /*Set to true if you want the program to display debugging messages.*/
  33. private boolean debugging = true;
  34. /* Connection variables. */
  35. private int serverPort;
  36. private int partnerPort;
  37. private MessagesRepository msgToReceiveList;
  38. private ReceiveServerMessages receiveMessenger;
  39. /* The lock to synchronize with the server. */
  40. private ChangeStatusLock statusLock;
  41. /* This variables is used when both servers decide, at the same time
  42. * that they should be the main server. When this happens and both of them
  43. * detect this inconsistency (two main servers), the one with a 'false' value
  44. * will give up from being main server.
  45. */
  46. private boolean isDefaultServer;
  47. /* Variables that checks whether this is the primary server or not. */
  48. private boolean isPrimaryServer = false;
  49. /*Variables related to the sending action.*/
  50. private DatagramSocket aSocket = null;
  51. /* The port to which we must connect to simulate the STONITH situation. */
  52. private int partnerStonithPort;
  53. private int stonithPort;
  54. public ConnectionWithServerManager(int sPort, int pPort, int sStonith, int pStonith, boolean isDefaultServer, ChangeStatusLock lock){
  55. serverPort = sPort;
  56. partnerPort = pPort;
  57. this.isDefaultServer = isDefaultServer;
  58. msgToReceiveList = new MessagesRepository();
  59. receiveMessenger = new ReceiveServerMessages(serverPort, msgToReceiveList, this);
  60. statusLock = lock;
  61. partnerStonithPort = pStonith;
  62. stonithPort = sStonith;
  63. /* Initializes the UDP socket to send messages to the other server. */
  64. try {
  65. aSocket = new DatagramSocket();
  66. } catch (SocketException e) {
  67. System.out.println("Socket (ConnectionWithServerManager Constructor): " + e.getMessage());
  68. }
  69. this.start();
  70. }
  71. public void run(){
  72. String partnerAnswer = "NOT_RECEIVED"; //By default
  73. int repetitions = 0; // In this variable, we count the number of times we tried to send
  74. // the first message to our partner.
  75. int limit = 3; //The upper limit of these retries.
  76. /* When the server is up, it sends the first message,
  77. * corresponding to the I_WILL_BE_PRIMARY_SERVER.
  78. */
  79. while (repetitions < limit){
  80. sendMessage("I_WILL_BE_PRIMARY_SERVER");
  81. /* Then, it waits for the other server to respond,
  82. * acting accordingly to the answer received (or not
  83. * received at all...) .
  84. */
  85. try {
  86. Thread.sleep(Constants.FIRST_WAITING_TIME);
  87. } catch (InterruptedException e) {
  88. /* We have just received an answer.
  89. * So, we can go off this cycle.
  90. */
  91. break;
  92. }
  93. repetitions++;
  94. }
  95. /* This means the other server hasn't responded. */
  96. if (repetitions == limit){
  97. /* Now, we have to test the STONITH scenario. */
  98. /* TODO: We have to change this local host. */
  99. Socket s = null;
  100. try {
  101. s = new Socket("localHost", partnerStonithPort);
  102. /* The other server is alive. */
  103. partnerAnswer = "I_M_ALREADY_PRIMARY_SERVER";
  104. isPrimaryServer = false;
  105. if (debugging){
  106. System.out.println("The STONITH link confirmed the other server is alive.");
  107. }
  108. } catch (Exception e) {
  109. /* The other server is dead, so, it's not only a link's problem. */
  110. partnerAnswer = "NOT_RECEIVED";
  111. isPrimaryServer = true;
  112. if (debugging){
  113. System.out.println("The STONITH link confirmed the other server is really dead.");
  114. }
  115. } finally {
  116. /* We close the socket that simulates the STONITH link. */
  117. if (s != null){
  118. try {
  119. s.close();
  120. } catch (IOException e) {
  121. System.out.println("close:" + e.getMessage());
  122. }
  123. }
  124. }
  125. }
  126. /* We initialize and start the STONITH Manager, that will accept any connections
  127. * in case the other server tries to connect. */
  128. new StonithManager(stonithPort, partnerPort, this);
  129. while(true){
  130. if (debugging){
  131. System.out.println("I'm primary server?: " + isPrimaryServer);
  132. }
  133. synchronized(msgToReceiveList){
  134. /* We have some messages to read. */
  135. if (msgToReceiveList.listSize() > 0){
  136. partnerAnswer = msgToReceiveList.getMsg();
  137. }
  138. }
  139. /* We are now the primary server. */
  140. if ((partnerAnswer.equals("OK"))
  141. || (partnerAnswer.equals("I_WILL_BE_PRIMARY_SERVER"))){
  142. if (debugging){
  143. System.out.println("ConnectionWithServerManager: We fulfilled the first condition.");
  144. }
  145. isPrimaryServer = true;
  146. /* Informs that parent server about its status. */
  147. synchronized (statusLock){
  148. statusLock.setInitialProcessConcluded(true);
  149. statusLock.setPrimaryServer(true);
  150. if (statusLock.hasChangedStatus()){
  151. statusLock.notifyAll();
  152. }
  153. }
  154. /* We can now terminate the receiveMensager, it won't be needed any longer. */
  155. if (debugging){
  156. System.out.println("We are going to terminate the receive messenger thread.");
  157. }
  158. receiveMessenger.terminateThread();
  159. sendTerminateMessage();
  160. while(true){
  161. /* Once we are the main server, we will only give up from
  162. * that position if the server crashes.
  163. * Consequently, we enter this endless cycle, always sending
  164. * KEEP_ALIVE messages hoping the system does never fail.
  165. */
  166. try {
  167. Thread.sleep(Constants.KEEP_ALIVE_TIME);
  168. } catch (InterruptedException e) {
  169. /* We have received a message, so keep going.
  170. /* However, this shouldn't happen, as we have
  171. * terminate the receving thread up there.
  172. * Therefore, it's like to be something else.
  173. */
  174. }
  175. sendMessage("KEEP_ALIVE");
  176. }
  177. }
  178. /* We are now the secondary server. If we get here. */
  179. else if(partnerAnswer.equals("KEEP_ALIVE")
  180. || partnerAnswer.equals("I_M_ALREADY_PRIMARY_SERVER")
  181. /* The partner isn't considered dead, so it is likely that we have
  182. * just sent the first message. */
  183. || (partnerAnswer.equals("I_WILL_BE_PRIMARY_SERVER") && !isDefaultServer)){
  184. if (debugging){
  185. System.out.println("ConnectionWithServerManager: We fulfilled the third condition.");
  186. }
  187. isPrimaryServer = false;
  188. /* Informs that parent server about its status. */
  189. synchronized (statusLock){
  190. statusLock.setInitialProcessConcluded(true);
  191. statusLock.setPrimaryServer(false);
  192. if (statusLock.hasChangedStatus()){
  193. statusLock.notifyAll();
  194. }
  195. }
  196. }
  197. /* If we ever get here, it means that we are not the primary server.*/
  198. while (!isPrimaryServer){
  199. if (debugging){
  200. System.out.println("ConnectionWithServerManager: We fulfilled the fourth condition.");
  201. }
  202. try {
  203. Thread.sleep(Constants.SERVER_WAITING_TIME);
  204. } catch (InterruptedException e) {
  205. /* A message has arrived before the timeout. */
  206. synchronized(msgToReceiveList){
  207. while (msgToReceiveList.listSize() > 0){
  208. partnerAnswer = msgToReceiveList.getMsg();
  209. /* Our partner has informed us that it is still alive. */
  210. if (partnerAnswer.equals("KEEP_ALIVE")){
  211. continue;
  212. }
  213. /* The other server has crashed but recover before the
  214. * timeout occurred. So, it will still be the primary server.
  215. */
  216. else if (partnerAnswer.equals("I_WILL_BE_PRIMARY_SERVER")){
  217. sendMessage("OK");
  218. }
  219. } // while
  220. continue;
  221. }// synchronized (msgToReceiveList)
  222. }// catch (InterruptedException e);
  223. /* If we ever get here, it means that the partner hasn't answer before
  224. * the timeout occurred. Consequently, we have to test the STONITH link
  225. * to know if we are really going to be the primary server.
  226. */
  227. /* We have to test the STONITH scenario. */
  228. /* TODO: We have to change this local host. */
  229. Socket s = null;
  230. try {
  231. s = new Socket("localHost", partnerStonithPort);
  232. /* The other server is alive. */
  233. isPrimaryServer = false;
  234. /* We have to send a message to the other server, because
  235. * when the primary server doesn't get an answer from its
  236. * partner, it considers the partner dead and to stop wasting
  237. * link resources, stops sending messages.
  238. * Consequently, we have to send a message from this side in
  239. * case the link recovered and to make the primary server
  240. * start sending messages again.
  241. */
  242. sendMessage("I_WILL_BE_PRIMARY_SERVER");
  243. if (debugging){
  244. System.out.println("The STONITH link confirmed the other server is alive.");
  245. }
  246. } catch (Exception e) {
  247. /* The other server is dead, so, it's not only a link's problem. */
  248. isPrimaryServer = true;
  249. /* Informs the parent thread about its status. */
  250. synchronized (statusLock){
  251. statusLock.setPrimaryServer(true);
  252. if (statusLock.hasChangedStatus()){
  253. statusLock.notifyAll();
  254. }
  255. }
  256. if (debugging){
  257. System.out.println("The STONITH link confirmed the other server is really dead.");
  258. }
  259. } finally {
  260. /* We close the socket that simulates the STONITH link. */
  261. if (s != null){
  262. try {
  263. s.close();
  264. } catch (IOException e) {
  265. System.out.println("close:" + e.getMessage());
  266. }
  267. }
  268. }
  269. }// while (!isPrimaryServer)
  270. try {
  271. /* We will sleep till the other server sends a sign (i.e. a message)
  272. * that it's alive and communicating. Meanwhile, it's pointless
  273. * to waste both local and network resources by sending messages.
  274. */
  275. if (debugging){
  276. System.out.println("We are now going to stop sending messages till our partner " +
  277. " sends us a message.");
  278. }
  279. /* Informs that parent server about its status. */
  280. synchronized (statusLock){
  281. statusLock.setInitialProcessConcluded(true);
  282. statusLock.setPrimaryServer(true);
  283. if (statusLock.hasChangedStatus()){
  284. statusLock.notifyAll();
  285. }
  286. }
  287. synchronized(msgToReceiveList){
  288. msgToReceiveList.wait();
  289. }
  290. } catch (InterruptedException e) {
  291. /* Our partner has awaken! */
  292. }
  293. }// while(true) from high above!
  294. }
  295. public void sendMessage(String msgToSend){
  296. /* Sends a message to the partner port. */
  297. if (debugging){
  298. System.out.println("We are sending " + msgToSend + " to the other server, in port " + partnerPort + ".");
  299. }
  300. try {
  301. byte [] m = msgToSend.getBytes();
  302. InetAddress aHost = InetAddress.getByName("localhost");
  303. DatagramPacket request = new DatagramPacket(m,m.length,aHost,partnerPort);
  304. aSocket.send(request);
  305. } catch (IOException e){
  306. System.out.println("IO from sendMessage (ConnectionWithServerManager): " + e.getMessage());
  307. } catch (Exception e){
  308. System.out.println("Exception from sendMessage (ConnectionWithServerManager): " + e.getMessage());
  309. }
  310. }
  311. public void sendTerminateMessage(){
  312. /* Sends a terminate thread message to our receive messenger. */
  313. String message = "TERMINATE THREAD";
  314. if (debugging){
  315. System.out.println("We are sending a terminate thread message.");
  316. }
  317. try {
  318. byte [] m = message.getBytes();
  319. InetAddress aHost = InetAddress.getByName("localhost");
  320. DatagramPacket request = new DatagramPacket(m,m.length,aHost,serverPort);
  321. aSocket.send(request);
  322. } catch (IOException e){
  323. System.out.println("IO from sendTerminateThread (ConnectionWithServerManager): " + e.getMessage());
  324. }
  325. }
  326. /* This method is used when we want to simulate the STONITH scenario and cause
  327. * failure on the link
  328. */
  329. public void setPartnetPort(int port){
  330. partnerPort = port;
  331. }
  332. }