1 package org.wamblee.system.spring;
4 import java.util.Properties;
6 import org.springframework.beans.MutablePropertyValues;
7 import org.springframework.beans.factory.config.BeanDefinition;
8 import org.springframework.beans.factory.config.ConstructorArgumentValues;
9 import org.springframework.beans.factory.support.RootBeanDefinition;
10 import org.springframework.context.support.AbstractApplicationContext;
11 import org.springframework.context.support.ClassPathXmlApplicationContext;
12 import org.springframework.context.support.GenericApplicationContext;
13 import org.wamblee.system.AbstractComponent;
14 import org.wamblee.system.ProvidedInterfaceDescriptor;
15 import org.wamblee.system.RequiredInterfaceDescriptor;
16 import org.wamblee.system.Service;
17 import org.wamblee.system.ServiceRegistry;
18 import org.wamblee.system.SystemAssembler;
19 import org.wamblee.system.SystemAssemblyException;
22 * Represents a system configured based on spring.
23 * The spring config files that are configured should not contain any PropertyPlaceholderConfigurer
26 * @author Erik Brakkee
28 public class SpringComponent extends AbstractComponent {
31 * Singleton access to the service registry. Required while starting up.
33 static ThreadLocal<ServiceRegistry> REGISTRY = new ThreadLocal<ServiceRegistry>();
35 private Properties _properties;
36 private String[] _configFiles;
37 private Map<String, ProvidedInterfaceDescriptor> _provided;
38 private Map<RequiredInterfaceDescriptor, String> _required;
40 * Parent application context containing required services.
42 private GenericApplicationContext _parentContext;
45 * Application context containing parsed objects.
47 private AbstractApplicationContext _context;
50 * Constructs a spring system.
55 * Spring config files to read.
57 * Map of bean name to service descriptor describing the bean
58 * names that the spring config files use for each required
61 * Map of bean name to service descriptor describing the bean
62 * names that the spring config files use for each required
65 public SpringComponent(String aName, ServiceRegistry aRegistry, String[] aConfigFiles,
66 Map<String, ProvidedInterfaceDescriptor> aProvided,
67 Map<RequiredInterfaceDescriptor, String> aRequired) {
68 super(aName, aRegistry, aProvided.values().toArray(new ProvidedInterfaceDescriptor[0]),
69 aRequired.keySet().toArray(new RequiredInterfaceDescriptor[0]));
70 _properties = new Properties();
71 _configFiles = aConfigFiles;
72 _provided = aProvided;
73 _required = aRequired;
77 * Must be called to make a property available in the application context.
78 * @param aKey Property key.
79 * @param aValue Property value.
81 public void setProperty(String aKey, String aValue) {
82 _properties.put(aKey, aValue);
85 public void addProperties(Properties aProperties) {
86 for (Object key: aProperties.keySet()) {
87 setProperty((String)key, aProperties.getProperty((String)key));
92 protected void doStart(String aContext,
93 Service[] aRequiredServices) {
94 ServiceRegistry oldRegistry = REGISTRY.get();
96 REGISTRY.set(getRegistry());
98 _parentContext = new GenericApplicationContext();
100 registerRequiredServices(aRequiredServices);
102 _parentContext.refresh();
106 _context.addBeanFactoryPostProcessor(new PropertySetter(_properties));
109 exposeProvidedServices(aContext);
110 } catch (Exception e) {
111 throw new SystemAssemblyException(
112 "Failed to assemble spring system", e);
115 REGISTRY.set(oldRegistry);
119 private void exposeProvidedServices(String aContext) {
120 // Call addService for each provided service.
122 for (String name : _provided.keySet()) {
123 Object svc = _context.getBean(name);
125 throw new IllegalArgumentException(aContext + ": service '"
126 + name + "' is null");
128 addService(aContext, _provided.get(name), svc);
132 private void parseConfigFiles() {
133 // Parse spring config files
135 _context = new ClassPathXmlApplicationContext((String[]) _configFiles,
139 private void registerRequiredServices(Service[] aRequiredServices) {
140 // Register required services in a parent context
142 for (Service svc: aRequiredServices) {
143 String id = svc.getId();
144 ProvidedInterfaceDescriptor descriptor = svc.getDescriptor();
145 RequiredInterfaceDescriptor[] requiredServices = SystemAssembler.filterRequiredServices(descriptor,
147 for (RequiredInterfaceDescriptor required: requiredServices) {
148 String beanName = _required.get(required);
149 ConstructorArgumentValues cargs = new ConstructorArgumentValues();
150 cargs.addGenericArgumentValue(id);
151 BeanDefinition definition = new RootBeanDefinition(RequiredServiceBean.class, cargs,
152 new MutablePropertyValues());
153 _parentContext.registerBeanDefinition(beanName, definition);
159 protected void doStop() {