now distinguishing between provided and required service and added
[utils] / system / general / src / main / java / org / wamblee / system / SystemAssembler.java
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);
                        }