<name>wamblee.org system spring</name>
<url>http://wamblee.org</url>
<dependencies>
+ <dependency>
+ <groupId>org.wamblee</groupId>
+ <artifactId>wamblee-support</artifactId>
+ <version>${project.version}</version>
+ </dependency>
<dependency>
<groupId>org.wamblee</groupId>
<artifactId>wamblee-system-general</artifactId>
--- /dev/null
+package org.wamblee.system.spring;
+
+import java.util.Properties;
+
+import org.springframework.beans.BeansException;
+import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
+import org.springframework.beans.factory.config.PropertyPlaceholderConfigurer;
+
+/**
+ * Bean that provides postprocessing of the bean factory based on
+ * a given set of properties.
+ *
+ * @author Erik Brakkee
+ */
+class PropertySetter extends PropertyPlaceholderConfigurer {
+
+ /**
+ * Constructs the property setter.
+ * @param aProps Properties.
+ */
+ public PropertySetter(Properties aProps) {
+ StringBuffer buf = new StringBuffer();
+ for (Object key: aProps.keySet()) {
+ buf.append(key);
+ buf.append("=");
+ buf.append(aProps.get(key));
+ buf.append("\n");
+ }
+ setLocation(new StringResource(buf.toString()));
+ }
+}
+++ /dev/null
-package org.wamblee.system.spring;
-
-import org.springframework.beans.factory.FactoryBean;
-
-public class ProvidedServiceBean implements FactoryBean {
-
- private String _id;
-
- public ProvidedServiceBean(String aId) {
- _id = aId;
- }
-
- @Override
- public Object getObject() throws Exception {
- return SpringSystem.REGISTRY.get().find(_id).reference(Object.class);
- }
-
- @Override
- public Class getObjectType() {
- return null;
- }
-
- @Override
- public boolean isSingleton() {
- return true;
- }
-
-}
--- /dev/null
+package org.wamblee.system.spring;
+
+import org.springframework.beans.factory.FactoryBean;
+
+/**
+ * Bean which adds a service required by the spring component to
+ * the application context so that other spring beans can use it.
+ *
+ * @author Erik Brakkee
+ */
+class RequiredServiceBean implements FactoryBean {
+
+ private String _id;
+
+ /**
+ * Constructs the bean.
+ * @param aId Id of the bean in the service registry.
+ */
+ public RequiredServiceBean(String aId) {
+ _id = aId;
+ }
+
+ @Override
+ public Object getObject() throws Exception {
+ return SpringComponent.REGISTRY.get().find(_id).reference(Object.class);
+ }
+
+ @Override
+ public Class getObjectType() {
+ return null;
+ }
+
+ @Override
+ public boolean isSingleton() {
+ return true;
+ }
+
+}
package org.wamblee.system.spring;
import java.util.Map;
+import java.util.Properties;
+import java.util.Set;
import org.springframework.beans.MutablePropertyValues;
import org.springframework.beans.factory.config.BeanDefinition;
/**
* Represents a system configured based on spring.
+ * The spring config files that are configured should not contain any PropertyPlaceholderConfigurer
+ * objects.
*
* @author Erik Brakkee
*/
-public class SpringSystem extends AbstractComponent {
+public class SpringComponent extends AbstractComponent {
/**
* Singleton access to the service registry. Required while starting up.
*/
static ThreadLocal<ServiceRegistry> REGISTRY = new ThreadLocal<ServiceRegistry>();
+ private Properties _properties;
private String[] _configFiles;
private Map<String, ProvidedInterfaceDescriptor> _provided;
private Map<RequiredInterfaceDescriptor, String> _required;
private AbstractApplicationContext _context;
/**
- * Construcst a spring system.
+ * Constructs a spring system.
*
* @param aName
* Name of the system.
- * @param aConfigFiles
+ * @param aConfigFil
* Spring config files to read.
* @param aProvided
* Map of bean name to service descriptor describing the bean
* names that the spring config files use for each required
* service.
*/
- public SpringSystem(String aName, ServiceRegistry aRegistry, String[] aConfigFiles,
+ public SpringComponent(String aName, ServiceRegistry aRegistry, String[] aConfigFiles,
Map<String, ProvidedInterfaceDescriptor> aProvided,
Map<RequiredInterfaceDescriptor, String> aRequired) {
super(aName, aRegistry, aProvided.values().toArray(new InterfaceDescriptor[0]),
aRequired.keySet().toArray(new InterfaceDescriptor[0]));
+ _properties = new Properties();
_configFiles = aConfigFiles;
_provided = aProvided;
_required = aRequired;
}
+
+ /**
+ * Must be called to make a property available in the application context.
+ * @param aKey Property key.
+ * @param aValue Property value.
+ */
+ public void setProperty(String aKey, String aValue) {
+ _properties.put(aKey, aValue);
+ }
+
+ public void addProperties(Properties aProperties) {
+ for (Object key: aProperties.keySet()) {
+ setProperty((String)key, aProperties.getProperty((String)key));
+ }
+ }
@Override
protected void doStart(String aContext,
Service[] aRequiredServices) {
- ServiceRegistry old = REGISTRY.get();
+ ServiceRegistry oldRegistry = REGISTRY.get();
try {
- REGISTRY.set(getRegistry());
+ REGISTRY.set(getRegistry());
try {
+ _parentContext = new GenericApplicationContext();
registerRequiredServices(aRequiredServices);
+
+ _parentContext.refresh();
parseConfigFiles();
+
+ _context.addBeanFactoryPostProcessor(new PropertySetter(_properties));
+ _context.refresh();
exposeProvidedServices(aContext);
} catch (Exception e) {
"Failed to assemble spring system", e);
}
} finally {
- REGISTRY.set(old);
+ REGISTRY.set(oldRegistry);
}
}
private void registerRequiredServices(Service[] aRequiredServices) {
// Register required services in a parent context
- // Register the Hibernate mapping files as a bean.
- _parentContext = new GenericApplicationContext();
-
for (Service svc: aRequiredServices) {
String id = svc.getId();
ProvidedInterfaceDescriptor descriptor = svc.getDescriptor();
String beanName = _required.get(required);
ConstructorArgumentValues cargs = new ConstructorArgumentValues();
cargs.addGenericArgumentValue(id);
- BeanDefinition definition = new RootBeanDefinition(ProvidedServiceBean.class, cargs,
+ BeanDefinition definition = new RootBeanDefinition(RequiredServiceBean.class, cargs,
new MutablePropertyValues());
_parentContext.registerBeanDefinition(beanName, definition);
}
}
- _parentContext.refresh();
}
@Override
--- /dev/null
+package org.wamblee.system.spring;
+
+import java.io.ByteArrayInputStream;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+
+import org.springframework.core.io.Resource;
+
+class StringResource implements Resource {
+
+ private String _value;
+
+ public StringResource(String aValue) {
+ _value = aValue;
+ }
+
+ @Override
+ public Resource createRelative(String aRelativePath) throws IOException {
+ throw new IOException("No relative resource possible");
+ }
+
+ @Override
+ public boolean exists() {
+ return false;
+ }
+
+ @Override
+ public String getDescription() {
+ return "Properties of a spring component";
+ }
+
+ @Override
+ public File getFile() throws IOException {
+ throw new IOException();
+ }
+
+ @Override
+ public String getFilename() {
+ return "springcomponent.properties";
+ }
+
+ @Override
+ public URL getURL() throws IOException {
+ throw new IOException();
+ }
+
+ @Override
+ public boolean isOpen() {
+ return false;
+ }
+
+ @Override
+ public InputStream getInputStream() throws IOException {
+ return new ByteArrayInputStream(_value.getBytes());
+ }
+
+}
package org.wamblee.system.spring;
+import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
+import java.util.Properties;
import junit.framework.TestCase;
+import org.wamblee.io.ClassPathResource;
import org.wamblee.system.AbstractInterfaceDescriptor;
import org.wamblee.system.DefaultProvidedInterfaceDescriptor;
import org.wamblee.system.DefaultRequiredInterfaceDescriptor;
import org.wamblee.system.ServiceRegistry;
import org.wamblee.system.SystemAssemblyException;
-public class SpringSystemTest extends TestCase {
+public class SpringComponentTest extends TestCase {
private static final String HELLO_SERVICE_SPRING_XML = "test.org.wamblee.system.spring.xml";
private static final String HELLO_SERVICE_SPRING_WITH_REQS_XML = "test.org.wamblee.system.springWithRequirements.xml";
+ private static final String HELLO_SERVICE_SPRING_WITH_PROPERTIES_XML = "test.org.wamblee.system.springWithProperties.xml";
+ private static final String PROPERTY_FILE = "test.org.wamblee.system.spring.properties";
private ServiceRegistry _registry;
}
public void testBlackboxSystem() {
- SpringSystem system = new SpringSystem("system", _registry,
+ SpringComponent system = new SpringComponent("system", _registry,
new String[] { HELLO_SERVICE_SPRING_XML },
new HashMap<String, ProvidedInterfaceDescriptor>(),
new HashMap<RequiredInterfaceDescriptor, String>());
provided.put("helloService", new DefaultProvidedInterfaceDescriptor(
"hello", HelloService.class));
- SpringSystem system = new SpringSystem("system", _registry,
+ SpringComponent system = new SpringComponent("system", _registry,
new String[] { HELLO_SERVICE_SPRING_XML }, provided,
new HashMap<RequiredInterfaceDescriptor, String>());
system.start("Hello", new Service[0]);
.say());
system.stop();
}
+
+ public void testWithProperties() throws IOException {
+ Map<String, ProvidedInterfaceDescriptor> provided = new HashMap<String, ProvidedInterfaceDescriptor>();
+ provided.put("helloService", new DefaultProvidedInterfaceDescriptor(
+ "hello", HelloService.class));
+ SpringComponent system = new SpringComponent("system", _registry,
+ new String[] { HELLO_SERVICE_SPRING_WITH_PROPERTIES_XML },
+ provided,
+ new HashMap<RequiredInterfaceDescriptor, String>());
+ Properties props = new Properties();
+ props.load(new ClassPathResource(PROPERTY_FILE).getInputStream());
+ system.addProperties(props);
+
+ system.start("Hello", new Service[0]);
+ Service[] services = system.getRunningServices();
+ assertEquals("Property Value", services[0].reference(HelloService.class).say());
+ }
- public void testWithMissingRequiremnt() {
+ public void testWithMissingRequirement() {
try {
- SpringSystem system = new SpringSystem("system", _registry,
+ SpringComponent system = new SpringComponent("system", _registry,
new String[] { HELLO_SERVICE_SPRING_WITH_REQS_XML },
new HashMap<String, ProvidedInterfaceDescriptor>(),
new HashMap<RequiredInterfaceDescriptor, String>());
Map<RequiredInterfaceDescriptor, String> required = new HashMap<RequiredInterfaceDescriptor, String>();
required.put(new DefaultRequiredInterfaceDescriptor("hello", HelloService.class),
"helloService");
- SpringSystem system = new SpringSystem("system", _registry,
+ SpringComponent system = new SpringComponent("system", _registry,
new String[] { HELLO_SERVICE_SPRING_WITH_REQS_XML },
new HashMap<String, ProvidedInterfaceDescriptor>(), required);
provided.put("blaService", new DefaultProvidedInterfaceDescriptor("bla",
BlaService.class));
- SpringSystem system = new SpringSystem("system", _registry,
+ SpringComponent system = new SpringComponent("system", _registry,
new String[] { HELLO_SERVICE_SPRING_WITH_REQS_XML },
provided, required);
--- /dev/null
+myproperty=Property Value
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<beans xmlns="http://www.springframework.org/schema/beans"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://www.springframework.org/schema/beans
+ http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
+
+ <bean id="helloService" class="org.wamblee.system.spring.HelloService">
+ <constructor-arg>
+ <value>${myproperty}</value>
+ </constructor-arg>
+ </bean>
+
+</beans>