From: Erik Brakkee Date: Tue, 15 Apr 2008 21:19:41 +0000 (+0000) Subject: added default container to support classes directly. X-Git-Tag: wamblee-utils-0.7~770 X-Git-Url: http://wamblee.org/gitweb/?a=commitdiff_plain;h=fddbe9b130633c7d8925f2580afea65767d1d615;p=utils added default container to support classes directly. Also added test cases for duplicate components and for adding components that are already part of another hierarchy. --- diff --git a/system/general/src/main/java/org/wamblee/system/adapters/DefaultContainer.java b/system/general/src/main/java/org/wamblee/system/adapters/DefaultContainer.java new file mode 100644 index 00000000..c54206ea --- /dev/null +++ b/system/general/src/main/java/org/wamblee/system/adapters/DefaultContainer.java @@ -0,0 +1,56 @@ +/* + * Copyright 2008 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.adapters; + +import org.wamblee.system.core.Component; +import org.wamblee.system.core.Container; +import org.wamblee.system.core.ProvidedInterface; +import org.wamblee.system.core.RequiredInterface; + +public class DefaultContainer extends Container { + + public DefaultContainer(String aName) { + super(aName); + } + + @Override + public DefaultContainer addComponent(Component aComponent) { + super.addComponent(aComponent); + return this; + } + + public DefaultContainer addComponent(String aName, Class aClass) { + return addComponent(new ClassAdapter(aName, new ClassConfiguration( + aClass))); + } + + public DefaultContainer addComponent(String aName, ClassConfiguration aConfiguration) { + return addComponent(new ClassAdapter(aName, aConfiguration)); + } + + @Override + public DefaultContainer addRequiredInterface(RequiredInterface aRequired) { + super.addRequiredInterface(aRequired); + return this; + } + + @Override + public DefaultContainer addProvidedInterface(ProvidedInterface aProvided) { + super.addProvidedInterface(aProvided); + return this; + } + +} diff --git a/system/general/src/main/java/org/wamblee/system/core/AbstractComponent.java b/system/general/src/main/java/org/wamblee/system/core/AbstractComponent.java index 9608f417..28bb6ff1 100644 --- a/system/general/src/main/java/org/wamblee/system/core/AbstractComponent.java +++ b/system/general/src/main/java/org/wamblee/system/core/AbstractComponent.java @@ -63,12 +63,12 @@ public abstract class AbstractComponent implements Component { this(aName, new ProvidedInterface[0], new RequiredInterface[0]); } - protected AbstractComponent addProvidedInterface(ProvidedInterface aProvided) { + public AbstractComponent addProvidedInterface(ProvidedInterface aProvided) { _provided.add(aProvided); return this; } - protected AbstractComponent addRequiredInterface(RequiredInterface aRequired) { + public AbstractComponent addRequiredInterface(RequiredInterface aRequired) { _required.add(aRequired); return this; } @@ -87,6 +87,7 @@ public abstract class AbstractComponent implements Component { } } + @Override public String getContext() { return _context; } diff --git a/system/general/src/main/java/org/wamblee/system/core/Component.java b/system/general/src/main/java/org/wamblee/system/core/Component.java index d14eb08a..48293d45 100644 --- a/system/general/src/main/java/org/wamblee/system/core/Component.java +++ b/system/general/src/main/java/org/wamblee/system/core/Component.java @@ -42,6 +42,12 @@ public interface Component { */ void addContext(String aContext); + /** + * Getst the context. + * @return Context or null if not set. + */ + String getContext(); + /** * Gets the fully qualified name of the component which includes * the context of the component. 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 a4b0620f..b9056971 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,363 +18,397 @@ package org.wamblee.system.core; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; +import java.util.HashSet; import java.util.Iterator; import java.util.List; +import java.util.Set; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; /** - * Container consisting of multiple components. + * Container consisting of multiple components. * * @author Erik Brakkee */ public class Container extends AbstractComponent { - private static final Log LOG = LogFactory.getLog(Container.class); - - private List _components; - private boolean _sealed; - - public static RequiredInterface[] filterRequiredServices( - ProvidedInterface aProvided, - Collection aDescriptors) { - List required = new ArrayList(); - for (RequiredInterface descriptor : aDescriptors) { - if (descriptor.implementedBy(aProvided)) { - required.add(descriptor); - } - } - return required.toArray(new RequiredInterface[0]); - } - - public static ProvidedInterface[] filterProvidedServices( - RequiredInterface aRequired, Collection aProvided) { - List provided = new ArrayList(); - for (ProvidedInterface descriptor : aProvided) { - if (aRequired.implementedBy(descriptor)) { - provided.add(descriptor); - } - } - return provided.toArray(new ProvidedInterface[0]); - } - - /** - * Constructs the container - * - * @param aName - * Name of the container - * @param aComponents - * Components. - * @param aProvided - * Provided services of the container - * @param aRequired - * Required services by the container. - */ - public Container(String aName, Component[] aComponents, - ProvidedInterface[] aProvided, RequiredInterface[] aRequired) { - super(aName, aProvided, aRequired); - _components = new ArrayList(Arrays.asList(aComponents)); - for (Component component : aComponents) { - component.addContext(getQualifiedName()); - } - _sealed = false; - validate(); - } - - public Container(String aName) { - this(aName, new Component[0], new ProvidedInterface[0], new RequiredInterface[0]); - } - - public Container addComponent(Component aComponent) { - checkSealed(); - _components.add(aComponent); - return this; - } - - @Override - protected Container addProvidedInterface(ProvidedInterface aProvided) { - checkSealed(); - super.addProvidedInterface(aProvided); - return this; - } - - @Override - protected Container addRequiredInterface(RequiredInterface aRequired) { - checkSealed(); - super.addRequiredInterface(aRequired); - return this; - } - - /** - * 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. - * @throws SystemAssemblyException in case of any validation problems. - */ - public void validate() { - List provided = new ArrayList(); - for (Component component : _components) { - provided.addAll(Arrays.asList(component.getProvidedInterfaces())); - } - - List required = new ArrayList(); - for (Component component : _components) { - required.addAll(Arrays.asList(component.getRequiredInterfaces())); - } - - validateProvidedInterfaces(provided); - - 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 aProvided, List aRequired) { - List reallyRequired = new ArrayList( - aRequired); - // Compute all required interfaces that are not provided - - for (ProvidedInterface service : aProvided) { - 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(getRequiredInterfaces())); - return reallyRequired; - } - - private void validateRequiredInterfaces(List aRequired) { - for (RequiredInterface service : getRequiredInterfaces()) { - // TODO required interfaces by the component could be - // subclasses or implementations of the requirements - // of the contained components. The code below assumes - // an exact match. - if (!(aRequired.contains(service))) { - info("Service '" - + service - + "' 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: 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 aProvided) { - 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 (!(aProvided.contains(service))) { - throw new SystemAssemblyException(getName() + ": Service '" - + service - + "' is not provided by any of its components"); - } - } - } - - /** - * 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. - */ - public Scope start() { - checkSealed(); - validate(); - Scope scope = super.start(new DefaultScope(new ProvidedInterface[0])); - seal(); - return scope; - } - - /** - * Seal the container, meaning that no further components or interfaces may be added. - */ - public void seal() { - _sealed = true; - } - - /** - * Checks if the container is sealed. - * @return True iff the container is sealed. - */ - public boolean isSealed() { - return _sealed; - } - - @Override - 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 - // provided to the components inside it. - RequiredInterface[] required = getRequiredInterfaces(); - for (RequiredInterface intf : required) { - ProvidedInterface provider = intf.getProvider(); - if (provider != null ) { - allProvided.add(provider); - } else { - if ( !intf.isOptional()) { - throw new SystemAssemblyException(getQualifiedName() - + ": required interface '" + intf + "' is not provided"); - } - } - } - - List started = new ArrayList(); - for (Component component : _components) { - try { - checkAllRequiredServicesAlreadyProvided(allProvided, component); - - // Start the service. - Object runtime = component.start(scope); - scope.addRuntime(component, runtime); - started.add(component); - - // add all provided services - ProvidedInterface[] provided = component.getProvidedInterfaces(); - allProvided.addAll(Arrays.asList(provided)); - } catch (SystemAssemblyException e) { - throw e; - } catch (RuntimeException e) { - LOG.error(getQualifiedName() + ": could not start '" - + 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(Scope aScope) { - for (int i = _components.size() - 1; i >= 0; i--) { - Component component = _components.get(i); - Object runtime = aScope.getRuntime(component); - component.stop(runtime); - } - } - - private void info(String aMsg) { - LOG.info(getQualifiedName() + ": " + aMsg); - } - - 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: _components) { - for (RequiredInterface required: component.getRequiredInterfaces()) { - if ( required.equals(aRequirement) && required.isOptional() == aRequirement.isOptional()) { - clients.add(component); - } - } - } - return clients; - } - - private void checkSealed() { - if ( _sealed ) { - throw new SystemAssemblyException("Container is sealed"); - } - } + private static final Log LOG = LogFactory.getLog(Container.class); + + private List _components; + private Set _componentNames; + private boolean _sealed; + + public static RequiredInterface[] filterRequiredServices( + ProvidedInterface aProvided, + Collection aDescriptors) { + List required = new ArrayList(); + for (RequiredInterface descriptor : aDescriptors) { + if (descriptor.implementedBy(aProvided)) { + required.add(descriptor); + } + } + return required.toArray(new RequiredInterface[0]); + } + + public static ProvidedInterface[] filterProvidedServices( + RequiredInterface aRequired, Collection aProvided) { + List provided = new ArrayList(); + for (ProvidedInterface descriptor : aProvided) { + if (aRequired.implementedBy(descriptor)) { + provided.add(descriptor); + } + } + return provided.toArray(new ProvidedInterface[0]); + } + + /** + * Constructs the container + * + * @param aName + * Name of the container + * @param aComponents + * Components. + * @param aProvided + * Provided services of the container + * @param aRequired + * Required services by the container. + */ + public Container(String aName, Component[] aComponents, + ProvidedInterface[] aProvided, RequiredInterface[] aRequired) { + super(aName, aProvided, aRequired); + _components = new ArrayList(); + + _componentNames = new HashSet(); + _sealed = false; + for (Component component : aComponents) { + addComponent(component); + } + validate(); + } + + public Container(String aName) { + this(aName, new Component[0], new ProvidedInterface[0], + new RequiredInterface[0]); + } + + public Container addComponent(Component aComponent) { + checkSealed(); + if (aComponent.getContext() != null) { + throw new SystemAssemblyException( + "Inconsistent hierarchy, component '" + + aComponent.getName() + + "' is already part of another hierarchy"); + } + if (_componentNames.contains(aComponent.getName())) { + throw new SystemAssemblyException("Duplicate component '" + + aComponent.getName() + "'"); + } + _components.add(aComponent); + _componentNames.add(aComponent.getName()); + aComponent.addContext(getQualifiedName()); + return this; + } + + @Override + public Container addProvidedInterface(ProvidedInterface aProvided) { + checkSealed(); + super.addProvidedInterface(aProvided); + return this; + } + + @Override + public Container addRequiredInterface(RequiredInterface aRequired) { + checkSealed(); + super.addRequiredInterface(aRequired); + return this; + } + + /** + * 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. + * + * @throws SystemAssemblyException + * in case of any validation problems. + */ + public void validate() { + List provided = new ArrayList(); + for (Component component : _components) { + provided.addAll(Arrays.asList(component.getProvidedInterfaces())); + } + + List required = new ArrayList(); + for (Component component : _components) { + required.addAll(Arrays.asList(component.getRequiredInterfaces())); + } + + validateProvidedInterfaces(provided); + + 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 aProvided, List aRequired) { + List reallyRequired = new ArrayList( + aRequired); + // Compute all required interfaces that are not provided + + for (ProvidedInterface service : aProvided) { + 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(getRequiredInterfaces())); + return reallyRequired; + } + + private void validateRequiredInterfaces(List aRequired) { + for (RequiredInterface service : getRequiredInterfaces()) { + // TODO required interfaces by the component could be + // subclasses or implementations of the requirements + // of the contained components. The code below assumes + // an exact match. + if (!(aRequired.contains(service))) { + info("Service '" + + service + + "' 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 : 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 aProvided) { + 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 (!(aProvided.contains(service))) { + throw new SystemAssemblyException(getName() + ": Service '" + + service + + "' is not provided by any of its components"); + } + } + } + + /** + * 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. + */ + public Scope start() { + checkSealed(); + validate(); + Scope scope = super.start(new DefaultScope(new ProvidedInterface[0])); + seal(); + return scope; + } + + /** + * Seal the container, meaning that no further components or interfaces may + * be added. + */ + public void seal() { + _sealed = true; + } + + /** + * Checks if the container is sealed. + * + * @return True iff the container is sealed. + */ + public boolean isSealed() { + return _sealed; + } + + @Override + 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 + // provided to the components inside it. + RequiredInterface[] required = getRequiredInterfaces(); + for (RequiredInterface intf : required) { + ProvidedInterface provider = intf.getProvider(); + if (provider != null) { + allProvided.add(provider); + } else { + if (!intf.isOptional()) { + throw new SystemAssemblyException(getQualifiedName() + + ": required interface '" + intf + + "' is not provided"); + } + } + } + + List started = new ArrayList(); + for (Component component : _components) { + try { + checkAllRequiredServicesAlreadyProvided(allProvided, component); + + // Start the service. + Object runtime = component.start(scope); + scope.addRuntime(component, runtime); + started.add(component); + + // add all provided services + ProvidedInterface[] provided = component + .getProvidedInterfaces(); + allProvided.addAll(Arrays.asList(provided)); + } catch (SystemAssemblyException e) { + throw e; + } catch (RuntimeException e) { + LOG.error(getQualifiedName() + ": could not start '" + + 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(Scope aScope) { + for (int i = _components.size() - 1; i >= 0; i--) { + Component component = _components.get(i); + Object runtime = aScope.getRuntime(component); + component.stop(runtime); + } + } + + private void info(String aMsg) { + LOG.info(getQualifiedName() + ": " + aMsg); + } + + 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 : _components) { + for (RequiredInterface required : component.getRequiredInterfaces()) { + if (required.equals(aRequirement) + && required.isOptional() == aRequirement.isOptional()) { + clients.add(component); + } + } + } + return clients; + } + + private void checkSealed() { + if (_sealed) { + throw new SystemAssemblyException("Container is sealed"); + } + } } diff --git a/system/general/src/main/java/org/wamblee/system/core/DefaultScope.java b/system/general/src/main/java/org/wamblee/system/core/DefaultScope.java index b57f51f6..5ec26223 100644 --- a/system/general/src/main/java/org/wamblee/system/core/DefaultScope.java +++ b/system/general/src/main/java/org/wamblee/system/core/DefaultScope.java @@ -65,12 +65,17 @@ public class DefaultScope implements Scope { @Override public void addRuntime(Component aComponent, Object aRuntime) { - _runtimes.put(aComponent.getQualifiedName(), aRuntime); + _runtimes.put(aComponent.getName(), aRuntime); } @Override public Object getRuntime(Component aComponent) { - return _runtimes.get(aComponent.getQualifiedName()); + return _runtimes.get(aComponent.getName()); + } + + @Override + public Object getRuntime(String aName) { + return _runtimes.get(aName); } @Override diff --git a/system/general/src/main/java/org/wamblee/system/core/Scope.java b/system/general/src/main/java/org/wamblee/system/core/Scope.java index 9db462f5..ea814da3 100644 --- a/system/general/src/main/java/org/wamblee/system/core/Scope.java +++ b/system/general/src/main/java/org/wamblee/system/core/Scope.java @@ -73,5 +73,13 @@ public interface Scope { * @param aComponent Component for which we want to get the runtime. * @return Runtime. */ - Object getRuntime(Component aComponent); + Object getRuntime(Component aComponent); + + /** + * Gets the runtime for a component based on the name of the component + * (excluding its context). + * @param aName Component name. + * @return Component name. + */ + Object getRuntime(String aName); } diff --git a/system/general/src/test/java/org/wamblee/system/adapters/DefaultContainerTest.java b/system/general/src/test/java/org/wamblee/system/adapters/DefaultContainerTest.java new file mode 100644 index 00000000..913e3970 --- /dev/null +++ b/system/general/src/test/java/org/wamblee/system/adapters/DefaultContainerTest.java @@ -0,0 +1,39 @@ +/* + * Copyright 2008 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.adapters; + +import org.wamblee.system.core.Scope; +import org.wamblee.test.AssertionUtils; + +public class DefaultContainerTest extends AdapterTestCase { + + public void testConstructorInjection() { + ClassConfiguration x1Config = new ClassConfiguration(X1.class); + x1Config.getConstructorConfig().getParameters().setValue(0, "hello"); + + DefaultContainer container = new DefaultContainer("top").addComponent( + "x1", x1Config).addComponent("x4", X4.class); + + Scope scope = container.start(); + AssertionUtils.assertEquals(new String[] { "x1(hello)", "x4(x1)" }, + EVENT_TRACKER.getEvents(Thread.currentThread()).toArray()); + + Object obj = scope.getRuntime("x1"); + assertTrue(obj instanceof X1); + obj = scope.getRuntime("x4"); + assertTrue(obj instanceof X4); + } +} diff --git a/system/general/src/test/java/org/wamblee/system/core/Application.java b/system/general/src/test/java/org/wamblee/system/core/Application.java index d1302f58..c162bb04 100644 --- a/system/general/src/test/java/org/wamblee/system/core/Application.java +++ b/system/general/src/test/java/org/wamblee/system/core/Application.java @@ -42,6 +42,11 @@ public class Application extends AbstractComponent { _random = Math.random(); } + public Application(String aName) { + super(aName, new ProvidedInterface[0], required(false)); + _random = Math.random(); + } + public Application(boolean aIsOptinal) { super("application", new ProvidedInterface[0], required(true)); } diff --git a/system/general/src/test/java/org/wamblee/system/core/ContainerTest.java b/system/general/src/test/java/org/wamblee/system/core/ContainerTest.java index 7eb66757..8b6c61e8 100644 --- a/system/general/src/test/java/org/wamblee/system/core/ContainerTest.java +++ b/system/general/src/test/java/org/wamblee/system/core/ContainerTest.java @@ -215,6 +215,30 @@ public class ContainerTest extends TestCase { fail(); } + + public void testDuplicateComponent() { + try { + Component comp1 = new Application(); + Component comp2 = new Application(); + Container system = new Container("top"); + system.addComponent(comp1).addComponent(comp2); + } catch (SystemAssemblyException e) { + return; + } + fail(); + } + + + public void testInconsistentHierarchy() { + try { + Component comp = new Application(); + Container system = new Container("top").addComponent(comp); + Container system2 = new Container("top2").addComponent(comp); + } catch (SystemAssemblyException e) { + return; + } + fail(); + } public void testCompositeWithExternalDependencesProvided() { @@ -309,7 +333,7 @@ public class ContainerTest extends TestCase { // application 2 will throw an exception while starting Application application2 = control.createMock(Application.class, - new ConstructorArgs(Application.class.getConstructor()), + new ConstructorArgs(Application.class.getConstructor(String.class), "application2"), Application.class.getDeclaredMethod("doStart", Scope.class)); application2.doStart(EasyMockMatchers.anyObject(Scope.class));