Better solution for setting the context. The context is now known as soon as componen...
[utils] / system / general / src / main / java / org / wamblee / system / Container.java
index ee3a053595db2d7a7444d091db19947b0cd4c527..65d10f06e2960d74eff34b5ed63cd560d6fa1337 100644 (file)
@@ -1,14 +1,30 @@
+/*
+ * Copyright 2007 the original author or authors.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */ 
 package org.wamblee.system;
 
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Collection;
+import java.util.HashSet;
 import java.util.List;
+import java.util.Set;
 
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 
-import sun.util.LocaleServiceProviderPool.LocalizedObjectGetter;
-
 /**
  * Composite system consisting of multiple subsystems. 
  *
@@ -20,6 +36,30 @@ public class Container extends AbstractComponent {
 
        private Component[] _systems;
 
+       public static RequiredInterface[] filterRequiredServices(
+                       ProvidedInterface aProvided,
+                       Collection<RequiredInterface> aDescriptors) {
+               List<RequiredInterface> required = new ArrayList<RequiredInterface>();
+               for (RequiredInterface descriptor : aDescriptors) {
+                       if (descriptor.implementedBy(aProvided)) {
+                               required.add(descriptor);
+                       }
+               }
+               return required.toArray(new RequiredInterface[0]);
+       }
+
+       public static ProvidedInterface[] filterProvidedServices(
+                       RequiredInterface aRequired,
+                       Collection<ProvidedInterface> aProvided) {
+               List<ProvidedInterface> provided = new ArrayList<ProvidedInterface>();
+               for (ProvidedInterface descriptor : aProvided) {
+                       if (aRequired.implementedBy(descriptor)) {
+                               provided.add(descriptor);
+                       }
+               }
+               return provided.toArray(new ProvidedInterface[0]);
+       }
+       
        /**
         * Construcst the composite system. 
         * @param aName Name of the system. 
@@ -28,11 +68,14 @@ public class Container extends AbstractComponent {
         * @param aProvided Provided services of the system. 
         * @param aRequired Required services by the system. 
         */
-       public Container(String aName, ServiceRegistry aRegistry, Component[] aSystems,
-                       ProvidedInterfaceDescriptor[] aProvided, RequiredInterfaceDescriptor[] aRequired) {
-               super(aName, aRegistry, aProvided, aRequired);
+       public Container(String aName, Component[] aSystems,
+                       ProvidedInterface[] aProvided, RequiredInterface[] aRequired) {
+               super(aName, aProvided, aRequired);
                _systems = aSystems;
-               validate();
+               for (Component component: aSystems) { 
+                       component.addContext(getQualifiedName());
+               }
+               validate(aRequired);
        }
 
        /**
@@ -41,25 +84,25 @@ public class Container extends AbstractComponent {
         * no services in the provided list that cannot be provided. 
         * Also logs a warning in case of superfluous requirements.  
         */
-       private void validate() {
-               List<ProvidedInterfaceDescriptor> provided = new ArrayList<ProvidedInterfaceDescriptor>();
+       private void validate(RequiredInterface[] aRequired) {
+               List<ProvidedInterface> provided = new ArrayList<ProvidedInterface>();
                for (Component system : _systems) {
                        provided.addAll(Arrays.asList(system.getProvidedServices()));
                }
 
-               List<RequiredInterfaceDescriptor> required = new ArrayList<RequiredInterfaceDescriptor>();
+               List<RequiredInterface> required = new ArrayList<RequiredInterface>();
                for (Component system : _systems) {
                        required.addAll(Arrays.asList(system.getRequiredServices()));
                }
 
-               for (ProvidedInterfaceDescriptor service : getProvidedServices()) {
+               for (ProvidedInterface service : getProvidedServices()) {
                        if (!(provided.contains(service))) {
                                throw new SystemAssemblyException(getName() + ": Service '" + service
                                                + "' is not provided by any of the subsystems");
                        }
                }
 
-               for (RequiredInterfaceDescriptor service : getRequiredServices()) {
+               for (RequiredInterface service : getRequiredServices()) {
                        if (!(required.contains(service))) {
                                info("Service '"
                                                + service
@@ -67,16 +110,21 @@ public class Container extends AbstractComponent {
                        }
                }
 
-               List<RequiredInterfaceDescriptor> reallyRequired = new ArrayList<RequiredInterfaceDescriptor>(
+               List<RequiredInterface> reallyRequired = new ArrayList<RequiredInterface>(
                                required);
-               for (ProvidedInterfaceDescriptor service : provided) {
-                       reallyRequired.remove(service); 
-               }
-               for (RequiredInterfaceDescriptor service: getRequiredServices()) { 
-                       reallyRequired.remove(service); 
+               // Compute all required interfaces that are not provided
+               for (ProvidedInterface service : provided) {
+                       List<RequiredInterface> fulfilled = 
+                               Arrays.asList(filterRequiredServices(service, 
+                                       reallyRequired));
+                       reallyRequired.removeAll(fulfilled); 
                }
+               // Now the remaining interfaces should be covered by the required
+               // list. 
+               reallyRequired.removeAll(Arrays.asList(aRequired));
+               
                String missingRequired = "";
-               for (RequiredInterfaceDescriptor service: reallyRequired) {
+               for (RequiredInterface service: reallyRequired) {
                        missingRequired += service + "\n";
                }
                if ( missingRequired.length() > 0 ) { 
@@ -85,16 +133,79 @@ public class Container extends AbstractComponent {
        }
 
        @Override
-       protected void doStart(String aContext, Service[] aRequiredServices) {
-               List<ProvidedInterfaceDescriptor> descriptors = new ArrayList<ProvidedInterfaceDescriptor>();
-               for (Service service : aRequiredServices) {
-                       descriptors.add(service.getDescriptor());
+       protected void doStart() {
+               List<ProvidedInterface> provided = new ArrayList<ProvidedInterface>();
+               
+               // all interfaces from the required list of this container are
+               // provided to the components inside it.
+               RequiredInterface[] required = getRequiredServices();
+               for (RequiredInterface intf: required) { 
+                   ProvidedInterface provider = intf.getProvider(); 
+                   if ( provider == null ) { 
+                       throw new SystemAssemblyException(getQualifiedName() + ": required interface '" + intf +"' is not provided");
+                   }
+                       provided.add(intf.getProvider());
                }
-               SystemAssembler assembler = new SystemAssembler(aContext + "." + getName(), _systems,
-                               descriptors.toArray(new ProvidedInterfaceDescriptor[0]));
-               assembler.start(getRegistry(), aRequiredServices);
+               
+               startImpl();
        }
        
+       /**
+        * Starts the subsystems.
+        * 
+        * @param aRequiredServices
+        *            Services that are available from other systems that have been
+        *            started before.
+        */
+       private void startImpl() {
+               LOG.info("Starting '" + getQualifiedName() + "'");
+               List<ProvidedInterface> allProvided = new ArrayList<ProvidedInterface>();
+               
+               // Add the provides of all externally required interfaces to the list of available
+               // interfaces
+               for (RequiredInterface required: getRequiredServices()) { 
+                       allProvided.add(required.getProvider());
+               }
+               
+               for (Component system : _systems) {
+                       // Check if all required services are already provided by earlier
+                       // systems.
+                       RequiredInterface[] required = system.getRequiredServices();
+
+                       for (RequiredInterface descriptor : required) {
+                               ProvidedInterface[] filtered = filterProvidedServices(
+                                               descriptor, allProvided);
+
+                               if (filtered.length == 0) {
+                                       throw new SystemAssemblyException(
+                                                       "Service '"
+                                                                       + descriptor
+                                                                       + "' required by system '"
+                                                                       + 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));
+                               }
+                               descriptor.setProvider(filtered[0]);
+                       }
+                       
+                       // Start the service. 
+                       system.start();
+
+                       // add all provided services
+                       ProvidedInterface[] provided = system.getProvidedServices();
+                       allProvided.addAll(Arrays.asList(provided));
+               }
+       }
+
+       
        @Override
        protected void doStop() {
                for (int i = _systems.length-1; i >= 0; i--) {