source: other-projects/trunk/gs3-release-maker/apache-ant-1.6.5/src/main/org/apache/tools/ant/taskdefs/ProcessDestroyer.java@ 14627

Last change on this file since 14627 was 14627, checked in by oranfry, 17 years ago

initial import of the gs3-release-maker

File size: 7.8 KB
Line 
1/*
2 * Copyright 2001-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
18package org.apache.tools.ant.taskdefs;
19
20import java.lang.reflect.InvocationTargetException;
21import java.lang.reflect.Method;
22import java.util.Enumeration;
23import java.util.Vector;
24
25/**
26 * Destroys all registered <code>Process</code>es when the VM exits.
27 *
28 * @since Ant 1.5
29 */
30class ProcessDestroyer implements Runnable {
31
32 private Vector processes = new Vector();
33 // methods to register and unregister shutdown hooks
34 private Method addShutdownHookMethod;
35 private Method removeShutdownHookMethod;
36 private ProcessDestroyerImpl destroyProcessThread = null;
37
38 // whether or not this ProcessDestroyer has been registered as a
39 // shutdown hook
40 private boolean added = false;
41 // whether or not this ProcessDestroyer is currently running as
42 // shutdown hook
43 private boolean running = false;
44
45 private class ProcessDestroyerImpl extends Thread {
46 private boolean shouldDestroy = true;
47
48 public ProcessDestroyerImpl() {
49 super("ProcessDestroyer Shutdown Hook");
50 }
51 public void run() {
52 if (shouldDestroy) {
53 ProcessDestroyer.this.run();
54 }
55 }
56
57 public void setShouldDestroy(boolean shouldDestroy) {
58 this.shouldDestroy = shouldDestroy;
59 }
60 }
61
62 /**
63 * Constructs a <code>ProcessDestroyer</code> and obtains
64 * <code>Runtime.addShutdownHook()</code> and
65 * <code>Runtime.removeShutdownHook()</code> through reflection. The
66 * ProcessDestroyer manages a list of processes to be destroyed when the
67 * VM exits. If a process is added when the list is empty,
68 * this <code>ProcessDestroyer</code> is registered as a shutdown hook. If
69 * removing a process results in an empty list, the
70 * <code>ProcessDestroyer</code> is removed as a shutdown hook.
71 */
72 public ProcessDestroyer() {
73 try {
74 // check to see if the shutdown hook methods exists
75 // (support pre-JDK 1.3 VMs)
76 Class[] paramTypes = {Thread.class};
77 addShutdownHookMethod =
78 Runtime.class.getMethod("addShutdownHook", paramTypes);
79
80 removeShutdownHookMethod =
81 Runtime.class.getMethod("removeShutdownHook", paramTypes);
82 // wait to add shutdown hook as needed
83 } catch (NoSuchMethodException e) {
84 // it just won't be added as a shutdown hook... :(
85 } catch (Exception e) {
86 e.printStackTrace();
87 }
88 }
89
90 /**
91 * Registers this <code>ProcessDestroyer</code> as a shutdown hook,
92 * uses reflection to ensure pre-JDK 1.3 compatibility.
93 */
94 private void addShutdownHook() {
95 if (addShutdownHookMethod != null && !running) {
96 destroyProcessThread = new ProcessDestroyerImpl();
97 Object[] args = {destroyProcessThread};
98 try {
99 addShutdownHookMethod.invoke(Runtime.getRuntime(), args);
100 added = true;
101 } catch (IllegalAccessException e) {
102 e.printStackTrace();
103 } catch (InvocationTargetException e) {
104 Throwable t = e.getTargetException();
105 if (t != null && t.getClass() == IllegalStateException.class) {
106 // shutdown already is in progress
107 running = true;
108 } else {
109 e.printStackTrace();
110 }
111 }
112 }
113 }
114
115 /**
116 * Removes this <code>ProcessDestroyer</code> as a shutdown hook,
117 * uses reflection to ensure pre-JDK 1.3 compatibility
118 */
119 private void removeShutdownHook() {
120 if (removeShutdownHookMethod != null && added && !running) {
121 Object[] args = {destroyProcessThread};
122 try {
123 Boolean removed =
124 (Boolean) removeShutdownHookMethod.invoke(
125 Runtime.getRuntime(),
126 args);
127 if (!removed.booleanValue()) {
128 System.err.println("Could not remove shutdown hook");
129 }
130 } catch (IllegalAccessException e) {
131 e.printStackTrace();
132 } catch (InvocationTargetException e) {
133 Throwable t = e.getTargetException();
134 if (t != null && t.getClass() == IllegalStateException.class) {
135 // shutdown already is in progress
136 running = true;
137 } else {
138 e.printStackTrace();
139 }
140 }
141 // start the hook thread, a unstarted thread may not be
142 // eligible for garbage collection
143 // Cf.: http://developer.java.sun.com/developer/bugParade/bugs/4533087.html
144 destroyProcessThread.setShouldDestroy(false);
145 destroyProcessThread.start();
146 // this should return quickly, since it basically is a NO-OP.
147 try {
148 destroyProcessThread.join(20000);
149 } catch (InterruptedException ie) {
150 // the thread didn't die in time
151 // it should not kill any processes unexpectedly
152 }
153 destroyProcessThread = null;
154 added = false;
155 }
156 }
157
158 /**
159 * Returns whether or not the ProcessDestroyer is registered as
160 * as shutdown hook
161 * @return true if this is currently added as shutdown hook
162 */
163 public boolean isAddedAsShutdownHook() {
164 return added;
165 }
166
167 /**
168 * Returns <code>true</code> if the specified <code>Process</code> was
169 * successfully added to the list of processes to destroy upon VM exit.
170 *
171 * @param process the process to add
172 * @return <code>true</code> if the specified <code>Process</code> was
173 * successfully added
174 */
175 public boolean add(Process process) {
176 synchronized (processes) {
177 // if this list is empty, register the shutdown hook
178 if (processes.size() == 0) {
179 addShutdownHook();
180 }
181 processes.addElement(process);
182 return processes.contains(process);
183 }
184 }
185
186 /**
187 * Returns <code>true</code> if the specified <code>Process</code> was
188 * successfully removed from the list of processes to destroy upon VM exit.
189 *
190 * @param process the process to remove
191 * @return <code>true</code> if the specified <code>Process</code> was
192 * successfully removed
193 */
194 public boolean remove(Process process) {
195 synchronized (processes) {
196 boolean processRemoved = processes.removeElement(process);
197 if (processRemoved && processes.size() == 0) {
198 removeShutdownHook();
199 }
200 return processRemoved;
201 }
202 }
203
204 /**
205 * Invoked by the VM when it is exiting.
206 */
207 public void run() {
208 synchronized (processes) {
209 running = true;
210 Enumeration e = processes.elements();
211 while (e.hasMoreElements()) {
212 ((Process) e.nextElement()).destroy();
213 }
214 }
215 }
216}
Note: See TracBrowser for help on using the repository browser.