1 package org.wamblee.system.spring;
4 import java.util.Properties;
7 import org.springframework.beans.MutablePropertyValues;
8 import org.springframework.beans.factory.config.BeanDefinition;
9 import org.springframework.beans.factory.config.ConstructorArgumentValues;
10 import org.springframework.beans.factory.support.RootBeanDefinition;
11 import org.springframework.context.ApplicationContext;
12 import org.springframework.context.support.AbstractApplicationContext;
13 import org.springframework.context.support.ClassPathXmlApplicationContext;
14 import org.springframework.context.support.GenericApplicationContext;
15 import org.wamblee.system.AbstractComponent;
16 import org.wamblee.system.Container;
17 import org.wamblee.system.ProvidedInterfaceDescriptor;
18 import org.wamblee.system.RequiredInterfaceDescriptor;
19 import org.wamblee.system.Service;
20 import org.wamblee.system.InterfaceDescriptor;
21 import org.wamblee.system.ServiceRegistry;
22 import org.wamblee.system.SystemAssembler;
23 import org.wamblee.system.SystemAssemblyException;
26 * Represents a system configured based on spring.
27 * The spring config files that are configured should not contain any PropertyPlaceholderConfigurer
30 * @author Erik Brakkee
32 public class SpringComponent extends AbstractComponent {
35 * Singleton access to the service registry. Required while starting up.
37 static ThreadLocal<ServiceRegistry> REGISTRY = new ThreadLocal<ServiceRegistry>();
39 private Properties _properties;
40 private String[] _configFiles;
41 private Map<String, ProvidedInterfaceDescriptor> _provided;
42 private Map<RequiredInterfaceDescriptor, String> _required;
44 * Parent application context containing required services.
46 private GenericApplicationContext _parentContext;
49 * Application context containing parsed objects.
51 private AbstractApplicationContext _context;
54 * Constructs a spring system.
59 * Spring config files to read.
61 * Map of bean name to service descriptor describing the bean
62 * names that the spring config files use for each required
65 * Map of bean name to service descriptor describing the bean
66 * names that the spring config files use for each required
69 public SpringComponent(String aName, ServiceRegistry aRegistry, String[] aConfigFiles,
70 Map<String, ProvidedInterfaceDescriptor> aProvided,
71 Map<RequiredInterfaceDescriptor, String> aRequired) {
72 super(aName, aRegistry, aProvided.values().toArray(new ProvidedInterfaceDescriptor[0]),
73 aRequired.keySet().toArray(new RequiredInterfaceDescriptor[0]));
74 _properties = new Properties();
75 _configFiles = aConfigFiles;
76 _provided = aProvided;
77 _required = aRequired;
81 * Must be called to make a property available in the application context.
82 * @param aKey Property key.
83 * @param aValue Property value.
85 public void setProperty(String aKey, String aValue) {
86 _properties.put(aKey, aValue);
89 public void addProperties(Properties aProperties) {
90 for (Object key: aProperties.keySet()) {
91 setProperty((String)key, aProperties.getProperty((String)key));
96 protected void doStart(String aContext,
97 Service[] aRequiredServices) {
98 ServiceRegistry oldRegistry = REGISTRY.get();
100 REGISTRY.set(getRegistry());
102 _parentContext = new GenericApplicationContext();
104 registerRequiredServices(aRequiredServices);
106 _parentContext.refresh();
110 _context.addBeanFactoryPostProcessor(new PropertySetter(_properties));
113 exposeProvidedServices(aContext);
114 } catch (Exception e) {
115 throw new SystemAssemblyException(
116 "Failed to assemble spring system", e);
119 REGISTRY.set(oldRegistry);
123 private void exposeProvidedServices(String aContext) {
124 // Call addService for each provided service.
126 for (String name : _provided.keySet()) {
127 Object svc = _context.getBean(name);
129 throw new IllegalArgumentException(aContext + ": service '"
130 + name + "' is null");
132 addService(aContext, _provided.get(name), svc);
136 private void parseConfigFiles() {
137 // Parse spring config files
139 _context = new ClassPathXmlApplicationContext((String[]) _configFiles,
143 private void registerRequiredServices(Service[] aRequiredServices) {
144 // Register required services in a parent context
146 for (Service svc: aRequiredServices) {
147 String id = svc.getId();
148 ProvidedInterfaceDescriptor descriptor = svc.getDescriptor();
149 RequiredInterfaceDescriptor[] requiredServices = SystemAssembler.filterRequiredServices(descriptor,
151 for (RequiredInterfaceDescriptor required: requiredServices) {
152 String beanName = _required.get(required);
153 ConstructorArgumentValues cargs = new ConstructorArgumentValues();
154 cargs.addGenericArgumentValue(id);
155 BeanDefinition definition = new RootBeanDefinition(RequiredServiceBean.class, cargs,
156 new MutablePropertyValues());
157 _parentContext.registerBeanDefinition(beanName, definition);
163 protected void doStop() {