1. /*
  2. * Copyright 1999-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. package org.apache.commons.launcher;
  17. import java.io.File;
  18. import java.io.InputStream;
  19. import java.io.IOException;
  20. /**
  21. * A class for detecting if the parent JVM that launched this process has
  22. * terminated.
  23. *
  24. * @author Patrick Luby
  25. */
  26. public class ParentListener extends Thread {
  27. //------------------------------------------------------------------ Fields
  28. /**
  29. * Cached heartbeat file.
  30. */
  31. private File heartbeatFile = null;
  32. //------------------------------------------------------------ Constructors
  33. /**
  34. * Validates and caches a lock file created by the parent JVM.
  35. *
  36. * @param path the lock file that the parent JVM has an open
  37. * FileOutputStream
  38. * @throws IOException if the heartbeat cannot be converted into a valid
  39. * File object
  40. */
  41. public ParentListener(String path) throws IOException {
  42. if (path == null)
  43. throw new IOException();
  44. // Make sure we have a valid path
  45. heartbeatFile = new File(path);
  46. heartbeatFile.getCanonicalPath();
  47. }
  48. //----------------------------------------------------------------- Methods
  49. /**
  50. * Periodically check that the parent JVM has not terminated. On all
  51. * platforms other than Windows, this method will check that System.in has
  52. * not been closed. On Windows NT, 2000, and XP the lock file specified in
  53. * the {@link #ParentListener(String)} constructor is monitored as reading
  54. * System.in will block the entire process on Windows machines that use
  55. * some versions of Unix shells such as MKS, etc. No monitoring is done
  56. * on Window 95, 98, and ME.
  57. */
  58. public void run() {
  59. String osname = System.getProperty("os.name").toLowerCase();
  60. // We need to use file locking on Windows since reading System.in
  61. // will block the entire process on some Windows machines.
  62. if (osname.indexOf("windows") >= 0) {
  63. // Do nothing if this is a Windows 9x platform since our file
  64. // locking mechanism does not work on the early versions of
  65. // Windows
  66. if (osname.indexOf("nt") == -1 && osname.indexOf("2000") == -1 && osname.indexOf("xp") == -1)
  67. return;
  68. // If we can delete the heartbeatFile on Windows, it means that
  69. // the parent JVM has closed its FileOutputStream on the file.
  70. // Note that the parent JVM's stream should only be closed when
  71. // it exits.
  72. for ( ; ; ) {
  73. if (heartbeatFile.delete())
  74. break;
  75. // Wait awhile before we try again
  76. yield();
  77. try {
  78. sleep(5000);
  79. } catch (Exception e) {}
  80. }
  81. } else {
  82. // Cache System.in in case the application redirects
  83. InputStream is = System.in;
  84. int bytesAvailable = 0;
  85. int bytesRead = 0;
  86. byte[] buf = new byte[1024];
  87. try {
  88. while (true) {
  89. synchronized (is) {
  90. // Mark the stream position so that other threads can
  91. // reread the strea
  92. is.mark(buf.length);
  93. // Read one more byte than has already been read to
  94. // force the stream to wait for input
  95. bytesAvailable = is.available();
  96. if (bytesAvailable < buf.length) {
  97. bytesRead = is.read(buf, 0, bytesAvailable + 1);
  98. // Reset so that we "unread" the bytes that we read
  99. is.reset();
  100. if (bytesRead == -1)
  101. break;
  102. } else {
  103. // Make the buffer larger
  104. if (buf.length < Integer.MAX_VALUE / 2)
  105. buf = new byte[buf.length * 2];
  106. }
  107. }
  108. yield();
  109. }
  110. } catch (IOException ioe) {}
  111. }
  112. // Clean up before exiting
  113. if (heartbeatFile != null)
  114. heartbeatFile.delete();
  115. // Exit this process since the parent JVM has exited
  116. System.exit(0);
  117. }
  118. }