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.DefaultScope;
30 import org.wamblee.system.core.ProvidedInterface;
31 import org.wamblee.system.core.RequiredInterface;
32 import org.wamblee.system.core.Scope;
33 import org.wamblee.system.core.SystemAssemblyException;
36 * Represents a system configured based on spring. The spring config files that
37 * are configured should not contain any PropertyPlaceholderConfigurer objects.
39 * @author Erik Brakkee
41 public class SpringComponent extends AbstractComponent<Scope> {
43 private static final String CONTEXT_KEY = "context";
45 static final ThreadLocal<SpringComponent> THIS = new ThreadLocal<SpringComponent>();
46 static final ThreadLocal<Scope> SCOPE = new ThreadLocal<Scope>();
48 private Properties _properties;
49 private String[] _configFiles;
50 private Map<String, ProvidedInterface> _provided;
51 private Map<RequiredInterface, String> _required;
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, String[] aConfigFiles,
70 Map<String, ProvidedInterface> aProvided,
71 Map<RequiredInterface, String> aRequired) {
72 super(aName, aProvided.values().toArray(new ProvidedInterface[0]),
73 aRequired.keySet().toArray(new RequiredInterface[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.
88 public void setProperty(String aKey, String aValue) {
89 _properties.put(aKey, aValue);
92 public void addProperties(Properties aProperties) {
93 for (Object key : aProperties.keySet()) {
94 setProperty((String) key, aProperties.getProperty((String) key));
98 public Scope start() {
99 return super.start(new DefaultScope(new ProvidedInterface[0]));
103 protected Scope doStart(Scope aExternalScope) {
105 SpringComponent old = THIS.get();
106 Scope oldScope = SCOPE.get();
108 Scope scope = new DefaultScope(getProvidedInterfaces(), aExternalScope);
111 GenericApplicationContext parentContext = new GenericApplicationContext();
113 registerRequiredServices(parentContext);
115 parentContext.refresh();
117 AbstractApplicationContext context = parseConfigFiles(parentContext);
120 .addBeanFactoryPostProcessor(new PropertySetter(_properties));
123 exposeProvidedServices(context, scope);
125 scope.put(CONTEXT_KEY, context);
127 } catch (Exception e) {
128 throw new SystemAssemblyException(
129 "Failed to assemble spring system", e);
136 private void exposeProvidedServices(AbstractApplicationContext aContext, Scope aScope) {
137 // Call addService for each provided service.
139 for (String name : _provided.keySet()) {
140 Object svc = aContext.getBean(name);
142 throw new IllegalArgumentException(getQualifiedName() + ": service '"
143 + name + "' is null");
145 addInterface(_provided.get(name), svc, aScope);
146 System.out.println("addService " + _provided.get(name) + " " + svc);
147 aScope.publishInterface(_provided.get(name), svc);
151 private AbstractApplicationContext parseConfigFiles(GenericApplicationContext aParentContext) {
152 // Parse spring config files
154 return new ClassPathXmlApplicationContext((String[]) _configFiles,
158 private void registerRequiredServices(GenericApplicationContext aParentContext) {
159 // Register required services in a parent context
160 for (RequiredInterface required: getRequiredInterfaces()) {
161 String beanName = _required.get(required);
162 ConstructorArgumentValues cargs = new ConstructorArgumentValues();
163 cargs.addGenericArgumentValue(required.getName());
164 BeanDefinition definition = new RootBeanDefinition(
165 RequiredServiceBean.class, cargs,
166 new MutablePropertyValues());
167 aParentContext.registerBeanDefinition(beanName, definition);
172 protected void doStop(Scope aRuntime) {
173 AbstractApplicationContext context = (AbstractApplicationContext)aRuntime.get(CONTEXT_KEY);