View Javadoc

1   package org.apache.fulcrum.yaafi.framework.container;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *   http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  import java.io.File;
23  import java.io.IOException;
24  import java.io.InputStream;
25  import java.security.GeneralSecurityException;
26  import java.util.ArrayList;
27  import java.util.HashMap;
28  import java.util.List;
29  import java.util.Properties;
30  
31  import org.apache.avalon.framework.configuration.Configuration;
32  import org.apache.avalon.framework.configuration.ConfigurationException;
33  import org.apache.avalon.framework.configuration.DefaultConfiguration;
34  import org.apache.avalon.framework.configuration.DefaultConfigurationBuilder;
35  import org.apache.avalon.framework.container.ContainerUtil;
36  import org.apache.avalon.framework.context.Context;
37  import org.apache.avalon.framework.context.ContextException;
38  import org.apache.avalon.framework.context.DefaultContext;
39  import org.apache.avalon.framework.logger.Logger;
40  import org.apache.avalon.framework.parameters.ParameterException;
41  import org.apache.avalon.framework.parameters.Parameters;
42  import org.apache.avalon.framework.service.ServiceException;
43  import org.apache.avalon.framework.service.ServiceManager;
44  import org.apache.fulcrum.jce.crypto.CryptoStreamFactoryImpl;
45  import org.apache.fulcrum.yaafi.framework.component.AvalonServiceComponentImpl;
46  import org.apache.fulcrum.yaafi.framework.component.ServiceComponent;
47  import org.apache.fulcrum.yaafi.framework.configuration.ComponentConfigurationPropertiesResolver;
48  import org.apache.fulcrum.yaafi.framework.configuration.ComponentConfigurationPropertiesResolverImpl;
49  import org.apache.fulcrum.yaafi.framework.constant.AvalonYaafiConstants;
50  import org.apache.fulcrum.yaafi.framework.context.AvalonToYaafiContextMapper;
51  import org.apache.fulcrum.yaafi.framework.context.YaafiToAvalonContextMapper;
52  import org.apache.fulcrum.yaafi.framework.role.RoleConfigurationParser;
53  import org.apache.fulcrum.yaafi.framework.role.RoleConfigurationParserImpl;
54  import org.apache.fulcrum.yaafi.framework.role.RoleEntry;
55  import org.apache.fulcrum.yaafi.framework.util.ConfigurationUtil;
56  import org.apache.fulcrum.yaafi.framework.util.InputStreamLocator;
57  import org.apache.fulcrum.yaafi.framework.util.ReadWriteLock;
58  import org.apache.fulcrum.yaafi.framework.util.StringUtils;
59  import org.apache.fulcrum.yaafi.framework.util.ToStringBuilder;
60  import org.apache.fulcrum.yaafi.framework.util.Validate;
61  
62  /**
63   * Yet another avalon framework implementation (YAAFI).
64   *
65   * @author <a href="mailto:siegfried.goeschl@it20one.at">Siegfried Goeschl</a>
66   */
67  
68  public class ServiceContainerImpl
69      implements ServiceContainer, ServiceConstants
70  {
71      /** the timeout after getting a write lock for reconfiguration */
72      private static final int RECONFIGURATION_DELAY = 0;
73  
74      /** The role configuration file to be used */
75      private String componentRolesLocation;
76  
77      /** is the component role file encrypted? */
78      private String isComponentRolesEncrypted;
79  
80      /** which flavour of component role file we have to parse? */
81      private String componentRolesFlavour;
82  
83      /** The service configuration file to be used */
84      private String componentConfigurationLocation;
85  
86      /** is the component configuration file encrypted? */
87      private String isComponentConfigurationEncrypted;
88  
89      /** The parameters file to be used */
90      private String parametersLocation;
91  
92      /** is the parameters file encrypted? */
93      private String isParametersEncrypted;
94  
95      /** The application directory aka the current woring directory */
96      private File applicationRootDir;
97  
98      /** The directory for storing temporary files */
99      private File tempRootDir;
100 
101     /** The logger to be used passed by the caller */
102     private Logger logger;
103 
104     /** The service manager passed to the container */
105     private ServiceManager parentServiceManager;
106 
107     /** The list of services instantiated */
108     private List serviceList;
109 
110     /** The map of services used for the lookup */
111     private HashMap serviceMap;
112 
113     /** The Avalon role configuration loaded by this class */
114     private Configuration roleConfiguration;
115 
116     /** The Avalon service configuration loaded by this class */
117     private Configuration serviceConfiguration;
118 
119     /** The temporary Avalon context passed to the implementation */
120     private Context callerContext;
121 
122     /** The default Avalon context passed to the services */
123     private Context context;
124 
125     /** The default Avalon parameters */
126     private Parameters parameters;
127 
128     /** Is this instance already disposed? */
129     private boolean isDisposed;
130 
131     /** The type of container where YAAFI is embedded */
132     private String containerFlavour;
133 
134     /** The ms to wait before triggering a reconfiguration */
135     private int reconfigurationDelay;
136 
137     /** global flag for enabling/disabling dynamic proxies */
138     private boolean hasDynamicProxies;
139 
140     /** The list of interceptor services applied to all services */
141     private ArrayList defaultInterceptorServiceList;
142 
143     /** Read/Write lock to synchronize acess to services */
144     private ReadWriteLock readWriteLock;
145 
146     /** the configuration for running the ComponentConfigurationPropertiesResolver */
147     private Configuration componentConfigurationPropertiesResolverConfig;
148 
149     /////////////////////////////////////////////////////////////////////////
150     // Avalon Service Lifecycle
151     /////////////////////////////////////////////////////////////////////////
152 
153     /**
154      * Constructor using sensible defaults.
155      */
156     public ServiceContainerImpl()
157     {
158         super();
159 
160         this.reconfigurationDelay = RECONFIGURATION_DELAY;
161         this.containerFlavour = COMPONENT_CONTAINERFLAVOUR_VALUE;
162         this.componentRolesFlavour = COMPONENT_ROLECONFIGFLAVOUR_VALUE;
163 
164         this.componentRolesLocation = COMPONENT_ROLE_VALUE;
165         this.componentConfigurationLocation = COMPONENT_CONFIG_VALUE;
166         this.parametersLocation = COMPONENT_PARAMETERS_VALUE;
167 
168         this.isComponentConfigurationEncrypted = "false";
169         this.isComponentRolesEncrypted = "false";
170         this.isParametersEncrypted = "false";
171 
172         this.isDisposed = false;
173         this.serviceList = new ArrayList();
174         this.serviceMap = new HashMap();
175 
176         this.applicationRootDir = new File( new File("").getAbsolutePath() );
177         this.tempRootDir = new File( System.getProperty("java.io.tmpdir",".") );
178 
179         this.defaultInterceptorServiceList = new ArrayList();
180     }
181 
182     /**
183      * @see org.apache.avalon.framework.logger.LogEnabled#enableLogging(org.apache.avalon.framework.logger.Logger)
184      */
185     public void enableLogging(Logger logger)
186     {
187         Validate.notNull( logger, "logger" );
188         this.logger = logger;
189         this.readWriteLock = new ReadWriteLock(URN_YAAFI_KERNELLOCK, logger);
190     }
191 
192     /**
193      * @see org.apache.avalon.framework.context.Contextualizable#contextualize(org.apache.avalon.framework.context.Context)
194      */
195     public void contextualize(Context context) throws ContextException
196     {
197         Validate.notNull( context, "context" );
198         // Argghhh - I need to to parse the Configuration before I can map the Context
199         this.callerContext = context;
200     }
201 
202 
203     /**
204      * @see org.apache.avalon.framework.service.Serviceable#service(org.apache.avalon.framework.service.ServiceManager)
205      */
206     public void service(ServiceManager serviceManager) throws ServiceException
207     {
208         this.parentServiceManager = serviceManager;
209     }
210 
211     /**
212      * @see org.apache.avalon.framework.configuration.Configurable#configure(org.apache.avalon.framework.configuration.Configuration)
213      */
214     public void configure(Configuration configuration) throws ConfigurationException
215     {
216         Validate.notNull( configuration, "configuration" );
217 
218         // retrieve the reconfigurationDelay
219 
220         this.reconfigurationDelay =
221             configuration.getChild(RECONFIGURATION_DELAY_KEY).getValueAsInteger(
222                 RECONFIGURATION_DELAY
223                 );
224 
225         // evaluate if we are using dynamic proxies
226 
227         this.hasDynamicProxies =
228             configuration.getChild(DYNAMICPROXY_ENABLED_KEY).getValueAsBoolean(false);
229 
230         // retrieve the container flavour
231 
232         this.setContainerFlavour(
233             configuration.getChild(CONTAINERFLAVOUR_CONFIG_KEY).getValue(
234                 COMPONENT_CONTAINERFLAVOUR_VALUE )
235             );
236 
237         this.getLogger().debug( "Using the following container type : " + this.getContainerFlavour() );
238 
239         // process the caller-suppied context here
240 
241         try
242         {
243             // instantiate a mapper using the existing context - it might
244             // contain application specific entries we are not aware of
245 
246             AvalonToYaafiContextMapper mapper = new AvalonToYaafiContextMapper(
247                 this.getTempRootDir(),
248                 this.callerContext,
249                 this.getClassLoader()
250                 );
251 
252             // do the magic mapping
253 
254             this.context = mapper.mapFrom(
255                 this.callerContext,
256                 this.getContainerFlavour()
257                 );
258 
259             // don't keep a reference of the caller-supplide context
260 
261             this.callerContext = null;
262         }
263         catch( ContextException e )
264         {
265             String msg = "Failed to parse the caller-supplied context";
266             this.getLogger().error( msg, e );
267             throw new ConfigurationException( msg );
268         }
269 
270         // evaluate componentRoles
271 
272         Configuration currComponentRoles = configuration.getChild(COMPONENT_ROLE_KEYS);
273 
274         this.setComponentRolesLocation(
275             currComponentRoles.getChild(COMPONENT_LOCATION_KEY).getValue(
276                 COMPONENT_ROLE_VALUE )
277                 );
278 
279         this.setComponentRolesFlavour(
280             currComponentRoles.getChild(CONTAINERFLAVOUR_CONFIG_KEY).getValue(
281                 COMPONENT_ROLECONFIGFLAVOUR_VALUE )
282                 );
283 
284         this.setComponentRolesEncrypted(
285             currComponentRoles.getChild(COMPONENT_ISENCRYPTED_KEY).getValue(
286                 "false" )
287                 );
288 
289         // evaluate componentConfiguraion
290 
291         Configuration currComponentConfiguration = configuration.getChild(COMPONENT_CONFIG_KEY);
292 
293         this.setComponentConfigurationLocation(
294             currComponentConfiguration.getChild(COMPONENT_LOCATION_KEY).getValue(
295                 COMPONENT_CONFIG_VALUE )
296                 );
297 
298         this.setComponentConfigurationEncrypted(
299             currComponentConfiguration.getChild(COMPONENT_ISENCRYPTED_KEY).getValue(
300                 "false" )
301                 );
302 
303 
304         // get the configuration for componentConfigurationPropertiesResolver
305 
306         this.componentConfigurationPropertiesResolverConfig = configuration.getChild(
307             COMPONENT_CONFIG_PROPERTIES_KEY
308             );
309 
310         // evaluate parameters
311 
312         Configuration currParameters = configuration.getChild(COMPONENT_PARAMETERS_KEY);
313 
314         this.setParametersLocation(
315             currParameters.getChild(COMPONENT_LOCATION_KEY).getValue(
316                 COMPONENT_PARAMETERS_VALUE )
317                 );
318 
319         this.setParametersEncrypted(
320             currParameters.getChild(COMPONENT_ISENCRYPTED_KEY).getValue(
321                 "false" )
322                 );
323 
324         // evaluate the default interceptors
325 
326         Configuration currInterceptorList = configuration.getChild(
327             INTERCEPTOR_LIST_KEY
328             );
329 
330         Configuration[] interceptorConfigList = currInterceptorList.getChildren(
331             INTERCEPTOR_KEY
332             );
333 
334         for( int j=0; j<interceptorConfigList.length; j++ )
335         {
336             String interceptorServiceName = interceptorConfigList[j].getValue(null);
337 
338             if( !StringUtils.isEmpty(interceptorServiceName) && this.hasDynamicProxies())
339             {
340 	            this.defaultInterceptorServiceList.add( interceptorServiceName );
341 
342 	            this.getLogger().debug("Using the following default interceptor service : "
343 	                + interceptorServiceName
344 	                );
345             }
346         }
347     }
348 
349     /**
350      * @see org.apache.avalon.framework.parameters.Parameterizable#parameterize(org.apache.avalon.framework.parameters.Parameters)
351      */
352     public void parameterize(Parameters parameters) throws ParameterException
353     {
354         this.parameters = parameters;
355     }
356 
357     /**
358      * @see org.apache.avalon.framework.activity.Initializable#initialize()
359      */
360     public void initialize() throws Exception
361     {
362         this.getLogger().debug( "YAAFI Service Framework is starting up");
363 
364         // set the directories being used
365 
366         this.setApplicationRootDir(
367             (File) this.getContext().get(AvalonYaafiConstants.URN_AVALON_HOME )
368             );
369 
370         this.setTempRootDir(
371             (File) this.getContext().get(AvalonYaafiConstants.URN_AVALON_TEMP )
372             );
373 
374         // get the configuration files
375 
376         this.roleConfiguration = loadConfiguration(
377             this.componentRolesLocation,
378             this.isComponentRolesEncrypted()
379             );
380 
381         if( this.roleConfiguration == null )
382         {
383             String msg = "Unable to locate the role configuration : " + this.componentRolesLocation;
384             this.getLogger().error( msg );
385             throw new ConfigurationException( msg );
386         }
387 
388         this.serviceConfiguration = loadConfiguration(
389             this.componentConfigurationLocation,
390             this.isComponentConfigurationEncrypted()
391             );
392 
393         // create the configuration properties
394 
395         Properties componentConfigurationProperties = this.loadComponentConfigurationProperties();
396 
397         // expand the componentConfiguration using the componentConfigurationProperties
398 
399         ConfigurationUtil.expand(
400             this.getLogger(),
401             (DefaultConfiguration) this.serviceConfiguration,
402             componentConfigurationProperties
403             );
404 
405         // create the default parameters
406 
407         if( this.getParameters() == null )
408         {
409             this.parameters= this.loadParameters(
410                 this.parametersLocation,
411                 this.isParametersEncrypted()
412                 );
413         }
414 
415         // create the service implementaion instances
416 
417         List currServiceList = this.createServiceComponents(
418             this.roleConfiguration,
419             this.getLogger()
420             );
421 
422         this.setServiceList( currServiceList );
423 
424         // fill the service map mapping from a service name to an instance
425 
426         for( int i=0; i<this.getServiceList().size(); i++ )
427         {
428             ServiceComponent serviceComponent = (ServiceComponent) this.getServiceList().get(i);
429             this.getServiceMap().put( serviceComponent.getName(), serviceComponent );
430         }
431 
432         // run the various lifecycle stages
433 
434         this.incarnateAll( this.getServiceList() );
435 
436         // we are up and running
437 
438         this.isDisposed = false;
439         this.getLogger().debug( "YAAFI Avalon Service Container is up and running");
440     }
441 
442 
443     /**
444      * Disposes the service container implementation.
445      *
446      * @see org.apache.avalon.framework.activity.Disposable#dispose()
447      */
448     public void dispose()
449     {
450         Object lock = null;
451 
452         if( this.isDisposed )
453         {
454             return;
455         }
456 
457         try
458         {
459             lock = this.getWriteLock();
460 
461             if( this.getLogger() != null )
462             {
463                 this.getLogger().debug("Disposing all services");
464             }
465 
466             // decommision all servcies
467 
468             this.decommisionAll( this.getServiceList() );
469 
470             // dispose all servcies
471 
472             this.disposeAll( this.getServiceList() );
473 
474             // clean up
475 
476             this.getServiceList().clear();
477             this.getServiceMap().clear();
478 
479             this.componentRolesLocation = null;
480             this.componentConfigurationLocation = null;
481             this.context = null;
482             this.parametersLocation = null;
483             this.roleConfiguration = null;
484             this.serviceConfiguration = null;
485             this.parameters = null;
486             this.isDisposed = true;
487 
488             if( this.getLogger() != null )
489             {
490                 this.getLogger().debug( "All services are disposed" );
491             }
492         }
493         finally
494         {
495             this.releaseLock(lock);
496         }
497     }
498 
499     /**
500      * Reconfiguring the services. I'm not sure how to implement this properly since
501      * the Avalon docs is vague on this subject. For now we suspend, reconfigure and
502      * resume the services in the correct order.
503      *
504      * @see org.apache.avalon.framework.configuration.Reconfigurable#reconfigure(org.apache.avalon.framework.configuration.Configuration)
505      */
506     public void reconfigure(Configuration configuration)
507         throws ConfigurationException
508     {
509         Validate.notNull( configuration, "configuration" );
510 
511         Object lock = null;
512         int exceptionCounter = 0;
513         ServiceComponent serviceComponent = null;
514 
515         this.getLogger().warn("Reconfiguring all services ...");
516 
517         try
518         {
519             // 1) lock the service container
520 
521             lock = this.getWriteLock();
522 
523 	        // 2) store the new configuration
524 
525 	        this.serviceConfiguration = configuration;
526 
527             Properties componentConfigurationProperties = this.loadComponentConfigurationProperties();
528 
529             ConfigurationUtil.expand(
530                 this.getLogger(),
531                 (DefaultConfiguration) this.serviceConfiguration,
532                 componentConfigurationProperties
533                 );
534 
535 	        // 3) reconfigure the services
536 
537 	        for( int i=0; i<this.getServiceList().size(); i++ )
538 	        {
539 	            serviceComponent = (ServiceComponent) this.getServiceList().get(i);
540 
541 	            Configuration serviceComponentConfiguraton = this.getServiceConfiguration().getChild(
542 	                serviceComponent.getShorthand()
543 	                );
544 
545 	            try
546 	            {
547 	                serviceComponent.setConfiguration(serviceComponentConfiguraton);
548 	                serviceComponent.reconfigure();
549 	            }
550 	            catch(Throwable t)
551 	            {
552 	                String msg = "Reconfiguring of " + serviceComponent.getShorthand() + " failed";
553 	                this.getLogger().error(msg);
554 	                exceptionCounter++;
555 	            }
556 	        }
557 
558 	        // 4) check the result
559 
560 	        if( exceptionCounter > 0 )
561 	        {
562 	            String msg = "The reconfiguration failed with " + exceptionCounter + " exception(s)";
563 	            this.getLogger().error(msg);
564 	            throw new ConfigurationException(msg);
565 	        }
566         }
567         finally
568         {
569             this.releaseLock(lock);
570         }
571     }
572 
573     /////////////////////////////////////////////////////////////////////////
574     // Server Interface Implementation
575     /////////////////////////////////////////////////////////////////////////
576 
577     /**
578      * @see org.apache.fulcrum.yaafi.framework.container.ServiceLifecycleManager#getRoleEntry(java.lang.String)
579      */
580     public RoleEntry getRoleEntry(String name)
581         throws ServiceException
582     {
583         Object lock = null;
584 
585         try
586         {
587             lock = this.getReadLock();
588             return this.getServiceComponentEx(name).getRoleEntry();
589         }
590         finally
591         {
592             this.releaseLock(lock);
593         }
594     }
595 
596     /**
597      * @see org.apache.fulcrum.yaafi.framework.container.ServiceLifecycleManager#getRoleEntries()
598      */
599     public RoleEntry[] getRoleEntries()
600     {
601         Object lock = null;
602 
603         try
604         {
605             lock = this.getReadLock();
606 
607 	        List serviceList = this.getServiceList();
608 	        ServiceComponent serviceComponent = null;
609 	        RoleEntry[] result = new RoleEntry[serviceList.size()];
610 
611 	        for( int i=0; i<result.length; i++ )
612 	        {
613 	            serviceComponent = (ServiceComponent) serviceList.get(i);
614 	            result[i] = serviceComponent.getRoleEntry();
615 	        }
616 
617 	        return result;
618         }
619         finally
620         {
621             this.releaseLock(lock);
622         }
623     }
624 
625     /**
626      * @see org.apache.fulcrum.yaafi.framework.container.ServiceLifecycleManager#reconfigure(java.lang.String[])
627      */
628     public void reconfigure(String[] names) throws ServiceException,
629         ConfigurationException
630     {
631         Validate.notNull(names,"names");
632         Validate.noNullElements(names,"names");
633 
634         Object lock = null;
635 
636         try
637         {
638             // get exclusive access
639 
640             lock = this.getWriteLock();
641 
642 	        for( int i=0; i<names.length; i++ )
643 	        {
644 	            // ensure that the service exists since during our reconfiguration
645 	            // we might use a stle recofniguration entry
646 
647 	            if( this.getServiceMap().get(names[i]) != null )
648 	            {
649 	                this.reconfigure(names[i]);
650 	            }
651 	        }
652         }
653         finally
654         {
655             this.release(lock);
656         }
657     }
658 
659     /**
660      * @see org.apache.avalon.framework.service.ServiceManager#hasService(java.lang.String)
661      */
662     public boolean hasService(String name)
663     {
664         Validate.notEmpty( name, "name" );
665 
666         boolean result = false;
667         Object lock = null;
668         ServiceComponent serviceComponent = null;
669 
670         // look at our available service
671 
672         try
673         {
674             lock = this.getReadLock();
675             serviceComponent = this.getLocalServiceComponent(name);
676             result = ( serviceComponent != null ? true : false );
677         }
678         finally
679         {
680             this.releaseLock(lock);
681         }
682 
683         // if we haven't found anything ask the parent ServiceManager
684 
685         if( ( result == false ) && ( this.hasParentServiceManager() ) )
686         {
687             result = this.getParentServiceManager().hasService(name);
688         }
689 
690         return result;
691     }
692 
693     /**
694      * @see org.apache.avalon.framework.service.ServiceManager#lookup(java.lang.String)
695      */
696     public Object lookup(String name) throws ServiceException
697     {
698         Validate.notEmpty( name, "name" );
699 
700         Object lock = null;
701         Object result = null;
702         ServiceComponent serviceComponent = null;
703 
704         // look at our available service
705 
706         try
707         {
708             lock = this.getReadLock();
709             serviceComponent = this.getLocalServiceComponent(name);
710 
711             if( serviceComponent != null )
712             {
713                 result = serviceComponent.getInstance();
714             }
715         }
716         catch( Throwable t )
717         {
718             String msg = "Failed to lookup a service " + name;
719             this.getLogger().error( msg, t );
720             throw new ServiceException( name, msg, t );
721         }
722 		finally
723 		{
724 		    this.releaseLock(lock);
725 		}
726 
727         // if we haven't found anything ask the parent ServiceManager
728 
729         if( result == null )
730         {
731             if( this.hasParentServiceManager() )
732 	        {
733 	            result = this.getParentServiceManager().lookup(name);
734 	        }
735         }
736 
737         // if we still haven't found anything then complain
738 
739         if( result == null )
740         {
741             String msg = "The following component does not exist : " + name;
742             this.getLogger().error(msg);
743             throw new ServiceException( AvalonYaafiConstants.AVALON_CONTAINER_YAAFI, name );
744         }
745 
746         return result;
747     }
748 
749     /**
750      * @see org.apache.avalon.framework.service.ServiceManager#release(java.lang.Object)
751      */
752     public void release(Object object)
753     {
754         // AFAIK this is only useful for lifecycle management regarding
755         // lifestyle other than singleton.
756     }
757 
758     /**
759      * @see org.apache.fulcrum.yaafi.framework.container.ServiceContainer#decommision(java.lang.String)
760      */
761     public void decommision(String name) throws ServiceException
762     {
763         Object lock = null;
764 
765         try
766         {
767             lock = this.getWriteLock();
768             ServiceComponent serviceComponent = this.getServiceComponentEx(name);
769             this.decommision(serviceComponent);
770         }
771         finally
772         {
773             this.releaseLock(lock);
774         }
775     }
776 
777     /**
778      * @see org.apache.fulcrum.yaafi.framework.container.ServiceContainer#getParameters()
779      */
780     public Parameters getParameters()
781     {
782         Object lock = null;
783 
784         try
785         {
786             lock = this.getReadLock();
787             return this.parameters;
788         }
789         finally
790         {
791             this.releaseLock(lock);
792         }
793     }
794 
795     /**
796      * @see java.lang.Object#toString()
797      */
798     public String toString()
799     {
800         ToStringBuilder toStringBuilder = new ToStringBuilder(this);
801 
802         toStringBuilder.append("applicationRootDir", this.getApplicationRootDir());
803         toStringBuilder.append("tempRootDir", this.getTempRootDir());
804         toStringBuilder.append("componentRolesLocation", this.componentRolesLocation);
805         toStringBuilder.append("componentConfigurationLocation", this.componentConfigurationLocation);
806         toStringBuilder.append("parametersLocation", parametersLocation);
807         toStringBuilder.append("logger", this.getLogger().getClass().getName());
808         toStringBuilder.append("hasDynamicProxies", this.hasDynamicProxies);
809         toStringBuilder.append("containerFlavour", this.containerFlavour);
810         toStringBuilder.append("componentRolesFlavour", this.componentRolesFlavour);
811         toStringBuilder.append("isComponentRolesEncrypted", this.isComponentRolesEncrypted);
812         toStringBuilder.append("isComponentConfigurationEncrypted", this.isComponentConfigurationEncrypted);
813         toStringBuilder.append("isParametersEncrypted", this.isParametersEncrypted);
814 
815         return toStringBuilder.toString();
816     }
817 
818     /////////////////////////////////////////////////////////////////////////
819     // Service Implementation
820     /////////////////////////////////////////////////////////////////////////
821 
822     /**
823      * Create a role configuration parser based on the container flavour.
824      * @return the role configuration parser
825      */
826     private RoleConfigurationParser createRoleConfigurationParser()
827     {
828         return new RoleConfigurationParserImpl(
829             this.getComponentRolesFlavour()
830             );
831     }
832 
833     /**
834      * Reconfigure a single service
835      *
836      * @param name the name of the service to be reconfigured
837      * @param ServiceException the service was not found
838      * @param ConfigurationException the reconfiguration failed
839      */
840     private void reconfigure(String name)
841         throws ServiceException, ConfigurationException
842     {
843         Validate.notEmpty( name, "name" );
844         ServiceComponent serviceComponent = this.getServiceComponentEx(name);
845 
846         // reconfigure the component
847 
848         try
849         {
850             serviceComponent.reconfigure();
851         }
852         catch(ConfigurationException e)
853         {
854             String msg = "Reconfiguring failed : " + serviceComponent.getShorthand();
855             this.getLogger().error(msg,e);
856             throw new ConfigurationException(msg,e);
857         }
858         catch(Throwable t)
859         {
860             String msg = "Reconfiguring failed : " + serviceComponent.getShorthand();
861             this.getLogger().error(msg,t);
862             throw new ConfigurationException(msg,t);
863         }
864     }
865 
866     /**
867      * Enforce that a service is known to simplify error handling.
868      *
869      * @param name the name of the service component
870      * @return the service component
871      * @throws ServiceException the service was not found
872      */
873     private ServiceComponent getServiceComponentEx(String name)
874         throws ServiceException
875     {
876         Validate.notEmpty( name, "name" );
877         ServiceComponent result = (ServiceComponent) this. getServiceMap().get(name);
878 
879         if( result == null )
880         {
881             String msg = "The following component does not exist : " + name;
882             this.getLogger().error(msg);
883             throw new ServiceException( AvalonYaafiConstants.AVALON_CONTAINER_YAAFI, name );
884         }
885 
886         return result;
887     }
888 
889     /**
890      * Try to get a local service component
891      *
892      * @param name the name of the service component
893      * @return the service component if any
894      */
895     private ServiceComponent getLocalServiceComponent(String name)
896     {
897         Validate.notEmpty( name, "name" );
898         ServiceComponent result = (ServiceComponent) this. getServiceMap().get(name);
899         return result;
900     }
901 
902     /**
903      * @param string The location of the component configuration file
904      */
905     private void setComponentConfigurationLocation(String string)
906     {
907         this.componentConfigurationLocation = string;
908     }
909 
910     /**
911      * @param string The location of the component role file
912      */
913     private void setComponentRolesLocation(String string)
914     {
915         this.componentRolesLocation = string;
916     }
917 
918     /**
919      * @param string The location of the parameters file
920      */
921     private void setParametersLocation(String string)
922     {
923         this.parametersLocation = string;
924     }
925 
926     /**
927      * @return The logger of the service containe
928      */
929     private Logger getLogger()
930     {
931         return this.logger;
932     }
933 
934     /**
935      * @return Returns the serviceMap.
936      */
937     private HashMap getServiceMap()
938     {
939         return this.serviceMap;
940     }
941 
942     /**
943      * Incarnation of a list of services.
944      *
945      * @param serviceList the list of available services
946      * @throws Exception the incarnation of a service failed
947      */
948     private void incarnateAll(List serviceList)
949         throws Exception
950     {
951         ServiceComponent serviceComponent = null;
952 
953         // configure all services
954 
955         for( int i=0; i<serviceList.size(); i++ )
956         {
957             serviceComponent = (ServiceComponent) this.getServiceList().get(i);
958             this.configure( serviceComponent );
959         }
960 
961         // incarnate all services
962 
963         for( int i=0; i<serviceList.size(); i++ )
964         {
965             serviceComponent = (ServiceComponent) this.getServiceList().get(i);
966             this.incarnate( serviceComponent );
967         }
968 
969     }
970 
971     /**
972      * Configure a single service component. After the invocation
973      * the service component is ready to be incarnated.
974      *
975      * @param serviceComponent The service component to be configured
976      */
977     private void configure( ServiceComponent serviceComponent )
978         throws Exception
979     {
980         this.getLogger().debug( "Configuring the service component "
981             + serviceComponent.getShorthand()
982             );
983 
984         // map the context according to the Avalon component type
985 
986         YaafiToAvalonContextMapper mapper = new YaafiToAvalonContextMapper(
987             serviceComponent.getName(),
988             this.getClassLoader()
989             );
990 
991         RoleEntry roleEntry = serviceComponent.getRoleEntry();
992         String componentFlavour = roleEntry.getComponentFlavour();
993 
994         DefaultContext serviceComponentContext = mapper.mapTo(
995             this.getContext(),
996             componentFlavour
997             );
998 
999         // add the read/write lock to the context
1000 
1001         serviceComponentContext.put(
1002             URN_YAAFI_KERNELLOCK,
1003             this.readWriteLock
1004             );
1005 
1006         // create the remaining Avalon artifacts for the service component
1007 
1008         Logger serviceComponentLogger = this.getLogger().getChildLogger(
1009             roleEntry.getLogCategory()
1010             );
1011 
1012         Configuration serviceComponentConfiguraton = this.getServiceConfiguration().getChild(
1013             roleEntry.getShorthand()
1014             );
1015 
1016         Parameters serviceComponentParameters = this.getParameters();
1017 
1018         // configure the service component with all the artifacts
1019 
1020         serviceComponent.setLogger(serviceComponentLogger);
1021         serviceComponent.setServiceManager(this);
1022         serviceComponent.setContext(serviceComponentContext);
1023         serviceComponent.setConfiguration(serviceComponentConfiguraton);
1024         serviceComponent.setParameters(serviceComponentParameters);
1025 
1026         // load the implementation class of the service
1027 
1028         serviceComponent.loadImplemtationClass(
1029            this.getClassLoader()
1030             );
1031     }
1032 
1033     /**
1034      * Incarnation of a configured service component. After the
1035      * incarnation the service component is operational.
1036      *
1037      * @param serviceComponent The service component to incarnate
1038      */
1039     private void incarnate( ServiceComponent serviceComponent )
1040         throws Exception
1041     {
1042         this.getLogger().debug( "Incarnating the service "
1043             + serviceComponent.getShorthand()
1044             );
1045 
1046         serviceComponent.incarnate();
1047     }
1048 
1049     /**
1050      * Decommision a ist of services
1051      */
1052     private void decommisionAll(List serviceList)
1053     {
1054         ServiceComponent serviceComponent = null;
1055 
1056         for( int i=serviceList.size()-1; i>=0; i-- )
1057         {
1058             serviceComponent = (ServiceComponent) serviceList.get(i);
1059             this.decommision( serviceComponent );
1060         }
1061     }
1062 
1063     /**
1064      * Decommision of a single service component. Decommision consists of running the
1065      * whole Avalon decommision lifecycle process for a service component. After
1066      * decommision the service is not operational any longer. During decommisioning
1067      * we ignore any exceptions since it is quite common that something goes wrong.
1068      *
1069      * @param serviceComponent The service component to decommision
1070      */
1071     private void decommision( ServiceComponent serviceComponent )
1072     {
1073         this.getLogger().debug( "Decommision the service " + serviceComponent.getShorthand() );
1074 
1075         try
1076         {
1077             serviceComponent.decommision();
1078         }
1079         catch (Throwable e)
1080         {
1081             String msg = "Decommisioning the following service failed : " + serviceComponent.getName();
1082             this.getLogger().error( msg, e );
1083         }
1084     }
1085 
1086     /**
1087      * Disposing a ist of services
1088      */
1089     private void disposeAll(List serviceList)
1090     {
1091         ServiceComponent serviceComponent = null;
1092 
1093         for( int i=serviceList.size()-1; i>=0; i-- )
1094         {
1095             serviceComponent = (ServiceComponent) serviceList.get(i);
1096             this.dispose( serviceComponent );
1097         }
1098     }
1099 
1100     /**
1101      * Disposing of a single service component.
1102 
1103      * @param serviceComponent The service component to decommision
1104      */
1105     private void dispose( ServiceComponent serviceComponent )
1106     {
1107         this.getLogger().debug( "Disposing the service " + serviceComponent.getShorthand() );
1108 
1109         try
1110         {
1111             serviceComponent.dispose();
1112         }
1113         catch (Throwable e)
1114         {
1115             String msg = "Disposing the following service failed : " + serviceComponent.getName();
1116             this.getLogger().error( msg, e );
1117         }
1118     }
1119 
1120     /**
1121      * @return The list of currently know services
1122      */
1123     private List getServiceList()
1124     {
1125         return this.serviceList;
1126     }
1127 
1128     /**
1129      * @param list The list of known services
1130      */
1131     private void setServiceList(List list)
1132     {
1133         this.serviceList = list;
1134     }
1135 
1136     /**
1137      * @return The service configuration
1138      */
1139     private Configuration getServiceConfiguration()
1140     {
1141         return this.serviceConfiguration;
1142     }
1143 
1144     /**
1145      * Factory method for creating services. The service
1146      * instances are not initialized at this point.
1147      *
1148      * @param roleConfiguration the role configuration file
1149      * @param logger the logger
1150      * @throws ConfigurationException creating the service instance failed
1151      */
1152     private List createServiceComponents(Configuration roleConfiguration, Logger logger )
1153         throws ConfigurationException
1154     {
1155         Validate.notNull(roleConfiguration,"roleConfiguration");
1156         Validate.notNull(logger,"logger");
1157 
1158         ArrayList result = new ArrayList();
1159         ServiceComponent serviceComponent = null;
1160 
1161         // create an appropriate instance of role configuration parser
1162 
1163         RoleConfigurationParser roleConfigurationParser =
1164             this.createRoleConfigurationParser();
1165 
1166         // extract the role entries
1167 
1168         RoleEntry[] roleEntryList = roleConfigurationParser.parse(roleConfiguration);
1169 
1170         // get the default interceptors defined for the container
1171 
1172         ArrayList defaultInterceptorList = this.getDefaultInterceptorServiceList();
1173 
1174         // create the service components based on the role entries
1175 
1176         for ( int i=0; i<roleEntryList.length; i++ )
1177         {
1178             try
1179             {
1180                 // add the default interceptors to all role entries
1181 
1182                 RoleEntry roleEntry = roleEntryList[i];
1183 
1184                 if( this.hasDynamicProxies() )
1185                 {
1186                     roleEntry.addInterceptors(defaultInterceptorList);
1187                 }
1188                 else
1189                 {
1190                     roleEntry.setHasDynamicProxy(false);
1191                 }
1192 
1193                 serviceComponent = new AvalonServiceComponentImpl(
1194                     roleEntry,
1195                     this.getLogger(),
1196                     logger,
1197                     this.readWriteLock
1198                     );
1199 
1200                 result.add( serviceComponent );
1201             }
1202             catch( Throwable t )
1203             {
1204                 String msg = "Failed to load the service " + serviceComponent.getName();
1205                 this.getLogger().error( msg, t );
1206                 throw new ConfigurationException( msg, t );
1207             }
1208         }
1209 
1210         return result;
1211     }
1212 
1213     /**
1214      * Load a configuration file either from a file or using the class loader.
1215      * @param location the location of the file
1216      * @param isEncrypted  is the configuration encryped
1217      * @return The loaded configuration
1218      * @throws Exception Something went wrong
1219      */
1220     private Configuration loadConfiguration( String location, String isEncrypted )
1221         throws Exception
1222     {
1223         Configuration result = null;
1224         InputStreamLocator locator = this.createInputStreamLocator();
1225         InputStream is = locator.locate( location );
1226         DefaultConfigurationBuilder builder = new DefaultConfigurationBuilder();
1227 
1228         if( is != null )
1229         {
1230             try
1231             {
1232                 if( isEncrypted.equalsIgnoreCase("false") == false)
1233                 {
1234                     is = this.getDecryptingInputStream( is, isEncrypted );
1235                 }
1236 
1237                 result = builder.build( is );
1238 
1239                 is.close();
1240                 is = null;
1241             }
1242             catch ( Exception e )
1243             {
1244                 String msg = "Unable to parse the following file : " + location;
1245                 this.getLogger().error( msg , e );
1246                 throw e;
1247             }
1248         }
1249 
1250         return result;
1251     }
1252 
1253     /**
1254      * Load a configuration property file either from a file or using the class loader.
1255      * @param location the location of the file
1256      * @return The loaded proeperty file
1257      * @throws ConfigurationException Something went wrong
1258      */
1259     private Properties loadComponentConfigurationProperties()
1260     	throws ConfigurationException
1261     {
1262         Properties result = new Properties();
1263         ComponentConfigurationPropertiesResolver resolver = null;
1264 
1265         String className = this.componentConfigurationPropertiesResolverConfig.getChild("resolver").getValue(
1266             ComponentConfigurationPropertiesResolverImpl.class.getName()
1267             );
1268 
1269         try
1270         {
1271             Class resolverClass = this.getClassLoader().loadClass( className );
1272             resolver = (ComponentConfigurationPropertiesResolver) resolverClass.newInstance();
1273             ContainerUtil.enableLogging(resolver, this.getLogger());
1274             ContainerUtil.contextualize(resolver, this.getContext());
1275             ContainerUtil.configure(resolver, this.componentConfigurationPropertiesResolverConfig);
1276 
1277             result = resolver.resolve(null);
1278 
1279             this.getLogger().debug("Using the following componentConfigurationProperties: " + result);
1280         }
1281         catch (Exception e)
1282         {
1283             String msg = "Resolving componentConfigurationProperties failed using the following class : " + className;
1284             this.getLogger().error(msg, e);
1285             throw new ConfigurationException(msg, e);
1286         }
1287 
1288         return result;
1289     }
1290 
1291     /**
1292      * Load the parameters
1293      * @param location The location as a file
1294      * @param isEncrypted is the file encrypted
1295      * @return The loaded configuration
1296      * @throws Exception Something went wrong
1297      */
1298     private Parameters loadParameters( String location, String isEncrypted )
1299         throws Exception
1300     {
1301         InputStreamLocator locator = this.createInputStreamLocator();
1302         InputStream is = locator.locate( location );
1303         Parameters result = new Parameters();
1304 
1305         if( is != null )
1306         {
1307             if( isEncrypted.equalsIgnoreCase("false") == false )
1308             {
1309                 is = this.getDecryptingInputStream( is, isEncrypted );
1310             }
1311 
1312             Properties props = new Properties();
1313             props.load( is );
1314             result = Parameters.fromProperties( props );
1315 
1316             is.close();
1317             is = null;
1318         }
1319 
1320         return result;
1321     }
1322 
1323 
1324     /**
1325      * Creates a locator to find a resource either in the file system or in
1326      * the classpath
1327      */
1328     private InputStreamLocator createInputStreamLocator()
1329     {
1330         return new InputStreamLocator( this.getApplicationRootDir(), this.getLogger() );
1331     }
1332 
1333     /**
1334      * Set the application directory of the container.
1335      *
1336      * @param dir The applicationRootDir to set.
1337      */
1338     private File setApplicationRootDir(File dir)
1339     {
1340         this.getLogger().debug( "Setting applicationRootDir to " + dir.getAbsolutePath() );
1341 
1342         Validate.notNull(dir,"applicationRootDir is <null>");
1343         Validate.isTrue(dir.exists(),"applicationRootDir does not exist");
1344 
1345         this.applicationRootDir = dir;
1346         return this.applicationRootDir;
1347     }
1348 
1349     /**
1350      * @return Returns the applicationRootDir.
1351      */
1352     private File getApplicationRootDir()
1353     {
1354         return this.applicationRootDir;
1355     }
1356 
1357     /**
1358      * @return Returns the serviceManager of the parent container
1359      */
1360     private ServiceManager getParentServiceManager()
1361     {
1362         return this.parentServiceManager;
1363     }
1364 
1365     /**
1366      * @return is a parent ServiceManager available
1367      */
1368     private boolean hasParentServiceManager()
1369     {
1370         return (this.getParentServiceManager() != null ? true : false );
1371     }
1372     /**
1373      * Set the temporary directory of the container.
1374      *
1375      * @param dir The tempRootDir to set.
1376      */
1377     private File setTempRootDir(File dir)
1378     {
1379         this.getLogger().debug( "Setting tempRootDir to " + dir.getAbsolutePath() );
1380 
1381         Validate.notNull(dir,"tempRootDir is <null>");
1382         Validate.isTrue(dir.exists(),"tempRootDir does not exist");
1383         Validate.isTrue(dir.canWrite(),"tempRootDir is not writeable");
1384 
1385         this.tempRootDir = dir;
1386         return this.tempRootDir;
1387     }
1388 
1389     /**
1390      * @return Returns the tempRootDir.
1391      */
1392     private File getTempRootDir()
1393     {
1394         return tempRootDir;
1395     }
1396 
1397     /**
1398      * @return Returns the isComponentConfigurationEncrypted.
1399      */
1400     private String isComponentConfigurationEncrypted()
1401     {
1402         return isComponentConfigurationEncrypted;
1403     }
1404 
1405     /**
1406      * @param isComponentConfigurationEncrypted The isComponentConfigurationEncrypted to set.
1407      */
1408     private void setComponentConfigurationEncrypted(
1409         String isComponentConfigurationEncrypted)
1410     {
1411         this.isComponentConfigurationEncrypted = isComponentConfigurationEncrypted;
1412     }
1413 
1414     /**
1415      * @return Returns the isComponentRolesEncrypted.
1416      */
1417     private String isComponentRolesEncrypted()
1418     {
1419         return isComponentRolesEncrypted;
1420     }
1421 
1422     /**
1423      * @param isComponentRolesEncrypted The isComponentRolesEncrypted to set.
1424      */
1425     private void setComponentRolesEncrypted(String isComponentRolesEncrypted)
1426     {
1427         this.isComponentRolesEncrypted = isComponentRolesEncrypted;
1428     }
1429 
1430     /**
1431      * @return Returns the isParametersEncrypted.
1432      */
1433     private String isParametersEncrypted()
1434     {
1435         return isParametersEncrypted;
1436     }
1437 
1438     /**
1439      * @param isParametersEncrypted The isParametersEncrypted to set.
1440      */
1441     private void setParametersEncrypted(String isParametersEncrypted)
1442     {
1443         this.isParametersEncrypted = isParametersEncrypted;
1444     }
1445 
1446     /**
1447      * Create a decrypting input stream using the default password.
1448      *
1449      * @param is the input stream to be decrypted
1450      * @return an decrypting input stream
1451      * @throws IOException
1452      * @throws GeneralSecurityException
1453      */
1454     private InputStream getDecryptingInputStream( InputStream is, String isEncrypted )
1455         throws IOException, GeneralSecurityException
1456     {
1457         InputStream result = null;
1458 
1459         if( isEncrypted.equalsIgnoreCase("true") )
1460         {
1461             result = CryptoStreamFactoryImpl.getInstance().getInputStream(is);
1462         }
1463         else if( isEncrypted.equalsIgnoreCase("auto") )
1464         {
1465             result = CryptoStreamFactoryImpl.getInstance().getSmartInputStream(is);
1466         }
1467         else
1468         {
1469             result = is;
1470         }
1471         return result;
1472     }
1473 
1474     /**
1475      * @return Returns the containerFlavour.
1476      */
1477     private String getContainerFlavour()
1478     {
1479         return containerFlavour;
1480     }
1481 
1482     /**
1483      * @param containerFlavour The containerFlavour to set.
1484      */
1485     private void setContainerFlavour(String containerFlavour)
1486     {
1487         this.containerFlavour = containerFlavour;
1488     }
1489 
1490     /**
1491      * @return Returns the componentRolesFlavour.
1492      */
1493     private String getComponentRolesFlavour()
1494     {
1495         return componentRolesFlavour;
1496     }
1497 
1498     /**
1499      * @param componentRolesFlavour The componentRolesFlavour to set.
1500      */
1501     private void setComponentRolesFlavour(String componentRolesFlavour)
1502     {
1503         this.componentRolesFlavour = componentRolesFlavour;
1504     }
1505 
1506     /**
1507      * @return Returns the context.
1508      */
1509     private Context getContext()
1510     {
1511         return context;
1512     }
1513 
1514     /**
1515      * @return Returns the hasDynamicProxies.
1516      */
1517     private final boolean hasDynamicProxies()
1518     {
1519         return this.hasDynamicProxies;
1520     }
1521 
1522     /**
1523      * @return Returns the defaultInterceptorServiceList.
1524      */
1525     private ArrayList getDefaultInterceptorServiceList()
1526     {
1527         return defaultInterceptorServiceList;
1528     }
1529 
1530     /**
1531      * @return a read lock
1532      */
1533     private final Object getReadLock()
1534     {
1535         try
1536         {
1537             return this.readWriteLock.getReadLock(AVALON_CONTAINER_YAAFI);
1538         }
1539         catch (InterruptedException e)
1540         {
1541             String msg = "Interrupted while getting read lock";
1542             throw new RuntimeException(msg);
1543         }
1544     }
1545 
1546     /**
1547      * @return a write lock
1548      */
1549     private final Object getWriteLock()
1550     {
1551         Object result = null;
1552 
1553         try
1554         {
1555             result = this.readWriteLock.getWriteLock(AVALON_CONTAINER_YAAFI);
1556 
1557             // wait for a certain time to get non-proxied services
1558             // either finished or blocked
1559 
1560             try
1561             {
1562                 Thread.sleep( this.reconfigurationDelay );
1563             }
1564             catch (InterruptedException e)
1565             {
1566                 // nothing to do
1567             }
1568 
1569             return result;
1570         }
1571         catch (InterruptedException e)
1572         {
1573             String msg = "Interrupted while getting read lock";
1574             throw new RuntimeException(msg);
1575         }
1576     }
1577 
1578     /**
1579      * Release the read/write lock.
1580      */
1581     private final void releaseLock(Object lock)
1582     {
1583         this.readWriteLock.releaseLock(lock, AVALON_CONTAINER_YAAFI);
1584     }
1585 
1586     /**
1587      * @return the containers class loader
1588      */
1589     private ClassLoader getClassLoader()
1590     {
1591         return this.getClass().getClassLoader();
1592     }
1593 }