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.Service;
17 import org.wamblee.system.SystemAssembler;
18 import org.wamblee.system.SystemAssemblyException;
21 * Represents a system configured based on spring. The spring config files that
22 * are configured should not contain any PropertyPlaceholderConfigurer objects.
24 * @author Erik Brakkee
26 public class SpringComponent extends AbstractComponent {
28 static final ThreadLocal<SpringComponent> THIS = new ThreadLocal<SpringComponent>();
30 private Properties _properties;
31 private String[] _configFiles;
32 private Map<String, ProvidedInterface> _provided;
33 private Map<RequiredInterface, String> _required;
35 * Parent application context containing required services.
37 private GenericApplicationContext _parentContext;
40 * Application context containing parsed objects.
42 private AbstractApplicationContext _context;
45 * Constructs a spring system.
50 * Spring config files to read.
52 * Map of bean name to service descriptor describing the bean
53 * names that the spring config files use for each required
56 * Map of bean name to service descriptor describing the bean
57 * names that the spring config files use for each required
60 public SpringComponent(String aName, String[] aConfigFiles,
61 Map<String, ProvidedInterface> aProvided,
62 Map<RequiredInterface, String> aRequired) {
63 super(aName, aProvided.values().toArray(new ProvidedInterface[0]),
64 aRequired.keySet().toArray(new RequiredInterface[0]));
65 _properties = new Properties();
66 _configFiles = aConfigFiles;
67 _provided = aProvided;
68 _required = aRequired;
72 * Must be called to make a property available in the application context.
79 public void setProperty(String aKey, String aValue) {
80 _properties.put(aKey, aValue);
83 public void addProperties(Properties aProperties) {
84 for (Object key : aProperties.keySet()) {
85 setProperty((String) key, aProperties.getProperty((String) key));
90 protected void doStart(String aContext) {
92 SpringComponent old = THIS.get();
95 _parentContext = new GenericApplicationContext();
97 registerRequiredServices();
99 _parentContext.refresh();
104 .addBeanFactoryPostProcessor(new PropertySetter(_properties));
107 exposeProvidedServices(aContext);
108 } catch (Exception e) {
109 throw new SystemAssemblyException(
110 "Failed to assemble spring system", e);
116 private void exposeProvidedServices(String aContext) {
117 // Call addService for each provided service.
119 for (String name : _provided.keySet()) {
120 Object svc = _context.getBean(name);
122 throw new IllegalArgumentException(aContext + ": service '"
123 + name + "' is null");
125 addService(aContext, _provided.get(name), svc);
129 private void parseConfigFiles() {
130 // Parse spring config files
132 _context = new ClassPathXmlApplicationContext((String[]) _configFiles,
136 private void registerRequiredServices() {
137 // Register required services in a parent context
138 for (RequiredInterface required: getRequiredServices()) {
139 String beanName = _required.get(required);
140 ConstructorArgumentValues cargs = new ConstructorArgumentValues();
141 cargs.addGenericArgumentValue(required.getName());
142 BeanDefinition definition = new RootBeanDefinition(
143 RequiredServiceBean.class, cargs,
144 new MutablePropertyValues());
145 _parentContext.registerBeanDefinition(beanName, definition);
150 protected void doStop() {