X-Git-Url: http://wamblee.org/gitweb/?a=blobdiff_plain;f=system%2Fgeneral%2Fsrc%2Fmain%2Fjava%2Forg%2Fwamblee%2Fsystem%2Fcore%2FContainer.java;h=81dcb6a2c95bc106ce2195e384eb7c521d07b5c6;hb=d26bc47d9b0d293ae3d2bd38975f24310fc9be6e;hp=8436ebca4174ba7090966756a5b6b2e5b8923ea5;hpb=6529b7c64ced21f376ea35f764cb0e5f14cd2e7d;p=utils diff --git a/system/general/src/main/java/org/wamblee/system/core/Container.java b/system/general/src/main/java/org/wamblee/system/core/Container.java index 8436ebca..81dcb6a2 100644 --- a/system/general/src/main/java/org/wamblee/system/core/Container.java +++ b/system/general/src/main/java/org/wamblee/system/core/Container.java @@ -18,6 +18,7 @@ package org.wamblee.system.core; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; +import java.util.Iterator; import java.util.List; import org.apache.commons.logging.Log; @@ -78,7 +79,7 @@ public class Container extends AbstractComponent { for (Component component : aSystems) { component.addContext(getQualifiedName()); } - validate(aRequired); + validate(); } /** @@ -87,7 +88,7 @@ public class Container extends AbstractComponent { * that cannot be provided. Also logs a warning in case of superfluous * requirements. */ - private void validate(RequiredInterface[] aRequired) { + private void validate() { List provided = new ArrayList(); for (Component system : _systems) { provided.addAll(Arrays.asList(system.getProvidedInterfaces())); @@ -98,79 +99,105 @@ public class Container extends AbstractComponent { required.addAll(Arrays.asList(system.getRequiredInterfaces())); } - for (ProvidedInterface service : getProvidedInterfaces()) { - if (!(provided.contains(service))) { - throw new SystemAssemblyException(getName() + ": Service '" - + service - + "' is not provided by any of the subsystems"); - } - } + validateProvidedInterfaces(provided); - for (RequiredInterface service : getRequiredInterfaces()) { - if (!(required.contains(service))) { - info("Service '" - + service - + "' indicated as required is not actually required by any of the subsystems"); - } + validateRequiredInterfaces(required); + + List reallyRequired = validateRequiredProvidedMatch( + provided, required); + + String missingRequired = ""; + for (RequiredInterface service : reallyRequired) { + missingRequired += service + "\n"; + } + if (missingRequired.length() > 0) { + throw new SystemAssemblyException(getName() + + ": missing required services\n" + missingRequired); } + } + private List validateRequiredProvidedMatch( + List provided, List required) { List reallyRequired = new ArrayList( required); // Compute all required interfaces that are not provided + for (ProvidedInterface service : provided) { List fulfilled = Arrays .asList(filterRequiredServices(service, reallyRequired)); reallyRequired.removeAll(fulfilled); } + // Now remove all optional interfaces from the list. + for (Iterator i = + reallyRequired.iterator(); i.hasNext(); ) { + RequiredInterface req = i.next(); + if ( req.isOptional() ) { + i.remove(); + } + } // Now the remaining interfaces should be covered by the required // list. - reallyRequired.removeAll(Arrays.asList(aRequired)); + reallyRequired.removeAll(Arrays.asList(getRequiredInterfaces())); + return reallyRequired; + } - String missingRequired = ""; - for (RequiredInterface service : reallyRequired) { - missingRequired += service + "\n"; + private void validateRequiredInterfaces(List required) { + for (RequiredInterface service : getRequiredInterfaces()) { + // TODO required services by the subsystem could be + // subclasses or implementations of the requirements + // of the contained systems. The code below assumes + // an exact match. + if (!(required.contains(service))) { + info("Service '" + + service + + "' indicated as required is not actually required by any of the subsystems"); + } + // Check for the case that the externally required service + // is optional whereas the internally required service is + // mandatory. + if ( service.isOptional()) { + for (RequiredInterface intf: required) { + if ( intf.equals(service) && !intf.isOptional()) { + // TODO indicate which subsystem this is. + warn("Required service '" + service + "' indicated as optional is mandatory by one of its subsystems (" + getClients(intf) + ", " + intf + "), this can lead to problems when the system is started and the service is not there."); + } + } + } } - if (missingRequired.length() > 0) { - throw new SystemAssemblyException(getName() - + ": missing required services\n" + missingRequired); + } + + private void validateProvidedInterfaces(List provided) { + for (ProvidedInterface service : getProvidedInterfaces()) { + // TODO provided interfaces by subsystems could be + // provide subclasses or implementations of the + // provided interfaces of the container. + // The code below assumes an exact match. + if (!(provided.contains(service))) { + throw new SystemAssemblyException(getName() + ": Service '" + + service + + "' is not provided by any of the subsystems"); + } } } @Override protected void doStart() { - List provided = new ArrayList(); + LOG.info("Starting '" + getQualifiedName() + "'"); + List allProvided = new ArrayList(); // all interfaces from the required list of this container are // provided to the components inside it. RequiredInterface[] required = getRequiredInterfaces(); for (RequiredInterface intf : required) { ProvidedInterface provider = intf.getProvider(); - if (provider == null) { - throw new SystemAssemblyException(getQualifiedName() - + ": required interface '" + intf + "' is not provided"); + if (provider != null ) { + allProvided.add(provider); + } else { + if ( !intf.isOptional()) { + throw new SystemAssemblyException(getQualifiedName() + + ": required interface '" + intf + "' is not provided"); + } } - provided.add(intf.getProvider()); - } - - 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 allProvided = new ArrayList(); - - // Add the provides of all externally required interfaces to the list of - // available - // interfaces - for (RequiredInterface required : getRequiredInterfaces()) { - allProvided.add(required.getProvider()); } List started = new ArrayList(); @@ -179,21 +206,13 @@ public class Container extends AbstractComponent { // Check if all required services are already provided by // earlier // systems. - RequiredInterface[] required = system.getRequiredInterfaces(); - for (RequiredInterface descriptor : required) { + for (RequiredInterface descriptor : system.getRequiredInterfaces()) { 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) { + if ( filtered.length == 1 ) { + descriptor.setProvider(filtered[0]); + } else if ( filtered.length > 1 ) { throw new SystemAssemblyException( "Service '" + descriptor @@ -201,8 +220,17 @@ public class Container extends AbstractComponent { + system + "' matches multiple services provided by other systems: " + Arrays.asList(filtered)); + } else { + // filtered.length == 0 + if ( !descriptor.isOptional()) { + throw new SystemAssemblyException( + "Service '" + + descriptor + + "' required by system '" + + system + + "' is not provided by systems that are started earlier"); + } } - descriptor.setProvider(filtered[0]); } // Start the service. @@ -241,7 +269,22 @@ public class Container extends AbstractComponent { } private void info(String aMsg) { - LOG.info(getName() + ": " + aMsg); + LOG.info(getQualifiedName() + ": " + aMsg); + } + + private void warn(String aMsg) { + LOG.warn(getQualifiedName() + ": " + aMsg); } + private List getClients(RequiredInterface aRequirement) { + List clients = new ArrayList(); + for (Component component: _systems) { + for (RequiredInterface required: component.getRequiredInterfaces()) { + if ( required.equals(aRequirement) && required.isOptional() == aRequirement.isOptional()) { + clients.add(component); + } + } + } + return clients; + } }