1. /*
  2. * Copyright 2000-2004 The Apache Software Foundation
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. *
  16. */
  17. package org.apache.tools.ant.taskdefs;
  18. import org.apache.tools.ant.BuildException;
  19. import org.apache.tools.ant.util.TimeoutObserver;
  20. import org.apache.tools.ant.util.Watchdog;
  21. /**
  22. * Destroys a process running for too long.
  23. * For example:
  24. * <pre>
  25. * ExecuteWatchdog watchdog = new ExecuteWatchdog(30000);
  26. * Execute exec = new Execute(myloghandler, watchdog);
  27. * exec.setCommandLine(mycmdline);
  28. * int exitvalue = exec.execute();
  29. * if (Execute.isFailure(exitvalue) && watchdog.killedProcess()) {
  30. * // it was killed on purpose by the watchdog
  31. * }
  32. * </pre>
  33. * @see Execute
  34. * @see org.apache.tools.ant.util.Watchdog
  35. * @since Ant 1.2
  36. */
  37. public class ExecuteWatchdog implements TimeoutObserver {
  38. /** the process to execute and watch for duration */
  39. private Process process;
  40. /** say whether or not the watchdog is currently monitoring a process */
  41. private boolean watch = false;
  42. /** exception that might be thrown during the process execution */
  43. private Exception caught = null;
  44. /** say whether or not the process was killed due to running overtime */
  45. private boolean killedProcess = false;
  46. /** will tell us whether timeout has occurred */
  47. private Watchdog watchdog;
  48. /**
  49. * Creates a new watchdog with a given timeout.
  50. *
  51. * @param timeout the timeout for the process in milliseconds.
  52. * It must be greater than 0.
  53. */
  54. public ExecuteWatchdog(long timeout) {
  55. watchdog = new Watchdog(timeout);
  56. watchdog.addTimeoutObserver(this);
  57. }
  58. /**
  59. * @see #ExecuteWatchdog(long)
  60. * @deprecated Use constructor with a long type instead.
  61. * (1.4.x compatibility)
  62. */
  63. public ExecuteWatchdog(int timeout) {
  64. this((long) timeout);
  65. }
  66. /**
  67. * Watches the given process and terminates it, if it runs for too long.
  68. * All information from the previous run are reset.
  69. * @param process the process to monitor. It cannot be <tt>null</tt>
  70. * @throws IllegalStateException if a process is still being monitored.
  71. */
  72. public synchronized void start(Process process) {
  73. if (process == null) {
  74. throw new NullPointerException("process is null.");
  75. }
  76. if (this.process != null) {
  77. throw new IllegalStateException("Already running.");
  78. }
  79. this.caught = null;
  80. this.killedProcess = false;
  81. this.watch = true;
  82. this.process = process;
  83. watchdog.start();
  84. }
  85. /**
  86. * Stops the watcher. It will notify all threads possibly waiting
  87. * on this object.
  88. */
  89. public synchronized void stop() {
  90. watchdog.stop();
  91. watch = false;
  92. process = null;
  93. }
  94. /**
  95. * Called after watchdog has finished.
  96. */
  97. public void timeoutOccured(Watchdog w) {
  98. try {
  99. try {
  100. // We must check if the process was not stopped
  101. // before being here
  102. process.exitValue();
  103. } catch (IllegalThreadStateException itse) {
  104. // the process is not terminated, if this is really
  105. // a timeout and not a manual stop then kill it.
  106. if (watch) {
  107. killedProcess = true;
  108. process.destroy();
  109. }
  110. }
  111. } catch (Exception e) {
  112. caught = e;
  113. } finally {
  114. cleanUp();
  115. }
  116. }
  117. /**
  118. * reset the monitor flag and the process.
  119. */
  120. protected void cleanUp() {
  121. watch = false;
  122. process = null;
  123. }
  124. /**
  125. * This method will rethrow the exception that was possibly caught during
  126. * the run of the process. It will only remains valid once the process has
  127. * been terminated either by 'error', timeout or manual intervention.
  128. * Information will be discarded once a new process is ran.
  129. * @throws BuildException a wrapped exception over the one that was
  130. * silently swallowed and stored during the process run.
  131. */
  132. public void checkException() throws BuildException {
  133. if (caught != null) {
  134. throw new BuildException("Exception in ExecuteWatchdog.run: "
  135. + caught.getMessage(), caught);
  136. }
  137. }
  138. /**
  139. * Indicates whether or not the watchdog is still monitoring the process.
  140. * @return <tt>true</tt> if the process is still running, otherwise
  141. * <tt>false</tt>.
  142. */
  143. public boolean isWatching() {
  144. return watch;
  145. }
  146. /**
  147. * Indicates whether the last process run was killed on timeout or not.
  148. * @return <tt>true</tt> if the process was killed otherwise
  149. * <tt>false</tt>.
  150. */
  151. public boolean killedProcess() {
  152. return killedProcess;
  153. }
  154. }