X-Git-Url: http://wamblee.org/gitweb/?a=blobdiff_plain;f=system%2Fgeneral%2Fsrc%2Fmain%2Fjava%2Forg%2Fwamblee%2Fsystem%2Fcore%2FContainer.java;h=f1b8b1ec0380fe4204f7f2021dd97c9bf8e53de9;hb=dea786c9d49228a37cb5fd5b4113b86d9f6cddbf;hp=81dcb6a2c95bc106ce2195e384eb7c521d07b5c6;hpb=971e905b3afccdf5b17e9303cee353a33a6db030;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 81dcb6a2..f1b8b1ec 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 @@ -25,15 +25,15 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; /** - * Composite system consisting of multiple subsystems. + * Container consisting of multiple components. * * @author Erik Brakkee */ -public class Container extends AbstractComponent { +public class Container extends AbstractComponent { private static final Log LOG = LogFactory.getLog(Container.class); - private Component[] _systems; + private Component[] _components; public static RequiredInterface[] filterRequiredServices( ProvidedInterface aProvided, @@ -59,44 +59,42 @@ public class Container extends AbstractComponent { } /** - * Construcst the composite system. + * Construcst the container * * @param aName - * Name of the system. - * @param aRegistry - * Service registry. - * @param aSystems - * Subsystems. + * Name of the container + * @param aComponents + * Components. * @param aProvided - * Provided services of the system. + * Provided services of the container * @param aRequired - * Required services by the system. + * Required services by the container. */ - public Container(String aName, Component[] aSystems, + public Container(String aName, Component[] aComponents, ProvidedInterface[] aProvided, RequiredInterface[] aRequired) { super(aName, aProvided, aRequired); - _systems = aSystems; - for (Component component : aSystems) { + _components = aComponents; + for (Component component : aComponents) { component.addContext(getQualifiedName()); } validate(); } /** - * Validates the subsystems together to check that there are no required + * Validates the components together to check that there are no required * services not in the required list and no services in the provided list * that cannot be provided. Also logs a warning in case of superfluous * requirements. */ private void validate() { List provided = new ArrayList(); - for (Component system : _systems) { - provided.addAll(Arrays.asList(system.getProvidedInterfaces())); + for (Component component : _components) { + provided.addAll(Arrays.asList(component.getProvidedInterfaces())); } List required = new ArrayList(); - for (Component system : _systems) { - required.addAll(Arrays.asList(system.getRequiredInterfaces())); + for (Component component : _components) { + required.addAll(Arrays.asList(component.getRequiredInterfaces())); } validateProvidedInterfaces(provided); @@ -117,12 +115,12 @@ public class Container extends AbstractComponent { } private List validateRequiredProvidedMatch( - List provided, List required) { + List aProvided, List aRequired) { List reallyRequired = new ArrayList( - required); + aRequired); // Compute all required interfaces that are not provided - for (ProvidedInterface service : provided) { + for (ProvidedInterface service : aProvided) { List fulfilled = Arrays .asList(filterRequiredServices(service, reallyRequired)); reallyRequired.removeAll(fulfilled); @@ -141,48 +139,55 @@ public class Container extends AbstractComponent { return reallyRequired; } - private void validateRequiredInterfaces(List required) { + private void validateRequiredInterfaces(List aRequired) { for (RequiredInterface service : getRequiredInterfaces()) { - // TODO required services by the subsystem could be + // TODO required interfaces by the component could be // subclasses or implementations of the requirements - // of the contained systems. The code below assumes + // of the contained components. The code below assumes // an exact match. - if (!(required.contains(service))) { + if (!(aRequired.contains(service))) { info("Service '" + service - + "' indicated as required is not actually required by any of the subsystems"); + + "' indicated as required is not actually required by any of the components"); } // 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."); + for (RequiredInterface intf: aRequired) { + if ( intf.equals(service) && !intf.isOptional()) { + warn("Required service '" + service + "' indicated as optional is mandatory by one of its components (" + getClients(intf) + ", " + intf + "), this can lead to problems when the container is started and the interface is not provided to the container."); } } } } } - private void validateProvidedInterfaces(List provided) { + private void validateProvidedInterfaces(List aProvided) { for (ProvidedInterface service : getProvidedInterfaces()) { - // TODO provided interfaces by subsystems could be + // TODO provided interfaces by components could be // provide subclasses or implementations of the // provided interfaces of the container. // The code below assumes an exact match. - if (!(provided.contains(service))) { + if (!(aProvided.contains(service))) { throw new SystemAssemblyException(getName() + ": Service '" + service - + "' is not provided by any of the subsystems"); + + "' is not provided by any of its components"); } } } + + public Scope start() { + return super.start(new DefaultScope(new ProvidedInterface[0])); + } @Override - protected void doStart() { + protected Scope doStart(Scope aExternalScope) { LOG.info("Starting '" + getQualifiedName() + "'"); + + Scope scope = new DefaultScope(getProvidedInterfaces(), + aExternalScope); + List allProvided = new ArrayList(); // all interfaces from the required list of this container are @@ -201,70 +206,82 @@ public class Container extends AbstractComponent { } List started = new ArrayList(); - for (Component system : _systems) { + for (Component component : _components) { try { - // Check if all required services are already provided by - // earlier - // systems. - - for (RequiredInterface descriptor : system.getRequiredInterfaces()) { - ProvidedInterface[] filtered = filterProvidedServices( - descriptor, allProvided); - if ( filtered.length == 1 ) { - descriptor.setProvider(filtered[0]); - } else if ( filtered.length > 1 ) { - throw new SystemAssemblyException( - "Service '" - + descriptor - + "' required by system '" - + 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"); - } - } - } + checkAllRequiredServicesAlreadyProvided(allProvided, component); // Start the service. - system.start(); - started.add(system); + Object runtime = component.start(scope); + scope.addRuntime(component, runtime); + started.add(component); // add all provided services - ProvidedInterface[] provided = system.getProvidedInterfaces(); + ProvidedInterface[] provided = component.getProvidedInterfaces(); allProvided.addAll(Arrays.asList(provided)); } catch (SystemAssemblyException e) { throw e; } catch (RuntimeException e) { LOG.error(getQualifiedName() + ": could not start '" - + system.getQualifiedName() + "'", e); - // an exception occurred, stop the successfully started - // systems - for (int i = started.size() - 1; i >= 0; i--) { - try { - started.get(i).stop(); - } catch (Throwable t) { - LOG.error(getQualifiedName() + ": error stopping " - + started.get(i).getQualifiedName()); - } - } + + component.getQualifiedName() + "'", e); + stopAlreadyStartedComponents(started, scope); throw e; } } + return scope; + } + + private void stopAlreadyStartedComponents(List aStarted, Scope aScope) { + // an exception occurred, stop the successfully started + // components + for (int i = aStarted.size() - 1; i >= 0; i--) { + try { + aStarted.get(i).stop(aScope); + } catch (Throwable t) { + LOG.error(getQualifiedName() + ": error stopping " + + aStarted.get(i).getQualifiedName()); + } + } + } + private void checkAllRequiredServicesAlreadyProvided( + List aAllProvided, Component aComponent) { + // Check if all required services are already provided by + // earlier + // systems. + + for (RequiredInterface descriptor : aComponent.getRequiredInterfaces()) { + ProvidedInterface[] filtered = filterProvidedServices( + descriptor, aAllProvided); + if ( filtered.length == 1 ) { + descriptor.setProvider(filtered[0]); + } else if ( filtered.length > 1 ) { + throw new SystemAssemblyException( + "Service '" + + descriptor + + "' required by system '" + + aComponent + + "' matches multiple services provided by other systems: " + + getServers(filtered)); + } else { + // filtered.length == 0 + if ( !descriptor.isOptional()) { + throw new SystemAssemblyException( + "Service '" + + descriptor + + "' required by system '" + + aComponent + + "' is not provided by systems that are started earlier"); + } + } + } } @Override - protected void doStop() { - for (int i = _systems.length - 1; i >= 0; i--) { - _systems[i].stop(); + protected void doStop(Scope aScope) { + for (int i = _components.length - 1; i >= 0; i--) { + Component component = _components[i]; + Object runtime = aScope.getRuntime(component); + component.stop(runtime); } } @@ -275,10 +292,26 @@ public class Container extends AbstractComponent { private void warn(String aMsg) { LOG.warn(getQualifiedName() + ": " + aMsg); } + + private String getServers(ProvidedInterface[] aProvidedList ) { + String result = ""; + for (ProvidedInterface provided: aProvidedList) { + result += "(components "; + for (Component component: _components) { + for (ProvidedInterface provided2: component.getProvidedInterfaces()) { + if ( provided.equals(provided2)) { + result += component + " "; + } + } + } + result += ", interface " + provided + ")"; + } + return result; + } private List getClients(RequiredInterface aRequirement) { List clients = new ArrayList(); - for (Component component: _systems) { + for (Component component: _components) { for (RequiredInterface required: component.getRequiredInterfaces()) { if ( required.equals(aRequirement) && required.isOptional() == aRequirement.isOptional()) { clients.add(component);