KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > codehaus > loom > components > application > DefaultApplication


1 /* ====================================================================
2  * Loom Software License, version 1.1
3  *
4  * Copyright (c) 2003, Loom Group. All rights reserved.
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  * 1. Redistributions of source code must retain the above copyright
10  * notice, this list of conditions and the following disclaimer.
11  *
12  * 2. Redistributions in binary form must reproduce the above copyright
13  * notice, this list of conditions and the following disclaimer in
14  * the documentation and/or other materials provided with the
15  * distribution.
16  *
17  * 3. Neither the name of the Loom Group nor the name "Loom" nor
18  * the names of its contributors may be used to endorse or promote
19  * products derived from this software without specific prior
20  * written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
25  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
26  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
27  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
28  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
29  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
30  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
32  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33  * POSSIBILITY OF SUCH DAMAGE.
34  *
35  * ====================================================================
36  *
37  * Loom includes code from the Apache Software Foundation
38  *
39  * ====================================================================
40  * The Apache Software License, Version 1.1
41  *
42  * Copyright (c) 1997-2003 The Apache Software Foundation. All rights
43  * reserved.
44  *
45  * Redistribution and use in source and binary forms, with or without
46  * modification, are permitted provided that the following conditions
47  * are met:
48  *
49  * 1. Redistributions of source code must retain the above copyright
50  * notice, this list of conditions and the following disclaimer.
51  *
52  * 2. Redistributions in binary form must reproduce the above copyright
53  * notice, this list of conditions and the following disclaimer in
54  * the documentation and/or other materials provided with the
55  * distribution.
56  *
57  * 3. The end-user documentation included with the redistribution,
58  * if any, must include the following acknowledgment:
59  * "This product includes software developed by the
60  * Apache Software Foundation (http://www.apache.org/)."
61  * Alternately, this acknowledgment may appear in the software
62  * itself, if and wherever such third-party acknowledgments
63  * normally appear.
64  *
65  * 4. The names "Jakarta", "Avalon", and "Apache Software Foundation"
66  * must not be used to endorse or promote products derived from this
67  * software without prior written permission. For written
68  * permission, please contact apache@apache.org.
69  *
70  * 5. Products derived from this software may not be called "Apache",
71  * nor may "Apache" appear in their name, without prior written
72  * permission of the Apache Software Foundation.
73  *
74  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
75  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
76  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
77  * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
78  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
79  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
80  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
81  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
82  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
83  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
84  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
85  * SUCH DAMAGE.
86  */

87 package org.codehaus.loom.components.application;
88
89 import java.io.File JavaDoc;
90 import java.util.Arrays JavaDoc;
91 import java.util.HashMap JavaDoc;
92 import java.util.List JavaDoc;
93
94 import org.apache.avalon.phoenix.ApplicationListener;
95 import org.apache.avalon.phoenix.BlockListener;
96 import org.apache.avalon.phoenix.metadata.SarMetaData;
97
98 import org.codehaus.loom.components.util.ComponentMetaDataConverter;
99 import org.codehaus.loom.components.util.lifecycle.LifecycleHelper;
100 import org.codehaus.loom.components.util.profile.ComponentProfile;
101 import org.codehaus.loom.components.util.profile.PartitionProfile;
102 import org.codehaus.loom.interfaces.Application;
103 import org.codehaus.loom.interfaces.ApplicationContext;
104 import org.codehaus.loom.interfaces.ContainerConstants;
105 import org.codehaus.loom.interfaces.LoomException;
106 import org.codehaus.spice.salt.i18n.ResourceManager;
107 import org.codehaus.spice.salt.i18n.Resources;
108 import org.codehaus.dna.AbstractLogEnabled;
109 import org.codehaus.dna.Active;
110 import org.codehaus.dna.Logger;
111
112 /**
113  * This is the basic container of blocks. A server application represents an aggregation of blocks that act together to
114  * form an application.
115  *
116  * @author Peter Donald
117  * @author Leo Simons
118  * @dna.component
119  * @mx.component
120  */

121 public final class DefaultApplication
122     extends AbstractLogEnabled
123     implements Application, Active
124 {
125     private static final Resources REZ =
126         ResourceManager.getPackageResources( DefaultApplication.class );
127
128     private static final String JavaDoc PHASE_STARTUP = "startup";
129
130     private static final String JavaDoc PHASE_SHUTDOWN = "shutdown";
131
132     private boolean m_running = false;
133
134     private ApplicationContext m_context;
135
136     private final HashMap JavaDoc m_entries = new HashMap JavaDoc();
137
138     /**
139      * ResourceProvider for blocks.
140      */

141     private BlockResourceProvider m_blockAccessor;
142
143     /**
144      * Object to support notification of ApplicationListeners.
145      */

146     private final ListenerSupport m_listenerSupport = new ListenerSupport();
147
148     /**
149      * Object to support running objects through lifecycle phases.
150      */

151     private final LifecycleHelper m_lifecycleHelper = new LifecycleHelper();
152
153     ///////////////////////
154
// LifeCycle Methods //
155
///////////////////////
156
public void enableLogging( final Logger logger )
157     {
158         super.enableLogging( logger );
159         setupLogger( m_lifecycleHelper );
160     }
161
162     public void initialize()
163         throws Exception JavaDoc
164     {
165         try
166         {
167             // load block listeners
168
loadBlockListeners();
169         }
170         catch( final Throwable JavaDoc t )
171         {
172             getLogger().info( "Exception loading listeners:" + t.getMessage() + "\n", t );
173             throw new LoomException( t.getMessage(), t );
174         }
175         try
176         {
177             final PartitionProfile partition =
178                 m_context.getPartitionProfile().getPartition( ContainerConstants.BLOCK_PARTITION );
179             final ComponentProfile[] blocks = partition.getComponents();
180             for( int i = 0; i < blocks.length; i++ )
181             {
182                 final String JavaDoc blockName = blocks[i].getTemplate().getName();
183                 final BlockEntry blockEntry = new BlockEntry( blocks[i] );
184                 m_entries.put( blockName, blockEntry );
185             }
186
187             // load blocks
188
runPhase( PHASE_STARTUP );
189         }
190         catch( final Throwable JavaDoc t )
191         {
192             getLogger().info( "exception while starting:" + t.getMessage() + "\n" );
193             t.printStackTrace();
194             throw new LoomException( t.getMessage(), t );
195         }
196
197         m_running = true;
198     }
199
200     public void dispose()
201     {
202         try
203         {
204             runPhase( PHASE_SHUTDOWN );
205         }
206         catch( final Throwable JavaDoc t )
207         {
208             getLogger().info( "Exception stopping:" + t.getMessage() + "\n",
209                               t );
210         }
211
212         m_running = false;
213         m_entries.clear();
214     }
215
216     ////////////////////////////
217
// Public Utility Methods //
218
////////////////////////////
219
public void setApplicationContext( final ApplicationContext context )
220     {
221         m_context = context;
222         m_blockAccessor = new BlockResourceProvider( context, this );
223         setupLogger( m_blockAccessor, "lifecycle" );
224     }
225
226     /**
227      * @mx.attribute description="the names of the blocks that compose this Application"
228      */

229     public String JavaDoc[] getBlockNames()
230     {
231         return (String JavaDoc[])m_entries.keySet().toArray( new String JavaDoc[0] );
232     }
233
234     public Object JavaDoc getBlock( final String JavaDoc name )
235     {
236         final BlockEntry entry = (BlockEntry)m_entries.get( name );
237         if( null == entry )
238         {
239             return null;
240         }
241         else
242         {
243             return entry.getProxy();
244         }
245     }
246
247     /**
248      * @mx.attribute description="the name of the application."
249      */

250     public String JavaDoc getName()
251     {
252         return m_context.getPartitionProfile().getMetaData().getName();
253     }
254
255     /**
256      * @mx.attribute description="the name to display in Management UI."
257      */

258     public String JavaDoc getDisplayName()
259     {
260         return m_context.getPartitionProfile().getMetaData().getName();
261     }
262
263     /**
264      * @mx.attribute description="the string used to describe the application in the UI."
265      */

266     public String JavaDoc getDescription()
267     {
268         return "The " + getDisplayName() + " application.";
269     }
270
271     /**
272      * @mx.attribute description="the location of Application installation"
273      */

274     public String JavaDoc getHomeDirectory()
275     {
276         return m_context.getHomeDirectory().getPath();
277     }
278
279     /**
280      * @mx.attribute description="True if the application is running or false otherwise."
281      */

282     public boolean isRunning()
283     {
284         return m_running;
285     }
286
287     /////////////////////////////
288
// Private Utility Methods //
289
/////////////////////////////
290

291     private void loadBlockListeners()
292         throws Exception JavaDoc
293     {
294         //Setup thread context for calling visitors
295
final ClassLoader JavaDoc loader = Thread.currentThread()
296             .getContextClassLoader();
297         Thread.currentThread().setContextClassLoader( m_context.getClassLoader() );
298
299         try
300         {
301             doLoadBlockListeners();
302         }
303         finally
304         {
305             Thread.currentThread().setContextClassLoader( loader );
306         }
307     }
308
309     /**
310      * Actually perform loading of each individual Listener. Note that by this stage it is assumed that the Thread
311      * Context has already been setup correctly.
312      */

313     private void doLoadBlockListeners()
314         throws Exception JavaDoc
315     {
316         final ComponentProfile[] listeners =
317             getComponentsInPartition( ContainerConstants.LISTENER_PARTITION );
318         for( int i = 0; i < listeners.length; i++ )
319         {
320             try
321             {
322                 startupListener( listeners[i] );
323             }
324             catch( final Exception JavaDoc e )
325             {
326                 final String JavaDoc name = listeners[i].getTemplate().getName();
327                 final String JavaDoc message =
328                     REZ.format( "bad-listener",
329                                 "startup",
330                                 name,
331                                 e.getMessage() );
332                 getLogger().error( message, e );
333                 throw e;
334             }
335         }
336     }
337
338     private ComponentProfile[] getComponentsInPartition( final String JavaDoc key )
339     {
340         final PartitionProfile partition =
341             m_context.getPartitionProfile().getPartition( key );
342         return partition.getComponents();
343     }
344
345     /**
346      * Run a phase for application. Each phase transitions application into new state and processes all the blocks to
347      * make sure they are in that state aswell. Exceptions leave the blocks in an indeterminate state.
348      *
349      * @param name the name of phase (for logging purposes)
350      *
351      * @throws Exception if an error occurs
352      */

353     private final void runPhase( final String JavaDoc name )
354         throws Exception JavaDoc
355     {
356         //Setup thread context for calling visitors
357
final ClassLoader JavaDoc loader = Thread.currentThread()
358             .getContextClassLoader();
359         Thread.currentThread().setContextClassLoader( m_context.getClassLoader() );
360
361         try
362         {
363             doRunPhase( name );
364         }
365         finally
366         {
367             Thread.currentThread().setContextClassLoader( loader );
368         }
369     }
370
371     /**
372      * Actually run applications phas. By this methods calling it is assumed that Thread Context has already been
373      * setup.
374      *
375      * @param name the name of phase (for logging purposes)
376      *
377      * @throws Exception if an error occurs
378      */

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

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

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

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

542     private void startupListener( final ComponentProfile profile )
543         throws Exception JavaDoc
544     {
545         final String JavaDoc name = profile.getTemplate().getName();
546         final Object JavaDoc listener =
547             m_lifecycleHelper.startup( name,
548                                        new BlockEntry( profile ),
549                                        m_blockAccessor );
550
551         // However onky ApplicationListners can avail of block events.
552
if( listener instanceof ApplicationListener )
553         {
554             m_listenerSupport.addApplicationListener( (ApplicationListener)listener );
555         }
556         else
557         {
558             // As ApplicationListners are BlockListeners then
559
//this is applicable for all
560
m_listenerSupport.addBlockListener( (BlockListener)listener );
561
562             final String JavaDoc message =
563                 REZ.format( "helper.isa-blocklistener.error",
564                             name,
565                             profile.getTemplate().getImplementationKey() );
566             getLogger().error( message );
567             System.err.println( message );
568         }
569     }
570 }
571
Popular Tags