X-Git-Url: http://wamblee.org/gitweb/?a=blobdiff_plain;ds=sidebyside;f=system%2Fgeneral%2Fsrc%2Fmain%2Fjava%2Forg%2Fwamblee%2Fsystem%2Fcore%2FContainer.java;h=d117da95462055d1bfe2a0d703cc1e4551805be2;hb=233af25ef5109b768f4fe1099241047fb51e671f;hp=a0130f7cf3420094198d72b616f3b281a1973987;hpb=9a87e60f9f7be0bb7166c03f9fc8bce8f8bbec41;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 a0130f7c..d117da95 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 @@ -185,38 +185,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. @@ -233,16 +237,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>(); @@ -256,8 +282,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); } @@ -272,11 +298,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(