1 package org.apache.fulcrum.yaafi.cli;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import java.io.File;
23
24 import org.apache.avalon.framework.activity.Disposable;
25 import org.apache.avalon.framework.logger.ConsoleLogger;
26 import org.apache.avalon.framework.logger.Logger;
27 import org.apache.avalon.framework.service.ServiceManager;
28 import org.apache.fulcrum.yaafi.framework.container.ServiceContainer;
29 import org.apache.fulcrum.yaafi.framework.factory.ServiceContainerConfiguration;
30 import org.apache.fulcrum.yaafi.framework.factory.ServiceContainerFactory;
31
32
33 /**
34 * An example of the embedding of a YAAFI kernel inside an
35 * arbitrary application.
36 */
37
38 public class Main implements Runnable, Disposable
39 {
40 /** parameter for the application name */
41 public static final String APPLICATION_NAME = "yaafi.cli.applicationName";
42
43 /** parameter for the application home directory */
44 public static final String APPLICATION_HOME = "yaafi.cli.applicationHome";
45
46 /** parameter for the application temporary directory */
47 public static final String APPLICATION_TEMP = "yaafi.cli.tempHome";
48
49 /** parameter for the application container configuration file */
50 public static final String APPLICATION_CONFIG = "yaafi.cli.config";
51
52 /** parameter for setting a shutdown hook */
53 public static final String APPLICATION_HASSHUTDOWNHOOK = "yaafi.cli.hasShutdownHook";
54
55 /** parameter for blocking the main thread in Main.run() */
56 public static final String APPLICATION_ISBLOCKING = "yaafi.cli.isBlocking";
57
58 /** the interval to check for termination */
59 private static final int SLEEP_TIME = 100;
60
61 /** the timeout for joing the shutdown thread */
62 private static final int JOIN_TIME = 1000;
63
64 /** The service manager */
65 private ServiceContainer container;
66
67 /** The location of the container configuration */
68 private String containerConfigValue;
69
70 /** Thread for processing the shutdown notification of the JVM */
71 private Thread shutdownThread;
72
73 /** Do we block the invoking thread until the JVM terminates ?! */
74 private boolean isBlocking;
75
76 /** Do we install a shutdown hook for the JVM ?! */
77 private boolean hasShutdownHook;
78
79 /** The logger being used */
80 private Logger logger;
81
82 /** the name of the application */
83 private String applicationName;
84
85 /** the working directory */
86 private String applicationHome;
87
88 /** the temp directory */
89 private String tempHome;
90
91 /** the command line arguments */
92 private String[] args;
93
94 /** is the instance properly initialized */
95 private volatile boolean isInitialized;
96
97
98 /**
99 * Constructor
100 */
101 public Main()
102 {
103
104
105 this.containerConfigValue = "./conf/containerConfiguration.xml";
106 this.logger = new ConsoleLogger();
107 this.applicationHome = ".";
108 this.tempHome = System.getProperty("java.io.tmpdir",".");
109 this.applicationName = "main";
110 this.args = ( args != null ? args : new String[0] );
111 this.isBlocking = false;
112 this.hasShutdownHook = true;
113 this.isInitialized = false;
114
115
116
117 this.containerConfigValue = System.getProperty(
118 APPLICATION_CONFIG,
119 this.containerConfigValue
120 );
121
122 this.applicationName = System.getProperty(
123 APPLICATION_NAME,
124 this.applicationName
125 );
126
127 this.applicationHome = System.getProperty(
128 APPLICATION_HOME,
129 this.applicationHome
130 );
131
132 this.tempHome = System.getProperty(
133 APPLICATION_TEMP,
134 this.tempHome
135 );
136 }
137
138 /**
139 * Constructor
140 *
141 * The following command line parameters are supported
142 * <ul>
143 * <li>--yaafi.cli.applicationName name</li>
144 * <li>--yaafi.cli.applicationHome dir</li>
145 * <li>--yaafi.cli.tempHome dir</li>
146 * <li>--yaafi.cli.isBlocking [true|false]</li>
147 * <li>--yaafi.cli.hasShutdownHook [true|false]</li>
148 * <li>--yaafi.cli.config file</li>
149 * </ul>
150 *
151 * @param args the command line arguments
152 */
153 public Main( String[] args )
154 {
155 this();
156
157 this.args = args;
158
159
160
161 Getopt getopt = new Getopt(this.args);
162
163 this.setApplicationName(
164 getopt.getStringValue( APPLICATION_NAME, this.getApplicationName() )
165 );
166
167 this.setApplicationHome(
168 getopt.getStringValue( APPLICATION_HOME, this.getApplicationHome() )
169 );
170
171 this.setTempHome(
172 getopt.getStringValue( APPLICATION_TEMP, this.getTempHome() )
173 );
174
175 this.setContainerConfigValue(
176 getopt.getStringValue( APPLICATION_CONFIG, this.getContainerConfigValue() )
177 );
178
179 this.setIsBlocking(
180 getopt.getBooleanValue( APPLICATION_ISBLOCKING, this.isBlocking )
181 );
182
183 this.setHasShutdownHook(
184 getopt.getBooleanValue( APPLICATION_HASSHUTDOWNHOOK, this.hasShutdownHook )
185 );
186 }
187
188 /**
189 * The main method.
190 *
191 * @param args Command line arguments
192 * @throws Exception the execution failed
193 */
194 public static void main( String[] args ) throws Exception
195 {
196 int exitCode = 0;
197
198 Main impl = new Main(args);
199
200 try
201 {
202 impl.run();
203 }
204 catch (Throwable t)
205 {
206 exitCode = 1;
207 }
208 finally
209 {
210 System.exit(exitCode);
211 }
212 }
213
214 /**
215 * Determines the file location of the given name. If the name denotes
216 * a relative file location it will be rsolved using the application
217 * home directory.
218 *
219 * @param baseDir the base directory
220 * @param name the filename
221 * @return the file
222 */
223 public static File makeAbsoluteFile( File baseDir, String name )
224 {
225 File result = new File(name);
226
227 if( result.isAbsolute() == false )
228 {
229 result = new File( baseDir, name );
230 }
231
232 return result;
233 }
234
235 /**
236 * Dispose the YAAFI container
237 */
238
239 public synchronized void dispose()
240 {
241 this.shutdown();
242 }
243
244 /**
245 * Runs the instance by initializing it and potentially blocking
246 * the invoking thread depending on the configuration.
247 *
248 * @see java.lang.Runnable#run()
249 */
250 public void run()
251 {
252 try
253 {
254 this.initialize();
255 this.onWait();
256 }
257 catch (Throwable t)
258 {
259 String msg = "Failed to run " + this.getClass().getName();
260 this.getLogger().error(msg,t);
261 throw new RuntimeException(t.getMessage());
262 }
263 }
264
265 /**
266 * Depending on the configuration this method might block
267 * the calling thread or return immediatly. We currently
268 * poll a volatile variable which is not the most elegant
269 * solution.
270 */
271 public void onWait()
272 {
273 while( this.isBlocking() && this.isInitialized() )
274 {
275 try
276 {
277 Thread.sleep(Main.SLEEP_TIME);
278 }
279 catch (InterruptedException e)
280 {
281
282 }
283 }
284 }
285
286 /**
287 * Locates the file for the given file name.
288 * @param fileName the filename
289 * @return an absolute file
290 */
291 public File makeAbsoluteFile( String fileName )
292 {
293 return Main.makeAbsoluteFile(
294 new File(this.getApplicationHome()),
295 fileName
296 );
297 }
298
299 /**
300 * Locates the file for the given file name.
301 * @param fileName the filename
302 * @return an absolute path
303 */
304 public String makeAbsolutePath( String fileName )
305 {
306 return Main.makeAbsoluteFile(
307 new File(this.getApplicationHome()),
308 fileName
309 ).getAbsolutePath();
310 }
311
312
313
314
315
316 /**
317 * @return Returns the ServiceContainer interface
318 */
319 public ServiceContainer getServiceContainer()
320 {
321 return this.container;
322 }
323
324 /**
325 * @return Returns the ServiceManager interface
326 */
327 public ServiceManager getServiceManager()
328 {
329 return this.container;
330 }
331
332 /**
333 * @return Returns the applicationHome.
334 */
335 public String getApplicationHome()
336 {
337 return this.applicationHome;
338 }
339
340 /**
341 * @param applicationHome The applicationHome to set.
342 */
343 public void setApplicationHome(String applicationHome)
344 {
345 this.applicationHome = applicationHome;
346 }
347
348 /**
349 * @return Returns the containerConfigValue.
350 */
351 public String getContainerConfigValue()
352 {
353 return containerConfigValue;
354 }
355
356 /**
357 * @param containerConfigValue The containerConfigValue to set.
358 */
359 public void setContainerConfigValue(String containerConfigValue)
360 {
361 this.containerConfigValue = containerConfigValue;
362 }
363
364 /**
365 * @return Returns the isBlocking.
366 */
367 public boolean isBlocking()
368 {
369 return isBlocking;
370 }
371
372 /**
373 * @param isBlocking The isBlocking to set.
374 */
375 public void setIsBlocking(boolean isBlocking)
376 {
377 this.isBlocking = isBlocking;
378 }
379
380 /**
381 * @param isBlocking The isBlocking to set.
382 */
383 public void setIsBlocking(Boolean isBlocking)
384 {
385 this.isBlocking = isBlocking.booleanValue();
386 }
387
388 /**
389 * @param isBlocking The isBlocking to set.
390 */
391 public void setIsBlocking(String isBlocking)
392 {
393 this.isBlocking = Boolean.valueOf(isBlocking).booleanValue();
394 }
395
396 /**
397 * @return Returns the tempHome.
398 */
399 public String getTempHome()
400 {
401 return this.tempHome;
402 }
403
404 /**
405 * @param tempHome The tempHome to set.
406 */
407 public void setTempHome(String tempHome)
408 {
409 this.tempHome = tempHome;
410 }
411
412 /**
413 * @return Returns the logger.
414 */
415 public Logger getLogger()
416 {
417 return this.logger;
418 }
419
420 /**
421 * @param logger The logger to set.
422 */
423 public void setLogger(Logger logger)
424 {
425 this.logger = logger;
426 }
427
428 /**
429 * @return Returns the applicationName.
430 */
431 public String getApplicationName()
432 {
433 return applicationName;
434 }
435
436 /**
437 * @param applicationName The applicationName to set.
438 */
439 public void setApplicationName(String applicationName)
440 {
441 this.applicationName = applicationName;
442 }
443
444 /**
445 * @return Returns the args.
446 */
447 public String [] getArgs()
448 {
449 return args;
450 }
451 /**
452 * @param args The args to set.
453 */
454 public void setArgs(String [] args)
455 {
456 this.args = args;
457 }
458
459 /**
460 * @return Returns the hasShutdownHook.
461 */
462 public boolean hasShutdownHook()
463 {
464 return hasShutdownHook;
465 }
466
467 /**
468 * @param hasShutdownHook The hasShutdownHook to set.
469 */
470 public void setHasShutdownHook(boolean hasShutdownHook)
471 {
472 this.hasShutdownHook = hasShutdownHook;
473 }
474
475 /**
476 * @param hasShutdownHook The hasShutdownHook to set.
477 */
478 public void setHasShutdownHook(Boolean hasShutdownHook)
479 {
480 this.hasShutdownHook = hasShutdownHook.booleanValue();
481 }
482
483 /**
484 * @param hasShutdownHook The hasShutdownHook to set.
485 */
486 public void setHasShutdownHook(String hasShutdownHook)
487 {
488 this.hasShutdownHook = Boolean.valueOf(hasShutdownHook).booleanValue();
489 }
490
491 /**
492 * @see java.lang.Object#toString()
493 */
494 public String toString()
495 {
496 StringBuffer result = new StringBuffer();
497 StringBuffer argsLine = new StringBuffer();
498
499 result.append(getClass().getName() + "@" + Integer.toHexString(hashCode()));
500
501 result.append('[');
502 result.append("workingDir=" + new File("").getAbsolutePath());
503 result.append(',');
504
505 result.append("args=");
506
507 for( int i=0; i<this.getArgs().length; i++ )
508 {
509 argsLine.append( this.getArgs()[i] );
510
511 if( (i+1) < this.getArgs().length )
512 {
513 argsLine.append( " " );
514 }
515 }
516
517 result.append( argsLine.toString() );
518 result.append(',');
519
520 result.append("applicationName=" + this.getApplicationName());
521 result.append(',');
522 result.append("applicationHome=" + this.getApplicationHome());
523 result.append(',');
524 result.append("tempHome=" + this.getTempHome());
525 result.append(',');
526 result.append("logger=" + this.getLogger().getClass().getName());
527 result.append(',');
528 result.append("isBlocking=" + this.isBlocking);
529 result.append(',');
530 result.append("hasShutdownHook=" + this.hasShutdownHook());
531 result.append(',');
532 result.append("containerConfigValue=" + this.getContainerConfigValue());
533 result.append(']');
534
535 return result.toString();
536 }
537
538 /**
539 * @return Returns the isInitialized.
540 */
541 public boolean isInitialized()
542 {
543 return isInitialized;
544 }
545
546
547
548
549
550 /**
551 * @param isInitialized The isInitialized to set.
552 */
553 protected void setInitialized(boolean isInitialized)
554 {
555 this.isInitialized = isInitialized;
556 }
557
558 /**
559 * Initialize the instance
560 *
561 * @throws Exception the initialization failed
562 */
563 public void initialize() throws Exception
564 {
565 this.getLogger().debug( "Initializing " + this.getClass().getName() );
566
567 ServiceContainerConfiguration config = new ServiceContainerConfiguration();
568
569
570
571 config.setLogger( this.getLogger() );
572 config.setApplicationRootDir( this.getApplicationHome() );
573 config.setTempRootDir( this.getTempHome() );
574 config.loadContainerConfiguration( this.getContainerConfigValue(), "auto" );
575
576 this.container = ServiceContainerFactory.create( config );
577
578
579
580 if( this.hasShutdownHook() )
581 {
582 this.getLogger().debug( "Registering shutdown hook" );
583 Shutdown shutdown = new Shutdown( this );
584 this.shutdownThread = new Thread( shutdown, "ShutdownThread" );
585 Runtime.getRuntime().addShutdownHook( this.shutdownThread );
586 }
587
588 this.setInitialized(true);
589 }
590
591 /**
592 * Terminates the instance
593 */
594 protected void shutdown()
595 {
596 if( this.isInitialized() == false )
597 {
598 return;
599 }
600
601 this.getLogger().debug( "Terminating " + this.getClass().getName() );
602
603 try
604 {
605
606
607 if( this.shutdownThread != null )
608 {
609 try
610 {
611 this.getLogger().debug( "Waiting for shutdown handler thread to terminate" );
612 this.shutdownThread.join(JOIN_TIME);
613 this.shutdownThread = null;
614 this.getLogger().debug( "Shutdown handler thread is terminated" );
615 }
616 catch (InterruptedException e)
617 {
618
619 }
620 }
621
622
623
624 if( this.getServiceContainer() != null )
625 {
626 this.getServiceContainer().dispose();
627 this.container = null;
628 }
629
630 this.setInitialized(false);
631 }
632
633 catch (Exception e)
634 {
635 String msg = "Failed to terminate " + this.getClass().getName();
636 this.getLogger().error(msg,e);
637 }
638 }
639 }