1. /*
  2. * @(#)ClientCommunicatorAdmin.java 1.14 04/05/12
  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 java.io.InterruptedIOException;
  10. import com.sun.jmx.remote.util.ClassLogger;
  11. import com.sun.jmx.remote.util.EnvHelp;
  12. public abstract class ClientCommunicatorAdmin {
  13. public ClientCommunicatorAdmin(long period) {
  14. this.period = period;
  15. if (period > 0) {
  16. checker = new Checker();
  17. Thread t = new Thread(checker);
  18. t.setDaemon(true);
  19. t.start();
  20. } else
  21. checker = null;
  22. }
  23. /**
  24. * Called by a client to inform of getting an IOException.
  25. */
  26. public void gotIOException (IOException ioe) throws IOException {
  27. restart(ioe);
  28. }
  29. /**
  30. * Called by this class to check a client connection.
  31. */
  32. protected abstract void checkConnection() throws IOException;
  33. /**
  34. * Tells a client to re-start again.
  35. */
  36. protected abstract void doStart() throws IOException;
  37. /**
  38. * Tells a client to stop becaue failing to call checkConnection.
  39. */
  40. protected abstract void doStop();
  41. /**
  42. * Terminates this object.
  43. */
  44. public void terminate() {
  45. synchronized(lock) {
  46. if (state == TERMINATED) {
  47. return;
  48. }
  49. state = TERMINATED;
  50. lock.notifyAll();
  51. if (checker != null)
  52. checker.stop();
  53. }
  54. }
  55. private void restart(IOException ioe) throws IOException {
  56. // check state
  57. synchronized(lock) {
  58. if (state == TERMINATED) {
  59. throw new IOException("The client has been closed.");
  60. } else if (state == FAILED) { // already failed to re-start by another thread
  61. throw ioe;
  62. } else if (state == RE_CONNECTING) {
  63. // restart process has been called by another thread
  64. // we need to wait
  65. while(state == RE_CONNECTING) {
  66. try {
  67. lock.wait();
  68. } catch (InterruptedException ire) {
  69. // be asked to give up
  70. InterruptedIOException iioe = new InterruptedIOException(ire.toString());
  71. EnvHelp.initCause(iioe, ire);
  72. throw iioe;
  73. }
  74. }
  75. if (state == TERMINATED) {
  76. throw new IOException("The client has been closed.");
  77. } else if (state != CONNECTED) {
  78. // restarted is failed by another thread
  79. throw ioe;
  80. }
  81. } else {
  82. state = RE_CONNECTING;
  83. lock.notifyAll();
  84. }
  85. }
  86. // re-starting
  87. try {
  88. doStart();
  89. synchronized(lock) {
  90. if (state == TERMINATED) {
  91. throw new IOException("The client has been closed.");
  92. }
  93. state = CONNECTED;
  94. lock.notifyAll();
  95. }
  96. return;
  97. } catch (Exception e) {
  98. logger.warning("restart", "Failed to restart: " + e);
  99. logger.debug("restart",e);
  100. synchronized(lock) {
  101. if (state == TERMINATED) {
  102. throw new IOException("The client has been closed.");
  103. }
  104. state = FAILED;
  105. lock.notifyAll();
  106. }
  107. try {
  108. doStop();
  109. } catch (Exception eee) {
  110. // OK.
  111. // We know there is a problem.
  112. }
  113. terminate();
  114. throw ioe;
  115. }
  116. }
  117. // --------------------------------------------------------------
  118. // private varaibles
  119. // --------------------------------------------------------------
  120. private class Checker implements Runnable {
  121. public void run() {
  122. myThread = Thread.currentThread();
  123. while (state != TERMINATED && !myThread.isInterrupted()) {
  124. try {
  125. Thread.sleep(period);
  126. } catch (InterruptedException ire) {
  127. // OK.
  128. // We will check the state at the following steps
  129. }
  130. if (state == TERMINATED || myThread.isInterrupted()) {
  131. break;
  132. }
  133. try {
  134. checkConnection();
  135. } catch (Exception e) {
  136. synchronized(lock) {
  137. if (state == TERMINATED || myThread.isInterrupted()) {
  138. break;
  139. }
  140. }
  141. e = (Exception)EnvHelp.getCause(e);
  142. if (e instanceof IOException &&
  143. !(e instanceof InterruptedIOException)) {
  144. try {
  145. restart((IOException)e);
  146. } catch (Exception ee) {
  147. logger.warning("Checker-run",
  148. "Failed to check connection: "+ e);
  149. logger.warning("Checker-run", "stopping");
  150. logger.debug("Checker-run",e);
  151. break;
  152. }
  153. } else {
  154. logger.warning("Checker-run",
  155. "Failed to check the connection: " + e);
  156. logger.debug("Checker-run",e);
  157. // XXX stop checking?
  158. break;
  159. }
  160. }
  161. }
  162. if (logger.traceOn()) {
  163. logger.trace("Checker-run", "Finished.");
  164. }
  165. }
  166. private void stop() {
  167. if (myThread != null && myThread != Thread.currentThread()) {
  168. myThread.interrupt();
  169. }
  170. }
  171. private Thread myThread;
  172. }
  173. // --------------------------------------------------------------
  174. // private variables
  175. // --------------------------------------------------------------
  176. private final Checker checker;
  177. private long period;
  178. // state
  179. private final static int CONNECTED = 0;
  180. private final static int RE_CONNECTING = 1;
  181. private final static int FAILED = 2;
  182. private final static int TERMINATED = 3;
  183. private int state = CONNECTED;
  184. private final int[] lock = new int[0];
  185. private static final ClassLogger logger =
  186. new ClassLogger("javax.management.remote.misc",
  187. "ClientCommunicatorAdmin");
  188. }