X-Git-Url: http://wamblee.org/gitweb/?a=blobdiff_plain;f=system%2Fgeneral%2Fsrc%2Fmain%2Fjava%2Forg%2Fwamblee%2Fsystem%2Fcore%2FContainer.java;h=1a3e9911cccc80b0ae47a3b3890711bb5bcaeda5;hb=756145743d46d1cf4e4e32c03a32526aa059f1e1;hp=8075abab3c7fcc703b5cbcdc9a22c2e105a58096;hpb=2f12e7060f56e12189f407f309c1d8fb3be93af8;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 8075abab..1a3e9911 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,6 +25,8 @@ import java.util.Set; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.wamblee.collections.CollectionFilter; +import org.wamblee.conditions.Condition; import org.wamblee.general.Pair; /** @@ -40,9 +42,8 @@ public class Container extends AbstractComponent { private Set _componentNames; private CompositeInterfaceRestriction _restriction; private boolean _sealed; - - - public static ProvidedInterface[] filterProvidedServices( + + static ProvidedInterface[] filterProvidedServices( Component aClient, RequiredInterface aRequired, Collection> aProvided, InterfaceRestriction aRestriction) { List result = new ArrayList(); @@ -130,6 +131,14 @@ public class Container extends AbstractComponent { super.addRequiredInterface(aRequired); return this; } + + @Override + public void addContext(String aContext) { + super.addContext(aContext); + for (Component component: _components) { + component.addContext(aContext); + } + } /** * Validates the components together to check that there are no required @@ -184,38 +193,42 @@ public class Container extends AbstractComponent { } private void validateProvidedInterfacesArePresent() { - List provided = new ArrayList(); - for (Component component : _components) { - provided.addAll(Arrays.asList(component.getProvidedInterfaces())); - } for (ProvidedInterface service : getProvidedInterfaces()) { - // 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))) { - throw new SystemAssemblyException(getName() + ": Service '" - + service - + "' is not provided by any of its components"); - } + findProvidedInterface(service); } } - + /** - * Starts the container. After the container is started, the container - * becomes sealed meaning that no further components, required or provided - * interfaces may be added. - * - * @return Scope. + * Finds the component and provided interface that matches a provided interface of this + * container. + * @param aProvided Interface to provide externally. + * @return Pair of component and provided interface + * @throws SystemAssemblyException In case there are multiple matches or no match at all. */ - public Scope start() { - checkSealed(); - validate(); - Scope scope = super.start(new DefaultScope(new ProvidedInterface[0])); - seal(); - return scope; + private Pair findProvidedInterface(ProvidedInterface aProvided) { + List> result = + new ArrayList>(); + for (Component component: _components) { + for (ProvidedInterface provided: component.getProvidedInterfaces()) { + if ( aProvided.equals(provided) ) { + result.add(new Pair(component, provided)); + } + } + } + if ( result.size() == 0) { + throw new SystemAssemblyException(getQualifiedName() + ": Service '" + + aProvided + + "' is not provided by any of its components"); + } + if ( result.size() > 1) { + throw new SystemAssemblyException(getQualifiedName() + ": Service '" + + aProvided + + "' is provided by multiple components: " + result); + } + return result.get(0); } + /** * Seal the container, meaning that no further components or interfaces may * be added. @@ -232,16 +245,38 @@ public class Container extends AbstractComponent { public boolean isSealed() { return _sealed; } + + /** + * Utility method to start with an empty external scope. This is useful for + * top-level containers which are not part of another container. + * @return Scope. + */ + public Scope start() { + Scope scope = new DefaultScope(getProvidedInterfaces()); + return super.start(scope); + } @Override protected Scope doStart(Scope aExternalScope) { - return doStartOptionalDryRun(aExternalScope, false); + checkSealed(); + validate(); + Scope scope = new DefaultScope(getProvidedInterfaces(), aExternalScope); + doStartOptionalDryRun(scope, false); + exposeProvidedInterfaces(aExternalScope, scope); + seal(); + return scope; } - private Scope doStartOptionalDryRun(Scope aExternalScope, boolean aDryRun) { - LOG.info("Starting '" + getQualifiedName() + "'"); + private void exposeProvidedInterfaces(Scope aExternalScope, Scope aInternalScope) { + for (ProvidedInterface intf: getProvidedInterfaces()) { + Pair found = findProvidedInterface(intf); + Object svc = aInternalScope.getInterfaceImplementation(found.getSecond(), Object.class); + addInterface(intf, svc, aExternalScope); + } + } - Scope scope = new DefaultScope(getProvidedInterfaces(), aExternalScope); + private void doStartOptionalDryRun(Scope aScope, boolean aDryRun) { + LOG.info("Starting '" + getQualifiedName() + "'"); List> allProvided = new ArrayList>(); @@ -255,8 +290,8 @@ public class Container extends AbstractComponent { // Start the service. if (!aDryRun) { - Object runtime = component.start(scope); - scope.addRuntime(component, runtime); + Object runtime = component.start(aScope); + aScope.addRuntime(component, runtime); started.add(component); } @@ -271,11 +306,10 @@ public class Container extends AbstractComponent { } catch (RuntimeException e) { LOG.error(getQualifiedName() + ": could not start '" + component.getQualifiedName() + "'", e); - stopAlreadyStartedComponents(started, scope); + stopAlreadyStartedComponents(started, aScope); throw e; } } - return scope; } private void addProvidersOfRequiredInterfaces(