KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > tools > ant > taskdefs > ProcessDestroyer


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
19 package org.apache.tools.ant.taskdefs;
20
21 import java.lang.reflect.InvocationTargetException JavaDoc;
22 import java.lang.reflect.Method JavaDoc;
23 import java.util.Enumeration JavaDoc;
24 import java.util.Vector JavaDoc;
25
26 /**
27  * Destroys all registered <code>Process</code>es when the VM exits.
28  *
29  * @since Ant 1.5
30  */

31 class ProcessDestroyer implements Runnable JavaDoc {
32
33     private Vector JavaDoc processes = new Vector JavaDoc();
34     // methods to register and unregister shutdown hooks
35
private Method JavaDoc addShutdownHookMethod;
36     private Method JavaDoc removeShutdownHookMethod;
37     private ProcessDestroyerImpl destroyProcessThread = null;
38
39     // whether or not this ProcessDestroyer has been registered as a
40
// shutdown hook
41
private boolean added = false;
42     // whether or not this ProcessDestroyer is currently running as
43
// shutdown hook
44
private boolean running = false;
45
46     private class ProcessDestroyerImpl extends Thread JavaDoc {
47         private boolean shouldDestroy = true;
48
49         public ProcessDestroyerImpl() {
50             super("ProcessDestroyer Shutdown Hook");
51         }
52         public void run() {
53             if (shouldDestroy) {
54                 ProcessDestroyer.this.run();
55             }
56         }
57
58         public void setShouldDestroy(boolean shouldDestroy) {
59             this.shouldDestroy = shouldDestroy;
60         }
61     }
62
63     /**
64      * Constructs a <code>ProcessDestroyer</code> and obtains
65      * <code>Runtime.addShutdownHook()</code> and
66      * <code>Runtime.removeShutdownHook()</code> through reflection. The
67      * ProcessDestroyer manages a list of processes to be destroyed when the
68      * VM exits. If a process is added when the list is empty,
69      * this <code>ProcessDestroyer</code> is registered as a shutdown hook. If
70      * removing a process results in an empty list, the
71      * <code>ProcessDestroyer</code> is removed as a shutdown hook.
72      */

73     public ProcessDestroyer() {
74         try {
75             // check to see if the shutdown hook methods exists
76
// (support pre-JDK 1.3 VMs)
77
Class JavaDoc[] paramTypes = {Thread JavaDoc.class};
78             addShutdownHookMethod =
79                 Runtime JavaDoc.class.getMethod("addShutdownHook", paramTypes);
80
81             removeShutdownHookMethod =
82                 Runtime JavaDoc.class.getMethod("removeShutdownHook", paramTypes);
83             // wait to add shutdown hook as needed
84
} catch (NoSuchMethodException JavaDoc e) {
85             // it just won't be added as a shutdown hook... :(
86
} catch (Exception JavaDoc e) {
87             e.printStackTrace();
88         }
89     }
90
91     /**
92      * Registers this <code>ProcessDestroyer</code> as a shutdown hook,
93      * uses reflection to ensure pre-JDK 1.3 compatibility.
94      */

95     private void addShutdownHook() {
96         if (addShutdownHookMethod != null && !running) {
97             destroyProcessThread = new ProcessDestroyerImpl();
98             Object JavaDoc[] args = {destroyProcessThread};
99             try {
100                 addShutdownHookMethod.invoke(Runtime.getRuntime(), args);
101                 added = true;
102             } catch (IllegalAccessException JavaDoc e) {
103                 e.printStackTrace();
104             } catch (InvocationTargetException JavaDoc e) {
105                 Throwable JavaDoc t = e.getTargetException();
106                 if (t != null && t.getClass() == IllegalStateException JavaDoc.class) {
107                     // shutdown already is in progress
108
running = true;
109                 } else {
110                     e.printStackTrace();
111                 }
112             }
113         }
114     }
115
116     /**
117      * Removes this <code>ProcessDestroyer</code> as a shutdown hook,
118      * uses reflection to ensure pre-JDK 1.3 compatibility
119      */

120     private void removeShutdownHook() {
121         if (removeShutdownHookMethod != null && added && !running) {
122             Object JavaDoc[] args = {destroyProcessThread};
123             try {
124                 Boolean JavaDoc removed =
125                     (Boolean JavaDoc) removeShutdownHookMethod.invoke(
126                         Runtime.getRuntime(),
127                         args);
128                 if (!removed.booleanValue()) {
129                     System.err.println("Could not remove shutdown hook");
130                 }
131             } catch (IllegalAccessException JavaDoc e) {
132                 e.printStackTrace();
133             } catch (InvocationTargetException JavaDoc e) {
134                 Throwable JavaDoc t = e.getTargetException();
135                 if (t != null && t.getClass() == IllegalStateException JavaDoc.class) {
136                     // shutdown already is in progress
137
running = true;
138                 } else {
139                     e.printStackTrace();
140                 }
141             }
142             // start the hook thread, a unstarted thread may not be
143
// eligible for garbage collection
144
// Cf.: http://developer.java.sun.com/developer/bugParade/bugs/4533087.html
145
destroyProcessThread.setShouldDestroy(false);
146             if (!destroyProcessThread.getThreadGroup().isDestroyed()) {
147                 // start() would throw IllegalThreadStateException from
148
// ThreadGroup.add if it were destroyed
149
destroyProcessThread.start();
150             }
151             // this should return quickly, since it basically is a NO-OP.
152
try {
153                 destroyProcessThread.join(20000);
154             } catch (InterruptedException JavaDoc ie) {
155                 // the thread didn't die in time
156
// it should not kill any processes unexpectedly
157
}
158             destroyProcessThread = null;
159             added = false;
160         }
161     }
162
163     /**
164      * Returns whether or not the ProcessDestroyer is registered as
165      * as shutdown hook
166      * @return true if this is currently added as shutdown hook
167      */

168     public boolean isAddedAsShutdownHook() {
169         return added;
170     }
171
172     /**
173      * Returns <code>true</code> if the specified <code>Process</code> was
174      * successfully added to the list of processes to destroy upon VM exit.
175      *
176      * @param process the process to add
177      * @return <code>true</code> if the specified <code>Process</code> was
178      * successfully added
179      */

180     public boolean add(Process JavaDoc process) {
181         synchronized (processes) {
182             // if this list is empty, register the shutdown hook
183
if (processes.size() == 0) {
184                 addShutdownHook();
185             }
186             processes.addElement(process);
187             return processes.contains(process);
188         }
189     }
190
191     /**
192      * Returns <code>true</code> if the specified <code>Process</code> was
193      * successfully removed from the list of processes to destroy upon VM exit.
194      *
195      * @param process the process to remove
196      * @return <code>true</code> if the specified <code>Process</code> was
197      * successfully removed
198      */

199     public boolean remove(Process JavaDoc process) {
200         synchronized (processes) {
201             boolean processRemoved = processes.removeElement(process);
202             if (processRemoved && processes.size() == 0) {
203                 removeShutdownHook();
204             }
205             return processRemoved;
206         }
207     }
208
209     /**
210      * Invoked by the VM when it is exiting.
211      */

212     public void run() {
213         synchronized (processes) {
214             running = true;
215             Enumeration JavaDoc e = processes.elements();
216             while (e.hasMoreElements()) {
217                 ((Process JavaDoc) e.nextElement()).destroy();
218             }
219         }
220     }
221 }
222
Popular Tags