Classes in this File | Line Coverage | Branch Coverage | Complexity | ||||
ParentListener |
|
| 9.0;9 |
1 | /* | |
2 | * Licensed to the Apache Software Foundation (ASF) under one or more | |
3 | * contributor license agreements. See the NOTICE file distributed with | |
4 | * this work for additional information regarding copyright ownership. | |
5 | * The ASF licenses this file to You under the Apache License, Version 2.0 | |
6 | * (the "License"); you may not use this file except in compliance with | |
7 | * the License. You may obtain a copy of the License at | |
8 | * | |
9 | * http://www.apache.org/licenses/LICENSE-2.0 | |
10 | * | |
11 | * Unless required by applicable law or agreed to in writing, software | |
12 | * distributed under the License is distributed on an "AS IS" BASIS, | |
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
14 | * See the License for the specific language governing permissions and | |
15 | * limitations under the License. | |
16 | */ | |
17 | ||
18 | package org.apache.commons.launcher; | |
19 | ||
20 | import java.io.File; | |
21 | import java.io.InputStream; | |
22 | import java.io.IOException; | |
23 | ||
24 | /** | |
25 | * A class for detecting if the parent JVM that launched this process has | |
26 | * terminated. | |
27 | * | |
28 | * @author Patrick Luby | |
29 | */ | |
30 | public class ParentListener extends Thread { | |
31 | ||
32 | //------------------------------------------------------------------ Fields | |
33 | ||
34 | /** | |
35 | * Cached heartbeat file. | |
36 | */ | |
37 | 0 | private File heartbeatFile = null; |
38 | ||
39 | //------------------------------------------------------------ Constructors | |
40 | ||
41 | /** | |
42 | * Validates and caches a lock file created by the parent JVM. | |
43 | * | |
44 | * @param path the lock file that the parent JVM has an open | |
45 | * FileOutputStream | |
46 | * @throws IOException if the heartbeat cannot be converted into a valid | |
47 | * File object | |
48 | */ | |
49 | 0 | public ParentListener(String path) throws IOException { |
50 | ||
51 | 0 | if (path == null) |
52 | 0 | throw new IOException(); |
53 | ||
54 | // Make sure we have a valid path | |
55 | 0 | heartbeatFile = new File(path); |
56 | 0 | heartbeatFile.getCanonicalPath(); |
57 | ||
58 | 0 | } |
59 | ||
60 | //----------------------------------------------------------------- Methods | |
61 | ||
62 | /** | |
63 | * Periodically check that the parent JVM has not terminated. On all | |
64 | * platforms other than Windows, this method will check that System.in has | |
65 | * not been closed. On Windows NT, 2000, and XP the lock file specified in | |
66 | * the {@link #ParentListener(String)} constructor is monitored as reading | |
67 | * System.in will block the entire process on Windows machines that use | |
68 | * some versions of Unix shells such as MKS, etc. No monitoring is done | |
69 | * on Window 95, 98, and ME. | |
70 | */ | |
71 | public void run() { | |
72 | ||
73 | 0 | String osname = System.getProperty("os.name").toLowerCase(); |
74 | ||
75 | // We need to use file locking on Windows since reading System.in | |
76 | // will block the entire process on some Windows machines. | |
77 | 0 | if (osname.indexOf("windows") >= 0) { |
78 | ||
79 | // Do nothing if this is a Windows 9x platform since our file | |
80 | // locking mechanism does not work on the early versions of | |
81 | // Windows | |
82 | 0 | if (osname.indexOf("nt") == -1 && osname.indexOf("2000") == -1 && osname.indexOf("xp") == -1) |
83 | 0 | return; |
84 | ||
85 | // If we can delete the heartbeatFile on Windows, it means that | |
86 | // the parent JVM has closed its FileOutputStream on the file. | |
87 | // Note that the parent JVM's stream should only be closed when | |
88 | // it exits. | |
89 | for ( ; ; ) { | |
90 | 0 | if (heartbeatFile.delete()) |
91 | 0 | break; |
92 | // Wait awhile before we try again | |
93 | 0 | yield(); |
94 | try { | |
95 | 0 | sleep(5000); |
96 | 0 | } catch (Exception e) {} |
97 | } | |
98 | ||
99 | } else { | |
100 | ||
101 | // Cache System.in in case the application redirects | |
102 | 0 | InputStream is = System.in; |
103 | 0 | int bytesAvailable = 0; |
104 | 0 | int bytesRead = 0; |
105 | 0 | byte[] buf = new byte[1024]; |
106 | try { | |
107 | while (true) { | |
108 | 0 | synchronized (is) { |
109 | // Mark the stream position so that other threads can | |
110 | // reread the strea | |
111 | 0 | is.mark(buf.length); |
112 | // Read one more byte than has already been read to | |
113 | // force the stream to wait for input | |
114 | 0 | bytesAvailable = is.available(); |
115 | 0 | if (bytesAvailable < buf.length) { |
116 | 0 | bytesRead = is.read(buf, 0, bytesAvailable + 1); |
117 | // Reset so that we "unread" the bytes that we read | |
118 | 0 | is.reset(); |
119 | 0 | if (bytesRead == -1) |
120 | 0 | break; |
121 | } else { | |
122 | // Make the buffer larger | |
123 | 0 | if (buf.length < Integer.MAX_VALUE / 2) |
124 | 0 | buf = new byte[buf.length * 2]; |
125 | } | |
126 | 0 | } |
127 | 0 | yield(); |
128 | } | |
129 | 0 | } catch (IOException ioe) {} |
130 | ||
131 | } | |
132 | ||
133 | // Clean up before exiting | |
134 | 0 | if (heartbeatFile != null) |
135 | 0 | heartbeatFile.delete(); |
136 | ||
137 | // Exit this process since the parent JVM has exited | |
138 | 0 | System.exit(0); |
139 | ||
140 | 0 | } |
141 | ||
142 | } |