Classes in this File | Line Coverage | Branch Coverage | Complexity | ||||
ChildMain |
|
| 5.25;5.25 | ||||
ChildMain$1 |
|
| 5.25;5.25 | ||||
ChildMain$ChildWindowAdapter |
|
| 5.25;5.25 |
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.awt.Frame; | |
21 | import java.awt.Image; | |
22 | import java.awt.Rectangle; | |
23 | import java.awt.Toolkit; | |
24 | import java.awt.event.WindowAdapter; | |
25 | import java.awt.event.WindowEvent; | |
26 | import java.io.FileOutputStream; | |
27 | import java.io.PrintStream; | |
28 | import java.lang.reflect.Method; | |
29 | ||
30 | /** | |
31 | * A wrapper class that invokes another class' | |
32 | * <code>main(String[])</code>. This particular class uses several system | |
33 | * properties to control features: | |
34 | * <ul> | |
35 | * <li>Redirecting System.out and System.err. | |
36 | * <li>Displaying a minimized window in the Windows taskbar. | |
37 | * </ul> | |
38 | * This class is normally not invoked directly. Instead, it is invoked by the | |
39 | * {@link LaunchTask} class. | |
40 | * | |
41 | * @author Patrick Luby | |
42 | */ | |
43 | public class ChildMain extends Thread { | |
44 | ||
45 | //----------------------------------------------------------- Static Fields | |
46 | ||
47 | /** | |
48 | * The appendOutput system property name. | |
49 | */ | |
50 | public final static String APPEND_OUTPUT_PROP_NAME = | |
51 | "org.apache.commons.launcher.appendOutput"; | |
52 | ||
53 | /** | |
54 | * The displayMiminizedWindow system property name. | |
55 | */ | |
56 | public final static String DISPLAY_MINIMIZED_WINDOW_PROP_NAME = | |
57 | "org.apache.commons.launcher.displayMinimizedWindow"; | |
58 | ||
59 | /** | |
60 | * The disposeMiminizedWindow system property name. | |
61 | */ | |
62 | public final static String DISPOSE_MINIMIZED_WINDOW_PROP_NAME = | |
63 | "org.apache.commons.launcher.disposeMinimizedWindow"; | |
64 | ||
65 | /** | |
66 | * The executableName system property name. | |
67 | */ | |
68 | public final static String EXECUTABLE_PROP_NAME = | |
69 | "org.apache.commons.launcher.executableName"; | |
70 | ||
71 | /** | |
72 | * The heartbeatFile system property name. | |
73 | */ | |
74 | public final static String HEARTBEAT_FILE_PROP_NAME = | |
75 | "org.apache.commons.launcher.heartbeatFile"; | |
76 | ||
77 | /** | |
78 | * The miminizedWindowTitle system property name. | |
79 | */ | |
80 | public final static String MINIMIZED_WINDOW_TITLE_PROP_NAME = | |
81 | "org.apache.commons.launcher.minimizedWindowTitle"; | |
82 | ||
83 | /** | |
84 | * The miminizedWindowIcon system property name. | |
85 | */ | |
86 | public final static String MINIMIZED_WINDOW_ICON_PROP_NAME= | |
87 | "org.apache.commons.launcher.minimizedWindowIcon"; | |
88 | ||
89 | /** | |
90 | * The outputFile system property name. | |
91 | */ | |
92 | public final static String OUTPUT_FILE_PROP_NAME = | |
93 | "org.apache.commons.launcher.outputFile"; | |
94 | ||
95 | /** | |
96 | * The waitForChild system property name. | |
97 | */ | |
98 | public final static String WAIT_FOR_CHILD_PROP_NAME = | |
99 | "org.apache.commons.launcher.waitForChild"; | |
100 | ||
101 | //------------------------------------------------------------------ Fields | |
102 | ||
103 | /** | |
104 | * Cached command line arguments | |
105 | */ | |
106 | 0 | private String[] args = null; |
107 | ||
108 | //------------------------------------------------------------ Constructors | |
109 | ||
110 | /** | |
111 | * Construct an instance of this {@link Thread} subclass and cache the | |
112 | * args parameter for use by the {@link #run()} method. | |
113 | * | |
114 | * @param group the ThreadGroup to use for this thread | |
115 | * @param args the command line arguments | |
116 | */ | |
117 | private ChildMain(ThreadGroup group, String[] args) { | |
118 | ||
119 | 0 | super(group, ChildMain.class.getName()); |
120 | 0 | this.args = args; |
121 | ||
122 | 0 | } |
123 | ||
124 | //---------------------------------------------------------- Static Methods | |
125 | ||
126 | /** | |
127 | * Main entry point for the child process. This method should only be | |
128 | * invoked by the {@link LaunchTask} class. | |
129 | * | |
130 | * @param args command line arguments | |
131 | */ | |
132 | public static void main(String[] args) { | |
133 | ||
134 | // Invoke the target application in a separate thread so that we | |
135 | // caught any uncaught errors thrown by the target application | |
136 | 0 | Thread mainThread = new ChildMain(new ExitOnErrorThreadGroup(ChildMain.class.getName()), args); |
137 | 0 | mainThread.start(); |
138 | ||
139 | 0 | } |
140 | ||
141 | //----------------------------------------------------------------- Methods | |
142 | ||
143 | /** | |
144 | * Invoke the target application. | |
145 | */ | |
146 | public void run() { | |
147 | ||
148 | // If there are no command line arguments, do nothing | |
149 | 0 | if (args == null || args.length == 0) |
150 | 0 | return; |
151 | ||
152 | // Invoke the target application | |
153 | try { | |
154 | ||
155 | // Start the thread to check if the parent JVM exits. | |
156 | 0 | boolean waitForChild = false; |
157 | 0 | if (System.getProperty(ChildMain.WAIT_FOR_CHILD_PROP_NAME) != null) { |
158 | 0 | waitForChild = true; |
159 | 0 | String heartbeatFile = System.getProperty(ChildMain.HEARTBEAT_FILE_PROP_NAME); |
160 | 0 | ParentListener heartbeat = new ParentListener(heartbeatFile); |
161 | // Make the thread a daemon thread so that it does not | |
162 | // prevent this process from exiting when all of the | |
163 | // appliation's threads finish. | |
164 | 0 | heartbeat.setDaemon(true); |
165 | 0 | heartbeat.start(); |
166 | } | |
167 | ||
168 | // If applicable, redirect output and error streams | |
169 | 0 | String outputPath = System.getProperty(ChildMain.OUTPUT_FILE_PROP_NAME); |
170 | 0 | if (outputPath != null) { |
171 | 0 | boolean appendOutput = false; |
172 | 0 | if (System.getProperty(ChildMain.APPEND_OUTPUT_PROP_NAME) != null) |
173 | 0 | appendOutput = true; |
174 | 0 | PrintStream ps = new PrintStream(new FileOutputStream(outputPath, appendOutput), true); |
175 | 0 | System.setOut(ps); |
176 | 0 | System.setErr(ps); |
177 | } | |
178 | ||
179 | // The first argument should be the class that we really want to | |
180 | // invoke. Try to load the class and invoke its main(String[]) | |
181 | // method with the first argument shifted out. | |
182 | 0 | Class mainClass = Class.forName(args[0]); |
183 | 0 | Class[] paramTypes = new Class[1]; |
184 | 0 | Object[] paramValues = new Object[1]; |
185 | 0 | String[] params = new String[args.length - 1]; |
186 | // Shift args[0] out of the arguments | |
187 | 0 | for (int i = 0; i < params.length; i++) |
188 | 0 | params[i] = args[i + 1]; |
189 | 0 | paramTypes[0] = params.getClass(); |
190 | 0 | paramValues[0] = params; |
191 | ||
192 | // Create the icon window if this is a waitForChild task | |
193 | 0 | Frame frame = null; |
194 | 0 | boolean displayMinimizedWindow = false; |
195 | 0 | if (System.getProperty(ChildMain.DISPLAY_MINIMIZED_WINDOW_PROP_NAME) != null) |
196 | 0 | displayMinimizedWindow = true; |
197 | 0 | String osname = System.getProperty("os.name").toLowerCase(); |
198 | 0 | if (displayMinimizedWindow && osname.indexOf("windows") >= 0) { |
199 | try { | |
200 | 0 | frame = new Frame(); |
201 | 0 | String title = System.getProperty(ChildMain.MINIMIZED_WINDOW_TITLE_PROP_NAME); |
202 | 0 | if (title != null) |
203 | 0 | frame.setTitle(title); |
204 | 0 | frame.setState(Frame.ICONIFIED); |
205 | 0 | String icon = System.getProperty(ChildMain.MINIMIZED_WINDOW_ICON_PROP_NAME); |
206 | 0 | if (icon != null) { |
207 | 0 | Image iconImage = Toolkit.getDefaultToolkit().createImage(icon); |
208 | 0 | if (iconImage != null) |
209 | 0 | frame.setIconImage(iconImage); |
210 | } | |
211 | ||
212 | // Ensure that window always remains minimized | |
213 | 0 | frame.addWindowListener(new ChildWindowAdapter()); |
214 | 0 | Rectangle bounds = frame.getGraphicsConfiguration().getBounds(); |
215 | 0 | int width = (int)frame.getBounds().getWidth(); |
216 | 0 | int height = frame.getInsets().top + frame.getInsets().bottom; |
217 | 0 | int x = (int)bounds.getWidth() - width; |
218 | 0 | int y = (int)bounds.getHeight() - height; |
219 | 0 | frame.setBounds(x, y, width, height); |
220 | 0 | frame.setResizable(false); |
221 | 0 | frame.setVisible(true); |
222 | 0 | } catch(Exception fe) {} |
223 | } | |
224 | ||
225 | // Invoke the main() method | |
226 | 0 | Method mainMethod = mainClass.getDeclaredMethod("main", paramTypes); |
227 | 0 | mainMethod.invoke(null, paramValues); |
228 | ||
229 | // Close the frame if it exists | |
230 | 0 | if (frame != null && System.getProperty(ChildMain.DISPOSE_MINIMIZED_WINDOW_PROP_NAME) != null) { |
231 | // Exit this process. Closing or disposing of the window is not | |
232 | // enough to allow the process to exit. | |
233 | 0 | System.exit(0); |
234 | } | |
235 | ||
236 | 0 | } catch (Throwable t) { |
237 | 0 | String message = t.getMessage(); |
238 | 0 | t.printStackTrace(); |
239 | 0 | System.exit(1); |
240 | 0 | } |
241 | ||
242 | 0 | } |
243 | ||
244 | /** | |
245 | * A WindowAdapter subclass that causes the application to exit when its | |
246 | * {@link #windowClosing(WindowEvent)} method is invoked. | |
247 | */ | |
248 | 0 | private static class ChildWindowAdapter extends WindowAdapter { |
249 | ||
250 | /** | |
251 | * Invoked when a window is in the process of being closed. | |
252 | * | |
253 | * @param e the event | |
254 | */ | |
255 | public void windowClosing(WindowEvent e) { | |
256 | ||
257 | 0 | System.exit(0); |
258 | ||
259 | 0 | } |
260 | ||
261 | } | |
262 | ||
263 | } |