From 6a914dcbd1c89027eafae6021af4199a636e4e48 Mon Sep 17 00:00:00 2001 From: erik Date: Fri, 4 Apr 2008 22:06:16 +0000 Subject: [PATCH] some major refactoring. ServiceREgistry eliminated as well as Service and DefaultService. There is now a many-to-one relation from required to provided service which leads to a more natural design. --- .../org/wamblee/system/AbstractComponent.java | 51 ++---- .../java/org/wamblee/system/Component.java | 9 +- .../java/org/wamblee/system/Container.java | 44 +++-- .../DefaultProvidedInterfaceDescriptor.java | 13 +- .../DefaultRequiredInterfaceDescriptor.java | 69 +++++++- .../org/wamblee/system/DefaultService.java | 48 ------ .../system/DefaultServiceRegistry.java | 45 ----- .../org/wamblee/system/ProvidedInterface.java | 12 ++ .../org/wamblee/system/RequiredInterface.java | 20 +++ .../main/java/org/wamblee/system/Service.java | 27 --- .../org/wamblee/system/ServiceRegistry.java | 12 -- .../org/wamblee/system/SystemAssembler.java | 41 ++--- .../java/org/wamblee/system/Application.java | 10 +- .../java/org/wamblee/system/Environment.java | 15 +- .../wamblee/system/SystemAssemblerTest.java | 154 +++++++++--------- .../system/spring/RequiredServiceBean.java | 16 +- .../system/spring/SpringComponent.java | 113 ++++++------- .../system/spring/SpringComponentTest.java | 62 +++---- 18 files changed, 368 insertions(+), 393 deletions(-) delete mode 100644 system/general/src/main/java/org/wamblee/system/DefaultService.java delete mode 100644 system/general/src/main/java/org/wamblee/system/DefaultServiceRegistry.java delete mode 100644 system/general/src/main/java/org/wamblee/system/Service.java delete mode 100644 system/general/src/main/java/org/wamblee/system/ServiceRegistry.java diff --git a/system/general/src/main/java/org/wamblee/system/AbstractComponent.java b/system/general/src/main/java/org/wamblee/system/AbstractComponent.java index a78b46f1..074e3ab0 100644 --- a/system/general/src/main/java/org/wamblee/system/AbstractComponent.java +++ b/system/general/src/main/java/org/wamblee/system/AbstractComponent.java @@ -2,14 +2,12 @@ package org.wamblee.system; import java.util.ArrayList; import java.util.Arrays; -import java.util.Collection; -import java.util.HashMap; +import java.util.HashSet; import java.util.List; -import java.util.Map; +import java.util.Set; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; -import org.wamblee.system.Component.Status; /** * Abstract subsystem class making it easy to implement new subsystems. @@ -19,17 +17,14 @@ public abstract class AbstractComponent implements Component { private static final Log LOG = LogFactory.getLog(AbstractComponent.class); private Status _status; - private String _name; - private ServiceRegistry _registry; + private String _name; private List _provided; private List _required; - private Map _running; + private Set _running; /** * Constructs the subsystem. - * - * @param aRegistry - * Registry of services. + * * @param aName * Name of the system. * @param aProvided @@ -37,16 +32,15 @@ public abstract class AbstractComponent implements Component { * @param aRequired * Required services. */ - protected AbstractComponent(String aName, ServiceRegistry aRegistry, ProvidedInterface[] aProvided, + protected AbstractComponent(String aName, ProvidedInterface[] aProvided, RequiredInterface[] aRequired) { _status = Status.NOT_STARTED; _name = aName; - _registry = aRegistry; _provided = new ArrayList(); _provided.addAll(Arrays.asList(aProvided)); _required = new ArrayList(); _required.addAll(Arrays.asList(aRequired)); - _running = new HashMap(); + _running = new HashSet(); } @Override @@ -58,10 +52,6 @@ public abstract class AbstractComponent implements Component { public final String getName() { return _name; } - - public ServiceRegistry getRegistry() { - return _registry; - } @Override public final ProvidedInterface[] getProvidedServices() { @@ -74,25 +64,17 @@ public abstract class AbstractComponent implements Component { } @Override - public final Service[] start(String aContext, - Service[] aRequiredServices) { - LOG.info("Initializing '" + aContext + "." + _name + "' with " - + Arrays.asList(aRequiredServices)); - doStart(aContext + "." + getName(), aRequiredServices); + public final void start(String aContext) { + LOG.info("Initializing '" + aContext + "." + _name + "'"); + doStart(aContext + "." + getName()); _status = Status.RUNNING; - return _running.values().toArray(new Service[0]); } /** * Must be implemented for initializing the subsystem. The implementation * must call {@link #addService(Service)} for each service that is started. - * - * @param aRequiredServices - * Services that are already running from other subsystems that - * may be used. */ - protected abstract void doStart(String aContext, - Service[] aRequiredServices); + protected abstract void doStart(String aContext); /** * Implementations must call this method to indicate that a new service has @@ -104,21 +86,18 @@ public abstract class AbstractComponent implements Component { protected final void addService(String aContext, ProvidedInterface aDescriptor, Object aService) { LOG.info(aContext + ": service '" + aService + "' started."); - Service svc = getRegistry().register(aDescriptor, aService); - _running.put(svc.getDescriptor(), svc); + _running.add(aDescriptor); + aDescriptor.publish(aService); } @Override - public Service[] getRunningServices() { - return _running.values().toArray(new Service[0]); + public ProvidedInterface[] getRunningServices() { + return _running.toArray(new ProvidedInterface[0]); } @Override public void stop() { doStop(); - for (Service svc: _running.values()) { - getRegistry().remove(svc); - } _status = Status.STOPPED; } diff --git a/system/general/src/main/java/org/wamblee/system/Component.java b/system/general/src/main/java/org/wamblee/system/Component.java index e72dd7f0..4083c5bd 100644 --- a/system/general/src/main/java/org/wamblee/system/Component.java +++ b/system/general/src/main/java/org/wamblee/system/Component.java @@ -40,12 +40,9 @@ public interface Component { /** * Initialises the subsytem by starting all the services that * it described as provided. - * @param aContext Unique name for the subsystem. - * @param aRequiredServices Running services from other - * subsystems that are required by this subsystem. - * @return Services that are running in the subsystem. + * @param aContext Unique name for the subsystem. */ - Service[] start(String aContext, Service[] aRequiredServices); + void start(String aContext); /** * Stops a subsystem. @@ -59,5 +56,5 @@ public interface Component { * {@link #initialize(String, Service[])} has been called. * @return */ - Service[] getRunningServices(); + ProvidedInterface[] getRunningServices(); } diff --git a/system/general/src/main/java/org/wamblee/system/Container.java b/system/general/src/main/java/org/wamblee/system/Container.java index a23a7373..d9dc29be 100644 --- a/system/general/src/main/java/org/wamblee/system/Container.java +++ b/system/general/src/main/java/org/wamblee/system/Container.java @@ -28,11 +28,11 @@ public class Container extends AbstractComponent { * @param aProvided Provided services of the system. * @param aRequired Required services by the system. */ - public Container(String aName, ServiceRegistry aRegistry, Component[] aSystems, + public Container(String aName, Component[] aSystems, ProvidedInterface[] aProvided, RequiredInterface[] aRequired) { - super(aName, aRegistry, aProvided, aRequired); + super(aName, aProvided, aRequired); _systems = aSystems; - validate(); + validate(aRequired); } /** @@ -41,7 +41,7 @@ public class Container extends AbstractComponent { * no services in the provided list that cannot be provided. * Also logs a warning in case of superfluous requirements. */ - private void validate() { + private void validate(RequiredInterface[] aRequired) { List provided = new ArrayList(); for (Component system : _systems) { provided.addAll(Arrays.asList(system.getProvidedServices())); @@ -69,12 +69,17 @@ public class Container extends AbstractComponent { List reallyRequired = new ArrayList( required); + // Compute all required interfaces that are not provided for (ProvidedInterface service : provided) { - reallyRequired.remove(service); - } - for (RequiredInterface service: getRequiredServices()) { - reallyRequired.remove(service); + List fulfilled = + Arrays.asList(SystemAssembler.filterRequiredServices(service, + reallyRequired)); + reallyRequired.removeAll(fulfilled); } + // Now the remaining interfaces should be covered by the required + // list. + reallyRequired.removeAll(Arrays.asList(aRequired)); + String missingRequired = ""; for (RequiredInterface service: reallyRequired) { missingRequired += service + "\n"; @@ -85,14 +90,23 @@ public class Container extends AbstractComponent { } @Override - protected void doStart(String aContext, Service[] aRequiredServices) { - List descriptors = new ArrayList(); - for (Service service : aRequiredServices) { - descriptors.add(service.getDescriptor()); + protected void doStart(String aContext) { + List provided = new ArrayList(); + + // all interfaces from the required list of this container are + // provided to the components inside it. + RequiredInterface[] required = getRequiredServices(); + for (RequiredInterface intf: required) { + ProvidedInterface provider = intf.getProvider(); + if ( provider == null ) { + throw new SystemAssemblyException(aContext + ": required interface '" + intf +"' is not provided"); + } + provided.add(intf.getProvider()); } - SystemAssembler assembler = new SystemAssembler(aContext + "." + getName(), _systems, - descriptors.toArray(new ProvidedInterface[0])); - assembler.start(getRegistry(), aRequiredServices); + + SystemAssembler assembler = new SystemAssembler( _systems, + provided.toArray(new ProvidedInterface[0])); + assembler.start(); } @Override diff --git a/system/general/src/main/java/org/wamblee/system/DefaultProvidedInterfaceDescriptor.java b/system/general/src/main/java/org/wamblee/system/DefaultProvidedInterfaceDescriptor.java index 2b51c60a..3b38be7a 100644 --- a/system/general/src/main/java/org/wamblee/system/DefaultProvidedInterfaceDescriptor.java +++ b/system/general/src/main/java/org/wamblee/system/DefaultProvidedInterfaceDescriptor.java @@ -10,7 +10,8 @@ import java.util.Arrays; public class DefaultProvidedInterfaceDescriptor implements ProvidedInterface { private String _name; - private Class[] _interfaces; + private Class[] _interfaces; + private Object _implementation; /** * Constructs the descriptor. @@ -36,6 +37,16 @@ public class DefaultProvidedInterfaceDescriptor implements ProvidedInterface { return _interfaces; } + @Override + public void publish(Object aImplementation) { + _implementation = aImplementation; + } + + @Override + public Object getImplementation() { + return _implementation; + } + @Override public boolean equals(Object obj) { if ( !(obj instanceof DefaultProvidedInterfaceDescriptor)) { diff --git a/system/general/src/main/java/org/wamblee/system/DefaultRequiredInterfaceDescriptor.java b/system/general/src/main/java/org/wamblee/system/DefaultRequiredInterfaceDescriptor.java index 9e434c08..580b390b 100644 --- a/system/general/src/main/java/org/wamblee/system/DefaultRequiredInterfaceDescriptor.java +++ b/system/general/src/main/java/org/wamblee/system/DefaultRequiredInterfaceDescriptor.java @@ -1,20 +1,31 @@ package org.wamblee.system; -public class DefaultRequiredInterfaceDescriptor extends DefaultProvidedInterfaceDescriptor - implements RequiredInterface { +import java.util.Arrays; +public class DefaultRequiredInterfaceDescriptor implements RequiredInterface { + + private String _name; + private Class[] _required; + private ProvidedInterface _provider; + public DefaultRequiredInterfaceDescriptor(String aName, Class aInterface) { - super(aName, aInterface); + this(aName, new Class[] { aInterface }); } public DefaultRequiredInterfaceDescriptor(String aName, Class[] aInterfaces) { - super(aName, aInterfaces); + _name = aName; + _required = aInterfaces; } + @Override + public String getName() { + return _name; + } + @Override public boolean implementedBy(ProvidedInterface aDescriptor) { Class[] provided = aDescriptor.getInterfaceTypes(); - for (Class required : getInterfaceTypes()) { + for (Class required : _required) { if ( !serviceProvided(required, provided)) { return false; } @@ -40,5 +51,53 @@ public class DefaultRequiredInterfaceDescriptor extends DefaultProvidedInterface } return false; } + + @Override + public ProvidedInterface getProvider() { + return _provider; + } + + @Override + public void setProvider(ProvidedInterface aProvider) { + _provider = aProvider; + } + + @Override + public T getImplementation(Class aClass) { + return (T)_provider.getImplementation(); + } + + @Override + public boolean equals(Object obj) { + if ( !(obj instanceof DefaultRequiredInterfaceDescriptor)) { + return false; + } + DefaultRequiredInterfaceDescriptor descr = (DefaultRequiredInterfaceDescriptor)obj; + if ( _required.length != descr._required.length ) { + return false; + } + String[] interfaces1 = new String[_required.length]; + String[] interfaces2 = new String[_required.length]; + for (int i = 0; i < _required.length; i++) { + interfaces1[i] = _required[i].getName(); + interfaces2[i] = descr._required[i].getName(); + } + Arrays.sort(interfaces1); + Arrays.sort(interfaces2); + return Arrays.equals(interfaces1, interfaces2); + } + @Override + public int hashCode() { + return _required.hashCode(); + } + + @Override + public String toString() { + StringBuffer buf = new StringBuffer(); + for (Class intf: _required) { + buf.append("." + intf.getName()); + } + return buf.toString(); + } } diff --git a/system/general/src/main/java/org/wamblee/system/DefaultService.java b/system/general/src/main/java/org/wamblee/system/DefaultService.java deleted file mode 100644 index a8a2692e..00000000 --- a/system/general/src/main/java/org/wamblee/system/DefaultService.java +++ /dev/null @@ -1,48 +0,0 @@ -package org.wamblee.system; - -/** - * Default service implementation. - * - * @author Erik Brakkee - */ -public class DefaultService implements Service { - - private String _id; - private ProvidedInterface _descriptor; - private Object _service; - - /** - * Constructs the service. - * - * @param aDescriptor - * Descriptor to use. - * @param aService - * Service. - */ - public DefaultService(String aId, ProvidedInterface aDescriptor, - Object aService) { - _id = aId; - _descriptor = aDescriptor; - _service = aService; - } - - @Override - public String getId() { - return _id; - } - - @Override - public ProvidedInterface getDescriptor() { - return _descriptor; - } - - @Override - public T reference(Class aClass) { - return (T) _service; - } - - @Override - public String toString() { - return "(" + _descriptor + ", " + _service + ")"; - } -} diff --git a/system/general/src/main/java/org/wamblee/system/DefaultServiceRegistry.java b/system/general/src/main/java/org/wamblee/system/DefaultServiceRegistry.java deleted file mode 100644 index 27d576e5..00000000 --- a/system/general/src/main/java/org/wamblee/system/DefaultServiceRegistry.java +++ /dev/null @@ -1,45 +0,0 @@ -package org.wamblee.system; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.Map; - -public class DefaultServiceRegistry implements ServiceRegistry { - - private int _count; - private Map _services; - - public DefaultServiceRegistry() { - _count = 0; - _services = new HashMap(); - } - - @Override - public synchronized Service register(ProvidedInterface aDescriptor, - Object aService) { - _count++; - String id = "" + _count; - Service svc = new DefaultService(id, aDescriptor, aService); - _services.put(id, svc); - return svc; - } - - @Override - public void remove(Service aService) { - Service svc = _services.remove(aService.getId()); - if ( svc == null ) { - throw new IllegalArgumentException("Service '" + aService.getId() + "' does not exist"); - } - } - - @Override - public synchronized Service find(String aId) { - return _services.get(aId); - } - - @Override - public Service[] listAllServices() { - return new ArrayList(_services.values()) - .toArray(new Service[0]); - } -} diff --git a/system/general/src/main/java/org/wamblee/system/ProvidedInterface.java b/system/general/src/main/java/org/wamblee/system/ProvidedInterface.java index 11b56646..20976d8a 100644 --- a/system/general/src/main/java/org/wamblee/system/ProvidedInterface.java +++ b/system/general/src/main/java/org/wamblee/system/ProvidedInterface.java @@ -20,4 +20,16 @@ public interface ProvidedInterface { * @return Service type. */ Class[] getInterfaceTypes(); + + /** + * Publish an implementation of the interface. + * @param aImplementation + */ + void publish(Object aImplementation); + + /** + * Gets the implementation. + * @return Implementation or null if not started. + */ + Object getImplementation(); } diff --git a/system/general/src/main/java/org/wamblee/system/RequiredInterface.java b/system/general/src/main/java/org/wamblee/system/RequiredInterface.java index fd607403..f012df51 100644 --- a/system/general/src/main/java/org/wamblee/system/RequiredInterface.java +++ b/system/general/src/main/java/org/wamblee/system/RequiredInterface.java @@ -13,4 +13,24 @@ public interface RequiredInterface { * @return */ boolean implementedBy(ProvidedInterface aInterface); + + /** + * Sets the provider of this interface. + * @param aProvider Provider. + */ + void setProvider(ProvidedInterface aProvider); + + /** + * Getst the provider interface. + * @return Provider or null if not set. + */ + ProvidedInterface getProvider(); + + /** + * Gets the implementation of the required interface. + * @param + * @param aClass Interface type. + * @return Interface implementation or null if not known yet. + */ + T getImplementation(Class aClass); } diff --git a/system/general/src/main/java/org/wamblee/system/Service.java b/system/general/src/main/java/org/wamblee/system/Service.java deleted file mode 100644 index 8624c0cc..00000000 --- a/system/general/src/main/java/org/wamblee/system/Service.java +++ /dev/null @@ -1,27 +0,0 @@ -package org.wamblee.system; - -/** - * Represents a running service. - * - * @author Erik Brakkee - */ -public interface Service { - - /** - * Gets the ide of the service in the registry. - * @return Service id. - */ - String getId(); - - /** - * Gets the descriptor of the service. - * @return Descriptor. - */ - ProvidedInterface getDescriptor(); - - /** - * Returns a reference to the running service. - * @return Service. - */ - T reference(Class aClass); -} diff --git a/system/general/src/main/java/org/wamblee/system/ServiceRegistry.java b/system/general/src/main/java/org/wamblee/system/ServiceRegistry.java deleted file mode 100644 index 7fe35063..00000000 --- a/system/general/src/main/java/org/wamblee/system/ServiceRegistry.java +++ /dev/null @@ -1,12 +0,0 @@ -package org.wamblee.system; - -public interface ServiceRegistry { - - Service register(ProvidedInterface aDescriptor, Object aService); - - void remove(Service aService); - - Service find(String aId); - - Service[] listAllServices(); -} diff --git a/system/general/src/main/java/org/wamblee/system/SystemAssembler.java b/system/general/src/main/java/org/wamblee/system/SystemAssembler.java index 5cdb3890..50e0e3ab 100644 --- a/system/general/src/main/java/org/wamblee/system/SystemAssembler.java +++ b/system/general/src/main/java/org/wamblee/system/SystemAssembler.java @@ -4,8 +4,10 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Set; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -23,6 +25,7 @@ public class SystemAssembler { private static final String ROOT_CONTEXT_NAME = "root"; private String _context; private Component[] _systems; + private ProvidedInterface[] _required; public static RequiredInterface[] filterRequiredServices( ProvidedInterface aProvided, @@ -77,18 +80,19 @@ public class SystemAssembler { ProvidedInterface[] aAvailableServices) { _context = aContext; _systems = aSystems; - validate(aAvailableServices); + _required = aAvailableServices; + validate(); } /** * Determines if the systems are ordered appropriately so that all * dependencies are met. */ - private void validate(ProvidedInterface[] aDescriptors) + private void validate() throws SystemAssemblyException { List allProvided = new ArrayList(); - for (ProvidedInterface descriptor : aDescriptors) { + for (ProvidedInterface descriptor : _required) { allProvided.add(descriptor); } for (Component system : _systems) { @@ -128,39 +132,36 @@ public class SystemAssembler { /** * Starts the subsystems. * - * @param aRegistry - * Service registry to which created services must be registered. * @param aRequiredServices * Services that are available from other systems that have been * started before. */ - public void start(ServiceRegistry aRegistry, Service[] aRequiredServices) { + public void start() { LOG.info("Starting '" + _context + "'"); - Map allProvided = new HashMap(); - - for (Service service : aRequiredServices) { - allProvided.put(service.getDescriptor(), service); - } + Set allProvided = new HashSet(); + allProvided.addAll(Arrays.asList(_required)); + for (Component system : _systems) { // Compose a list of the required services required for the subsystem. RequiredInterface[] descriptors = system .getRequiredServices(); - List services = new ArrayList(); - for (RequiredInterface descriptor : descriptors) { + List services = new ArrayList(); + for (RequiredInterface required : descriptors) { ProvidedInterface[] provided = filterProvidedServices( - descriptor, allProvided.keySet()); - services.add(allProvided.get(provided[0])); + required, allProvided); + assert provided.length == 1; + services.add(provided[0]); + required.setProvider(provided[0]); } // Start the service. - Service[] provided = system.start(_context, services - .toArray(new Service[0])); + system.start(_context); - // Add started services to the map of started services. - for (Service service : provided) { - allProvided.put(service.getDescriptor(), service); + // Add started services to the set of started services. + for (ProvidedInterface service : system.getProvidedServices()) { + allProvided.add(service); } } diff --git a/system/general/src/test/java/org/wamblee/system/Application.java b/system/general/src/test/java/org/wamblee/system/Application.java index 3825c989..b84ca5e2 100644 --- a/system/general/src/test/java/org/wamblee/system/Application.java +++ b/system/general/src/test/java/org/wamblee/system/Application.java @@ -3,18 +3,20 @@ package org.wamblee.system; import javax.sql.DataSource; public class Application extends AbstractComponent { - private static final RequiredInterface[] REQUIRED = + private static RequiredInterface[] required() { + return new RequiredInterface[] { new DefaultRequiredInterfaceDescriptor("datasource", DataSource.class), new DefaultRequiredInterfaceDescriptor("integer", Integer.class) }; + } - public Application(ServiceRegistry aRegistry) { - super("application", aRegistry, new ProvidedInterface[0], REQUIRED); + public Application() { + super("application", new ProvidedInterface[0], required()); } @Override - protected void doStart(String aContext, Service[] aRequiredServices) { + protected void doStart(String aContext) { // Empty, no services provided externally. } diff --git a/system/general/src/test/java/org/wamblee/system/Environment.java b/system/general/src/test/java/org/wamblee/system/Environment.java index e2bd2b80..27537e0a 100644 --- a/system/general/src/test/java/org/wamblee/system/Environment.java +++ b/system/general/src/test/java/org/wamblee/system/Environment.java @@ -5,20 +5,21 @@ import javax.sql.DataSource; public class Environment extends AbstractComponent { - private static final ProvidedInterface[] PROVIDED = - new ProvidedInterface[] { + private static final ProvidedInterface[] provided() { + return new ProvidedInterface[] { new DefaultProvidedInterfaceDescriptor("datasource", DataSource.class), new DefaultProvidedInterfaceDescriptor("integer", Integer.class) }; + } - public Environment(ServiceRegistry aRegistry) { - super("environment", aRegistry, PROVIDED, new RequiredInterface[0]); + public Environment() { + super("environment", provided(), new RequiredInterface[0]); } @Override - protected void doStart(String aContext, Service[] aRequiredServices) { - addService(aContext, PROVIDED[0], new Integer(1)); - addService(aContext, PROVIDED[1], new Integer(2)); + protected void doStart(String aContext) { + addService(aContext, getProvidedServices()[0], new Integer(1)); + addService(aContext, getProvidedServices()[1], new Integer(2)); } @Override diff --git a/system/general/src/test/java/org/wamblee/system/SystemAssemblerTest.java b/system/general/src/test/java/org/wamblee/system/SystemAssemblerTest.java index c372bf04..9412caee 100644 --- a/system/general/src/test/java/org/wamblee/system/SystemAssemblerTest.java +++ b/system/general/src/test/java/org/wamblee/system/SystemAssemblerTest.java @@ -11,12 +11,9 @@ import junit.framework.TestCase; public class SystemAssemblerTest extends TestCase { - private ServiceRegistry _registry; - @Override protected void setUp() throws Exception { super.setUp(); - _registry = new DefaultServiceRegistry(); } private static class MyMultiple implements Serializable, Runnable { @@ -27,10 +24,10 @@ public class SystemAssemblerTest extends TestCase { } public void testFilterProvided() { - RequiredInterface req1 = new DefaultRequiredInterfaceDescriptor( - "name", Runnable.class); - RequiredInterface req2 = new DefaultRequiredInterfaceDescriptor( - "name", Serializable.class); + RequiredInterface req1 = new DefaultRequiredInterfaceDescriptor("name", + Runnable.class); + RequiredInterface req2 = new DefaultRequiredInterfaceDescriptor("name", + Serializable.class); ProvidedInterface prov1 = new DefaultProvidedInterfaceDescriptor( "name", Runnable.class); ProvidedInterface prov2 = new DefaultProvidedInterfaceDescriptor( @@ -42,54 +39,46 @@ public class SystemAssemblerTest extends TestCase { SystemAssembler.filterRequiredServices(prov1, Arrays .asList(new RequiredInterface[] { req1 }))); AssertionUtils.assertEquals(new RequiredInterface[] { req1 }, - SystemAssembler.filterRequiredServices(prov1, - Arrays.asList(new RequiredInterface[] { req1, - req2 }))); - AssertionUtils.assertEquals(new RequiredInterface[] { req1, - req2 }, SystemAssembler.filterRequiredServices(prov3, Arrays - .asList(new RequiredInterface[] { req1, req2 }))); - - AssertionUtils.assertEquals( - new ProvidedInterface[] { prov1 }, + SystemAssembler.filterRequiredServices(prov1, Arrays + .asList(new RequiredInterface[] { req1, req2 }))); + AssertionUtils.assertEquals(new RequiredInterface[] { req1, req2 }, + SystemAssembler.filterRequiredServices(prov3, Arrays + .asList(new RequiredInterface[] { req1, req2 }))); + + AssertionUtils.assertEquals(new ProvidedInterface[] { prov1 }, SystemAssembler.filterProvidedServices(req1, Arrays .asList(new ProvidedInterface[] { prov1 }))); - AssertionUtils.assertEquals( - new ProvidedInterface[] { prov1 }, SystemAssembler - .filterProvidedServices(req1, Arrays - .asList(new ProvidedInterface[] { - prov1, prov2 }))); - AssertionUtils.assertEquals(new ProvidedInterface[] { prov1, - prov3 }, SystemAssembler.filterProvidedServices(req1, Arrays - .asList(new ProvidedInterface[] { prov1, prov3 }))); + AssertionUtils.assertEquals(new ProvidedInterface[] { prov1 }, + SystemAssembler.filterProvidedServices(req1, Arrays + .asList(new ProvidedInterface[] { prov1, prov2 }))); + AssertionUtils.assertEquals(new ProvidedInterface[] { prov1, prov3 }, + SystemAssembler.filterProvidedServices(req1, Arrays + .asList(new ProvidedInterface[] { prov1, prov3 }))); } public void testEnvironmentApplication() { - Component environment = new Environment(_registry); - Component application = new Application(_registry); + Component environment = new Environment(); + Component application = new Application(); SystemAssembler assembler = new SystemAssembler(new Component[] { environment, application }, new ProvidedInterface[0]); - assembler.start(_registry, new Service[0]); - Service[] envServices = environment.getRunningServices(); + assembler.start(); + ProvidedInterface[] envServices = environment.getRunningServices(); assertEquals(2, envServices.length); - Service[] appServices = environment.getRunningServices(); + ProvidedInterface[] appServices = environment.getRunningServices(); assertEquals(2, appServices.length); - assertEquals(2, _registry.listAllServices().length); + // TODO test stopping!!!!!! environment.stop(); - assertEquals(0, _registry.listAllServices().length); - application.stop(); - assertEquals(0, _registry.listAllServices().length); } public void testApplicationEnvironment() { try { - Component environment = new Environment(_registry); - Component application = new Application(_registry); + Component environment = new Environment(); + Component application = new Application(); SystemAssembler assembler = new SystemAssembler(new Component[] { - application, environment }, - new ProvidedInterface[0]); - assembler.start(_registry, new Service[0]); + application, environment }, new ProvidedInterface[0]); + assembler.start(); } catch (SystemAssemblyException e) { // e.printStackTrace(); return; @@ -98,15 +87,15 @@ public class SystemAssemblerTest extends TestCase { } public void testComposite() { - Component environment = new Environment(_registry); - Component application = new Application(_registry); + Component environment = new Environment(); + Component application = new Application(); assertEquals(Status.NOT_STARTED, environment.getStatus()); assertEquals(Status.NOT_STARTED, application.getStatus()); - Container system = new Container("all", _registry, new Component[] { - environment, application }, new ProvidedInterface[0], + Container system = new Container("all", new Component[] { environment, + application }, new ProvidedInterface[0], new RequiredInterface[0]); assertEquals(Status.NOT_STARTED, system.getStatus()); - system.start("root", new Service[0]); + system.start("root"); RequiredInterface[] required = system.getRequiredServices(); assertEquals(0, required.length); ProvidedInterface[] provided = system.getProvidedServices(); @@ -123,11 +112,10 @@ public class SystemAssemblerTest extends TestCase { public void testCompositeWithWrongProvidedInfo() { try { - Component environment = new Environment(_registry); - Component application = new Application(_registry); + Component environment = new Environment(); + Component application = new Application(); Container system = new Container( "all", - _registry, new Component[] { environment, application }, new ProvidedInterface[] { new DefaultProvidedInterfaceDescriptor( "string", String.class) }, @@ -138,17 +126,35 @@ public class SystemAssemblerTest extends TestCase { fail(); } + public void testCompositeRequiredInterfaceNotProvided() { + try { + Component environment = new Environment(); + Component application = new Application(); + Container system = new Container( + "all", + new Component[] { environment, application }, + new ProvidedInterface[0], + new RequiredInterface[] { new DefaultRequiredInterfaceDescriptor( + "string", String.class) }); + system.start("root"); + } catch (SystemAssemblyException e) { + return; + } + fail(); + } + public void testCompositeWithSuperfluousRequiredInfo() { - Component environment = new Environment(_registry); - Component application = new Application(_registry); + Component environment = new Environment(); + Component application = new Application(); Container system = new Container( "all", - _registry, new Component[] { environment, application }, new ProvidedInterface[0], new RequiredInterface[] { new DefaultRequiredInterfaceDescriptor( "string", String.class) }); - system.start("root", new Service[0]); + system.getRequiredServices()[0].setProvider( + new DefaultProvidedInterfaceDescriptor("hallo", String.class)); + system.start("root"); RequiredInterface[] required = system.getRequiredServices(); assertEquals(1, required.length); ProvidedInterface[] provided = system.getProvidedServices(); @@ -157,13 +163,12 @@ public class SystemAssemblerTest extends TestCase { public void testCompositeWithExternalDependencesNotProvided() { try { - Component environment = new Environment(_registry); - Component application = new Application(_registry); - Container system = new Container("all", _registry, - new Component[] { application }, - new ProvidedInterface[0], application - .getRequiredServices()); - system.start("root", new Service[0]); + Component environment = new Environment(); + Component application = new Application(); + Container system = new Container("all", + new Component[] { application }, new ProvidedInterface[0], + application.getRequiredServices()); + system.start("root"); } catch (SystemAssemblyException e) { return; } @@ -173,14 +178,16 @@ public class SystemAssemblerTest extends TestCase { public void testCompositeWithExternalDependencesProvided() { - Component environment = new Environment(_registry); - Component application = new Application(_registry); - Container system = new Container("all", _registry, - new Component[] { application }, - new ProvidedInterface[0], application - .getRequiredServices()); - Service[] envServices = environment.start("env", new Service[0]); - system.start("root", envServices); + Component environment = new Environment(); + Component application = new Application(); + Container system = new Container("all", + new Component[] { application }, new ProvidedInterface[0], + application.getRequiredServices()); + environment.start("env"); + system.getRequiredServices()[0].setProvider(environment.getProvidedServices()[0]); + system.getRequiredServices()[1].setProvider(environment.getProvidedServices()[1]); + + system.start("root"); RequiredInterface[] required = system.getRequiredServices(); assertEquals(2, required.length); ProvidedInterface[] provided = system.getProvidedServices(); @@ -190,13 +197,13 @@ public class SystemAssemblerTest extends TestCase { public void testAmbiguousInterfaces() { try { - Component environment1 = new Environment(_registry); - Component environment2 = new Environment(_registry); - Component application = new Application(_registry); + Component environment1 = new Environment(); + Component environment2 = new Environment(); + Component application = new Application(); SystemAssembler assembler = new SystemAssembler(new Component[] { environment1, environment2, application }, new ProvidedInterface[0]); - assembler.start(_registry, new Service[0]); + assembler.start(); } catch (SystemAssemblyException e) { return; @@ -206,12 +213,11 @@ public class SystemAssemblerTest extends TestCase { public void testIncompleteRequirements() { try { - Component application = new Application(_registry); - Container system = new Container("all", _registry, - new Component[] { application }, - new ProvidedInterface[0], + Component application = new Application(); + Container system = new Container("all", + new Component[] { application }, new ProvidedInterface[0], new RequiredInterface[0]); - system.start("root", new Service[0]); + system.start("root"); } catch (SystemAssemblyException e) { return; } diff --git a/system/spring/src/main/java/org/wamblee/system/spring/RequiredServiceBean.java b/system/spring/src/main/java/org/wamblee/system/spring/RequiredServiceBean.java index eaf55336..50e7e967 100644 --- a/system/spring/src/main/java/org/wamblee/system/spring/RequiredServiceBean.java +++ b/system/spring/src/main/java/org/wamblee/system/spring/RequiredServiceBean.java @@ -1,6 +1,9 @@ package org.wamblee.system.spring; import org.springframework.beans.factory.FactoryBean; +import org.wamblee.system.ProvidedInterface; +import org.wamblee.system.RequiredInterface; +import org.wamblee.system.SystemAssemblyException; /** * Bean which adds a service required by the spring component to @@ -10,19 +13,26 @@ import org.springframework.beans.factory.FactoryBean; */ class RequiredServiceBean implements FactoryBean { - private String _id; + private RequiredInterface _required; /** * Constructs the bean. * @param aId Id of the bean in the service registry. */ public RequiredServiceBean(String aId) { - _id = aId; + RequiredInterface[] required = SpringComponent.THIS.get().getRequiredServices(); + for ( RequiredInterface intf: required) { + if ( intf.getName().equals(aId)) { + _required = intf; + return; + } + } + throw new SystemAssemblyException("Cannot resolve provided component '" + aId + "'"); } @Override public Object getObject() throws Exception { - return SpringComponent.REGISTRY.get().find(_id).reference(Object.class); + return _required.getImplementation(Object.class); } @Override diff --git a/system/spring/src/main/java/org/wamblee/system/spring/SpringComponent.java b/system/spring/src/main/java/org/wamblee/system/spring/SpringComponent.java index b9a2648c..0b0921e6 100644 --- a/system/spring/src/main/java/org/wamblee/system/spring/SpringComponent.java +++ b/system/spring/src/main/java/org/wamblee/system/spring/SpringComponent.java @@ -14,25 +14,20 @@ import org.wamblee.system.AbstractComponent; import org.wamblee.system.ProvidedInterface; import org.wamblee.system.RequiredInterface; import org.wamblee.system.Service; -import org.wamblee.system.ServiceRegistry; import org.wamblee.system.SystemAssembler; import org.wamblee.system.SystemAssemblyException; /** - * Represents a system configured based on spring. - * The spring config files that are configured should not contain any PropertyPlaceholderConfigurer - * objects. - * + * 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 SpringComponent extends AbstractComponent { - /** - * Singleton access to the service registry. Required while starting up. - */ - static ThreadLocal REGISTRY = new ThreadLocal(); + static final ThreadLocal THIS = new ThreadLocal(); - private Properties _properties; + private Properties _properties; private String[] _configFiles; private Map _provided; private Map _required; @@ -62,57 +57,59 @@ public class SpringComponent extends AbstractComponent { * names that the spring config files use for each required * service. */ - public SpringComponent(String aName, ServiceRegistry aRegistry, String[] aConfigFiles, + public SpringComponent(String aName, String[] aConfigFiles, Map aProvided, Map aRequired) { - super(aName, aRegistry, aProvided.values().toArray(new ProvidedInterface[0]), + super(aName, aProvided.values().toArray(new ProvidedInterface[0]), aRequired.keySet().toArray(new RequiredInterface[0])); - _properties = new Properties(); + _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. + * 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) { + 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)); + + 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 oldRegistry = REGISTRY.get(); - try { - REGISTRY.set(getRegistry()); - try { - _parentContext = new GenericApplicationContext(); - - registerRequiredServices(aRequiredServices); - - _parentContext.refresh(); - - parseConfigFiles(); - - _context.addBeanFactoryPostProcessor(new PropertySetter(_properties)); - _context.refresh(); - - exposeProvidedServices(aContext); - } catch (Exception e) { - throw new SystemAssemblyException( - "Failed to assemble spring system", e); - } + protected void doStart(String aContext) { + + SpringComponent old = THIS.get(); + THIS.set(this); + try { + _parentContext = new GenericApplicationContext(); + + registerRequiredServices(); + + _parentContext.refresh(); + + parseConfigFiles(); + + _context + .addBeanFactoryPostProcessor(new PropertySetter(_properties)); + _context.refresh(); + + exposeProvidedServices(aContext); + } catch (Exception e) { + throw new SystemAssemblyException( + "Failed to assemble spring system", e); } finally { - REGISTRY.set(oldRegistry); + THIS.set(old); } } @@ -136,27 +133,21 @@ public class SpringComponent extends AbstractComponent { _parentContext); } - private void registerRequiredServices(Service[] aRequiredServices) { + private void registerRequiredServices() { // Register required services in a parent context - - for (Service svc: aRequiredServices) { - String id = svc.getId(); - ProvidedInterface descriptor = svc.getDescriptor(); - RequiredInterface[] requiredServices = SystemAssembler.filterRequiredServices(descriptor, - _required.keySet()); - for (RequiredInterface required: requiredServices) { - String beanName = _required.get(required); - ConstructorArgumentValues cargs = new ConstructorArgumentValues(); - cargs.addGenericArgumentValue(id); - BeanDefinition definition = new RootBeanDefinition(RequiredServiceBean.class, cargs, - new MutablePropertyValues()); - _parentContext.registerBeanDefinition(beanName, definition); - } + for (RequiredInterface required: getRequiredServices()) { + String beanName = _required.get(required); + ConstructorArgumentValues cargs = new ConstructorArgumentValues(); + cargs.addGenericArgumentValue(required.getName()); + BeanDefinition definition = new RootBeanDefinition( + RequiredServiceBean.class, cargs, + new MutablePropertyValues()); + _parentContext.registerBeanDefinition(beanName, definition); } } @Override protected void doStop() { - _context.close(); + _context.close(); } } diff --git a/system/spring/src/test/java/org/wamblee/system/spring/SpringComponentTest.java b/system/spring/src/test/java/org/wamblee/system/spring/SpringComponentTest.java index b0f7f8ab..0b4ffb08 100644 --- a/system/spring/src/test/java/org/wamblee/system/spring/SpringComponentTest.java +++ b/system/spring/src/test/java/org/wamblee/system/spring/SpringComponentTest.java @@ -10,11 +10,10 @@ import junit.framework.TestCase; import org.wamblee.io.ClassPathResource; import org.wamblee.system.DefaultProvidedInterfaceDescriptor; import org.wamblee.system.DefaultRequiredInterfaceDescriptor; -import org.wamblee.system.DefaultServiceRegistry; +import org.wamblee.system.DefaultService; import org.wamblee.system.ProvidedInterface; import org.wamblee.system.RequiredInterface; import org.wamblee.system.Service; -import org.wamblee.system.ServiceRegistry; import org.wamblee.system.SystemAssemblyException; public class SpringComponentTest extends TestCase { @@ -24,21 +23,18 @@ public class SpringComponentTest extends TestCase { 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; - @Override protected void setUp() throws Exception { super.setUp(); - _registry = new DefaultServiceRegistry(); } public void testBlackboxSystem() { - SpringComponent system = new SpringComponent("system", _registry, + SpringComponent system = new SpringComponent("system", new String[] { HELLO_SERVICE_SPRING_XML }, new HashMap(), new HashMap()); - system.start("Hello", new Service[0]); - Service[] services = system.getRunningServices(); + system.start("Hello"); + ProvidedInterface[] services = system.getRunningServices(); assertEquals(0, services.length); system.stop(); @@ -49,14 +45,14 @@ public class SpringComponentTest extends TestCase { provided.put("helloService", new DefaultProvidedInterfaceDescriptor( "hello", HelloService.class)); - SpringComponent system = new SpringComponent("system", _registry, + SpringComponent system = new SpringComponent("system", new String[] { HELLO_SERVICE_SPRING_XML }, provided, new HashMap()); - system.start("Hello", new Service[0]); - Service[] services = system.getRunningServices(); + system.start("Hello"); + ProvidedInterface[] services = system.getRunningServices(); assertEquals(1, services.length); - assertTrue(services[0].reference(HelloService.class) instanceof HelloService); - assertEquals("Hello world!", services[0].reference(HelloService.class) + assertTrue(services[0].getImplementation() instanceof HelloService); + assertEquals("Hello world!", ((HelloService)services[0].getImplementation()) .say()); system.stop(); } @@ -65,7 +61,7 @@ public class SpringComponentTest extends TestCase { Map provided = new HashMap(); provided.put("helloService", new DefaultProvidedInterfaceDescriptor( "hello", HelloService.class)); - SpringComponent system = new SpringComponent("system", _registry, + SpringComponent system = new SpringComponent("system", new String[] { HELLO_SERVICE_SPRING_WITH_PROPERTIES_XML }, provided, new HashMap()); @@ -73,18 +69,19 @@ public class SpringComponentTest extends TestCase { 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()); + system.start("Hello"); + ProvidedInterface[] services = system.getRunningServices(); + assertEquals("Property Value", + ((HelloService)services[0].getImplementation()).say()); } public void testWithMissingRequirement() { try { - SpringComponent system = new SpringComponent("system", _registry, + SpringComponent system = new SpringComponent("system", new String[] { HELLO_SERVICE_SPRING_WITH_REQS_XML }, new HashMap(), new HashMap()); - system.start("Bla", new Service[0]); + system.start("Bla"); } catch (SystemAssemblyException e) { //e.printStackTrace(); return; @@ -96,13 +93,16 @@ public class SpringComponentTest extends TestCase { Map required = new HashMap(); required.put(new DefaultRequiredInterfaceDescriptor("hello", HelloService.class), "helloService"); - SpringComponent system = new SpringComponent("system", _registry, + SpringComponent system = new SpringComponent("system", new String[] { HELLO_SERVICE_SPRING_WITH_REQS_XML }, new HashMap(), required); HelloService helloObject = new HelloService("ladida"); - Service helloService = _registry.register(new DefaultProvidedInterfaceDescriptor("hello", HelloService.class), helloObject); - system.start("Bla", new Service[] { helloService } ); + ProvidedInterface helloService = new DefaultProvidedInterfaceDescriptor("hello", HelloService.class); + helloService.publish(helloObject); + system.getRequiredServices()[0].setProvider(helloService); + + system.start("Bla"); system.stop(); } @@ -114,18 +114,22 @@ public class SpringComponentTest extends TestCase { provided.put("blaService", new DefaultProvidedInterfaceDescriptor("bla", BlaService.class)); - SpringComponent system = new SpringComponent("system", _registry, + SpringComponent system = new SpringComponent("system", new String[] { HELLO_SERVICE_SPRING_WITH_REQS_XML }, provided, required); HelloService helloObject = new HelloService("ladida"); - Service helloService = _registry.register(new DefaultProvidedInterfaceDescriptor("hello", HelloService.class), helloObject); - Service[] services = system.start("Bla", new Service[] { helloService } ); - assertEquals(1, services.length); + ProvidedInterface helloService = + new DefaultProvidedInterfaceDescriptor("hello", HelloService.class); + helloService.publish(helloObject); + system.getRequiredServices()[0].setProvider(helloService); + system.start("Bla"); + ProvidedInterface started = system.getProvidedServices()[0]; - assertTrue(services[0].reference(BlaService.class) instanceof BlaService); - assertEquals("ladida", services[0].reference(BlaService.class) - .execute()); + assertNotNull(started.getImplementation()); + assertTrue(started.getImplementation() instanceof BlaService); + assertEquals("ladida", + ((BlaService)started.getImplementation()).execute()); system.stop(); } -- 2.31.1