1. /*
  2. * @(#)ServerCommunicatorAdmin.java 1.15 03/12/19
  3. *
  4. * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
  5. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
  6. */
  7. package com.sun.jmx.remote.internal;
  8. import java.io.IOException;
  9. import com.sun.jmx.remote.util.ClassLogger;
  10. public abstract class ServerCommunicatorAdmin {
  11. public ServerCommunicatorAdmin(long timeout) {
  12. if (logger.traceOn()) {
  13. logger.trace("Constructor",
  14. "Creates a new ServerCommunicatorAdmin object "+
  15. "with the timeout "+timeout);
  16. }
  17. this.timeout = timeout;
  18. timestamp = 0;
  19. adminor = new Adminor();
  20. final Thread t = new Thread(adminor);
  21. t.setDaemon(true);
  22. t.start();
  23. }
  24. /**
  25. * Tells that a new request message is received.
  26. * A caller of this method should always call the method
  27. * <code>rspOutgoing</code> to inform that a response is sent out
  28. * for the received request.
  29. * @return the value of the termination flag:
  30. * <ul><code>true</code> if the connection is already being terminated,
  31. * <br><code>false</code> otherwise.</ul>
  32. */
  33. public boolean reqIncoming() {
  34. if (logger.traceOn()) {
  35. logger.trace("reqIncoming", "Receive a new request.");
  36. }
  37. synchronized(lock) {
  38. if (terminated) {
  39. logger.warning("reqIncoming",
  40. "The server has decided to close " +
  41. "this client connection.");
  42. }
  43. ++currentJobs;
  44. return terminated;
  45. }
  46. }
  47. /**
  48. * Tells that a response is sent out for a received request.
  49. * @return the value of the termination flag:
  50. * <ul><code>true</code> if the connection is already being terminated,
  51. * <br><code>false</code> otherwise.</ul>
  52. */
  53. public boolean rspOutgoing() {
  54. if (logger.traceOn()) {
  55. logger.trace("reqIncoming", "Finish a request.");
  56. }
  57. synchronized(lock) {
  58. if (--currentJobs == 0) {
  59. timestamp = System.currentTimeMillis();
  60. logtime("Admin: Timestamp=",timestamp);
  61. // tells the adminor to restart waiting with timeout
  62. lock.notify();
  63. }
  64. return terminated;
  65. }
  66. }
  67. /**
  68. * Called by this class to tell an implementation to do stop.
  69. */
  70. protected abstract void doStop();
  71. /**
  72. * Terminates this object.
  73. * Called only by outside, so do not need to call doStop
  74. */
  75. public void terminate() {
  76. if (logger.traceOn()) {
  77. logger.trace("terminate",
  78. "terminate the ServerCommunicatorAdmin object.");
  79. }
  80. synchronized(lock) {
  81. if (terminated) {
  82. return;
  83. }
  84. terminated = true;
  85. // tell Adminor to terminate
  86. lock.notify();
  87. }
  88. }
  89. // --------------------------------------------------------------
  90. // private classes
  91. // --------------------------------------------------------------
  92. private class Adminor implements Runnable {
  93. public void run() {
  94. boolean stopping = false;
  95. synchronized(lock) {
  96. if (timestamp == 0) timestamp = System.currentTimeMillis();
  97. logtime("Admin: timeout=",timeout);
  98. logtime("Admin: Timestamp=",timestamp);
  99. while(!terminated) {
  100. try {
  101. // wait until there is no more job
  102. while(!terminated && currentJobs != 0) {
  103. if (logger.traceOn()) {
  104. logger.trace("Adminor-run",
  105. "Waiting without timeout.");
  106. }
  107. lock.wait();
  108. }
  109. if (terminated) return;
  110. final long remaining = timeout + (timestamp -
  111. System.currentTimeMillis());
  112. logtime("Admin: remaining timeout=",remaining);
  113. if (remaining > 0) {
  114. if (logger.traceOn()) {
  115. logger.trace("Adminor-run",
  116. "Waiting with timeout: "+
  117. remaining + " ms remaining");
  118. }
  119. lock.wait(remaining);
  120. }
  121. if (currentJobs > 0) continue;
  122. final long elapsed =
  123. System.currentTimeMillis() - timestamp;
  124. logtime("Admin: elapsed=",elapsed);
  125. if (!terminated && elapsed > timeout) {
  126. if (logger.traceOn()) {
  127. logger.trace("Adminor-run",
  128. "timeout elapsed");
  129. }
  130. logtime("Admin: timeout elapsed! "+
  131. elapsed+">",timeout);
  132. // stopping
  133. terminated = true;
  134. stopping = true;
  135. break;
  136. }
  137. } catch (InterruptedException ire) {
  138. logger.warning("Adminor-run","Unexpected Exception: "+
  139. ire);
  140. logger.debug("Adminor-run",ire);
  141. return;
  142. }
  143. }
  144. }
  145. if (stopping) {
  146. if (logger.traceOn()) {
  147. logger.trace("Adminor-run", "Call the doStop.");
  148. }
  149. doStop();
  150. }
  151. }
  152. }
  153. private void logtime(String desc,long time) {
  154. timelogger.trace("synchro",desc+time);
  155. }
  156. // --------------------------------------------------------------
  157. // private variables
  158. // --------------------------------------------------------------
  159. private final Adminor adminor;
  160. private long timestamp;
  161. private final int[] lock = new int[0];
  162. private int currentJobs = 0;
  163. private long timeout;
  164. // state issue
  165. private boolean terminated = false;
  166. private static final ClassLogger logger =
  167. new ClassLogger("javax.management.remote.misc",
  168. "ServerCommunicatorAdmin");
  169. private static final ClassLogger timelogger =
  170. new ClassLogger("javax.management.remote.timeout",
  171. "ServerCommunicatorAdmin");
  172. }