2 * Copyright 2007 the original author or authors.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
16 package org.wamblee.system.spring;
19 import java.util.Properties;
21 import org.springframework.beans.MutablePropertyValues;
22 import org.springframework.beans.factory.config.BeanDefinition;
23 import org.springframework.beans.factory.config.ConstructorArgumentValues;
24 import org.springframework.beans.factory.support.RootBeanDefinition;
25 import org.springframework.context.support.AbstractApplicationContext;
26 import org.springframework.context.support.ClassPathXmlApplicationContext;
27 import org.springframework.context.support.GenericApplicationContext;
28 import org.wamblee.system.core.AbstractComponent;
29 import org.wamblee.system.core.ProvidedInterface;
30 import org.wamblee.system.core.RequiredInterface;
31 import org.wamblee.system.core.SystemAssemblyException;
34 * Represents a system configured based on spring. The spring config files that
35 * are configured should not contain any PropertyPlaceholderConfigurer objects.
37 * @author Erik Brakkee
39 public class SpringComponent extends AbstractComponent {
41 static final ThreadLocal<SpringComponent> THIS = new ThreadLocal<SpringComponent>();
43 private Properties _properties;
44 private String[] _configFiles;
45 private Map<String, ProvidedInterface> _provided;
46 private Map<RequiredInterface, String> _required;
48 * Parent application context containing required services.
50 private GenericApplicationContext _parentContext;
53 * Application context containing parsed objects.
55 private AbstractApplicationContext _context;
58 * Constructs a spring system.
63 * Spring config files to read.
65 * Map of bean name to service descriptor describing the bean
66 * names that the spring config files use for each required
69 * Map of bean name to service descriptor describing the bean
70 * names that the spring config files use for each required
73 public SpringComponent(String aName, String[] aConfigFiles,
74 Map<String, ProvidedInterface> aProvided,
75 Map<RequiredInterface, String> aRequired) {
76 super(aName, aProvided.values().toArray(new ProvidedInterface[0]),
77 aRequired.keySet().toArray(new RequiredInterface[0]));
78 _properties = new Properties();
79 _configFiles = aConfigFiles;
80 _provided = aProvided;
81 _required = aRequired;
85 * Must be called to make a property available in the application context.
92 public void setProperty(String aKey, String aValue) {
93 _properties.put(aKey, aValue);
96 public void addProperties(Properties aProperties) {
97 for (Object key : aProperties.keySet()) {
98 setProperty((String) key, aProperties.getProperty((String) key));
103 protected void doStart() {
105 SpringComponent old = THIS.get();
108 _parentContext = new GenericApplicationContext();
110 registerRequiredServices();
112 _parentContext.refresh();
117 .addBeanFactoryPostProcessor(new PropertySetter(_properties));
120 exposeProvidedServices();
121 } catch (Exception e) {
122 throw new SystemAssemblyException(
123 "Failed to assemble spring system", e);
129 private void exposeProvidedServices() {
130 // Call addService for each provided service.
132 for (String name : _provided.keySet()) {
133 Object svc = _context.getBean(name);
135 throw new IllegalArgumentException(getQualifiedName() + ": service '"
136 + name + "' is null");
138 addInterface(_provided.get(name), svc);
142 private void parseConfigFiles() {
143 // Parse spring config files
145 _context = new ClassPathXmlApplicationContext((String[]) _configFiles,
149 private void registerRequiredServices() {
150 // Register required services in a parent context
151 for (RequiredInterface required: getRequiredInterfaces()) {
152 String beanName = _required.get(required);
153 ConstructorArgumentValues cargs = new ConstructorArgumentValues();
154 cargs.addGenericArgumentValue(required.getName());
155 BeanDefinition definition = new RootBeanDefinition(
156 RequiredServiceBean.class, cargs,
157 new MutablePropertyValues());
158 _parentContext.registerBeanDefinition(beanName, definition);
163 protected void doStop() {
165 for (ProvidedInterface provided: getProvidedInterfaces()) {
166 removeInterface(provided);