WaitingRoom.java 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127
  1. package com.serotonin.cdc.messaging;
  2. import java.util.HashMap;
  3. import java.util.Map;
  4. /**
  5. * The waiting room is a place for request messages to hang out while awaiting their responses.
  6. *
  7. * @author Matthew Lohbihler
  8. */
  9. class WaitingRoom {
  10. private final Map/* <WaitingRoomKey, Member> */waitHere = new HashMap();
  11. private WaitingRoomKeyFactory keyFactory;
  12. void setKeyFactory(WaitingRoomKeyFactory keyFactory) {
  13. this.keyFactory = keyFactory;
  14. }
  15. /**
  16. * The request message should be sent AFTER entering the waiting room so that the (vanishingly small) chance of a
  17. * response being returned before the thread is waiting for it is eliminated.
  18. *
  19. * @return
  20. */
  21. void enter(WaitingRoomKey key) {
  22. Member member = new Member();
  23. synchronized (this) {
  24. while (waitHere.get(key) != null) {
  25. try {
  26. wait();
  27. }
  28. catch (InterruptedException e) {
  29. // no op
  30. }
  31. }
  32. // Member dup = waitHere.get(key);
  33. // if (dup != null) {
  34. //
  35. // throw new WaitingRoomException("Waiting room too crowded. Already contains the key " + key);
  36. // }
  37. waitHere.put(key, member);
  38. }
  39. }
  40. IncomingResponseMessage getResponse(WaitingRoomKey key, long timeout) throws WaitingRoomException {
  41. // Get the member.
  42. Member member;
  43. synchronized (this) {
  44. member = (Member) waitHere.get(key);
  45. }
  46. if (member == null)
  47. throw new WaitingRoomException("No member for key " + key);
  48. // Wait for the response.
  49. return member.getResponse(timeout);
  50. }
  51. void leave(WaitingRoomKey key) {
  52. // Leave the waiting room
  53. synchronized (this) {
  54. waitHere.remove(key);
  55. // Notify any threads that are waiting to get in. This could probably be just a notify() call.
  56. notifyAll();
  57. }
  58. }
  59. /**
  60. * This method is used by the data listening thread to post responses as they are received from the transport.
  61. *
  62. * @param response
  63. * the response message
  64. * @throws WaitingRoomException
  65. */
  66. void response(IncomingResponseMessage response) throws WaitingRoomException {
  67. WaitingRoomKey key = keyFactory.createWaitingRoomKey(response);
  68. Member member;
  69. synchronized (this) {
  70. member = (Member) waitHere.get(key);
  71. }
  72. if (member != null)
  73. member.setResponse(response);
  74. else
  75. throw new WaitingRoomException("No recipient was found waiting for response for key " + key);
  76. }
  77. /**
  78. * This class is used by network message controllers to manage the blocking of threads sending confirmed messages.
  79. * The instance itself serves as a monitor upon which the sending thread can wait (with a timeout). When a response
  80. * is received, the message controller can set it in here, automatically notifying the sending thread that the
  81. * response is available.
  82. *
  83. * @author Matthew Lohbihler
  84. */
  85. class Member {
  86. private IncomingResponseMessage response;
  87. synchronized void setResponse(IncomingResponseMessage response) {
  88. this.response = response;
  89. notify();
  90. }
  91. synchronized IncomingResponseMessage getResponse(long timeout) {
  92. // Check if there is a response object now.
  93. if (response != null)
  94. return response;
  95. // If not, wait the timeout and then check again.
  96. waitNoThrow(timeout);
  97. return response;
  98. }
  99. private void waitNoThrow(long timeout) {
  100. try {
  101. wait(timeout);
  102. }
  103. catch (InterruptedException e) {
  104. // Ignore
  105. }
  106. }
  107. }
  108. }