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.ProvidedInterface;
15 import org.wamblee.system.RequiredInterface;
16 import org.wamblee.system.SystemAssemblyException;
19 * Represents a system configured based on spring. The spring config files that
20 * are configured should not contain any PropertyPlaceholderConfigurer objects.
22 * @author Erik Brakkee
24 public class SpringComponent extends AbstractComponent {
26 static final ThreadLocal<SpringComponent> THIS = new ThreadLocal<SpringComponent>();
28 private Properties _properties;
29 private String[] _configFiles;
30 private Map<String, ProvidedInterface> _provided;
31 private Map<RequiredInterface, String> _required;
33 * Parent application context containing required services.
35 private GenericApplicationContext _parentContext;
38 * Application context containing parsed objects.
40 private AbstractApplicationContext _context;
43 * Constructs a spring system.
48 * Spring config files to read.
50 * Map of bean name to service descriptor describing the bean
51 * names that the spring config files use for each required
54 * Map of bean name to service descriptor describing the bean
55 * names that the spring config files use for each required
58 public SpringComponent(String aName, String[] aConfigFiles,
59 Map<String, ProvidedInterface> aProvided,
60 Map<RequiredInterface, String> aRequired) {
61 super(aName, aProvided.values().toArray(new ProvidedInterface[0]),
62 aRequired.keySet().toArray(new RequiredInterface[0]));
63 _properties = new Properties();
64 _configFiles = aConfigFiles;
65 _provided = aProvided;
66 _required = aRequired;
70 * Must be called to make a property available in the application context.
77 public void setProperty(String aKey, String aValue) {
78 _properties.put(aKey, aValue);
81 public void addProperties(Properties aProperties) {
82 for (Object key : aProperties.keySet()) {
83 setProperty((String) key, aProperties.getProperty((String) key));
88 protected void doStart(String aContext) {
90 SpringComponent old = THIS.get();
93 _parentContext = new GenericApplicationContext();
95 registerRequiredServices();
97 _parentContext.refresh();
102 .addBeanFactoryPostProcessor(new PropertySetter(_properties));
105 exposeProvidedServices(aContext);
106 } catch (Exception e) {
107 throw new SystemAssemblyException(
108 "Failed to assemble spring system", e);
114 private void exposeProvidedServices(String aContext) {
115 // Call addService for each provided service.
117 for (String name : _provided.keySet()) {
118 Object svc = _context.getBean(name);
120 throw new IllegalArgumentException(aContext + ": service '"
121 + name + "' is null");
123 addService(aContext, _provided.get(name), svc);
127 private void parseConfigFiles() {
128 // Parse spring config files
130 _context = new ClassPathXmlApplicationContext((String[]) _configFiles,
134 private void registerRequiredServices() {
135 // Register required services in a parent context
136 for (RequiredInterface required: getRequiredServices()) {
137 String beanName = _required.get(required);
138 ConstructorArgumentValues cargs = new ConstructorArgumentValues();
139 cargs.addGenericArgumentValue(required.getName());
140 BeanDefinition definition = new RootBeanDefinition(
141 RequiredServiceBean.class, cargs,
142 new MutablePropertyValues());
143 _parentContext.registerBeanDefinition(beanName, definition);
148 protected void doStop() {