now distinguishing between provided and required service and added
authorErik Brakkee <erik@brakkee.org>
Fri, 28 Mar 2008 22:54:30 +0000 (22:54 +0000)
committerErik Brakkee <erik@brakkee.org>
Fri, 28 Mar 2008 22:54:30 +0000 (22:54 +0000)
behaviro to the required service to determine if a proided service
matches.

20 files changed:
system/general/pom.xml
system/general/src/main/java/org/wamblee/system/AbstractServiceDescriptor.java [new file with mode: 0644]
system/general/src/main/java/org/wamblee/system/AbstractSubSystem.java
system/general/src/main/java/org/wamblee/system/CompositeSystem.java
system/general/src/main/java/org/wamblee/system/DefaultProvidedServiceDescriptor.java [new file with mode: 0644]
system/general/src/main/java/org/wamblee/system/DefaultRequiredServiceDescriptor.java [new file with mode: 0644]
system/general/src/main/java/org/wamblee/system/DefaultService.java
system/general/src/main/java/org/wamblee/system/DefaultServiceDescriptor.java [deleted file]
system/general/src/main/java/org/wamblee/system/DefaultServiceRegistry.java
system/general/src/main/java/org/wamblee/system/RequiredServiceDescriptor.java [new file with mode: 0644]
system/general/src/main/java/org/wamblee/system/Service.java
system/general/src/main/java/org/wamblee/system/ServiceDescriptor.java
system/general/src/main/java/org/wamblee/system/ServiceRegistry.java
system/general/src/main/java/org/wamblee/system/SubSystem.java
system/general/src/main/java/org/wamblee/system/SystemAssembler.java
system/general/src/test/java/org/wamblee/system/Application.java
system/general/src/test/java/org/wamblee/system/Environment.java
system/general/src/test/java/org/wamblee/system/SystemAssemblerTest.java
system/spring/src/main/java/org/wamblee/system/spring/SpringSystem.java
system/spring/src/test/java/org/wamblee/system/spring/SpringSystemTest.java

index 19302b13022b62c41420366f3d3662c26168d0ca..190d45ca7d4e345a3e3a4bc8c9340fdfb660c647 100644 (file)
       <groupId>commons-logging</groupId>
       <artifactId>commons-logging</artifactId>
     </dependency>
+    <dependency>
+      <groupId>org.wamblee</groupId>
+      <artifactId>wamblee-support</artifactId>
+      <type>test-jar</type>
+    </dependency>
   </dependencies>
 
 </project>
diff --git a/system/general/src/main/java/org/wamblee/system/AbstractServiceDescriptor.java b/system/general/src/main/java/org/wamblee/system/AbstractServiceDescriptor.java
new file mode 100644 (file)
index 0000000..3945402
--- /dev/null
@@ -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();
+       }
+}
index 6ae6f3cc566fc7f29cf01ca1fd74a3b7476a9b8b..6e9cebbd0966fa5b1814c735d67e0cca36a49334 100644 (file)
@@ -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);
index 155d56030f15e119b61ea04dbe0857976f575b7f..50554d7f19f21b7c9c5210446151bed5704bdaa4 100644 (file)
@@ -80,12 +80,12 @@ public class CompositeSystem extends AbstractSubSystem {
 
        @Override
        protected void doStart(String aContext, Service[] aRequiredServices) {
-               List<ServiceDescriptor> descriptors = new ArrayList<ServiceDescriptor>();
+               List<ProvidedServiceDescriptor> descriptors = new ArrayList<ProvidedServiceDescriptor>();
                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/system/general/src/main/java/org/wamblee/system/DefaultProvidedServiceDescriptor.java b/system/general/src/main/java/org/wamblee/system/DefaultProvidedServiceDescriptor.java
new file mode 100644 (file)
index 0000000..c270cb8
--- /dev/null
@@ -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/system/general/src/main/java/org/wamblee/system/DefaultRequiredServiceDescriptor.java b/system/general/src/main/java/org/wamblee/system/DefaultRequiredServiceDescriptor.java
new file mode 100644 (file)
index 0000000..ad63cb4
--- /dev/null
@@ -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; 
+       }
+
+}
index a110dfda5eb63bb4344fa6f2703e6eddd22ad866..29296cae576b5f6d70546a99bc46f9b73e849c8e 100644 (file)
@@ -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/system/general/src/main/java/org/wamblee/system/DefaultServiceDescriptor.java b/system/general/src/main/java/org/wamblee/system/DefaultServiceDescriptor.java
deleted file mode 100644 (file)
index 82f1456..0000000
+++ /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();
-       }
-}
index 59515fec04229161dedead759fe1c75d51d86878..464c6be59786a5e886ad37208406542342d0d02d 100644 (file)
@@ -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/system/general/src/main/java/org/wamblee/system/RequiredServiceDescriptor.java b/system/general/src/main/java/org/wamblee/system/RequiredServiceDescriptor.java
new file mode 100644 (file)
index 0000000..1c79923
--- /dev/null
@@ -0,0 +1,6 @@
+package org.wamblee.system;
+
+public interface RequiredServiceDescriptor extends ServiceDescriptor {
+
+       boolean implementedBy(ProvidedServiceDescriptor aDescriptor);
+}
index 61428399580e3caf86566445db392aed6b5cb0c4..6ee631d7902d2f77adc3f6a1a369e704f8ac8194 100644 (file)
@@ -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. 
index 793414c377fe0b3a0d8b7e0a9e5704350fb20e4a..f3c5cc835e5e51c5820aa20f035fe605e45eb790 100644 (file)
@@ -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();
 }
index ebe7229e1c42b3072bb6239f473abdeef3d2f25c..9fda9eef6a6e96d34168af5a5025ec4e4fbe919c 100644 (file)
@@ -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); 
        
index e25766d655eb43c4ca56cc4272449af683037ee8..38c9b9c9508a982dc33e7fc1609f6b840d2b90cb 100644 (file)
@@ -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();
 
        
        /**
index 9e38a3e1a0a332cf5c47c9433f53ac018b058873..80bab167fa1de1bf7c7c071d14f6ad60e93b627a 100644 (file)
@@ -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<RequiredServiceDescriptor> aDescriptors) {
+               List<RequiredServiceDescriptor> required = new ArrayList<RequiredServiceDescriptor>();
+               for (RequiredServiceDescriptor descriptor : aDescriptors) {
+                       if (descriptor.implementedBy(aProvided)) {
+                               required.add(descriptor);
+                       }
+               }
+               return required.toArray(new RequiredServiceDescriptor[0]);
+       }
+
+       public static ProvidedServiceDescriptor[] filterProvidedServices(
+                       RequiredServiceDescriptor aRequired,
+                       Collection<ProvidedServiceDescriptor> aProvided) {
+               List<ProvidedServiceDescriptor> provided = new ArrayList<ProvidedServiceDescriptor>();
+               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<ServiceDescriptor> allProvided = new ArrayList<ServiceDescriptor>();
-               for (ServiceDescriptor descriptor: aDescriptors) { 
+               List<ProvidedServiceDescriptor> allProvided = new ArrayList<ProvidedServiceDescriptor>();
+               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<ServiceDescriptor, Service> allProvided = new HashMap<ServiceDescriptor, Service>();
+               Map<ProvidedServiceDescriptor, Service> allProvided = new HashMap<ProvidedServiceDescriptor, Service>();
 
                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<Service> services = new ArrayList<Service>();
-                       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);
                        }
index d5a3590db2775b0479a4ac857323e3492e7a66d0..07b1e34cbc7939d6e30ce44b9acc8d7fcebfc40c 100644 (file)
@@ -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) {
index a82310686aeb7c372da52ec0cb2002af9c870964..56118ccbb7fb325d1c96616bc017800b9bff4549 100644 (file)
@@ -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) { 
index 1bd89ca5fb212765a7f5e78a016ed443c4f6a37f..2dba056e63197879c35e4e9e30a96c70b0516843 100644 (file)
@@ -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();
+       }
+
 }
index 5de2a948fadbaca991425a4f9d18cb1945fdcf20..ba0ccf8833b673055fb70def5decf4a881429b53 100644 (file)
@@ -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<ServiceRegistry> REGISTRY = new ThreadLocal<ServiceRegistry>();
 
        private String[] _configFiles;
-       private Map<String, ServiceDescriptor> _provided;
-       private Map<ServiceDescriptor, String> _required;
+       private Map<String, ProvidedServiceDescriptor> _provided;
+       private Map<RequiredServiceDescriptor, String> _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<String, ServiceDescriptor> aProvided,
-                       Map<ServiceDescriptor, String> aRequired) {
+                       Map<String, ProvidedServiceDescriptor> aProvided,
+                       Map<RequiredServiceDescriptor, String> 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();
        }
index 092a5bc11e47907ce74c93387388893ef8e55873..e12e0113a46e2d9a2b42e7f1b9ca3929d3cc64f2 100644 (file)
@@ -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<String, ServiceDescriptor>(),
-                               new HashMap<ServiceDescriptor, String>());
+                               new HashMap<String, ProvidedServiceDescriptor>(),
+                               new HashMap<RequiredServiceDescriptor, String>());
                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<String, ServiceDescriptor> provided = new HashMap<String, ServiceDescriptor>();
-               provided.put("helloService", new DefaultServiceDescriptor(
-                               HelloService.class));
+               Map<String, ProvidedServiceDescriptor> provided = new HashMap<String, ProvidedServiceDescriptor>();
+               provided.put("helloService", new DefaultProvidedServiceDescriptor(
+                               "hello", HelloService.class));
 
                SpringSystem system = new SpringSystem("system", _registry,
                                new String[] { HELLO_SERVICE_SPRING_XML }, provided,
-                               new HashMap<ServiceDescriptor, String>());
+                               new HashMap<RequiredServiceDescriptor, String>());
                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<String, ServiceDescriptor>(),
-                                       new HashMap<ServiceDescriptor, String>());
+                                       new HashMap<String, ProvidedServiceDescriptor>(),
+                                       new HashMap<RequiredServiceDescriptor, String>());
                        system.start("Bla", new Service[0]);
                } catch (SystemAssemblyException e) {
                        //e.printStackTrace();
@@ -69,25 +73,25 @@ public class SpringSystemTest extends TestCase {
        }
 
        public void testWithRequirement() {
-               Map<ServiceDescriptor, String> required = new HashMap<ServiceDescriptor, String>();
-               required.put(new DefaultServiceDescriptor(HelloService.class),
+               Map<RequiredServiceDescriptor, String> required = new HashMap<RequiredServiceDescriptor, String>();
+               required.put(new DefaultRequiredServiceDescriptor("hello", HelloService.class),
                                "helloService");
                SpringSystem system = new SpringSystem("system", _registry,
                                new String[] { HELLO_SERVICE_SPRING_WITH_REQS_XML },
-                               new HashMap<String, ServiceDescriptor>(), required);
+                               new HashMap<String, ProvidedServiceDescriptor>(), 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<ServiceDescriptor, String> required = new HashMap<ServiceDescriptor, String>();
-               required.put(new DefaultServiceDescriptor(HelloService.class),
+               Map<RequiredServiceDescriptor, String> required = new HashMap<RequiredServiceDescriptor, String>();
+               required.put(new DefaultRequiredServiceDescriptor("hello", HelloService.class),
                                "helloService");
-               Map<String,ServiceDescriptor> provided = new HashMap<String, ServiceDescriptor>();
-               provided.put("blaService", new DefaultServiceDescriptor(
+               Map<String,ProvidedServiceDescriptor> provided = new HashMap<String, ProvidedServiceDescriptor>();
+               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);