1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package org.apache.geronimo.genesis.ant;
21
22 import java.io.File;
23 import java.util.ArrayList;
24 import java.util.HashMap;
25 import java.util.Iterator;
26 import java.util.List;
27 import java.util.Map;
28 import java.util.Properties;
29 import java.util.StringTokenizer;
30 import java.util.Timer;
31 import java.util.TimerTask;
32
33 import org.apache.maven.artifact.Artifact;
34 import org.apache.maven.artifact.repository.ArtifactRepository;
35 import org.apache.maven.plugin.MojoExecutionException;
36 import org.apache.maven.project.MavenProject;
37 import org.apache.tools.ant.taskdefs.Java;
38 import org.apache.tools.ant.types.Path;
39 import org.codehaus.plexus.util.FileUtils;
40
41 import org.apache.geronimo.genesis.util.ObjectHolder;
42
43
44
45
46
47 /**
48 * Support for mojos that launch Java processes.
49 *
50 * @version $Rev: 463461 $ $Date: 2006-10-12 15:11:08 -0700 (Thu, 12 Oct 2006) $
51 */
52 public abstract class JavaLauncherMojoSupport
53 extends AntMojoSupport
54 {
55
56
57
58
59 private Timer timer = new Timer(true);
60
61 /**
62 * Set the maximum memory for the forked JVM.
63 *
64 * @parameter expression="${maximumMemory}"
65 */
66 private String maximumMemory = null;
67
68 /**
69 * The base working directory where process will be started from, a sub-directory
70 * the process name will be used for the effective working directory.
71 *
72 * @parameter expression="${project.build.directory}"
73 * @required
74 */
75 protected File baseWorkingDirectory = null;
76
77 /**
78 * Enable logging mode.
79 *
80 * @parameter expression="${logOutput}" default-value="false"
81 */
82 protected boolean logOutput = false;
83
84 /**
85 * Flag to control if we background the process or block Maven execution.
86 *
87 * @parameter default-value="false"
88 * @required
89 */
90 protected boolean background = false;
91
92 /**
93 * Timeout for the process in seconds.
94 *
95 * @parameter expression="${timeout}" default-value="-1"
96 */
97 protected int timeout = -1;
98
99 /**
100 * Time in seconds to wait while verifing that the process has started (if there is custom validation).
101 *
102 * @parameter expression="${verifyTimeout}" default-value="-1"
103 */
104 private int verifyTimeout = -1;
105
106 /**
107 * An array of option sets which can be enabled by setting <tt>options</tt>.
108 *
109 * @parameter
110 */
111 protected OptionSet[] optionSets = null;
112
113 /**
114 * A comma seperated list of <tt>optionSets</tt> to enabled.
115 *
116 * @parameter expression="${options}"
117 */
118 protected String options = null;
119
120 /**
121 * Map of of plugin artifacts.
122 *
123 * @parameter expression="${plugin.artifactMap}"
124 * @required
125 * @readonly
126 */
127 protected Map pluginArtifactMap = null;
128
129 protected void doExecute() throws Exception {
130 log.info("Starting " + getProcessTitle() + "...");
131
132 final Java java = (Java)createTask("java");
133
134 File workingDirectory = getWorkingDirectory();
135 FileUtils.forceMkdir(workingDirectory);
136 java.setDir(workingDirectory);
137
138 java.setFailonerror(true);
139 java.setFork(true);
140
141 if (maximumMemory != null) {
142 java.setMaxmemory(maximumMemory);
143 }
144
145 if (timeout > 0) {
146 log.info("Timeout after: " + timeout + " seconds");
147
148 java.setTimeout(new Long(timeout * 1000));
149 }
150
151 if (logOutput) {
152 File file = getLogFile();
153 log.info("Redirecting output to: " + file);
154 FileUtils.forceMkdir(file.getParentFile());
155
156 java.setLogError(true);
157 java.setOutput(file);
158 }
159
160 java.setClassname(getClassName());
161 setClassPath(java.createClasspath());
162
163 applyOptionSets(java);
164
165 customizeJava(java);
166
167
168 final ObjectHolder errorHolder = new ObjectHolder();
169
170
171 Thread t = new Thread(getProcessTitle() + " Runner") {
172 public void run() {
173 try {
174 java.execute();
175 }
176 catch (Exception e) {
177 errorHolder.set(e);
178
179
180
181
182
183 }
184 }
185 };
186 t.start();
187
188 log.debug("Waiting for " + getProcessTitle() + "...");
189
190
191 final ObjectHolder verifyTimedOut = new ObjectHolder();
192
193 TimerTask timeoutTask = new TimerTask() {
194 public void run() {
195 verifyTimedOut.set(Boolean.TRUE);
196 }
197 };
198
199 if (verifyTimeout > 0) {
200 log.debug("Starting verify timeout task; triggers in: " + verifyTimeout + "s");
201 timer.schedule(timeoutTask, verifyTimeout * 1000);
202 }
203
204
205 boolean started = false;
206 while (!started) {
207 if (verifyTimedOut.isSet()) {
208 throw new MojoExecutionException("Unable to verify if the " + getProcessTitle() + " process was started in the given time");
209 }
210
211 if (errorHolder.isSet()) {
212 throw new MojoExecutionException("Failed to launch " + getProcessTitle(), (Throwable)errorHolder.get());
213 }
214
215 try {
216 started = verifyProcessStarted();
217 }
218 catch (Exception e) {
219
220 }
221
222 Thread.sleep(1000);
223 }
224
225 log.info(getProcessTitle() + " started");
226
227 if (!background) {
228 log.info("Waiting for " + getProcessTitle() + " to shutdown...");
229
230 t.join();
231 }
232 }
233
234 protected Artifact getPluginArtifact(final String name) throws MojoExecutionException {
235 assert name != null;
236
237 Artifact artifact = (Artifact)pluginArtifactMap.get(name);
238 if (artifact == null) {
239 throw new MojoExecutionException("Unable to locate '" + name + "' in the list of plugin artifacts");
240 }
241
242 return artifact;
243 }
244
245 protected void appendArtifactFile(final Path classpath, final String name) throws MojoExecutionException {
246 assert classpath != null;
247 assert name != null;
248
249 appendArtifact(classpath, getPluginArtifact(name));
250 }
251
252 protected void appendArtifact(final Path classpath, final Artifact artifact) throws MojoExecutionException {
253 assert classpath != null;
254 assert artifact != null;
255
256 File file = artifact.getFile();
257 if (file == null) {
258 throw new MojoExecutionException("Artifact does not have an attached file: " + artifact);
259 }
260
261 classpath.createPathElement().setLocation(file);
262 }
263
264 private void applyOptionSets(final Java java) throws MojoExecutionException {
265 assert java != null;
266
267
268
269
270
271
272 if (options != null && (optionSets == null || optionSets.length == 0)) {
273 throw new MojoExecutionException("At least one optionSet must be defined to select one using options");
274 }
275 else if (options == null) {
276 options = "default";
277 }
278
279 if (optionSets != null && optionSets.length != 0) {
280 OptionSet[] sets = selectOptionSets();
281
282 for (int i=0; i < sets.length; i++) {
283 if (log.isDebugEnabled()) {
284 log.debug("Selected option set: " + sets[i]);
285 }
286 else {
287 log.info("Selected option set: " + sets[i].getId());
288 }
289
290 String[] options = sets[i].getOptions();
291 if (options != null) {
292 for (int j=0; j < options.length; j++) {
293 java.createJvmarg().setValue(options[j]);
294 }
295 }
296
297 Properties props = sets[i].getProperties();
298 if (props != null) {
299 Iterator iter = props.keySet().iterator();
300 while (iter.hasNext()) {
301 String name = (String)iter.next();
302 String value = props.getProperty(name);
303
304 setSystemProperty(java, name, value);
305 }
306 }
307 }
308 }
309 }
310
311 private OptionSet[] selectOptionSets() throws MojoExecutionException {
312
313 Map map = new HashMap();
314 for (int i=0; i<optionSets.length; i++) {
315 if (log.isDebugEnabled()) {
316 log.debug("Checking option set: " + optionSets[i]);
317 }
318
319 String id = optionSets[i].getId();
320
321 if (id == null && optionSets.length > 1) {
322 throw new MojoExecutionException("Must specify id for optionSet when more than one optionSet is configured");
323 }
324 else if (id == null && optionSets.length == 1) {
325 id = "default";
326 optionSets[i].setId(id);
327 }
328
329 assert id != null;
330 id = id.trim();
331
332 if (map.containsKey(id)) {
333 throw new MojoExecutionException("Must specify unique id for optionSet: " + optionSets[i]);
334 }
335 map.put(id, optionSets[i]);
336 }
337
338 StringTokenizer stok = new StringTokenizer(options, ",");
339
340 List selected = new ArrayList();
341 while (stok.hasMoreTokens()) {
342 String id = stok.nextToken();
343 OptionSet set = (OptionSet)map.get(options);
344
345 if (set == null) {
346 if ("default".equals(options)) {
347 log.debug("Default optionSet selected, but no optionSet defined with that id; ignoring");
348 }
349 else {
350 throw new MojoExecutionException("Missing optionSet for id: " + id);
351 }
352 }
353 else {
354 selected.add(set);
355 }
356 }
357
358 return (OptionSet[]) selected.toArray(new OptionSet[selected.size()]);
359 }
360
361
362
363
364
365 /**
366 * The maven project.
367 *
368 * @parameter expression="${project}"
369 * @required
370 * @readonly
371 */
372 protected MavenProject project = null;
373
374 protected MavenProject getProject() {
375 return project;
376 }
377
378 /**
379 * @parameter expression="${localRepository}"
380 * @readonly
381 * @required
382 */
383 protected ArtifactRepository artifactRepository = null;
384
385 protected ArtifactRepository getArtifactRepository() {
386 return artifactRepository;
387 }
388
389
390
391
392
393 protected abstract String getProcessName();
394
395 protected String getProcessTitle() {
396 return getProcessName();
397 }
398
399 protected File getWorkingDirectory() {
400 return new File(baseWorkingDirectory, getProcessName());
401 }
402
403 protected File getLogFile() {
404 return new File(getWorkingDirectory(), getProcessName() + ".log");
405 }
406
407 protected abstract String getClassName();
408
409 protected abstract void setClassPath(Path classpath) throws Exception;
410
411 protected void customizeJava(final Java java) throws MojoExecutionException {
412 assert java != null;
413
414
415 }
416
417 protected boolean verifyProcessStarted() throws Exception {
418 return true;
419 }
420 }