KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > avalon > phoenix > components > application > DefaultApplication


1 /*
2  * Copyright (C) The Apache Software Foundation. All rights reserved.
3  *
4  * This software is published under the terms of the Apache Software License
5  * version 1.1, a copy of which has been included with this distribution in
6  * the LICENSE.txt file.
7  */

8 package org.apache.avalon.phoenix.components.application;
9
10 import java.util.Arrays JavaDoc;
11 import java.util.HashMap JavaDoc;
12 import java.util.List JavaDoc;
13 import org.apache.avalon.excalibur.i18n.ResourceManager;
14 import org.apache.avalon.excalibur.i18n.Resources;
15 import org.apache.avalon.framework.activity.Disposable;
16 import org.apache.avalon.framework.activity.Initializable;
17 import org.apache.avalon.framework.activity.Startable;
18 import org.apache.avalon.framework.logger.AbstractLogEnabled;
19 import org.apache.avalon.framework.logger.Logger;
20 import org.apache.avalon.phoenix.ApplicationListener;
21 import org.apache.avalon.phoenix.BlockListener;
22 import org.apache.avalon.phoenix.interfaces.Application;
23 import org.apache.avalon.phoenix.interfaces.ApplicationContext;
24 import org.apache.avalon.phoenix.interfaces.ApplicationException;
25 import org.apache.avalon.phoenix.interfaces.ApplicationMBean;
26 import org.apache.avalon.phoenix.metadata.BlockListenerMetaData;
27 import org.apache.avalon.phoenix.metadata.BlockMetaData;
28 import org.apache.avalon.phoenix.metadata.SarMetaData;
29 import org.apache.excalibur.containerkit.lifecycle.LifecycleException;
30 import org.apache.excalibur.containerkit.lifecycle.LifecycleHelper;
31 import org.apache.excalibur.threadcontext.ThreadContext;
32
33 /**
34  * This is the basic container of blocks. A server application
35  * represents an aggregation of blocks that act together to form
36  * an application.
37  *
38  * @author <a HREF="mailto:peter at apache.org">Peter Donald</a>
39  * @author <a HREF="mailto:leosimons@apache.org">Leo Simons</a>
40  */

41 public final class DefaultApplication
42     extends AbstractLogEnabled
43     implements Application, ApplicationMBean, Initializable, Startable, Disposable
44 {
45     private static final Resources REZ =
46         ResourceManager.getPackageResources( DefaultApplication.class );
47
48     private static final String JavaDoc PHASE_STARTUP = "startup";
49
50     private static final String JavaDoc PHASE_SHUTDOWN = "shutdown";
51
52     private boolean m_running = false;
53
54     private ApplicationContext m_context;
55
56     private HashMap JavaDoc m_entries = new HashMap JavaDoc();
57
58     /**
59      * ResourceProvider for blocks.
60      */

61     private BlockResourceProvider m_blockAccessor;
62
63     /**
64      * ResourceProvider for listeners.
65      */

66     private ListenerResourceProvider m_listenerAccessor;
67
68     /**
69      * Object to support notification of ApplicationListeners.
70      */

71     private ListenerSupport m_listenerSupport = new ListenerSupport();
72
73     /**
74      * Object to support running objects through lifecycle phases.
75      */

76     private final LifecycleHelper m_lifecycleHelper = new LifecycleHelper();
77
78     /**
79      * Object to help exporting object.
80      */

81     private final ExportHelper m_exportHelper = new ExportHelper();
82
83     ///////////////////////
84
// LifeCycle Methods //
85
///////////////////////
86
public void enableLogging( Logger logger )
87     {
88         super.enableLogging( logger );
89         setupLogger( m_lifecycleHelper );
90         setupLogger( m_exportHelper );
91     }
92
93     public void initialize()
94         throws Exception JavaDoc
95     {
96         try
97         {
98             // load block listeners
99
loadBlockListeners();
100         }
101         catch( final Throwable JavaDoc t )
102         {
103             getLogger().info( "exception while loading listeners:" + t.getMessage() + "\n" );
104             t.printStackTrace();
105             throw new ApplicationException( t.getMessage(), t );
106         }
107     }
108
109     /**
110      * Start the application running.
111      * This is only valid when isRunning() returns false,
112      * otherwise it will generate an IllegalStateException.
113      *
114      * @throws IllegalStateException if application is already running
115      * @throws ApplicationException if the application failed to start.
116      * the message part of exception will contain more information
117      * pertaining to why the application failed to startup
118      */

119     public void start()
120         throws IllegalStateException JavaDoc, ApplicationException
121     {
122         if( isRunning() )
123         {
124             throw new IllegalStateException JavaDoc();
125         }
126         else
127         {
128             try
129             {
130                 final BlockMetaData[] blocks = m_context.getMetaData().getBlocks();
131                 for( int i = 0; i < blocks.length; i++ )
132                 {
133                     final String JavaDoc blockName = blocks[ i ].getName();
134                     final BlockEntry blockEntry = new BlockEntry( blocks[ i ] );
135                     m_entries.put( blockName, blockEntry );
136                 }
137
138                 // load blocks
139
runPhase( PHASE_STARTUP );
140             }
141             catch( final Throwable JavaDoc t )
142             {
143                 getLogger().info( "exception while starting:" + t.getMessage() + "\n" );
144                 t.printStackTrace();
145                 throw new ApplicationException( t.getMessage(), t );
146             }
147
148             m_running = true;
149         }
150     }
151
152     /**
153      * Shutdown and restart the application running.
154      * This is only valid when isRunning() returns true,
155      * otherwise it will generate an IllegalStateException.
156      * This is equivelent to calling stop() and then start()
157      * in succession.
158      *
159      * @throws IllegalStateException if application is not already running
160      * @throws ApplicationException if the application failed to stop or start.
161      * the message part of exception will contain more information
162      * pertaining to why the application failed to startup/shutdown
163      */

164     public void restart()
165         throws IllegalStateException JavaDoc, ApplicationException
166     {
167         stop();
168         start();
169     }
170
171     /**
172      * Stop the application running.
173      * This is only valid when isRunning() returns true,
174      * otherwise it will generate an IllegalStateException.
175      *
176      * @throws IllegalStateException if application is not already running
177      * @throws ApplicationException if the application failed to shutdown.
178      * the message part of exception will contain more information
179      * pertaining to why the application failed to shutodwn
180      */

181     public void stop()
182         throws IllegalStateException JavaDoc, ApplicationException
183     {
184         if( !isRunning() )
185         {
186             throw new IllegalStateException JavaDoc();
187         }
188         else
189         {
190             try
191             {
192                 runPhase( PHASE_SHUTDOWN );
193             }
194             catch( final Throwable JavaDoc t )
195             {
196                 getLogger().info( "exception while stopping:" + t.getMessage() + "\n" );
197                 t.printStackTrace();
198                 throw new ApplicationException( t.getMessage(), t );
199             }
200
201             m_running = false;
202         }
203     }
204
205     public void dispose()
206     {
207         m_entries.clear();
208     }
209
210     ////////////////////////////
211
// Public Utility Methods //
212
////////////////////////////
213
public void setApplicationContext( final ApplicationContext context )
214     {
215         m_context = context;
216         m_blockAccessor = new BlockResourceProvider( context, this );
217         setupLogger( m_blockAccessor, "lifecycle" );
218         m_listenerAccessor = new ListenerResourceProvider( context );
219         setupLogger( m_listenerAccessor, "lifecycle" );
220     }
221
222     public String JavaDoc[] getBlockNames()
223     {
224         return (String JavaDoc[])m_entries.keySet().toArray( new String JavaDoc[ 0 ] );
225     }
226
227     /**
228      *
229      *
230      * @param name
231      * @return
232      */

233     public Object JavaDoc getBlock( final String JavaDoc name )
234     {
235         final BlockEntry entry = (BlockEntry)m_entries.get( name );
236         if( null == entry )
237         {
238             return null;
239         }
240         else
241         {
242             return entry.getProxy();
243         }
244     }
245
246     /**
247      * Get the name of the application.
248      *
249      * @return the name of the application
250      */

251     public String JavaDoc getName()
252     {
253         return getMetaData().getName();
254     }
255
256     /**
257      * Get the name to display in Management UI.
258      *
259      * @return the name of the application to display in UI
260      */

261     public String JavaDoc getDisplayName()
262     {
263         return getMetaData().getName();
264     }
265
266     /**
267      * Get the string used to describe the application in the UI.
268      *
269      * @return a short description of the application
270      */

271     public String JavaDoc getDescription()
272     {
273         return "The " + getDisplayName() + " application.";
274     }
275
276     /**
277      * Get location of Application installation
278      *
279      * @return the home directory of application
280      */

281     public String JavaDoc getHomeDirectory()
282     {
283         return getMetaData().getHomeDirectory().getPath();
284     }
285
286     /**
287      * Return true if the application is
288      * running or false otherwise.
289      *
290      * @return true if application is running, false otherwise
291      */

292     public boolean isRunning()
293     {
294         return m_running;
295     }
296
297     protected final SarMetaData getMetaData()
298     {
299         return m_context.getMetaData();
300     }
301
302     /////////////////////////////
303
// Private Utility Methods //
304
/////////////////////////////
305

306     private void loadBlockListeners()
307         throws Exception JavaDoc
308     {
309         //Setup thread context for calling visitors
310
ThreadContext.setThreadContext( m_context.getThreadContext() );
311
312         try
313         {
314             doLoadBlockListeners();
315         }
316         finally
317         {
318             ThreadContext.setThreadContext( null );
319         }
320     }
321
322     /**
323      * Actually perform loading of each individual Listener.
324      * Note that by this stage it is assumed that the ThreadContext
325      * has already been setup correctly.
326      */

327     private void doLoadBlockListeners()
328         throws Exception JavaDoc
329     {
330         final BlockListenerMetaData[] listeners = m_context.getMetaData().getListeners();
331         for( int i = 0; i < listeners.length; i++ )
332         {
333             try
334             {
335                 startupListener( listeners[ i ] );
336             }
337             catch( final Exception JavaDoc e )
338             {
339                 final String JavaDoc name = listeners[ i ].getName();
340                 final String JavaDoc message =
341                     REZ.getString( "bad-listener", "startup", name, e.getMessage() );
342                 getLogger().error( message, e );
343                 throw e;
344             }
345         }
346     }
347
348     /**
349      * Run a phase for application.
350      * Each phase transitions application into new state and processes
351      * all the blocks to make sure they are in that state aswell.
352      * Exceptions leave the blocks in an indeterminate state.
353      *
354      * @param name the name of phase (for logging purposes)
355      * @throws Exception if an error occurs
356      */

357     private final void runPhase( final String JavaDoc name )
358         throws Exception JavaDoc
359     {
360         //Setup thread context for calling visitors
361
ThreadContext.setThreadContext( m_context.getThreadContext() );
362
363         try
364         {
365             doRunPhase( name );
366         }
367         finally
368         {
369             ThreadContext.setThreadContext( null );
370         }
371     }
372
373     /**
374      * Actually run applications phas.
375      * By this methods calling it is assumed that ThreadContext
376      * has already been setup.
377      *
378      * @param name the name of phase (for logging purposes)
379      * @throws Exception if an error occurs
380      */

381     private final void doRunPhase( final String JavaDoc name )
382         throws Exception JavaDoc
383     {
384         final BlockMetaData[] blocks = m_context.getMetaData().getBlocks();
385         final String JavaDoc[] order = DependencyGraph.walkGraph( PHASE_STARTUP == name, blocks );
386
387         //Log message describing the number of blocks
388
//the phase in and the order in which they will be
389
//processed
390
if( getLogger().isInfoEnabled() )
391         {
392             final Integer JavaDoc count = new Integer JavaDoc( blocks.length );
393             final List JavaDoc pathList = Arrays.asList( order );
394             final String JavaDoc message =
395                 REZ.getString( "blocks-processing", count, name, pathList );
396             getLogger().info( message );
397         }
398
399         //All blocks about to be processed ...
400
if( PHASE_STARTUP == name )
401         {
402             //... for startup, so indicate to applicable listeners
403
m_listenerSupport.fireApplicationStartingEvent( getMetaData() );
404         }
405         else
406         {
407             //... for shutdown, so indicate to applicable listeners
408
m_listenerSupport.applicationStopping();
409         }
410
411         //Process blocks, one by one.
412

413         for( int i = 0; i < order.length; i++ )
414         {
415             final String JavaDoc block = order[ i ];
416
417             //Log message saying we are processing block
418
if( getLogger().isDebugEnabled() )
419             {
420                 final String JavaDoc message = REZ.getString( "process-block", block, name );
421                 getLogger().debug( message );
422             }
423
424             try
425             {
426                 final BlockEntry entry = (BlockEntry)m_entries.get( block );
427                 if( PHASE_STARTUP == name )
428                 {
429                     startup( entry );
430                 }
431                 else
432                 {
433                     shutdown( entry );
434                 }
435             }
436             catch( final Exception JavaDoc e )
437             {
438                 final String JavaDoc message =
439                     REZ.getString( "app.error.run-phase", name, block, e.getMessage() );
440                 getLogger().error( message, e );
441                 m_listenerSupport.applicationFailure( e );
442                 throw e;
443             }
444
445             //Log message saying we have processed block
446
if( getLogger().isDebugEnabled() )
447             {
448                 final String JavaDoc message = REZ.getString( "processed-block", block, name );
449                 getLogger().debug( message );
450             }
451         }
452
453         //All blocks processed ...
454
if( PHASE_STARTUP == name )
455         {
456             //... for startup, so indicate to applicable listeners
457
m_listenerSupport.applicationStarted();
458         }
459         else
460         {
461             //... for shutdown, so indicate to applicable listeners
462
m_listenerSupport.applicationStopped();
463         }
464     }
465
466     /**
467      * Method to run a Block through it's startup phase.
468      * This will involve notification of {@link BlockListener}
469      * objects, creation of the Block/Block Proxy object, calling the startup
470      * Avalon Lifecycle methods and updating State property of BlockEntry.
471      * Errors that occur during shutdown will be logged appropriately and
472      * cause exceptions with useful messages to be raised.
473      *
474      * @param entry the entry containing Block
475      * @throws Exception if an error occurs when block passes
476      * through a specific lifecycle stage
477      */

478     public void startup( final BlockEntry entry )
479         throws Exception JavaDoc
480     {
481         final Object JavaDoc block =
482             m_lifecycleHelper.startup( entry.getName(),
483                                        entry,
484                                        m_blockAccessor );
485
486         m_exportHelper.exportBlock( m_context,
487                                     entry.getMetaData(),
488                                     block );
489
490         entry.setObject( block );
491
492         m_listenerSupport.fireBlockAddedEvent( entry );
493     }
494
495     /**
496      * Method to run a Block through it's shutdown phase.
497      * This will involve notification of {@link BlockListener}
498      * objects, invalidating the proxy object, calling the shutdown
499      * Avalon Lifecycle methods and updating State property of BlockEntry.
500      * Errors that occur during shutdown will be logged appropraitely.
501      *
502      * @param entry the entry containing Block
503      */

504     public void shutdown( final BlockEntry entry )
505         throws LifecycleException
506     {
507         m_listenerSupport.fireBlockRemovedEvent( entry );
508
509         final Object JavaDoc object = entry.getObject();
510         try
511         {
512             //Remove block from Management system
513
m_exportHelper.unexportBlock( m_context,
514                                           entry.getMetaData(),
515                                           object );
516             entry.invalidate();
517
518             m_lifecycleHelper.shutdown( entry.getName(),
519                                         object );
520         }
521         finally
522         {
523             entry.setObject( null );
524         }
525     }
526
527     /**
528      * Method to run a {@link BlockListener} through it's startup phase.
529      * This will involve creation of BlockListener object and configuration of
530      * object if appropriate.
531      *
532      * @param metaData the BlockListenerMetaData
533      * @throws Exception if an error occurs when listener passes
534      * through a specific lifecycle stage
535      */

536     public void startupListener( final BlockListenerMetaData metaData )
537         throws Exception JavaDoc
538     {
539         final String JavaDoc name = metaData.getName();
540         final Object JavaDoc listener =
541             m_lifecycleHelper.startup( name,
542                                        metaData,
543                                        m_listenerAccessor );
544
545         // However onky ApplicationListners can avail of block events.
546
if( listener instanceof ApplicationListener )
547         {
548             m_listenerSupport.addApplicationListener( (ApplicationListener)listener );
549         }
550         else
551         {
552             // As ApplicationListners are BlockListeners then
553
//this is applicable for all
554
m_listenerSupport.addBlockListener( (BlockListener)listener );
555
556             final String JavaDoc message =
557                 REZ.getString( "helper.isa-blocklistener.error",
558                                name,
559                                metaData.getClassname() );
560             getLogger().error( message );
561             System.err.println( message );
562         }
563     }
564 }
565
Popular Tags