From 2c4698e022574a54f6ee23b5ff0ac3779bbbcff4 Mon Sep 17 00:00:00 2001 From: erik Date: Fri, 28 Mar 2008 22:54:30 +0000 Subject: [PATCH] now distinguishing between provided and required service and added behaviro to the required service to determine if a proided service matches. --- trunk/system/general/pom.xml | 5 + .../system/AbstractServiceDescriptor.java | 70 ++++++++++ .../org/wamblee/system/AbstractSubSystem.java | 11 +- .../org/wamblee/system/CompositeSystem.java | 4 +- .../DefaultProvidedServiceDescriptor.java | 19 +++ .../DefaultRequiredServiceDescriptor.java | 44 ++++++ .../org/wamblee/system/DefaultService.java | 6 +- .../system/DefaultServiceDescriptor.java | 41 ------ .../system/DefaultServiceRegistry.java | 2 +- .../system/RequiredServiceDescriptor.java | 6 + .../main/java/org/wamblee/system/Service.java | 2 +- .../org/wamblee/system/ServiceDescriptor.java | 10 +- .../org/wamblee/system/ServiceRegistry.java | 2 +- .../java/org/wamblee/system/SubSystem.java | 4 +- .../org/wamblee/system/SystemAssembler.java | 127 +++++++++++++----- .../java/org/wamblee/system/Application.java | 4 +- .../java/org/wamblee/system/Environment.java | 8 +- .../wamblee/system/SystemAssemblerTest.java | 107 ++++++++++++--- .../wamblee/system/spring/SpringSystem.java | 29 ++-- .../system/spring/SpringSystemTest.java | 40 +++--- 20 files changed, 393 insertions(+), 148 deletions(-) create mode 100644 trunk/system/general/src/main/java/org/wamblee/system/AbstractServiceDescriptor.java create mode 100644 trunk/system/general/src/main/java/org/wamblee/system/DefaultProvidedServiceDescriptor.java create mode 100644 trunk/system/general/src/main/java/org/wamblee/system/DefaultRequiredServiceDescriptor.java delete mode 100644 trunk/system/general/src/main/java/org/wamblee/system/DefaultServiceDescriptor.java create mode 100644 trunk/system/general/src/main/java/org/wamblee/system/RequiredServiceDescriptor.java diff --git a/trunk/system/general/pom.xml b/trunk/system/general/pom.xml index 19302b13..190d45ca 100644 --- a/trunk/system/general/pom.xml +++ b/trunk/system/general/pom.xml @@ -19,6 +19,11 @@ commons-logging commons-logging + + org.wamblee + wamblee-support + test-jar + diff --git a/trunk/system/general/src/main/java/org/wamblee/system/AbstractServiceDescriptor.java b/trunk/system/general/src/main/java/org/wamblee/system/AbstractServiceDescriptor.java new file mode 100644 index 00000000..39454024 --- /dev/null +++ b/trunk/system/general/src/main/java/org/wamblee/system/AbstractServiceDescriptor.java @@ -0,0 +1,70 @@ +package org.wamblee.system; + +import java.util.Arrays; + +/** + * Default implementation of a service descriptor. + */ +public abstract class AbstractServiceDescriptor implements ServiceDescriptor { + + private String _name; + private Class[] _interfaces; + + /** + * Constructs the descriptor. + * @param aInterface Type of service. + */ + public AbstractServiceDescriptor(String aName, Class aInterface) { + _name = aName; + _interfaces = new Class[] { aInterface }; + } + + public AbstractServiceDescriptor(String aName, Class[] aInterfaces) { + _name = aName; + _interfaces = Arrays.copyOf(aInterfaces, aInterfaces.length); + } + + @Override + public String getName() { + return _name; + } + + @Override + public Class[] getInterfaceTypes() { + return _interfaces; + } + + @Override + public boolean equals(Object obj) { + if ( !(obj instanceof AbstractServiceDescriptor)) { + return false; + } + AbstractServiceDescriptor descr = (AbstractServiceDescriptor)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(); + } + + @Override + public String toString() { + StringBuffer buf = new StringBuffer(); + for (Class intf: _interfaces) { + buf.append("." + intf.getName()); + } + return buf.toString(); + } +} diff --git a/trunk/system/general/src/main/java/org/wamblee/system/AbstractSubSystem.java b/trunk/system/general/src/main/java/org/wamblee/system/AbstractSubSystem.java index 6ae6f3cc..6e9cebbd 100644 --- a/trunk/system/general/src/main/java/org/wamblee/system/AbstractSubSystem.java +++ b/trunk/system/general/src/main/java/org/wamblee/system/AbstractSubSystem.java @@ -2,6 +2,7 @@ package org.wamblee.system; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -55,13 +56,13 @@ public abstract class AbstractSubSystem implements SubSystem { } @Override - public final ServiceDescriptor[] getProvidedServices() { - return _provided.toArray(new ServiceDescriptor[0]); + public final ProvidedServiceDescriptor[] getProvidedServices() { + return _provided.toArray(new ProvidedServiceDescriptor[0]); } @Override - public final ServiceDescriptor[] getRequiredServices() { - return _required.toArray(new ServiceDescriptor[0]); + public final RequiredServiceDescriptor[] getRequiredServices() { + return _required.toArray(new RequiredServiceDescriptor[0]); } @Override @@ -92,7 +93,7 @@ public abstract class AbstractSubSystem implements SubSystem { * Service. */ protected final void addService(String aContext, - ServiceDescriptor aDescriptor, Object aService) { + ProvidedServiceDescriptor aDescriptor, Object aService) { LOG.info(aContext + ": service '" + aService + "' started."); Service svc = getRegistry().register(aDescriptor, aService); _running.put(svc.getDescriptor(), svc); diff --git a/trunk/system/general/src/main/java/org/wamblee/system/CompositeSystem.java b/trunk/system/general/src/main/java/org/wamblee/system/CompositeSystem.java index 155d5603..50554d7f 100644 --- a/trunk/system/general/src/main/java/org/wamblee/system/CompositeSystem.java +++ b/trunk/system/general/src/main/java/org/wamblee/system/CompositeSystem.java @@ -80,12 +80,12 @@ public class CompositeSystem extends AbstractSubSystem { @Override protected void doStart(String aContext, Service[] aRequiredServices) { - List descriptors = new ArrayList(); + List descriptors = new ArrayList(); for (Service service : aRequiredServices) { descriptors.add(service.getDescriptor()); } SystemAssembler assembler = new SystemAssembler(aContext + "." + getName(), _systems, - descriptors.toArray(new ServiceDescriptor[0])); + descriptors.toArray(new ProvidedServiceDescriptor[0])); assembler.start(getRegistry(), aRequiredServices); } diff --git a/trunk/system/general/src/main/java/org/wamblee/system/DefaultProvidedServiceDescriptor.java b/trunk/system/general/src/main/java/org/wamblee/system/DefaultProvidedServiceDescriptor.java new file mode 100644 index 00000000..c270cb80 --- /dev/null +++ b/trunk/system/general/src/main/java/org/wamblee/system/DefaultProvidedServiceDescriptor.java @@ -0,0 +1,19 @@ +package org.wamblee.system; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + + +public class DefaultProvidedServiceDescriptor extends AbstractServiceDescriptor implements + ProvidedServiceDescriptor { + + public DefaultProvidedServiceDescriptor(String aName, Class aInterface) { + super(aName, aInterface); + } + + public DefaultProvidedServiceDescriptor(String aName, Class[] aInterface) { + super(aName, aInterface); + } + +} diff --git a/trunk/system/general/src/main/java/org/wamblee/system/DefaultRequiredServiceDescriptor.java b/trunk/system/general/src/main/java/org/wamblee/system/DefaultRequiredServiceDescriptor.java new file mode 100644 index 00000000..ad63cb4a --- /dev/null +++ b/trunk/system/general/src/main/java/org/wamblee/system/DefaultRequiredServiceDescriptor.java @@ -0,0 +1,44 @@ +package org.wamblee.system; + +public class DefaultRequiredServiceDescriptor extends AbstractServiceDescriptor + implements RequiredServiceDescriptor { + + public DefaultRequiredServiceDescriptor(String aName, Class aInterface) { + super(aName, aInterface); + } + + public DefaultRequiredServiceDescriptor(String aName, Class[] aInterfaces) { + super(aName, aInterfaces); + } + + @Override + public boolean implementedBy(ProvidedServiceDescriptor aDescriptor) { + Class[] provided = aDescriptor.getInterfaceTypes(); + for (Class required : getInterfaceTypes()) { + if ( !serviceProvided(required, provided)) { + return false; + } + } + // all required interfaces are provided. + return true; + } + + /** + * Check if the required interface is implemented by one of the provided interfaces. + * @param aRequired required interface + * @param aProvided Provided interfaces. + * @return + */ + private boolean serviceProvided(Class aRequired, Class[] aProvided) { + for (Class provided: aProvided) { + try { + provided.asSubclass(aRequired); + return true; + } catch (ClassCastException e) { + // No match, try the next one. + } + } + return false; + } + +} diff --git a/trunk/system/general/src/main/java/org/wamblee/system/DefaultService.java b/trunk/system/general/src/main/java/org/wamblee/system/DefaultService.java index a110dfda..29296cae 100644 --- a/trunk/system/general/src/main/java/org/wamblee/system/DefaultService.java +++ b/trunk/system/general/src/main/java/org/wamblee/system/DefaultService.java @@ -6,7 +6,7 @@ package org.wamblee.system; public class DefaultService implements Service { private String _id; - private ServiceDescriptor _descriptor; + private ProvidedServiceDescriptor _descriptor; private Object _service; /** @@ -17,7 +17,7 @@ public class DefaultService implements Service { * @param aService * Service. */ - public DefaultService(String aId, ServiceDescriptor aDescriptor, + public DefaultService(String aId, ProvidedServiceDescriptor aDescriptor, Object aService) { _id = aId; _descriptor = aDescriptor; @@ -30,7 +30,7 @@ public class DefaultService implements Service { } @Override - public ServiceDescriptor getDescriptor() { + public ProvidedServiceDescriptor getDescriptor() { return _descriptor; } diff --git a/trunk/system/general/src/main/java/org/wamblee/system/DefaultServiceDescriptor.java b/trunk/system/general/src/main/java/org/wamblee/system/DefaultServiceDescriptor.java deleted file mode 100644 index 82f14565..00000000 --- a/trunk/system/general/src/main/java/org/wamblee/system/DefaultServiceDescriptor.java +++ /dev/null @@ -1,41 +0,0 @@ -package org.wamblee.system; - -/** - * Default implementation of a service descriptor. - */ -public class DefaultServiceDescriptor implements ServiceDescriptor { - - private Class _class; - - /** - * Constructs the descriptor. - * @param aClass Type of service. - */ - public DefaultServiceDescriptor(Class aClass) { - _class = aClass; - } - - @Override - public Class getInterfaceType() { - return _class; - } - - @Override - public boolean equals(Object obj) { - if ( !(obj instanceof DefaultServiceDescriptor)) { - return false; - } - DefaultServiceDescriptor descr = (DefaultServiceDescriptor)obj; - return _class.equals(descr._class); - } - - @Override - public int hashCode() { - return _class.hashCode(); - } - - @Override - public String toString() { - return _class.getName().toString(); - } -} diff --git a/trunk/system/general/src/main/java/org/wamblee/system/DefaultServiceRegistry.java b/trunk/system/general/src/main/java/org/wamblee/system/DefaultServiceRegistry.java index 59515fec..464c6be5 100644 --- a/trunk/system/general/src/main/java/org/wamblee/system/DefaultServiceRegistry.java +++ b/trunk/system/general/src/main/java/org/wamblee/system/DefaultServiceRegistry.java @@ -15,7 +15,7 @@ public class DefaultServiceRegistry implements ServiceRegistry { } @Override - public synchronized Service register(ServiceDescriptor aDescriptor, + public synchronized Service register(ProvidedServiceDescriptor aDescriptor, Object aService) { _count++; String id = "" + _count; diff --git a/trunk/system/general/src/main/java/org/wamblee/system/RequiredServiceDescriptor.java b/trunk/system/general/src/main/java/org/wamblee/system/RequiredServiceDescriptor.java new file mode 100644 index 00000000..1c799236 --- /dev/null +++ b/trunk/system/general/src/main/java/org/wamblee/system/RequiredServiceDescriptor.java @@ -0,0 +1,6 @@ +package org.wamblee.system; + +public interface RequiredServiceDescriptor extends ServiceDescriptor { + + boolean implementedBy(ProvidedServiceDescriptor aDescriptor); +} diff --git a/trunk/system/general/src/main/java/org/wamblee/system/Service.java b/trunk/system/general/src/main/java/org/wamblee/system/Service.java index 61428399..6ee631d7 100644 --- a/trunk/system/general/src/main/java/org/wamblee/system/Service.java +++ b/trunk/system/general/src/main/java/org/wamblee/system/Service.java @@ -15,7 +15,7 @@ public interface Service { * Gets the descriptor of the service. * @return Descriptor. */ - ServiceDescriptor getDescriptor(); + ProvidedServiceDescriptor getDescriptor(); /** * Returns a reference to the running service. diff --git a/trunk/system/general/src/main/java/org/wamblee/system/ServiceDescriptor.java b/trunk/system/general/src/main/java/org/wamblee/system/ServiceDescriptor.java index 793414c3..f3c5cc83 100644 --- a/trunk/system/general/src/main/java/org/wamblee/system/ServiceDescriptor.java +++ b/trunk/system/general/src/main/java/org/wamblee/system/ServiceDescriptor.java @@ -7,12 +7,20 @@ package org.wamblee.system; * NOTE: The current implemention only stores the type of the * descriptor but his can be extended towards more complex rules * for matching services. + * + * Implementations must implement {@link #equals(Object)} and {@link #hashCode()}. */ public interface ServiceDescriptor { + /** + * Symbolic name for the service as used by the subsystem. + * @return Service name. + */ + String getName(); + /** * Returns the service type. * @return Service type. */ - Class getInterfaceType(); + Class[] getInterfaceTypes(); } diff --git a/trunk/system/general/src/main/java/org/wamblee/system/ServiceRegistry.java b/trunk/system/general/src/main/java/org/wamblee/system/ServiceRegistry.java index ebe7229e..9fda9eef 100644 --- a/trunk/system/general/src/main/java/org/wamblee/system/ServiceRegistry.java +++ b/trunk/system/general/src/main/java/org/wamblee/system/ServiceRegistry.java @@ -2,7 +2,7 @@ package org.wamblee.system; public interface ServiceRegistry { - Service register(ServiceDescriptor aDescriptor, Object aService); + Service register(ProvidedServiceDescriptor aDescriptor, Object aService); void remove(Service aService); diff --git a/trunk/system/general/src/main/java/org/wamblee/system/SubSystem.java b/trunk/system/general/src/main/java/org/wamblee/system/SubSystem.java index e25766d6..38c9b9c9 100644 --- a/trunk/system/general/src/main/java/org/wamblee/system/SubSystem.java +++ b/trunk/system/general/src/main/java/org/wamblee/system/SubSystem.java @@ -16,13 +16,13 @@ public interface SubSystem { * Gets a description of the provided interfaces. * @return Provided interfaces. */ - ServiceDescriptor[] getProvidedServices(); + ProvidedServiceDescriptor[] getProvidedServices(); /** * Gets a description of the required interfaces. * @return Required interfaces. */ - ServiceDescriptor[] getRequiredServices(); + RequiredServiceDescriptor[] getRequiredServices(); /** diff --git a/trunk/system/general/src/main/java/org/wamblee/system/SystemAssembler.java b/trunk/system/general/src/main/java/org/wamblee/system/SystemAssembler.java index 9e38a3e1..80bab167 100644 --- a/trunk/system/general/src/main/java/org/wamblee/system/SystemAssembler.java +++ b/trunk/system/general/src/main/java/org/wamblee/system/SystemAssembler.java @@ -1,6 +1,8 @@ package org.wamblee.system; import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -9,9 +11,8 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; /** - * Assembler to control multiple subsystems. It makes sure that - * all dependencies are met and controls the order in which systems - * are initialized. + * Assembler to control multiple subsystems. It makes sure that all dependencies + * are met and controls the order in which systems are initialized. */ public class SystemAssembler { @@ -21,25 +22,57 @@ public class SystemAssembler { private String _context; private SubSystem[] _systems; + public static RequiredServiceDescriptor[] filterRequiredServices( + ProvidedServiceDescriptor aProvided, + Collection aDescriptors) { + List required = new ArrayList(); + for (RequiredServiceDescriptor descriptor : aDescriptors) { + if (descriptor.implementedBy(aProvided)) { + required.add(descriptor); + } + } + return required.toArray(new RequiredServiceDescriptor[0]); + } + + public static ProvidedServiceDescriptor[] filterProvidedServices( + RequiredServiceDescriptor aRequired, + Collection aProvided) { + List provided = new ArrayList(); + for (ProvidedServiceDescriptor descriptor : aProvided) { + if (aRequired.implementedBy(descriptor)) { + provided.add(descriptor); + } + } + return provided.toArray(new ProvidedServiceDescriptor[0]); + } + /** - * Constructs the assembler. - * @param aSystems Systems that must be assembled. - * @param aAvailableServices Available services from other systems - * outside of the systems that this assembler manages. + * Constructs the assembler. + * + * @param aSystems + * Systems that must be assembled. + * @param aAvailableServices + * Available services from other systems outside of the systems + * that this assembler manages. */ - public SystemAssembler(SubSystem[] aSystems, ServiceDescriptor[] aAvailableServices) { + public SystemAssembler(SubSystem[] aSystems, + ProvidedServiceDescriptor[] aAvailableServices) { this(ROOT_CONTEXT_NAME, aSystems, aAvailableServices); } /** - * Constructs the assembler. - * @param aContext Context (unique name) of the assembler. - * @param aSystems Systems that must be assembled. - * @param aAvailableServices Available services from other systems - * outside of the systems that this assembler manages. + * Constructs the assembler. + * + * @param aContext + * Context (unique name) of the assembler. + * @param aSystems + * Systems that must be assembled. + * @param aAvailableServices + * Available services from other systems outside of the systems + * that this assembler manages. */ - public SystemAssembler(String aContext, SubSystem[] aSystems, - ServiceDescriptor[] aAvailableServices) { + public SystemAssembler(String aContext, SubSystem[] aSystems, + ProvidedServiceDescriptor[] aAvailableServices) { _context = aContext; _systems = aSystems; validate(aAvailableServices); @@ -49,18 +82,23 @@ public class SystemAssembler { * Determines if the systems are ordered appropriately so that all * dependencies are met. */ - private void validate(ServiceDescriptor[] aDescriptors) throws SystemAssemblyException { + private void validate(ProvidedServiceDescriptor[] aDescriptors) + throws SystemAssemblyException { - List allProvided = new ArrayList(); - for (ServiceDescriptor descriptor: aDescriptors) { + List allProvided = new ArrayList(); + for (ProvidedServiceDescriptor descriptor : aDescriptors) { allProvided.add(descriptor); } for (SubSystem system : _systems) { // Check if all required services are already provided by earlier // systems. - ServiceDescriptor[] required = system.getRequiredServices(); - for (ServiceDescriptor descriptor : required) { - if (!(allProvided.contains(descriptor))) { + RequiredServiceDescriptor[] required = system.getRequiredServices(); + + for (RequiredServiceDescriptor descriptor : required) { + ProvidedServiceDescriptor[] filtered = filterProvidedServices( + descriptor, allProvided); + + if (filtered.length == 0) { throw new SystemAssemblyException( "Service '" + descriptor @@ -68,42 +106,57 @@ public class SystemAssembler { + system + "' is not provided by systems that are started earlier"); } + if (filtered.length > 1) { + throw new SystemAssemblyException( + "Service '" + + descriptor + + "' required by system '" + + system + + "' matches multiple services provided by other systems: " + + Arrays.asList(filtered)); + } } // add all provided services - ServiceDescriptor[] provided = system.getProvidedServices(); - for (ServiceDescriptor descriptor : provided) { - allProvided.add(descriptor); - } + ProvidedServiceDescriptor[] provided = system.getProvidedServices(); + allProvided.addAll(Arrays.asList(provided)); } } /** * 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. + * + * @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) { LOG.info("Starting '" + _context + "'"); - Map allProvided = new HashMap(); + Map allProvided = new HashMap(); for (Service service : aRequiredServices) { allProvided.put(service.getDescriptor(), service); } for (SubSystem system : _systems) { - ServiceDescriptor[] descriptors = system.getRequiredServices(); + + // Compose a list of the required services required for the subsystem. + + RequiredServiceDescriptor[] descriptors = system + .getRequiredServices(); List services = new ArrayList(); - for (ServiceDescriptor descriptor : descriptors) { - Service required = allProvided.get(descriptor); - if (required == null) { - throw new SystemAssemblyException("Service '" + descriptor - + "' required by '" + system + "' is null."); - } - services.add(required); + for (RequiredServiceDescriptor descriptor : descriptors) { + ProvidedServiceDescriptor[] provided = filterProvidedServices( + descriptor, allProvided.keySet()); + services.add(allProvided.get(provided[0])); } + + // Start the service. Service[] provided = system.start(_context, services .toArray(new Service[0])); + + // Add started services to the map of started services. for (Service service : provided) { allProvided.put(service.getDescriptor(), service); } diff --git a/trunk/system/general/src/test/java/org/wamblee/system/Application.java b/trunk/system/general/src/test/java/org/wamblee/system/Application.java index d5a3590d..07b1e34c 100644 --- a/trunk/system/general/src/test/java/org/wamblee/system/Application.java +++ b/trunk/system/general/src/test/java/org/wamblee/system/Application.java @@ -5,8 +5,8 @@ import javax.sql.DataSource; public class Application extends AbstractSubSystem { private static final ServiceDescriptor[] REQUIRED = new ServiceDescriptor[] { - new DefaultServiceDescriptor(DataSource.class), - new DefaultServiceDescriptor(Integer.class) + new DefaultRequiredServiceDescriptor("datasource", DataSource.class), + new DefaultRequiredServiceDescriptor("integer", Integer.class) }; public Application(ServiceRegistry aRegistry) { diff --git a/trunk/system/general/src/test/java/org/wamblee/system/Environment.java b/trunk/system/general/src/test/java/org/wamblee/system/Environment.java index a8231068..56118ccb 100644 --- a/trunk/system/general/src/test/java/org/wamblee/system/Environment.java +++ b/trunk/system/general/src/test/java/org/wamblee/system/Environment.java @@ -5,10 +5,10 @@ import javax.sql.DataSource; public class Environment extends AbstractSubSystem { - private static final ServiceDescriptor[] PROVIDED = - new ServiceDescriptor[] { - new DefaultServiceDescriptor(DataSource.class), - new DefaultServiceDescriptor(Integer.class) + private static final ProvidedServiceDescriptor[] PROVIDED = + new ProvidedServiceDescriptor[] { + new DefaultProvidedServiceDescriptor("datasource", DataSource.class), + new DefaultProvidedServiceDescriptor("integer", Integer.class) }; public Environment(ServiceRegistry aRegistry) { diff --git a/trunk/system/general/src/test/java/org/wamblee/system/SystemAssemblerTest.java b/trunk/system/general/src/test/java/org/wamblee/system/SystemAssemblerTest.java index 1bd89ca5..2dba056e 100644 --- a/trunk/system/general/src/test/java/org/wamblee/system/SystemAssemblerTest.java +++ b/trunk/system/general/src/test/java/org/wamblee/system/SystemAssemblerTest.java @@ -1,33 +1,82 @@ package org.wamblee.system; +import java.io.Serializable; +import java.util.ArrayList; +import java.util.Arrays; + +import org.wamblee.test.AssertionUtils; + import junit.framework.TestCase; public class SystemAssemblerTest extends TestCase { - - private ServiceRegistry _registry; - + + private ServiceRegistry _registry; + @Override protected void setUp() throws Exception { super.setUp(); - _registry = new DefaultServiceRegistry(); + _registry = new DefaultServiceRegistry(); + } + + private static class MyMultiple implements Serializable, Runnable { + @Override + public void run() { + // Empty + } + } + + public void testFilterProvided() { + RequiredServiceDescriptor req1 = new DefaultRequiredServiceDescriptor( + "name", Runnable.class); + RequiredServiceDescriptor req2 = new DefaultRequiredServiceDescriptor( + "name", Serializable.class); + ProvidedServiceDescriptor prov1 = new DefaultProvidedServiceDescriptor( + "name", Runnable.class); + ProvidedServiceDescriptor prov2 = new DefaultProvidedServiceDescriptor( + "name", Serializable.class); + ProvidedServiceDescriptor prov3 = new DefaultProvidedServiceDescriptor( + "name", MyMultiple.class); + + AssertionUtils.assertEquals(new RequiredServiceDescriptor[] { req1 }, + SystemAssembler.filterRequiredServices(prov1, Arrays + .asList(new RequiredServiceDescriptor[] { req1 }))); + AssertionUtils.assertEquals(new RequiredServiceDescriptor[] { req1 }, + SystemAssembler + .filterRequiredServices(prov1, Arrays + .asList(new RequiredServiceDescriptor[] { req1, + req2 }))); + AssertionUtils.assertEquals(new RequiredServiceDescriptor[] { req1, + req2 }, SystemAssembler.filterRequiredServices(prov3, Arrays + .asList(new RequiredServiceDescriptor[] { req1, req2 }))); + + AssertionUtils.assertEquals(new ProvidedServiceDescriptor[] { prov1 }, + SystemAssembler.filterProvidedServices(req1, Arrays + .asList(new ProvidedServiceDescriptor[] { prov1 }))); + AssertionUtils.assertEquals(new ProvidedServiceDescriptor[] { prov1 }, + SystemAssembler.filterProvidedServices(req1, + Arrays.asList(new ProvidedServiceDescriptor[] { prov1, + prov2 }))); + AssertionUtils.assertEquals(new ProvidedServiceDescriptor[] { prov1, + prov3 }, SystemAssembler.filterProvidedServices(req1, Arrays + .asList(new ProvidedServiceDescriptor[] { prov1, prov3 }))); } public void testEnvironmentApplication() { SubSystem environment = new Environment(_registry); SubSystem application = new Application(_registry); SystemAssembler assembler = new SystemAssembler(new SubSystem[] { - environment, application }, new ServiceDescriptor[0]); + environment, application }, new ProvidedServiceDescriptor[0]); assembler.start(_registry, new Service[0]); Service[] envServices = environment.getRunningServices(); assertEquals(2, envServices.length); Service[] appServices = environment.getRunningServices(); assertEquals(2, appServices.length); assertEquals(2, _registry.listAllServices().length); - + environment.stop(); assertEquals(0, _registry.listAllServices().length); - - application.stop(); + + application.stop(); assertEquals(0, _registry.listAllServices().length); } @@ -36,7 +85,8 @@ public class SystemAssemblerTest extends TestCase { SubSystem environment = new Environment(_registry); SubSystem application = new Application(_registry); SystemAssembler assembler = new SystemAssembler(new SubSystem[] { - application, environment }, new ServiceDescriptor[0]); + application, environment }, + new ProvidedServiceDescriptor[0]); assembler.start(_registry, new Service[0]); } catch (SystemAssemblyException e) { // e.printStackTrace(); @@ -48,9 +98,9 @@ public class SystemAssemblerTest extends TestCase { public void testComposite() { SubSystem environment = new Environment(_registry); SubSystem application = new Application(_registry); - CompositeSystem system = new CompositeSystem("all", _registry, new SubSystem[] { - environment, application }, new ServiceDescriptor[0], - new ServiceDescriptor[0]); + CompositeSystem system = new CompositeSystem("all", _registry, + new SubSystem[] { environment, application }, + new ServiceDescriptor[0], new ServiceDescriptor[0]); system.start("root", new Service[0]); ServiceDescriptor[] required = system.getRequiredServices(); assertEquals(0, required.length); @@ -62,10 +112,13 @@ public class SystemAssemblerTest extends TestCase { try { SubSystem environment = new Environment(_registry); SubSystem application = new Application(_registry); - CompositeSystem system = new CompositeSystem("all", _registry, + CompositeSystem system = new CompositeSystem( + "all", + _registry, new SubSystem[] { environment, application }, - new ServiceDescriptor[] { new DefaultServiceDescriptor( - String.class) }, new ServiceDescriptor[0]); + new ServiceDescriptor[] { new DefaultProvidedServiceDescriptor( + "string", String.class) }, + new DefaultRequiredServiceDescriptor[0]); } catch (SystemAssemblyException e) { return; } @@ -75,10 +128,11 @@ public class SystemAssemblerTest extends TestCase { public void testCompositeWithSuperfluousRequiredInfo() { SubSystem environment = new Environment(_registry); SubSystem application = new Application(_registry); - CompositeSystem system = new CompositeSystem("all", _registry,new SubSystem[] { - environment, application }, new ServiceDescriptor[0], - new ServiceDescriptor[] { new DefaultServiceDescriptor( - String.class) }); + CompositeSystem system = new CompositeSystem("all", _registry, + new SubSystem[] { environment, application }, + new ServiceDescriptor[0], + new ServiceDescriptor[] { new DefaultRequiredServiceDescriptor( + "string", String.class) }); system.start("root", new Service[0]); ServiceDescriptor[] required = system.getRequiredServices(); assertEquals(1, required.length); @@ -117,4 +171,19 @@ public class SystemAssemblerTest extends TestCase { } + public void testAmbiguousInterfaces() { + try { + SubSystem environment1 = new Environment(_registry); + SubSystem environment2 = new Environment(_registry); + SubSystem application = new Application(_registry); + SystemAssembler assembler = new SystemAssembler(new SubSystem[] { + environment1, environment2, application }, + new ProvidedServiceDescriptor[0]); + assembler.start(_registry, new Service[0]); + } catch (SystemAssemblyException e) { + return; + } + fail(); + } + } diff --git a/trunk/system/spring/src/main/java/org/wamblee/system/spring/SpringSystem.java b/trunk/system/spring/src/main/java/org/wamblee/system/spring/SpringSystem.java index 5de2a948..ba0ccf88 100644 --- a/trunk/system/spring/src/main/java/org/wamblee/system/spring/SpringSystem.java +++ b/trunk/system/spring/src/main/java/org/wamblee/system/spring/SpringSystem.java @@ -12,9 +12,12 @@ import org.springframework.context.support.ClassPathXmlApplicationContext; import org.springframework.context.support.GenericApplicationContext; import org.wamblee.system.AbstractSubSystem; import org.wamblee.system.CompositeSystem; +import org.wamblee.system.ProvidedServiceDescriptor; +import org.wamblee.system.RequiredServiceDescriptor; import org.wamblee.system.Service; import org.wamblee.system.ServiceDescriptor; import org.wamblee.system.ServiceRegistry; +import org.wamblee.system.SystemAssembler; import org.wamblee.system.SystemAssemblyException; /** @@ -28,8 +31,8 @@ public class SpringSystem extends AbstractSubSystem { static ThreadLocal REGISTRY = new ThreadLocal(); private String[] _configFiles; - private Map _provided; - private Map _required; + private Map _provided; + private Map _required; /** * Parent application context containing required services. */ @@ -57,8 +60,8 @@ public class SpringSystem extends AbstractSubSystem { * service. */ public SpringSystem(String aName, ServiceRegistry aRegistry, String[] aConfigFiles, - Map aProvided, - Map aRequired) { + Map aProvided, + Map aRequired) { super(aName, aRegistry, aProvided.values().toArray(new ServiceDescriptor[0]), aRequired.keySet().toArray(new ServiceDescriptor[0])); _configFiles = aConfigFiles; @@ -116,13 +119,17 @@ public class SpringSystem extends AbstractSubSystem { for (Service svc: aRequiredServices) { String id = svc.getId(); - ServiceDescriptor descriptor = svc.getDescriptor(); - String beanName = _required.get(descriptor); - ConstructorArgumentValues cargs = new ConstructorArgumentValues(); - cargs.addGenericArgumentValue(id); - BeanDefinition definition = new RootBeanDefinition(ProvidedServiceBean.class, cargs, - new MutablePropertyValues()); - _parentContext.registerBeanDefinition(beanName, definition); + ProvidedServiceDescriptor descriptor = svc.getDescriptor(); + RequiredServiceDescriptor[] requiredServices = SystemAssembler.filterRequiredServices(descriptor, + _required.keySet()); + for (RequiredServiceDescriptor required: requiredServices) { + String beanName = _required.get(required); + ConstructorArgumentValues cargs = new ConstructorArgumentValues(); + cargs.addGenericArgumentValue(id); + BeanDefinition definition = new RootBeanDefinition(ProvidedServiceBean.class, cargs, + new MutablePropertyValues()); + _parentContext.registerBeanDefinition(beanName, definition); + } } _parentContext.refresh(); } diff --git a/trunk/system/spring/src/test/java/org/wamblee/system/spring/SpringSystemTest.java b/trunk/system/spring/src/test/java/org/wamblee/system/spring/SpringSystemTest.java index 092a5bc1..e12e0113 100644 --- a/trunk/system/spring/src/test/java/org/wamblee/system/spring/SpringSystemTest.java +++ b/trunk/system/spring/src/test/java/org/wamblee/system/spring/SpringSystemTest.java @@ -5,8 +5,12 @@ import java.util.Map; import junit.framework.TestCase; -import org.wamblee.system.DefaultServiceDescriptor; +import org.wamblee.system.AbstractServiceDescriptor; +import org.wamblee.system.DefaultProvidedServiceDescriptor; +import org.wamblee.system.DefaultRequiredServiceDescriptor; import org.wamblee.system.DefaultServiceRegistry; +import org.wamblee.system.ProvidedServiceDescriptor; +import org.wamblee.system.RequiredServiceDescriptor; import org.wamblee.system.Service; import org.wamblee.system.ServiceDescriptor; import org.wamblee.system.ServiceRegistry; @@ -28,8 +32,8 @@ public class SpringSystemTest extends TestCase { public void testBlackboxSystem() { SpringSystem system = new SpringSystem("system", _registry, new String[] { HELLO_SERVICE_SPRING_XML }, - new HashMap(), - new HashMap()); + new HashMap(), + new HashMap()); system.start("Hello", new Service[0]); Service[] services = system.getRunningServices(); assertEquals(0, services.length); @@ -38,13 +42,13 @@ public class SpringSystemTest extends TestCase { } public void testOneProvidedService() { - Map provided = new HashMap(); - provided.put("helloService", new DefaultServiceDescriptor( - HelloService.class)); + Map provided = new HashMap(); + provided.put("helloService", new DefaultProvidedServiceDescriptor( + "hello", HelloService.class)); SpringSystem system = new SpringSystem("system", _registry, new String[] { HELLO_SERVICE_SPRING_XML }, provided, - new HashMap()); + new HashMap()); system.start("Hello", new Service[0]); Service[] services = system.getRunningServices(); assertEquals(1, services.length); @@ -58,8 +62,8 @@ public class SpringSystemTest extends TestCase { try { SpringSystem system = new SpringSystem("system", _registry, new String[] { HELLO_SERVICE_SPRING_WITH_REQS_XML }, - new HashMap(), - new HashMap()); + new HashMap(), + new HashMap()); system.start("Bla", new Service[0]); } catch (SystemAssemblyException e) { //e.printStackTrace(); @@ -69,25 +73,25 @@ public class SpringSystemTest extends TestCase { } public void testWithRequirement() { - Map required = new HashMap(); - required.put(new DefaultServiceDescriptor(HelloService.class), + Map required = new HashMap(); + required.put(new DefaultRequiredServiceDescriptor("hello", HelloService.class), "helloService"); SpringSystem system = new SpringSystem("system", _registry, new String[] { HELLO_SERVICE_SPRING_WITH_REQS_XML }, - new HashMap(), required); + new HashMap(), required); HelloService helloObject = new HelloService("ladida"); - Service helloService = _registry.register(new DefaultServiceDescriptor(HelloService.class), helloObject); + Service helloService = _registry.register(new DefaultProvidedServiceDescriptor("hello", HelloService.class), helloObject); system.start("Bla", new Service[] { helloService } ); system.stop(); } public void testWithRequirementAndProvidedService() { - Map required = new HashMap(); - required.put(new DefaultServiceDescriptor(HelloService.class), + Map required = new HashMap(); + required.put(new DefaultRequiredServiceDescriptor("hello", HelloService.class), "helloService"); - Map provided = new HashMap(); - provided.put("blaService", new DefaultServiceDescriptor( + Map provided = new HashMap(); + provided.put("blaService", new DefaultProvidedServiceDescriptor("bla", BlaService.class)); SpringSystem system = new SpringSystem("system", _registry, @@ -95,7 +99,7 @@ public class SpringSystemTest extends TestCase { provided, required); HelloService helloObject = new HelloService("ladida"); - Service helloService = _registry.register(new DefaultServiceDescriptor(HelloService.class), helloObject); + Service helloService = _registry.register(new DefaultProvidedServiceDescriptor("hello", HelloService.class), helloObject); Service[] services = system.start("Bla", new Service[] { helloService } ); assertEquals(1, services.length); -- 2.31.1