--- /dev/null
+/*
+ * Copyright 2008 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.wamblee.test;
+
+import org.easymock.IArgumentMatcher;
+import org.easymock.classextension.EasyMock;
+
+/**
+ * Some general matchers for easy mock.
+ *
+ * @author Erik Brakkee
+ */
+public class EasyMockMatchers {
+
+ public static class Any implements IArgumentMatcher {
+ public Any() {
+ // Empty
+ }
+
+ @Override
+ public boolean matches(Object aArg0) {
+ return true;
+ }
+
+ @Override
+ public void appendTo(StringBuffer aBuf) {
+ aBuf.append("anyObject()");
+ }
+ }
+
+ /**
+ * Type-safe matcher to match any object of a given type.
+ * @param <T>
+ * @param aType Type.
+ * @return Returns null.
+ */
+ public static <T> T anyObject(Class<T> aType) {
+ EasyMock.reportMatcher(new Any());
+ return null;
+ }
+}
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
- */
+ */
package org.wamblee.system.core;
import java.util.ArrayList;
/**
* Abstract subsystem class making it easy to implement new subsystems.
*/
-public abstract class AbstractComponent implements Component {
+public abstract class AbstractComponent<Type> implements Component<Type> {
private static final Log LOG = LogFactory.getLog(AbstractComponent.class);
- private String _context;
- private String _name;
+ private ThreadLocal<List<ProvidedInterface>> _remaining;
+
+ private String _context;
+ private String _name;
private List<ProvidedInterface> _provided;
private List<RequiredInterface> _required;
- private Set<ProvidedInterface> _running;
-
+
/**
* Constructs the subsystem.
- *
+ *
* @param aName
* Name of the system.
* @param aProvided
*/
protected AbstractComponent(String aName, ProvidedInterface[] aProvided,
RequiredInterface[] aRequired) {
- _context = null;
+ _remaining = new ThreadLocal<List<ProvidedInterface>>();
+ _context = null;
_name = aName;
_provided = new ArrayList<ProvidedInterface>();
_provided.addAll(Arrays.asList(aProvided));
_required = new ArrayList<RequiredInterface>();
_required.addAll(Arrays.asList(aRequired));
- _running = new HashSet<ProvidedInterface>();
}
@Override
public final String getName() {
return _name;
}
-
+
@Override
public void addContext(String aContext) {
- if (_context == null ) {
- _context = aContext;
- }
- else {
+ if (_context == null) {
+ _context = aContext;
+ } else {
_context = aContext + "." + _context;
}
}
-
+
@Override
public String getQualifiedName() {
- if ( _context == null ) {
- return getName();
+ if (_context == null) {
+ return getName();
}
- return _context + "." + getName();
+ return _context + "." + getName();
}
@Override
}
@Override
- public final void start() {
+ public final Type start(Scope aScope) {
LOG.info("Initializing '" + getQualifiedName() + "'");
- doStart();
- if ( _running.size() != _provided.size()) {
- List<ProvidedInterface> remaining =
- new ArrayList<ProvidedInterface>(_provided);
- remaining.removeAll(_running);
- throw new SystemAssemblyException(getQualifiedName() + ": not all services were started, missing " + remaining);
+ List<ProvidedInterface> oldRemaining = _remaining.get();
+ _remaining.set(new ArrayList<ProvidedInterface>(Arrays.asList(getProvidedInterfaces())));
+ try {
+ Type runtime = doStart(aScope);
+ checkNotStartedInterfaces();
+ return runtime;
+ } finally {
+ _remaining.set(oldRemaining);
+ }
+ }
+
+ private void checkNotStartedInterfaces() {
+ if (_remaining.get().size() > 0) {
+ String notProvided = "";
+ for (ProvidedInterface provided : _remaining.get()) {
+ notProvided += "\nComponent " + getQualifiedName()
+ + " did not start interface " + provided;
+ }
+ throw new SystemAssemblyException(notProvided);
}
}
/**
* Must be implemented for initializing the subsystem. The implementation
* must call {@link #addService(Service)} for each service that is started.
+ *
+ * @return Returns the runtime of the component.
*/
- protected abstract void doStart();
+ protected abstract Type doStart(Scope aScope);
/**
* Implementations must call this method to indicate that a new service has
* been started.
*
+ * @param aDescriptor
+ * Provided interface.
* @param aService
- * Service.
+ * Implementation of the interface.
+ * @param aScope
+ * scope in which to publish the implementation.
*/
- protected final void addInterface(
- ProvidedInterface aDescriptor, Object aService) {
- LOG.info("Interface '" + getQualifiedName() + "." + aDescriptor.getName() + "' started.");
- _running.add(aDescriptor);
- aDescriptor.publish(aService);
+ protected final void addInterface(ProvidedInterface aDescriptor,
+ Object aService, Scope aScope) {
+ LOG.info("Interface '" + getQualifiedName() + "."
+ + aDescriptor.getName() + "' started.");
+ _remaining.get().remove(aDescriptor);
+ aScope.publishInterface(aDescriptor, aService);
}
@Override
- public ProvidedInterface[] getRunningInterfaces() {
- return _running.toArray(new ProvidedInterface[0]);
- }
-
- @Override
- public void stop() {
- doStop();
- if ( _running.size() > 0 ) {
- // programming error.
- throw new RuntimeException(getQualifiedName() + ": still services running after the stop call.");
- }
- }
-
- protected abstract void doStop();
-
- /**
- * Implementations must call this method to indicate that a running service has
- * been stopped.
- *
- * @param aService
- * Service.
- */
- protected final void removeInterface(
- ProvidedInterface aDescriptor) {
- LOG.info("Interface '" + getQualifiedName() + "." + aDescriptor.getName() + "' stopped.");
- _running.remove(aDescriptor);
- aDescriptor.publish(null);
+ public void stop(Type aRuntime) {
+ doStop(aRuntime);
}
+ protected abstract void doStop(Type aRuntime);
+
@Override
public String toString() {
return getQualifiedName();
/**
* A component represents a part of a system that requires a
- * number of interfaces and provides a number of interfaces.
+ * number of interfaces and provides a number of interfaces.
+ *
+ * The component interface provides the meta-data for a component.
+ * After calling {@link #start(Scope)}, an actual runtime representation of the
+ * component can be created which is independent of this component.
+ * As a special case, the runtime representation may be identical to the
+ * component instance but in general it is not. This allows a component to be
+ * used as a factory for creating objects.
+ *
*
* @author Erik Brakkee
*/
-public interface Component {
+public interface Component<Type> {
/**
* Gets the name of the subsystem.
/**
- * Initialises the subsytem by starting all the services that
- * it described as provided.
- */
- void start();
-
- /**
- * Gets the list of running services in the subsystem.
- *
- * This method may only be called after the
- * {@link #initialize(String, Service[])} has been called.
- * @return
+ * Initialises the subsystem by starting all the services that
+ * it described as provided.
+ * @param aScope Scope with external interface implementations that are available. The component
+ * implementation can either oublish itself in this scope or it can decide to
+ * create a new scope with the scope passed in as a parent.
+ * @return Gets an object representing the runtime of the component.
*/
- ProvidedInterface[] getRunningInterfaces();
+ Type start(Scope aScope);
/**
- * Stops a subsystem.
+ * Stops a component.
+ * @param aRuntime THe runtime part of the component.
*/
- void stop();
+ void stop(Type aRuntime);
}
*
* @author Erik Brakkee
*/
-public class Container extends AbstractComponent {
+public class Container extends AbstractComponent<Scope> {
private static final Log LOG = LogFactory.getLog(Container.class);
}
}
}
+
+ public Scope start() {
+ return super.start(new DefaultScope(new ProvidedInterface[0]));
+ }
@Override
- protected void doStart() {
+ protected Scope doStart(Scope aExternalScope) {
LOG.info("Starting '" + getQualifiedName() + "'");
+
+ Scope scope = new DefaultScope(getProvidedInterfaces(),
+ aExternalScope);
+
List<ProvidedInterface> allProvided = new ArrayList<ProvidedInterface>();
// all interfaces from the required list of this container are
checkAllRequiredServicesAlreadyProvided(allProvided, component);
// Start the service.
- component.start();
+ Object runtime = component.start(scope);
+ scope.addRuntime(component, runtime);
started.add(component);
// add all provided services
} catch (RuntimeException e) {
LOG.error(getQualifiedName() + ": could not start '"
+ component.getQualifiedName() + "'", e);
- stopAlreadyStartedComponents(started);
+ stopAlreadyStartedComponents(started, scope);
throw e;
}
}
-
+ return scope;
}
- private void stopAlreadyStartedComponents(List<Component> aStarted) {
+ private void stopAlreadyStartedComponents(List<Component> aStarted, Scope aScope) {
// an exception occurred, stop the successfully started
// components
for (int i = aStarted.size() - 1; i >= 0; i--) {
try {
- aStarted.get(i).stop();
+ aStarted.get(i).stop(aScope);
} catch (Throwable t) {
LOG.error(getQualifiedName() + ": error stopping "
+ aStarted.get(i).getQualifiedName());
}
@Override
- protected void doStop() {
+ protected void doStop(Scope aScope) {
for (int i = _components.length - 1; i >= 0; i--) {
- _components[i].stop();
+ Component component = _components[i];
+ Object runtime = aScope.getRuntime(component);
+ component.stop(runtime);
}
}
private String _name;
private Class[] _interfaces;
- private Object _implementation;
+ private String _uniqueId;
/**
* Constructs the descriptor.
* @param aInterface Type of service.
*/
public DefaultProvidedInterface(String aName, Class aInterface) {
- _name = aName;
- _interfaces = new Class[] { aInterface };
+ this(aName, new Class[] { aInterface });
}
public DefaultProvidedInterface(String aName, Class[] aInterfaces) {
_name = aName;
- _interfaces = Arrays.copyOf(aInterfaces, aInterfaces.length);
+ _interfaces = Arrays.copyOf(aInterfaces, aInterfaces.length);
+ _uniqueId = null;
}
@Override
public Class[] getInterfaceTypes() {
return _interfaces;
}
-
+
@Override
- public void publish(Object aImplementation) {
- _implementation = aImplementation;
+ public void setUniqueId(String aId) {
+ _uniqueId = aId;
}
@Override
- public Object getImplementation() {
- return _implementation;
+ public String getUniqueId() {
+ return _uniqueId;
}
@Override
- public boolean equals(Object obj) {
- if ( !(obj instanceof DefaultProvidedInterface)) {
- return false;
- }
- DefaultProvidedInterface descr = (DefaultProvidedInterface)obj;
- if ( _interfaces.length != descr._interfaces.length ) {
- return false;
- }
- String[] interfaces1 = new String[_interfaces.length];
- String[] interfaces2 = new String[_interfaces.length];
- for (int i = 0; i < _interfaces.length; i++) {
- interfaces1[i] = _interfaces[i].getName();
- interfaces2[i] = descr._interfaces[i].getName();
- }
- Arrays.sort(interfaces1);
- Arrays.sort(interfaces2);
- return Arrays.equals(interfaces1, interfaces2);
- }
-
- @Override
- public int hashCode() {
- return _interfaces.hashCode();
+ public void publish(Object aImplementation, Scope aScope) {
+ aScope.publishInterface(this, aImplementation);
}
@Override
public void setProvider(ProvidedInterface aProvider) {
_provider = aProvider;
}
-
- @Override
- public <T> T getImplementation(Class<T> aClass) {
- if ( _provider == null ) {
- return null;
- }
- return (T)_provider.getImplementation();
- }
@Override
public boolean equals(Object obj) {
/**
* Represents an interface provided by a component.
+ * Different component objects should never share ProvidedInterface instances!
*
* @author Erik Brakkee
*/
Class[] getInterfaceTypes();
/**
- * Publish an implementation of the interface.
- * @param aImplementation
+ * Sets a unique id of the provided interface to identify it within a given scope.
+ * Will be called by the container as part of calling {@link #publish(Object, Scope)}.
+ * @param aId Unique id.
*/
- void publish(Object aImplementation);
-
+ void setUniqueId(String aId);
+
+ /**
+ * Gets the unique if of the provided interface. This is set by the container
+ * using {@link #setUniqueId(String)}.
+ */
+ String getUniqueId();
+
/**
- * Gets the implementation.
- * @return Implementation or null if not started.
+ * Publishes an implementation of the interface. The implementation must
+ * call {@link Scope#publishInterface(ProvidedInterface, Object)} to publish the
+ * interface implementation in a given scope.
+ * @param aImplementation Implementation to publish.
+ * @param aScope Scope in which to publish the implementation.
*/
- Object getImplementation();
+ void publish(Object aImplementation, Scope aScope);
}
* @return Provider or null if not set.
*/
ProvidedInterface getProvider();
-
- /**
- * Gets the implementation of the required interface.
- * @param <T>
- * @param aClass Interface type.
- * @return Interface implementation or null if not known yet.
- */
- <T> T getImplementation(Class<T> aClass);
}
public class AbstractComponentTest extends TestCase {
- public void testNotAllComponentsStarted() {
+ public void testNotAllInterfacesStarted() {
try {
Component component = new AbstractComponent("xx",
new ProvidedInterface[] { new DefaultProvidedInterface(
"xxx", String.class) }, new RequiredInterface[0]) {
@Override
- protected void doStart() {
+ protected Object doStart(Scope aScope) {
// Empty, not starting service.
+ return null;
}
@Override
- protected void doStop() {
+ protected void doStop(Object aRuntime) {
// Empty.
}
};
- component.start();
+ component.start(new DefaultScope(component.getProvidedInterfaces()));
} catch (SystemAssemblyException e) {
+ //e.printStackTrace();
return;
}
fail();
private EventTracker<String> _tracker;
private String _string;
- private Integer _integer;
+ private Integer _integer;
+ private double _random;
public Application() {
- super("application", new ProvidedInterface[0], required(false));
+ super("application", new ProvidedInterface[0], required(false));
+ _random = Math.random();
}
public Application(boolean aIsOptinal) {
}
@Override
- protected void doStart() {
+ protected Object doStart(Scope aScope) {
track("start." + getName());
- _string = getRequiredInterfaces()[0].getImplementation(String.class);
- _integer = getRequiredInterfaces()[1].getImplementation(Integer.class);
+ _string = aScope.retrieveInterfaceImplementation(getRequiredInterfaces()[0].getProvider(), String.class);
+ _integer = aScope.retrieveInterfaceImplementation(getRequiredInterfaces()[1].getProvider(), Integer.class);
+ return _random;
}
public String getString() {
}
@Override
- protected void doStop() {
- track("stop." + getName());
+ protected void doStop(Object aRuntime) {
+ track("stop." + getName());
+ if ( _random != (Double)aRuntime) {
+ throw new IllegalArgumentException("Wrong runtime: expected " + _random + " but got " +
+ aRuntime);
+ }
}
private void track(String aString) {
import org.easymock.classextension.EasyMock;
import org.easymock.classextension.IMocksControl;
import org.wamblee.test.AssertionUtils;
+import org.wamblee.test.EasyMockMatchers;
import org.wamblee.test.EventTracker;
public class ContainerTest extends TestCase {
environment, application }, new ProvidedInterface[0],
new RequiredInterface[0]);
- container.start();
+ Scope scope = container.start();
AssertionUtils.assertEquals(new String[] { "start.environment",
"start.application" }, _tracker.getEvents(
Thread.currentThread()).toArray(new String[0]));
- ProvidedInterface[] envServices = environment.getRunningInterfaces();
- assertEquals(2, envServices.length);
- ProvidedInterface[] appServices = application.getRunningInterfaces();
- assertEquals(0, appServices.length);
+ assertEquals(0, scope.getProvidedInterfaces().length);
assertEquals(environment.getString(), application.getString());
assertEquals(environment.getInteger(), application.getInteger());
Container system = new Container("all", new Component[] { environment,
application }, new ProvidedInterface[0],
new RequiredInterface[0]);
- system.start();
+ Scope runtime = system.start();
RequiredInterface[] required = system.getRequiredInterfaces();
assertEquals(0, required.length);
ProvidedInterface[] provided = system.getProvidedInterfaces();
Thread.currentThread()).toArray(new String[0]));
_tracker.clear();
- system.stop();
+ system.stop(runtime);
AssertionUtils.assertEquals(new String[] { "stop.application",
"stop.environment" }, _tracker
.getEvents(Thread.currentThread()).toArray(new String[0]));
Container system = new Container("all",
new Component[] { application }, new ProvidedInterface[0],
application.getRequiredInterfaces());
- environment.start();
+ environment.start(new DefaultScope(new ProvidedInterface[0]));
system.getRequiredInterfaces()[0].setProvider(environment
.getProvidedInterfaces()[0]);
system.getRequiredInterfaces()[1].setProvider(environment
Environment environment = new Environment(_tracker);
Application application = control.createMock(Application.class,
new ConstructorArgs(Application.class.getConstructor()),
- Application.class.getDeclaredMethod("doStart"));
+ Application.class.getDeclaredMethod("doStart", Scope.class));
- application.doStart();
+ application.doStart(EasyMockMatchers.anyObject(Scope.class));
EasyMock.expectLastCall().andThrow(new RuntimeException());
control.replay();
AssertionUtils.assertEquals(new String[] { "start.environment",
"stop.environment" }, _tracker.getEvents(
Thread.currentThread()).toArray(new String[0]));
- ProvidedInterface[] envServices = environment.getRunningInterfaces();
- assertEquals(0, envServices.length);
- assertNull(environment.getProvidedInterfaces()[0].getImplementation());
- assertNull(environment.getProvidedInterfaces()[0].getImplementation());
return;
}
fail();
// Application 1 will throw an exception while stopping.
Application application1 = control.createMock(Application.class,
new ConstructorArgs(Application.class.getConstructor()),
- Application.class.getDeclaredMethod("doStop"));
+ Application.class.getDeclaredMethod("doStop", Object.class));
- application1.doStop();
+ application1.doStop(EasyMock.anyObject());
EasyMock.expectLastCall().andThrow(new RuntimeException());
// application 2 will throw an exception while starting
Application application2 = control.createMock(Application.class,
new ConstructorArgs(Application.class.getConstructor()),
- Application.class.getDeclaredMethod("doStart"));
+ Application.class.getDeclaredMethod("doStart", Scope.class));
- application2.doStart();
+ application2.doStart(EasyMockMatchers.anyObject(Scope.class));
EasyMock.expectLastCall().andThrow(new RuntimeException());
control.replay();
AssertionUtils.assertEquals(new String[] { "start.environment",
"stop.environment" }, _tracker.getEvents(
Thread.currentThread()).toArray(new String[0]));
- ProvidedInterface[] envServices = environment.getRunningInterfaces();
- assertEquals(0, envServices.length);
- assertNull(environment.getProvidedInterfaces()[0].getImplementation());
- assertNull(environment.getProvidedInterfaces()[0].getImplementation());
return;
}
fail();
env.getProvidedInterfaces()[0]);
container.getRequiredInterfaces()[1].setProvider(
env.getProvidedInterfaces()[1]);
- container.start();
+ Scope external = new DefaultScope(env.getProvidedInterfaces());
+ env.start(external);
+
+ container.start(external);
assertSame(env.getProvidedInterfaces()[0], container.getRequiredInterfaces()[0].getProvider());
assertSame(env.getProvidedInterfaces()[1], container.getRequiredInterfaces()[1].getProvider());
assertSame(env.getProvidedInterfaces()[0], application.getRequiredInterfaces()[0].getProvider());
new ProvidedInterface[0], Application.required(true));
Environment env = new Environment();
container.getRequiredInterfaces()[0].setProvider(
- env.getProvidedInterfaces()[0]);
- container.start();
+ env.getProvidedInterfaces()[0]);
+ Scope external = new DefaultScope(new ProvidedInterface[0]);
+ external.publishInterface(env.getProvidedInterfaces()[0], env.getString());
+ container.start(external);
assertSame(env.getProvidedInterfaces()[0], container.getRequiredInterfaces()[0].getProvider());
assertNull(container.getRequiredInterfaces()[1].getProvider());
assertSame(env.getProvidedInterfaces()[0], application.getRequiredInterfaces()[0].getProvider());
new DefaultRequiredInterface("a", new Class[]{ String.class, Integer.class})));
}
-
- public void testGetImplementation() {
- RequiredInterface required = new DefaultRequiredInterface("hello", String.class);
- assertNull(required.getImplementation(String.class));
- }
}
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
- */
+ */
package org.wamblee.system.core;
import javax.sql.DataSource;
import org.wamblee.system.core.RequiredInterface;
import org.wamblee.test.EventTracker;
-
public class Environment extends AbstractComponent {
-
- private static final ProvidedInterface[] provided() {
- return new ProvidedInterface[] {
- new DefaultProvidedInterface("datasource", String.class),
- new DefaultProvidedInterface("integer", Integer.class)
- };
+
+ private static final ProvidedInterface[] provided() {
+ return new ProvidedInterface[] {
+ new DefaultProvidedInterface("datasource", String.class),
+ new DefaultProvidedInterface("integer", Integer.class) };
}
-
- private EventTracker<String> _tracker;
-
- public Environment() {
+
+ private EventTracker<String> _tracker;
+ private double _random;
+
+ public Environment() {
super("environment", provided(), new RequiredInterface[0]);
+ _random = Math.random();
}
-
- public Environment(EventTracker aTracker) {
+
+ public Environment(EventTracker aTracker) {
this();
- _tracker = aTracker;
+ _tracker = aTracker;
}
-
- public Integer getInteger() {
+
+ public Integer getInteger() {
return 2;
}
-
- public String getString() {
+
+ public String getString() {
return "Hello";
}
-
+
@Override
- protected void doStart() {
- addInterface(getProvidedInterfaces()[0], getString());
- addInterface(getProvidedInterfaces()[1], getInteger());
- track("start." + getName());
+ protected Object doStart(Scope aScope) {
+ addInterface(getProvidedInterfaces()[0], getString(), aScope);
+ addInterface(getProvidedInterfaces()[1], getInteger(), aScope);
+ track("start." + getName());
+ return _random;
}
@Override
- protected void doStop() {
+ protected void doStop(Object aRuntime) {
track("stop." + getName());
- removeInterface(getProvidedInterfaces()[0]);
- removeInterface(getProvidedInterfaces()[1]);
+ if (_random != (Double) aRuntime) {
+ throw new IllegalArgumentException("Wrong runtime: expected "
+ + _random + " but got " + aRuntime);
+ }
}
-
+
private void track(String aString) {
- if ( _tracker == null ) {
- return;
+ if (_tracker == null) {
+ return;
}
_tracker.eventOccurred(aString);
}
@Override
public Object getObject() throws Exception {
- return _required.getImplementation(Object.class);
+ return SpringComponent.SCOPE.get().retrieveInterfaceImplementation(
+ _required.getProvider(), Object.class);
}
@Override
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.context.support.GenericApplicationContext;
import org.wamblee.system.core.AbstractComponent;
+import org.wamblee.system.core.DefaultScope;
import org.wamblee.system.core.ProvidedInterface;
import org.wamblee.system.core.RequiredInterface;
+import org.wamblee.system.core.Scope;
import org.wamblee.system.core.SystemAssemblyException;
/**
*
* @author Erik Brakkee
*/
-public class SpringComponent extends AbstractComponent {
+public class SpringComponent extends AbstractComponent<Scope> {
+
+ private static final String CONTEXT_KEY = "context";
static final ThreadLocal<SpringComponent> THIS = new ThreadLocal<SpringComponent>();
+ static final ThreadLocal<Scope> SCOPE = new ThreadLocal<Scope>();
private Properties _properties;
private String[] _configFiles;
private Map<String, ProvidedInterface> _provided;
private Map<RequiredInterface, String> _required;
- /**
- * Parent application context containing required services.
- */
- private GenericApplicationContext _parentContext;
-
- /**
- * Application context containing parsed objects.
- */
- private AbstractApplicationContext _context;
/**
* Constructs a spring system.
setProperty((String) key, aProperties.getProperty((String) key));
}
}
+
+ public Scope start() {
+ return super.start(new DefaultScope(new ProvidedInterface[0]));
+ }
@Override
- protected void doStart() {
+ protected Scope doStart(Scope aExternalScope) {
SpringComponent old = THIS.get();
+ Scope oldScope = SCOPE.get();
THIS.set(this);
+ Scope scope = new DefaultScope(getProvidedInterfaces(), aExternalScope);
+ SCOPE.set(scope);
try {
- _parentContext = new GenericApplicationContext();
+ GenericApplicationContext parentContext = new GenericApplicationContext();
- registerRequiredServices();
+ registerRequiredServices(parentContext);
- _parentContext.refresh();
+ parentContext.refresh();
- parseConfigFiles();
+ AbstractApplicationContext context = parseConfigFiles(parentContext);
- _context
+ context
.addBeanFactoryPostProcessor(new PropertySetter(_properties));
- _context.refresh();
+ context.refresh();
- exposeProvidedServices();
+ exposeProvidedServices(context, scope);
+
+ scope.put(CONTEXT_KEY, context);
+ return scope;
} catch (Exception e) {
throw new SystemAssemblyException(
"Failed to assemble spring system", e);
} finally {
THIS.set(old);
+ SCOPE.set(oldScope);
}
}
- private void exposeProvidedServices() {
+ private void exposeProvidedServices(AbstractApplicationContext aContext, Scope aScope) {
// Call addService for each provided service.
for (String name : _provided.keySet()) {
- Object svc = _context.getBean(name);
+ Object svc = aContext.getBean(name);
if (svc == null) {
throw new IllegalArgumentException(getQualifiedName() + ": service '"
+ name + "' is null");
}
- addInterface(_provided.get(name), svc);
+ addInterface(_provided.get(name), svc, aScope);
+ System.out.println("addService " + _provided.get(name) + " " + svc);
+ aScope.publishInterface(_provided.get(name), svc);
}
}
- private void parseConfigFiles() {
+ private AbstractApplicationContext parseConfigFiles(GenericApplicationContext aParentContext) {
// Parse spring config files
- _context = new ClassPathXmlApplicationContext((String[]) _configFiles,
- _parentContext);
+ return new ClassPathXmlApplicationContext((String[]) _configFiles,
+ aParentContext);
}
- private void registerRequiredServices() {
+ private void registerRequiredServices(GenericApplicationContext aParentContext) {
// Register required services in a parent context
for (RequiredInterface required: getRequiredInterfaces()) {
String beanName = _required.get(required);
BeanDefinition definition = new RootBeanDefinition(
RequiredServiceBean.class, cargs,
new MutablePropertyValues());
- _parentContext.registerBeanDefinition(beanName, definition);
+ aParentContext.registerBeanDefinition(beanName, definition);
}
}
@Override
- protected void doStop() {
- _context.close();
- for (ProvidedInterface provided: getProvidedInterfaces()) {
- removeInterface(provided);
- }
+ protected void doStop(Scope aRuntime) {
+ AbstractApplicationContext context = (AbstractApplicationContext)aRuntime.get(CONTEXT_KEY);
+ context.close();
}
}
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
- */
+ */
package org.wamblee.system.spring;
import java.io.IOException;
import org.wamblee.io.ClassPathResource;
import org.wamblee.system.core.DefaultProvidedInterface;
import org.wamblee.system.core.DefaultRequiredInterface;
+import org.wamblee.system.core.DefaultScope;
import org.wamblee.system.core.ProvidedInterface;
import org.wamblee.system.core.RequiredInterface;
+import org.wamblee.system.core.Scope;
import org.wamblee.system.core.SystemAssemblyException;
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 static final String PROPERTY_FILE = "test.org.wamblee.system.spring.properties";
@Override
protected void setUp() throws Exception {
new String[] { HELLO_SERVICE_SPRING_XML },
new HashMap<String, ProvidedInterface>(),
new HashMap<RequiredInterface, String>());
- system.start();
- ProvidedInterface[] services = system.getRunningInterfaces();
- assertEquals(0, services.length);
-
- system.stop();
+ Scope runtime = system.start();
+ assertEquals(0, runtime.getProvidedInterfaces().length);
+
+ system.stop(runtime);
}
public void testOneProvidedService() {
Map<String, ProvidedInterface> provided = new HashMap<String, ProvidedInterface>();
- provided.put("helloService", new DefaultProvidedInterface(
- "hello", HelloService.class));
+ provided.put("helloService", new DefaultProvidedInterface("hello",
+ HelloService.class));
- SpringComponent system = new SpringComponent("system",
+ SpringComponent system = new SpringComponent("system",
new String[] { HELLO_SERVICE_SPRING_XML }, provided,
new HashMap<RequiredInterface, String>());
- system.start();
- ProvidedInterface[] services = system.getRunningInterfaces();
+ Scope runtime = system.start();
+ ProvidedInterface[] services = runtime.getProvidedInterfaces();
assertEquals(1, services.length);
- assertTrue(services[0].getImplementation() instanceof HelloService);
- assertEquals("Hello world!", ((HelloService)services[0].getImplementation())
- .say());
- system.stop();
+ Object service = runtime.retrieveInterfaceImplementation(services[0], Object.class);
+ assertTrue(service instanceof HelloService);
+ assertEquals("Hello world!", ((HelloService) service).say());
+ system.stop(runtime);
}
-
+
public void testWithProperties() throws IOException {
Map<String, ProvidedInterface> provided = new HashMap<String, ProvidedInterface>();
- provided.put("helloService", new DefaultProvidedInterface(
- "hello", HelloService.class));
- SpringComponent system = new SpringComponent("system",
+ provided.put("helloService", new DefaultProvidedInterface("hello",
+ HelloService.class));
+ SpringComponent system = new SpringComponent("system",
new String[] { HELLO_SERVICE_SPRING_WITH_PROPERTIES_XML },
- provided,
- new HashMap<RequiredInterface, String>());
+ provided, new HashMap<RequiredInterface, String>());
Properties props = new Properties();
props.load(new ClassPathResource(PROPERTY_FILE).getInputStream());
system.addProperties(props);
-
- system.start();
- ProvidedInterface[] services = system.getRunningInterfaces();
- assertEquals("Property Value",
- ((HelloService)services[0].getImplementation()).say());
+
+ Scope scope = system.start();
+ ProvidedInterface[] services = scope.getProvidedInterfaces();
+ assertEquals("Property Value", scope.retrieveInterfaceImplementation(services[0], HelloService.class).say());
}
public void testWithMissingRequirement() {
new HashMap<RequiredInterface, String>());
system.start();
} catch (SystemAssemblyException e) {
- //e.printStackTrace();
+ // e.printStackTrace();
return;
}
fail();
SpringComponent system = new SpringComponent("system",
new String[] { HELLO_SERVICE_SPRING_WITH_REQS_XML },
new HashMap<String, ProvidedInterface>(), required);
-
- HelloService helloObject = new HelloService("ladida");
- ProvidedInterface helloService = new DefaultProvidedInterface("hello", HelloService.class);
- helloService.publish(helloObject);
+
+ HelloService helloObject = new HelloService("ladida");
+ ProvidedInterface helloService = new DefaultProvidedInterface("hello",
+ HelloService.class);
+ Scope scope = new DefaultScope(new ProvidedInterface[]{ helloService });
+ scope.publishInterface(helloService, helloObject);
system.getRequiredInterfaces()[0].setProvider(helloService);
-
- system.start();
- system.stop();
+
+ Scope runtime = system.start(scope);
+ system.stop(runtime);
}
-
+
public void testWithRequirementAndProvidedService() {
Map<RequiredInterface, String> required = new HashMap<RequiredInterface, String>();
required.put(new DefaultRequiredInterface("hello", HelloService.class),
"helloService");
- Map<String,ProvidedInterface> provided = new HashMap<String, ProvidedInterface>();
+ Map<String, ProvidedInterface> provided = new HashMap<String, ProvidedInterface>();
provided.put("blaService", new DefaultProvidedInterface("bla",
BlaService.class));
SpringComponent system = new SpringComponent("system",
- new String[] { HELLO_SERVICE_SPRING_WITH_REQS_XML },
- provided, required);
-
- HelloService helloObject = new HelloService("ladida");
- ProvidedInterface helloService =
- new DefaultProvidedInterface("hello", HelloService.class);
- helloService.publish(helloObject);
+ new String[] { HELLO_SERVICE_SPRING_WITH_REQS_XML }, provided,
+ required);
+
+ HelloService helloObject = new HelloService("ladida");
+ ProvidedInterface helloService = new DefaultProvidedInterface("hello",
+ HelloService.class);
+ Scope scope = new DefaultScope(new ProvidedInterface[] { helloService });
+ scope.publishInterface(helloService, helloObject);
system.getRequiredInterfaces()[0].setProvider(helloService);
- system.start();
- ProvidedInterface started = system.getProvidedInterfaces()[0];
-
- assertNotNull(started.getImplementation());
- assertTrue(started.getImplementation() instanceof BlaService);
- assertEquals("ladida",
- ((BlaService)started.getImplementation()).execute());
- system.stop();
+ Scope runtime = system.start(scope);
+ ProvidedInterface started = runtime.getProvidedInterfaces()[0];
+
+ Object impl = runtime.retrieveInterfaceImplementation(started, BlaService.class);
+ assertNotNull(impl);
+ assertTrue(impl instanceof BlaService);
+ assertEquals("ladida", ((BlaService)impl).execute());
+ system.stop(runtime);
}
}