1 package org.apache.fulcrum.yaafi.framework.container;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import java.io.File;
23 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
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
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
219
220 this.reconfigurationDelay =
221 configuration.getChild(RECONFIGURATION_DELAY_KEY).getValueAsInteger(
222 RECONFIGURATION_DELAY
223 );
224
225
226
227 this.hasDynamicProxies =
228 configuration.getChild(DYNAMICPROXY_ENABLED_KEY).getValueAsBoolean(false);
229
230
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
240
241 try
242 {
243
244
245
246 AvalonToYaafiContextMapper mapper = new AvalonToYaafiContextMapper(
247 this.getTempRootDir(),
248 this.callerContext,
249 this.getClassLoader()
250 );
251
252
253
254 this.context = mapper.mapFrom(
255 this.callerContext,
256 this.getContainerFlavour()
257 );
258
259
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
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
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
305
306 this.componentConfigurationPropertiesResolverConfig = configuration.getChild(
307 COMPONENT_CONFIG_PROPERTIES_KEY
308 );
309
310
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
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
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
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
394
395 Properties componentConfigurationProperties = this.loadComponentConfigurationProperties();
396
397
398
399 ConfigurationUtil.expand(
400 this.getLogger(),
401 (DefaultConfiguration) this.serviceConfiguration,
402 componentConfigurationProperties
403 );
404
405
406
407 if( this.getParameters() == null )
408 {
409 this.parameters= this.loadParameters(
410 this.parametersLocation,
411 this.isParametersEncrypted()
412 );
413 }
414
415
416
417 List currServiceList = this.createServiceComponents(
418 this.roleConfiguration,
419 this.getLogger()
420 );
421
422 this.setServiceList( currServiceList );
423
424
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
433
434 this.incarnateAll( this.getServiceList() );
435
436
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
467
468 this.decommisionAll( this.getServiceList() );
469
470
471
472 this.disposeAll( this.getServiceList() );
473
474
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
520
521 lock = this.getWriteLock();
522
523
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
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
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
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
639
640 lock = this.getWriteLock();
641
642 for( int i=0; i<names.length; i++ )
643 {
644
645
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
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
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
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
728
729 if( result == null )
730 {
731 if( this.hasParentServiceManager() )
732 {
733 result = this.getParentServiceManager().lookup(name);
734 }
735 }
736
737
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
755
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
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
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
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
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
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
1000
1001 serviceComponentContext.put(
1002 URN_YAAFI_KERNELLOCK,
1003 this.readWriteLock
1004 );
1005
1006
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
1019
1020 serviceComponent.setLogger(serviceComponentLogger);
1021 serviceComponent.setServiceManager(this);
1022 serviceComponent.setContext(serviceComponentContext);
1023 serviceComponent.setConfiguration(serviceComponentConfiguraton);
1024 serviceComponent.setParameters(serviceComponentParameters);
1025
1026
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
1162
1163 RoleConfigurationParser roleConfigurationParser =
1164 this.createRoleConfigurationParser();
1165
1166
1167
1168 RoleEntry[] roleEntryList = roleConfigurationParser.parse(roleConfiguration);
1169
1170
1171
1172 ArrayList defaultInterceptorList = this.getDefaultInterceptorServiceList();
1173
1174
1175
1176 for ( int i=0; i<roleEntryList.length; i++ )
1177 {
1178 try
1179 {
1180
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
1558
1559
1560 try
1561 {
1562 Thread.sleep( this.reconfigurationDelay );
1563 }
1564 catch (InterruptedException e)
1565 {
1566
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 }