KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > avalon > phoenix > components > embeddor > DefaultEmbeddor


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.embeddor;
9
10 import java.io.File JavaDoc;
11 import java.util.Date JavaDoc;
12 import java.util.Observable JavaDoc;
13 import java.util.Observer JavaDoc;
14 import org.apache.avalon.excalibur.i18n.ResourceManager;
15 import org.apache.avalon.excalibur.i18n.Resources;
16 import org.apache.avalon.excalibur.io.ExtensionFileFilter;
17 import org.apache.avalon.framework.CascadingException;
18 import org.apache.avalon.framework.activity.Disposable;
19 import org.apache.avalon.framework.activity.Initializable;
20 import org.apache.avalon.framework.configuration.Configurable;
21 import org.apache.avalon.framework.configuration.Configuration;
22 import org.apache.avalon.framework.configuration.ConfigurationException;
23 import org.apache.avalon.framework.container.ContainerUtil;
24 import org.apache.avalon.framework.context.Context;
25 import org.apache.avalon.framework.context.ContextException;
26 import org.apache.avalon.framework.context.Contextualizable;
27 import org.apache.avalon.framework.logger.AbstractLogEnabled;
28 import org.apache.avalon.framework.logger.Logger;
29 import org.apache.avalon.framework.parameters.ParameterException;
30 import org.apache.avalon.framework.parameters.Parameterizable;
31 import org.apache.avalon.framework.parameters.Parameters;
32 import org.apache.avalon.framework.service.DefaultServiceManager;
33 import org.apache.avalon.framework.service.ServiceManager;
34 import org.apache.avalon.phoenix.Constants;
35 import org.apache.avalon.phoenix.interfaces.Deployer;
36 import org.apache.avalon.phoenix.interfaces.Embeddor;
37 import org.apache.avalon.phoenix.interfaces.EmbeddorMBean;
38 import org.apache.avalon.phoenix.interfaces.Kernel;
39 import org.apache.avalon.phoenix.interfaces.SystemManager;
40
41 /**
42  * This is the object that is interacted with to create, manage and
43  * dispose of the kernel and related resources.
44  *
45  * @author <a HREF="mail@leosimons.com">Leo Simons</a>
46  * @author <a HREF="peter at apache.org">Peter Donald</a>
47  * @author <a HREF="bauer@denic.de">Joerg Bauer</a>
48  */

49 public class DefaultEmbeddor
50     extends AbstractLogEnabled
51     implements Embeddor, EmbeddorMBean, Contextualizable,
52     Parameterizable, Configurable, Initializable, Disposable
53 {
54     private static final Resources REZ =
55         ResourceManager.getPackageResources( DefaultEmbeddor.class );
56
57     private static final String JavaDoc DEFAULT_APPS_PATH = "/apps";
58
59     private EmbeddorObservable m_observable = new EmbeddorObservable();
60
61     private Parameters m_parameters;
62
63     /**
64      * Context passed to embeddor. See the contextualize() method
65      * for details on what is stored in context.
66      *
67      * @see DefaultEmbeddor#contextualize(Context)
68      */

69     private Context m_context;
70
71     private String JavaDoc m_phoenixHome;
72
73     private EmbeddorEntry[] m_entries;
74
75     /**
76      * If true, flag indicates that the Embeddor should continue running
77      * even when there are no applications in kernel. Otherwise the
78      * Embeddor will shutdown when it detects there is no longer any
79      * applications running.
80      */

81     private boolean m_persistent;
82
83     /**
84      * Flag is set to true when the embeddor should shut itself down.
85      * It is set to true as a result of a call to shutdown() method.
86      *
87      * @see Embeddor#shutdown()
88      */

89     private boolean m_shutdown;
90
91     /**
92      * Time at which the embeddor was started.
93      */

94     private long m_startTime;
95
96     /**
97      * The default directory in which applications are deployed from.
98      */

99     private String JavaDoc m_appDir;
100
101     /**
102      * Pass the Context to the embeddor.
103      * It is expected that the following will be entries in context;
104      * <ul>
105      * <li><b>common.classloader</b>: ClassLoader shared betweeen
106      * container and applications</li>
107      * <li><b>container.classloader</b>: ClassLoader used to load
108      * container</li>
109      * </ul>
110      *
111      * @param context
112      * @throws ContextException
113      */

114     public void contextualize( final Context context )
115         throws ContextException
116     {
117         m_context = context;
118         try
119         {
120             final Observer JavaDoc observer = (Observer JavaDoc)context.get( Observer JavaDoc.class.getName() );
121             m_observable.addObserver( observer );
122         }
123         catch( final ContextException ce )
124         {
125             final String JavaDoc message = REZ.getString( "embeddor.notice.no-restart" );
126             getLogger().warn( message );
127         }
128     }
129
130     /**
131      * Set parameters for this component.
132      * This must be called after contextualize() and before initialize()
133      *
134      * Make sure to provide all the neccessary information through
135      * these parameters. All information it needs consists of strings.
136      * There are two types of strings included in parameters. The first
137      * type include parameters used to setup proeprties of the embeddor.
138      * The second type include the implementation names of the components
139      * that the Embeddor manages. For instance if you want to replace the
140      * {@link org.apache.avalon.phoenix.interfaces.ConfigurationRepository}
141      * with your own repository you would pass in a parameter such as;</p>
142      * <p>org.apache.avalon.phoenix.interfaces.ConfigurationRepository =
143      * com.biz.MyCustomConfigurationRepository</p>
144      *
145      * <p>Of the other type of parameters, the following are supported by
146      * the DefaultEmbeddor implementation of Embeddor. Note that some of
147      * the embedded components may support other parameters.</p>
148      * <ul>
149      * <li><b>phoenix.home</b>, the home directory of phoenix. Defaults
150      * to "..".</li>
151      * <li><b>log-destination</b>, the file to save log
152      * messages in. If omitted, ${phoenix.home}/logs/phoenix.log is used.</li>
153      * <li><b>log-priority</b>, the priority at which log messages are filteres.
154      * If omitted, then INFO will be default level used.</li>
155      * <li><b>applications-directory</b>, the directory in which
156      * the defaul applications to be loaded by the kernel are stored
157      * (in .sar format). Defaults to ${phoenix.home}/apps</li>
158      * </ul>
159      *
160      * @param parameters the Parameters for embeddor
161      * @throws ParameterException if an error occurs
162      */

163     public synchronized void parameterize( final Parameters parameters )
164         throws ParameterException
165     {
166         m_parameters = parameters;
167         m_phoenixHome = m_parameters.getParameter( "phoenix.home", ".." );
168         m_persistent = m_parameters.getParameterAsBoolean( "persistent", false );
169         m_appDir = m_parameters.getParameter( "phoenix.apps.dir",
170                                               m_phoenixHome + DEFAULT_APPS_PATH );
171     }
172
173     public void configure( final Configuration configuration )
174         throws ConfigurationException
175     {
176         final Configuration[] children = configuration.getChildren( "component" );
177         m_entries = new EmbeddorEntry[ children.length ];
178         for( int i = 0; i < children.length; i++ )
179         {
180             final String JavaDoc role = children[ i ].getAttribute( "role" );
181             final String JavaDoc classname = children[ i ].getAttribute( "class" );
182             final String JavaDoc logger = children[ i ].getAttribute( "logger" );
183             m_entries[ i ] =
184                 new EmbeddorEntry( role, classname, logger, children[ i ] );
185         }
186     }
187
188     /**
189      * Creates the core handlers - logger, deployer, Manager and
190      * Kernel. Note that these are not set up properly until you have
191      * called the {@link #execute()} method.
192      */

193     public void initialize()
194         throws Exception JavaDoc
195     {
196         m_startTime = System.currentTimeMillis();
197         try
198         {
199             createComponents();
200             setupComponents();
201             registerComponents();
202         }
203         catch( final Exception JavaDoc e )
204         {
205             // whoops!
206
final String JavaDoc message = REZ.getString( "embeddor.error.start.failed" );
207             getLogger().fatalError( message, e );
208             throw e;
209         }
210     }
211
212     /**
213      * This is the main method of the embeddor. It sets up the core
214      * components, and then deploys the <code>Facilities</code>. These
215      * are registered with the Kernel and the Manager. The same
216      * happens for the {@link org.apache.avalon.phoenix.interfaces.Application}s.
217      * Now, the Kernel is taken through its lifecycle. When it is
218      * finished, as well as all the applications running in it, it
219      * is shut down, after which the PhoenixEmbeddor is as well.
220      */

221     public void execute()
222         throws Exception JavaDoc
223     {
224         deployDefaultApplications();
225
226         // If the kernel is empty at this point, it is because the server was
227
// started without supplying any applications, display a message to
228
// give the user a clue as to why the server is shutting down
229
// immediately.
230
if( emptyKernel() )
231         {
232             final String JavaDoc message = REZ.getString( "embeddor.error.start.no-apps" );
233             getLogger().fatalError( message );
234         }
235         else
236         {
237             // loop until Shutdown occurs.
238
while( true )
239             {
240                 // wait() for shutdown() to take action...
241
if( m_shutdown
242                     || (emptyKernel() && !m_persistent) )
243                 {
244                     // The server will shut itself down when all applications are disposed.
245
if( emptyKernel() )
246                     {
247                         final String JavaDoc message =
248                             REZ.getString( "embeddor.shutdown.all-apps-disposed" );
249                         getLogger().info( message );
250                     }
251                     break;
252                 }
253                 gotoSleep();
254             }
255         }
256     }
257
258     private boolean emptyKernel()
259     {
260         final Kernel kernel = getKernel();
261         if( null != kernel )
262         {
263             final String JavaDoc[] names = kernel.getApplicationNames();
264             return (0 == names.length);
265         }
266         else
267         {
268             //Consider the kernel empty
269
//if it has been shutdown
270
return true;
271         }
272     }
273
274     private void gotoSleep()
275     {
276         try
277         {
278             synchronized( this )
279             {
280                 wait( 1000 );
281             }
282         }
283         catch( final InterruptedException JavaDoc e )
284         {
285             //NOOP
286
}
287     }
288
289     /**
290      * Release all the resources associated with kernel.
291      */

292     public synchronized void dispose()
293     {
294         shutdown();
295         try
296         {
297             unregisterComponents();
298             shutdownComponents();
299         }
300         catch( final Exception JavaDoc e )
301         {
302             // whoops!
303
final String JavaDoc message = REZ.getString( "embeddor.error.shutdown.failed" );
304             getLogger().fatalError( message, e );
305         }
306         for( int i = 0; i < m_entries.length; i++ )
307         {
308             m_entries[ i ].setObject( null );
309         }
310         System.gc(); // make sure resources are released
311
}
312
313     /**
314      * Request the Embeddor shutsdown.
315      */

316     public void shutdown()
317     {
318         m_shutdown = true;
319         synchronized( this )
320         {
321             notifyAll();
322         }
323     }
324
325     /**
326      * Ask the embeddor to restart itself if this operation is supported.
327      *
328      * @throws UnsupportedOperationException if restart not supported
329      */

330     public void restart()
331         throws UnsupportedOperationException JavaDoc
332     {
333         try
334         {
335             m_observable.change();
336             m_observable.notifyObservers( "restart" );
337         }
338         catch( final Exception JavaDoc e )
339         {
340             throw new UnsupportedOperationException JavaDoc();
341         }
342     }
343
344     /**
345      * Get name by which the server is know.
346      * Usually this defaults to "Phoenix" but the admin
347      * may assign another name. This is useful when you
348      * are managing a cluster of Phoenix servers.
349      *
350      * @return the name of server
351      */

352     public String JavaDoc getName()
353     {
354         return Constants.SOFTWARE;
355     }
356
357     /**
358      * Get location of Phoenix installation
359      *
360      * @return the home directory of phoenix
361      */

362     public String JavaDoc getHomeDirectory()
363     {
364         return m_phoenixHome;
365     }
366
367     /**
368      * Get the date at which this server started.
369      *
370      * @return the date at which this server started
371      */

372     public Date JavaDoc getStartTime()
373     {
374         return new Date JavaDoc( m_startTime );
375     }
376
377     /**
378      * Retrieve the number of millisecond
379      * the server has been up.
380      *
381      * @return the the number of millisecond the server has been up
382      */

383     public long getUpTimeInMillis()
384     {
385         return System.currentTimeMillis() - m_startTime;
386     }
387
388     /**
389      * Retrieve a string identifying version of server.
390      * Usually looks like "v4.0.1a".
391      *
392      * @return version string of server.
393      */

394     public String JavaDoc getVersion()
395     {
396         return Constants.VERSION;
397     }
398
399     /**
400      * Get a string defining the build.
401      * Possibly the date on which it was built, where it was built,
402      * with what features it was built and so forth.
403      *
404      * @return the string describing build
405      */

406     public String JavaDoc getBuild()
407     {
408         return "(" + Constants.DATE + ")";
409     }
410
411     //////////////////////
412
/// HELPER METHODS ///
413
//////////////////////
414
/**
415      * Create the logger, deployer and kernel components.
416      * Note that these components are not ready to be used
417      * until setupComponents() is called.
418      */

419     private synchronized void createComponents()
420     throws Exception JavaDoc
421     {
422         try
423         {
424             for( int i = 0; i < m_entries.length; i++ )
425             {
426                 final String JavaDoc className = m_entries[ i ].getClassName();
427                 final Class JavaDoc clazz = Class.forName( className );
428                 final Object JavaDoc object = createObject( className, clazz );
429                 m_entries[ i ].setObject( object );
430             }
431         }
432         catch( final Exception JavaDoc e )
433         {
434             final String JavaDoc message =
435                 REZ.getString( "embeddor.error.createComponents.failed" );
436             getLogger().fatalError( message, e );
437             throw new CascadingException( message, e );
438         }
439     }
440
441     /**
442      * The deployer is used to load the applications from the
443      * default-apps-location specified in Parameters.
444      * TODO: load facilities from .fars as well.
445      *
446      * @throws Exception if an error occurs
447      */

448     protected void deployDefaultApplications()
449         throws Exception JavaDoc
450     {
451         //Name of optional application specified on CLI
452
final String JavaDoc application =
453             m_parameters.getParameter( "application-location", null );
454         if( null != application )
455         {
456             final File JavaDoc file = new File JavaDoc( application );
457             deployFile( file );
458         }
459         if( null != m_appDir )
460         {
461             final File JavaDoc directory = new File JavaDoc( m_appDir );
462             final ExtensionFileFilter filter = new ExtensionFileFilter( ".sar" );
463             final File JavaDoc[] files = directory.listFiles( filter );
464             if( null != files )
465             {
466                 deployFiles( files );
467             }
468         }
469     }
470
471     private void deployFiles( final File JavaDoc[] files )
472         throws Exception JavaDoc
473     {
474         for( int i = 0; i < files.length; i++ )
475         {
476             deployFile( files[ i ] );
477         }
478     }
479
480     private void deployFile( final File JavaDoc file )
481         throws Exception JavaDoc
482     {
483         final String JavaDoc filename = file.getName();
484         int index = filename.lastIndexOf( '.' );
485         if( -1 == index )
486         {
487             index = filename.length();
488         }
489         final String JavaDoc name = filename.substring( 0, index );
490         final File JavaDoc canonicalFile = file.getCanonicalFile();
491         deployFile( name, canonicalFile );
492     }
493
494     protected final synchronized void deployFile( final String JavaDoc name, final File JavaDoc file )
495         throws Exception JavaDoc
496     {
497         final Deployer deployer = (Deployer)getEmbeddorComponent( Deployer.ROLE );
498         deployer.deploy( name, file.toURL() );
499     }
500
501     private void setupComponents()
502         throws Exception JavaDoc
503     {
504         for( int i = 0; i < m_entries.length; i++ )
505         {
506             final EmbeddorEntry entry = m_entries[ i ];
507             setupComponent( entry.getObject(),
508                             entry.getLoggerName(),
509                             entry.getConfiguration() );
510         }
511     }
512
513     /**
514      * Setup a component and run it through al of it's
515      * setup lifecycle stages.
516      *
517      * @param object the component
518      * @throws Exception if an error occurs
519      */

520     private void setupComponent( final Object JavaDoc object,
521                                  final String JavaDoc loggerName,
522                                  final Configuration config )
523         throws Exception JavaDoc
524     {
525         final Logger childLogger = getLogger().getChildLogger( loggerName );
526         ContainerUtil.enableLogging( object, childLogger );
527         ContainerUtil.contextualize( object, m_context );
528         ContainerUtil.service( object, getServiceManager() );
529         ContainerUtil.parameterize( object, createChildParameters() );
530         ContainerUtil.configure( object, config );
531         ContainerUtil.initialize( object );
532         ContainerUtil.start( object );
533     }
534
535     private Parameters createChildParameters()
536     {
537         final Parameters parameters = new Parameters();
538         parameters.merge( m_parameters );
539         parameters.setParameter( "phoenix.apps.dir", m_appDir );
540         return parameters;
541     }
542
543     private void shutdownComponents()
544         throws Exception JavaDoc
545     {
546         //for( int i = m_entries.length - 1; i >= 0; i-- )
547
for( int i = 0; i < m_entries.length; i++ )
548         {
549             final Object JavaDoc object = m_entries[ i ].getObject();
550             if( null == object )
551             {
552                 continue;
553             }
554             ContainerUtil.shutdown( object );
555         }
556     }
557
558     /**
559      * Create a component that implements an interface.
560      *
561      * @param classname the name of the objects class
562      * @param service the name of interface/type
563      * @return the created object
564      * @throws Exception if an error occurs
565      */

566     private Object JavaDoc createObject( final String JavaDoc classname,
567                                  final Class JavaDoc service )
568         throws Exception JavaDoc
569     {
570         try
571         {
572             final Object JavaDoc object = Class.forName( classname ).newInstance();
573             if( !service.isInstance( object ) )
574             {
575                 final String JavaDoc message =
576                     REZ.getString( "bad-type.error",
577                                    classname,
578                                    service.getName() );
579                 throw new Exception JavaDoc( message );
580             }
581             return object;
582         }
583         catch( final IllegalAccessException JavaDoc iae )
584         {
585             final String JavaDoc message = REZ.getString( "bad-ctor.error", service.getName(), classname );
586             throw new CascadingException( message, iae );
587         }
588         catch( final InstantiationException JavaDoc ie )
589         {
590             final String JavaDoc message =
591                 REZ.getString( "no-instantiate.error",
592                                service.getName(),
593                                classname );
594             throw new CascadingException( message, ie );
595         }
596         catch( final ClassNotFoundException JavaDoc cnfe )
597         {
598             final String JavaDoc message = REZ.getString( "no-class.error", service.getName(), classname );
599             throw new CascadingException( message, cnfe );
600         }
601     }
602
603     /**
604      * Register embeddor and it's components to <code>SystemManager</code>.
605      */

606     private void registerComponents()
607         throws Exception JavaDoc
608     {
609         final SystemManager systemManager =
610             (SystemManager)getServiceManager().lookup( SystemManager.ROLE );
611
612         final SystemManager componentManager =
613             systemManager.getSubContext( null, "component" );
614
615         componentManager.register( ManagementRegistration.EMBEDDOR.getName(),
616                                    this,
617                                    ManagementRegistration.EMBEDDOR.getInterfaces() );
618
619         for( int i = 0; i < m_entries.length; i++ )
620         {
621             final ManagementRegistration registration =
622                 ManagementRegistration.getManagementInfoForRole( m_entries[ i ].getRole() );
623             if( null != registration )
624             {
625                 componentManager.register( registration.getName(),
626                                            m_entries[ i ].getObject(),
627                                            registration.getInterfaces() );
628             }
629         }
630     }
631
632     /**
633      * Unregister embeddor and it's components from
634      * {@link SystemManager}.
635      */

636     private void unregisterComponents()
637         throws Exception JavaDoc
638     {
639         final SystemManager systemManager =
640             (SystemManager)getServiceManager().lookup( SystemManager.ROLE );
641
642         final SystemManager componentManager = systemManager.getSubContext( null, "component" );
643
644         componentManager.unregister( ManagementRegistration.EMBEDDOR.getName() );
645
646         for( int i = 0; i < m_entries.length; i++ )
647         {
648             final ManagementRegistration registration =
649                 ManagementRegistration.getManagementInfoForRole( m_entries[ i ].getRole() );
650             if( null != registration )
651             {
652                 componentManager.unregister( registration.getName() );
653             }
654         }
655     }
656
657     private ServiceManager getServiceManager()
658     {
659         final DefaultServiceManager serviceManager = new DefaultServiceManager();
660         serviceManager.put( Embeddor.ROLE, this );
661         for( int i = 0; i < m_entries.length; i++ )
662         {
663             final String JavaDoc role = m_entries[ i ].getRole();
664             final Object JavaDoc component = getEmbeddorComponent( role );
665             serviceManager.put( role, component );
666         }
667         return serviceManager;
668     }
669
670     /**
671      * Allow subclasses to get access to kernel.
672      *
673      * @return the Kernel
674      */

675     protected final Kernel getKernel()
676     {
677         return (Kernel)getEmbeddorComponent( Kernel.ROLE );
678     }
679
680     /**
681      * Allow subclasses to get access to parameters.
682      *
683      * @return the Parameters
684      */

685     protected final Parameters getParameters()
686     {
687         return m_parameters;
688     }
689
690     private Object JavaDoc getEmbeddorComponent( final String JavaDoc role )
691     {
692         for( int i = 0; i < m_entries.length; i++ )
693         {
694             final EmbeddorEntry entry = m_entries[ i ];
695             if( entry.getRole().equals( role ) )
696             {
697                 return m_entries[ i ].getObject();
698             }
699         }
700         // Should never happen
701
// TODO: create error / warning
702
return null;
703     }
704 }
705
706 class EmbeddorObservable
707     extends Observable JavaDoc
708 {
709     public void change()
710     {
711         super.setChanged();
712     }
713 }
714
Popular Tags