From: erik <erik@77661180-640e-0410-b3a8-9f9b13e6d0e0>
Date: Sun, 8 Jun 2008 11:57:23 +0000 (+0000)
Subject: all connect calls are now validated.
X-Git-Tag: wamblee-utils-0.2~1^2~80
X-Git-Url: http://wamblee.org/gitweb/?a=commitdiff_plain;h=4203992c65517e32656c1764fa0291e1e8340859;p=utils

all connect calls are now validated.
---

diff --git a/system/general/src/main/java/org/wamblee/system/container/Container.java b/system/general/src/main/java/org/wamblee/system/container/Container.java
index e4466d4a..d86ec1ce 100644
--- a/system/general/src/main/java/org/wamblee/system/container/Container.java
+++ b/system/general/src/main/java/org/wamblee/system/container/Container.java
@@ -184,7 +184,26 @@ public class Container extends AbstractComponent<Scope> {
     
     public void connectExternalProvided(String aExternalProvided, String aComponent, String aProvidedInterface) {
         checkSealed();
-        // TODO validate
+        Component server = findComponent(aComponent);
+       
+      
+        if ( server == null ) { 
+        	throw new SystemAssemblyException("No component '" + aComponent + "' in the container");
+        }
+        if ( aProvidedInterface != null ) { 
+        	if ( findInterface(server.getProvidedInterfaces(), aProvidedInterface) == null) { 
+        		throw new SystemAssemblyException(
+        				getQualifiedName() + ": Component '" + aComponent + "' does not have a provided interface named '" 
+        				+ aProvidedInterface + "'");
+        	}
+        }
+        if ( aExternalProvided != null ) { 
+        	if ( findInterface(getProvidedInterfaces(), aExternalProvided) == null) { 
+        		throw new SystemAssemblyException(
+        				getQualifiedName() + ": Container does not have a provided interface named '" 
+        				+ aExternalProvided + "'");
+        	}
+        }
         _edgeFilter.add(new ConnectExternalProvidedProvidedFilter(aExternalProvided, aComponent, aProvidedInterface));
     }
 
diff --git a/system/general/src/test/java/org/wamblee/system/container/ContainerTest.java b/system/general/src/test/java/org/wamblee/system/container/ContainerTest.java
index f6786388..e61c023c 100644
--- a/system/general/src/test/java/org/wamblee/system/container/ContainerTest.java
+++ b/system/general/src/test/java/org/wamblee/system/container/ContainerTest.java
@@ -41,668 +41,717 @@ import org.wamblee.test.EventTracker;
 
 public class ContainerTest extends TestCase {
 
-    private EventTracker<String> _tracker;
-
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        _tracker = new EventTracker<String>();
-    }
-
-    private static class MyMultiple implements Serializable, Runnable {
-        @Override
-        public void run() {
-            // Empty
-        }
-    }
-
-    private List<Pair<ProvidedInterface, Component>> createProvidedInput(
-            ProvidedInterface[] aProvided, Component aProvider) {
-        List<Pair<ProvidedInterface, Component>> result = new ArrayList<Pair<ProvidedInterface, Component>>();
-        for (ProvidedInterface provided : aProvided) {
-            result.add(new Pair<ProvidedInterface, Component>(provided,
-                    aProvider));
-        }
-        return result;
-    }
-
-    public void testEnvironmentApplication() {
-        Environment environment = new Environment(_tracker);
-        Application application = new Application(_tracker);
-        Container container = new Container("root", new Component[] {
-                environment, application }, new ProvidedInterface[0],
-                new RequiredInterface[0]);
-        Scope scope = container.start();
-        assertTrue(container.isSealed());
-        AssertionUtils.assertEquals(new String[] { "start.environment",
-                "start.application" }, _tracker.getEvents(
-                Thread.currentThread()).toArray(new String[0]));
-        assertEquals(0, scope.getProvidedInterfaces().size());
-
-        assertEquals(environment.getString(), application.getString());
-        assertEquals(environment.getInteger(), application.getInteger());
-
-    }
-
-    public void testEnvironmentApplicationSimpleConstructor() {
-        Environment environment = new Environment(_tracker);
-        Application application = new Application(_tracker);
-        Container container = new Container("root").addComponent(environment)
-                .addComponent(application);
-
-        Scope scope = container.start();
-        AssertionUtils.assertEquals(new String[] { "start.environment",
-                "start.application" }, _tracker.getEvents(
-                Thread.currentThread()).toArray(new String[0]));
-        assertEquals(0, scope.getProvidedInterfaces().size());
-
-        assertEquals(environment.getString(), application.getString());
-        assertEquals(environment.getInteger(), application.getInteger());
-
-    }
-
-    public void testApplicationEnvironment() {
-        try {
-            Component<?> environment = new Environment();
-            Component<?> application = new Application();
-            Container container = new Container("root", new Component[] {
-                    application, environment }, new ProvidedInterface[0],
-                    new RequiredInterface[0]);
-            container.start();
-        } catch (SystemAssemblyException e) {
-            // e.printStackTrace();
-            return;
-        }
-        fail();
-    }
-
-    public void testComposite() {
-        Component<?> environment = new Environment(_tracker);
-        Component<?> application = new Application(_tracker);
-        assertEquals(0, _tracker.getEventCount());
-
-        Container system = new Container("all", new Component[] { environment,
-                application }, new ProvidedInterface[0],
-                new RequiredInterface[0]);
-        Scope runtime = system.start();
-        List<RequiredInterface> required = system.getRequiredInterfaces();
-        assertEquals(0, required.size());
-        List<ProvidedInterface> provided = system.getProvidedInterfaces();
-        assertEquals(0, provided.size());
-
-        AssertionUtils.assertEquals(new String[] { "start.environment",
-                "start.application" }, _tracker.getEvents(
-                Thread.currentThread()).toArray(new String[0]));
-        _tracker.clear();
-
-        system.stop(runtime);
-        AssertionUtils.assertEquals(new String[] { "stop.application",
-                "stop.environment" }, _tracker
-                .getEvents(Thread.currentThread()).toArray(new String[0]));
-
-    }
-
-    public void testCompositeWithWrongProvidedInfo() {
-        try {
-            Component<?> environment = new Environment();
-            Component<?> application = new Application();
-            Container system = new Container("all", new Component[] {
-                    environment, application },
-                    new ProvidedInterface[] { new DefaultProvidedInterface(
-                            "float", Float.class) },
-                    new DefaultRequiredInterface[0]);
-            system.validate();
-        } catch (SystemAssemblyException e) {
-            return;
-        }
-        fail();
-    }
-
-    public void testCompositeRequiredInterfaceNotProvided() {
-        try {
-            Component<?> environment = new Environment();
-            Component<?> application = new Application();
-            Container system = new Container("all", new Component[] {
-                    environment, application }, new ProvidedInterface[0],
-                    new RequiredInterface[] { new DefaultRequiredInterface(
-                            "string", String.class) });
-            system.start();
-        } catch (SystemAssemblyException e) {
-            return;
-        }
-        fail();
-    }
-
-    public void testCompositeWithSuperfluousRequiredInfo() {
-        Component<?> environment = new Environment();
-        Component<?> application = new Application();
-        Container system = new Container("all", new Component[] { environment,
-                application }, new ProvidedInterface[0],
-                new RequiredInterface[] { new DefaultRequiredInterface("float",
-                        Float.class) });
-        system.getRequiredInterfaces().get(0)
-                .setProvider(new DefaultProvidedInterface("hallo", Float.class));
-        system.start();
-        List<RequiredInterface> required = system.getRequiredInterfaces();
-        assertEquals(1, required.size());
-        List<ProvidedInterface> provided = system.getProvidedInterfaces();
-        assertEquals(0, provided.size());
-    }
-
-    public void testCompositeWithExternalDependencesNotProvided() {
-        try {
-            Component<?> application = new Application();
-           
-            Container system = new Container("all",
-                    new Component[] { application }, new ProvidedInterface[0],
-                    application.getRequiredInterfaces().toArray(new RequiredInterface[0]));
-            system.start();
-        } catch (SystemAssemblyException e) {
-            return;
-        }
-        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() {
-
-        Component<?> environment = new Environment();
-        Component<?> application = new Application();
-        Container system = new Container("all",
-                new Component[] { application }, new ProvidedInterface[0],
-                application.getRequiredInterfaces().toArray(new RequiredInterface[0]));
-        environment.start(new DefaultScope(new ProvidedInterface[0]));
-        system.getRequiredInterfaces().get(0).setProvider(environment
-                .getProvidedInterfaces().get(0));
-        system.getRequiredInterfaces().get(1).setProvider(environment
-                .getProvidedInterfaces().get(1));
-
-        system.start();
-        List<RequiredInterface> required = system.getRequiredInterfaces();
-        assertEquals(2, required.size());
-        List<ProvidedInterface> provided = system.getProvidedInterfaces();
-        assertEquals(0, provided.size());
-
-    }
-
-    public void testAmbiguousInterfaces() {
-        try {
-            Component<?> environment1 = new Environment();
-            Component<?> environment2 = new Environment();
-            Component<?> application = new Application();
-            Container container = new Container("root", new Component[] {
-                    environment1, environment2, application },
-                    new ProvidedInterface[0], new RequiredInterface[0]);
-            container.start();
-
-        } catch (SystemAssemblyException e) {
-            return;
-        }
-        fail();
-    }
-
-    public void testIncompleteRequirements() {
-        try {
-            Component<?> application = new Application();
-            Container system = new Container("all",
-                    new Component[] { application }, new ProvidedInterface[0],
-                    new RequiredInterface[0]);
-            system.start();
-        } catch (SystemAssemblyException e) {
-            return;
-        }
-        fail();
-    }
-
-    public void testEnvironmentApplicationRollbackOnException()
-            throws Exception {
-        IMocksControl control = EasyMock.createStrictControl();
-
-        Environment environment = new Environment(_tracker);
-        Application application = control.createMock(Application.class,
-                new ConstructorArgs(Application.class.getConstructor()),
-                Application.class.getDeclaredMethod("doStart", Scope.class));
-
-        application.doStart(EasyMockMatchers.anyObject(Scope.class));
-        EasyMock.expectLastCall().andThrow(new RuntimeException());
-        control.replay();
-
-        try {
-            Container container = new Container("root", new Component[] {
-                    environment, application }, new ProvidedInterface[0],
-                    new RequiredInterface[0]);
-
-            container.start();
-        } catch (RuntimeException e) {
-            AssertionUtils.assertEquals(new String[] { "start.environment",
-                    "stop.environment" }, _tracker.getEvents(
-                    Thread.currentThread()).toArray(new String[0]));
-            return;
-        }
-        fail();
-    }
-
-    public void testEnvironmentApplicationRollbackOnExceptionWithExceptionOnStop()
-            throws Exception {
-        IMocksControl control = EasyMock.createControl();
-
-        Environment environment = new Environment(_tracker);
-        // Application 1 will throw an exception while stopping.
-        Application application1 = control.createMock(Application.class,
-                new ConstructorArgs(Application.class.getConstructor()),
-                Application.class.getDeclaredMethod("doStop", Object.class));
-
-        application1.doStop(EasyMock.anyObject());
-        EasyMock.expectLastCall().andThrow(new RuntimeException());
-
-        // application 2 will throw an exception while starting
-        Application application2 = control.createMock(Application.class,
-                new ConstructorArgs(Application.class
-                        .getConstructor(String.class), "application2"),
-                Application.class.getDeclaredMethod("doStart", Scope.class));
-
-        application2.doStart(EasyMockMatchers.anyObject(Scope.class));
-        EasyMock.expectLastCall().andThrow(new RuntimeException());
-
-        control.replay();
-
-        try {
-            Container container = new Container("root", new Component[] {
-                    environment, application1, application2 },
-                    new ProvidedInterface[0], new RequiredInterface[0]);
-
-            container.start();
-        } catch (RuntimeException e) {
-            AssertionUtils.assertEquals(new String[] { "start.environment",
-                    "stop.environment" }, _tracker.getEvents(
-                    Thread.currentThread()).toArray(new String[0]));
-            return;
-        }
-        fail();
-    }
-
-    public void testOptionalRequiredInterfaceProvidedOptionalInternal() {
-        Application application = new Application(true);
-        Container container = new Container("top",
-                new Component[] { application }, new ProvidedInterface[0],
-                Application.required(true));
-        Environment env = new Environment();
-        container.getRequiredInterfaces().get(0).setProvider(env
-                .getProvidedInterfaces().get(0));
-        container.getRequiredInterfaces().get(1).setProvider(env
-                .getProvidedInterfaces().get(1));
-        Scope external = new DefaultScope(env.getProvidedInterfaces());
-        env.start(external);
-
-        container.start(external);
-        assertSame(env.getProvidedInterfaces().get(0), container
-                .getRequiredInterfaces().get(0).getProvider());
-        assertSame(env.getProvidedInterfaces().get(1), container
-                .getRequiredInterfaces().get(1).getProvider());
-        assertSame(env.getProvidedInterfaces().get(0), application
-                .getRequiredInterfaces().get(0).getProvider());
-        assertSame(env.getProvidedInterfaces().get(1), application
-                .getRequiredInterfaces().get(1).getProvider());
-    }
-
-    public void testOptionalRequiredInterfaceNotProvidedOptionalInternal() {
-        Application application = new Application(true);
-        Container container = new Container("top",
-                new Component[] { application }, new ProvidedInterface[0],
-                Application.required(true));
-        Environment env = new Environment();
-        container.getRequiredInterfaces().get(0).setProvider(env
-                .getProvidedInterfaces().get(0));
-        Scope external = new DefaultScope(new ProvidedInterface[0]);
-        external.publishInterface(env.getProvidedInterfaces().get(0), env
-                .getString());
-        container.start(external);
-        assertSame(env.getProvidedInterfaces().get(0), container
-                .getRequiredInterfaces().get(0).getProvider());
-        assertNull(container.getRequiredInterfaces().get(1).getProvider());
-        assertSame(env.getProvidedInterfaces().get(0), application
-                .getRequiredInterfaces().get(0).getProvider());
-        assertNull(application.getRequiredInterfaces().get(1).getProvider());
-    }
-
-    public void testOptionalRequiredInterfaceProvidedMandatoryInternal() {
-        Application application = new Application();
-        Container container = new Container("top",
-                new Component[] { application }, new ProvidedInterface[0],
-                Application.required(true));
-        Environment env = new Environment();
-        container.getRequiredInterfaces().get(0).setProvider(env
-                .getProvidedInterfaces().get(0));
-        container.getRequiredInterfaces().get(1).setProvider(env
-                .getProvidedInterfaces().get(1));
-        try {
-            container.start();
-        } catch (SystemAssemblyException e) {
-            return;
-        }
-        fail();
-    }
-
-    public void testSealed() {
-        final Container container = new Container("xx");
-        assertFalse(container.isSealed());
-        container.start();
-        assertTrue(container.isSealed());
-
-        AssertionUtils.assertException(new AssertionUtils.ErroneousCode() {
-            @Override
-            public void run() throws Exception {
-                container.addComponent(new Application());
-            }
-        }, SystemAssemblyException.class);
-
-        AssertionUtils.assertException(new AssertionUtils.ErroneousCode() {
-            @Override
-            public void run() throws Exception {
-                container.connectRequiredProvided("x", "y", "a", "b");
-            }
-        }, SystemAssemblyException.class);
-        AssertionUtils.assertException(new AssertionUtils.ErroneousCode() {
-            @Override
-            public void run() throws Exception {
-                container.connectExternalRequired("x", "y", "a");
-            }
-        }, SystemAssemblyException.class);
-        AssertionUtils.assertException(new AssertionUtils.ErroneousCode() {
-            @Override
-            public void run() throws Exception {
-                container.connectExternalProvided("x", "y", "z");
-            }
-        }, SystemAssemblyException.class);
-        AssertionUtils.assertException(new AssertionUtils.ErroneousCode() {
-            @Override
-            public void run() throws Exception {
-                container.addProvidedInterface(new DefaultProvidedInterface(
-                        "xx", String.class));
-            }
-        }, SystemAssemblyException.class);
-
-        AssertionUtils.assertException(new AssertionUtils.ErroneousCode() {
-            @Override
-            public void run() throws Exception {
-                container.addRequiredInterface(new DefaultRequiredInterface(
-                        "xx", String.class));
-            }
-        }, SystemAssemblyException.class);
-    }
-
-    public void testRestriction() {
-        Environment env1 = new Environment("env1");
-        Environment env2 = new Environment("env2");
-        Application app = new Application("app");
-        Container container = new Container("top").addComponent(env1)
-                .addComponent(env2).addComponent(app);
-        container.connectRequiredProvided("app", null, "env1", null);
-        container.start();
-        assertEquals(env1.getString(), app.getString());
-        assertEquals(env1.getInteger(), app.getInteger());
-        assertFalse(env2.getString().equals(app.getString()));
-        assertFalse(env2.getInteger().equals(app.getInteger()));
-    }
-    
-    public void testRestrictionWithFromAndToInterfaceName() {
-        Environment env1 = new Environment("env1");
-        Environment env2 = new Environment("env2");
-        Application app = new Application("app");
-        Container container = new Container("top").addComponent(env1)
-                .addComponent(env2).addComponent(app);
-        container.connectRequiredProvided("app", app.getRequiredInterfaces().get(0).getName(), 
-        		"env1", env1.getProvidedInterfaces().get(0).getName());
-        container.connectRequiredProvided("app", app.getRequiredInterfaces().get(1).getName(), 
-        		"env2", env2.getProvidedInterfaces().get(1).getName());
-        container.start();
-        assertEquals(env1.getString(), app.getString());
-        assertEquals(env2.getInteger(), app.getInteger());
-        assertFalse(env2.getString().equals(app.getString()));
-        assertFalse(env1.getInteger().equals(app.getInteger()));
-    }
-    
-    public void testRestrictionWrongComponentNames() {
-        Environment env1 = new Environment("env1");
-        Environment env2 = new Environment("env2");
-        Application app = new Application("app");
-        final Container container = new Container("top").addComponent(env1)
-                .addComponent(env2).addComponent(app);
-        AssertionUtils.assertException(new AssertionUtils.ErroneousCode() { 
-        	@Override
-        	public void run() throws Exception {
-        		container.connectRequiredProvided("app2", null, "env1", null);
-        	}
-        }, SystemAssemblyException.class); 
-        AssertionUtils.assertException(new AssertionUtils.ErroneousCode() { 
-        	@Override
-        	public void run() throws Exception {
-        		container.connectRequiredProvided("app", null, "env3", null);
-        	}
-        }, SystemAssemblyException.class); 
-    }
-    
-    public void testRestrictionWrongInterfaceNames() {
-        final Environment env1 = new Environment("env1");
-        Environment env2 = new Environment("env2");
-        final Application app = new Application("app");
-        final Container container = new Container("top").addComponent(env1)
-                .addComponent(env2).addComponent(app);
-        AssertionUtils.assertException(new AssertionUtils.ErroneousCode() { 
-        	@Override
-        	public void run() throws Exception {
-        		container.connectRequiredProvided("app", 
-        				app.getRequiredInterfaces().get(0).getName() + "xxx", "env1", null);
-        	}
-        }, SystemAssemblyException.class); 
-        AssertionUtils.assertException(new AssertionUtils.ErroneousCode() { 
-        	@Override
-        	public void run() throws Exception {
-        		container.connectRequiredProvided("app", null, "env1", 
-        				env1.getProvidedInterfaces().get(0).getName() + "yyy");
-        	}
-        }, SystemAssemblyException.class); 
-    }
-
-
-    public void testProvidedInDifferentScopes() {
-        // Scoping problem occurred. Externally and internally provided
-        // components clashed
-        // because unique id generation in the scope was wrong.
-
-        StringComponent str = new StringComponent("string");
-        Application app = new Application("app");
-        Container container = new Container("top").addComponent(str)
-                .addComponent(app);
-        container.addRequiredInterface(new DefaultRequiredInterface("integer",
-                Integer.class));
-
-        ProvidedInterface provided = new DefaultProvidedInterface("hallo",
-                Integer.class);
-        container.getRequiredInterfaces().get(0).setProvider(provided);
-
-        Scope external = new DefaultScope(new ProvidedInterface[0]);
-        external.publishInterface(provided, 100);
-        Scope scope = container.start(external);
-    }
-
-    public void testProvidedInterfaces() {
-        Environment env = new Environment(_tracker);
-        Container envcontainer = new Container("0").addComponent(env)
-                .addProvidedInterface(
-                        new DefaultProvidedInterface("string", String.class))
-                .addProvidedInterface(
-                        new DefaultProvidedInterface("integer", Integer.class));
-        Scope scope = envcontainer.start();
-
-        AssertionUtils.assertEquals(new String[] { "start.environment" },
-                _tracker.getEvents(Thread.currentThread()).toArray(
-                        new String[0]));
-
-        envcontainer.stop(scope);
-    }
-
-    public void testCoupleTwoContainers() {
-        Environment env = new Environment(_tracker);
-        Container envcontainer = new Container("0").addComponent(env)
-                .addProvidedInterface(
-                        new DefaultProvidedInterface("string", String.class))
-                .addProvidedInterface(
-                        new DefaultProvidedInterface("integer", Integer.class));
-
-        Application app = new Application(_tracker);
-        Container appcontainer = new Container("1").addComponent(app)
-                .addRequiredInterface(
-                        new DefaultRequiredInterface("string", String.class))
-                .addRequiredInterface(
-                        new DefaultRequiredInterface("integer", Integer.class));
-
-        Container top = new Container("top");
-        top.addComponent(envcontainer).addComponent(appcontainer);
-
-        top.start();
-        AssertionUtils.assertEquals(new String[] { "start.environment",
-                "start.application" }, _tracker.getEvents(
-                Thread.currentThread()).toArray(new String[0]));
-
-    }
-
-    public void testNonUniqueRequiredInterface() {
-        final Container container = new Container("top");
-        container.addRequiredInterface(new DefaultRequiredInterface("i",
-                Integer.class));
-        container.addRequiredInterface(new DefaultRequiredInterface("x",
-                String.class));
-        container.addRequiredInterface(new DefaultRequiredInterface("y",
-                String.class));
-
-        Application app = new Application("1");
-        container.addComponent(app);
-
-        AssertionUtils.assertException(new AssertionUtils.ErroneousCode() {
-            @Override
-            public void run() throws Exception {
-                container.start();
-            }
-        }, SystemAssemblyException.class);
-
-        container.connectExternalRequired("1", app.getRequiredInterfaces().get(0)
-                .getName(), "y");
-
-        ProvidedInterface i = new DefaultProvidedInterface("i", Integer.class);
-        ProvidedInterface x = new DefaultProvidedInterface("x", String.class);
-        ProvidedInterface y = new DefaultProvidedInterface("y", String.class);
-
-        Scope externalScope = new DefaultScope(new ProvidedInterface[0]);
-
-        externalScope.publishInterface(i, 100);
-        externalScope.publishInterface(x, "x-value");
-        externalScope.publishInterface(y, "y-value");
-
-        container.getRequiredInterfaces().get(0).setProvider(i);
-        container.getRequiredInterfaces().get(1).setProvider(x);
-        container.getRequiredInterfaces().get(2).setProvider(y);
-
-        Scope runtime = container.start(externalScope);
-
-        assertEquals("y-value", app.getString());
-
-    }
-    
-    public void testNonUniqueRequiredInterfaceWrongNames() {
-        final Container container = new Container("top");
-        container.addRequiredInterface(new DefaultRequiredInterface("i",
-                Integer.class));
-        container.addRequiredInterface(new DefaultRequiredInterface("x",
-                String.class));
-        container.addRequiredInterface(new DefaultRequiredInterface("y",
-                String.class));
-
-        final Application app = new Application("1");
-        container.addComponent(app);
-        
-        // wrong component name. 
-        AssertionUtils.assertException(new AssertionUtils.ErroneousCode() {
-        	@Override
-        	public void run() throws Exception {
-        		container.connectExternalRequired("2", "x", "y"); 
-        	}
-        }, SystemAssemblyException.class);
-        
-        // Wrong interface name of component.
-        AssertionUtils.assertException(new AssertionUtils.ErroneousCode() {
-        	@Override
-        	public void run() throws Exception {
-        		container.connectExternalRequired("1", 
-        				app.getRequiredInterfaces().get(0).getName() + "xxx", "y"); 
-        	}
-        }, SystemAssemblyException.class);
-        
-        // Wrong external interface name of container
-        AssertionUtils.assertException(new AssertionUtils.ErroneousCode() {
-        	@Override
-        	public void run() throws Exception {
-        		container.connectExternalRequired("1", 
-        				app.getRequiredInterfaces().get(0).getName(), "z"); 
-        	}
-        }, SystemAssemblyException.class);
-    }
-
-    public void testNonUniqueProvidedInterface() {
-
-        final Container container = new Container("top")
-                .addProvidedInterface(new DefaultProvidedInterface("external",
-                        String.class));
-        Environment env1 = new Environment("env1");
-        Environment env2 = new Environment("env2");
-
-        container.addComponent(env1);
-        container.addComponent(env2);
-
-        AssertionUtils.assertException(new AssertionUtils.ErroneousCode() {
-            @Override
-            public void run() throws Exception {
-                container.start();
-            }
-        }, SystemAssemblyException.class);
-
-        // now choose env2
-
-        container.connectExternalProvided(container.getProvidedInterfaces().get(0)
-                .getName(), env2.getName(), env2.getProvidedInterfaces().get(0)
-                .getName());
-
-        Scope scope = container.start();
-
-        // check the value of the provided interface of the container
-
-        String value = scope.getInterfaceImplementation(container
-                .getProvidedInterfaces().get(0), String.class);
-        assertNotNull(value);
-        assertEquals(value, env2.getString());
-        assertFalse(value.equals(env1.getString()));
-    }
+	private EventTracker<String> _tracker;
+
+	@Override
+	protected void setUp() throws Exception {
+		super.setUp();
+		_tracker = new EventTracker<String>();
+	}
+
+	private static class MyMultiple implements Serializable, Runnable {
+		@Override
+		public void run() {
+			// Empty
+		}
+	}
+
+	private List<Pair<ProvidedInterface, Component>> createProvidedInput(
+			ProvidedInterface[] aProvided, Component aProvider) {
+		List<Pair<ProvidedInterface, Component>> result = new ArrayList<Pair<ProvidedInterface, Component>>();
+		for (ProvidedInterface provided : aProvided) {
+			result.add(new Pair<ProvidedInterface, Component>(provided,
+					aProvider));
+		}
+		return result;
+	}
+
+	public void testEnvironmentApplication() {
+		Environment environment = new Environment(_tracker);
+		Application application = new Application(_tracker);
+		Container container = new Container("root", new Component[] {
+				environment, application }, new ProvidedInterface[0],
+				new RequiredInterface[0]);
+		Scope scope = container.start();
+		assertTrue(container.isSealed());
+		AssertionUtils.assertEquals(new String[] { "start.environment",
+				"start.application" }, _tracker.getEvents(
+				Thread.currentThread()).toArray(new String[0]));
+		assertEquals(0, scope.getProvidedInterfaces().size());
+
+		assertEquals(environment.getString(), application.getString());
+		assertEquals(environment.getInteger(), application.getInteger());
+
+	}
+
+	public void testEnvironmentApplicationSimpleConstructor() {
+		Environment environment = new Environment(_tracker);
+		Application application = new Application(_tracker);
+		Container container = new Container("root").addComponent(environment)
+				.addComponent(application);
+
+		Scope scope = container.start();
+		AssertionUtils.assertEquals(new String[] { "start.environment",
+				"start.application" }, _tracker.getEvents(
+				Thread.currentThread()).toArray(new String[0]));
+		assertEquals(0, scope.getProvidedInterfaces().size());
+
+		assertEquals(environment.getString(), application.getString());
+		assertEquals(environment.getInteger(), application.getInteger());
+
+	}
+
+	public void testApplicationEnvironment() {
+		try {
+			Component<?> environment = new Environment();
+			Component<?> application = new Application();
+			Container container = new Container("root", new Component[] {
+					application, environment }, new ProvidedInterface[0],
+					new RequiredInterface[0]);
+			container.start();
+		} catch (SystemAssemblyException e) {
+			// e.printStackTrace();
+			return;
+		}
+		fail();
+	}
+
+	public void testComposite() {
+		Component<?> environment = new Environment(_tracker);
+		Component<?> application = new Application(_tracker);
+		assertEquals(0, _tracker.getEventCount());
+
+		Container system = new Container("all", new Component[] { environment,
+				application }, new ProvidedInterface[0],
+				new RequiredInterface[0]);
+		Scope runtime = system.start();
+		List<RequiredInterface> required = system.getRequiredInterfaces();
+		assertEquals(0, required.size());
+		List<ProvidedInterface> provided = system.getProvidedInterfaces();
+		assertEquals(0, provided.size());
+
+		AssertionUtils.assertEquals(new String[] { "start.environment",
+				"start.application" }, _tracker.getEvents(
+				Thread.currentThread()).toArray(new String[0]));
+		_tracker.clear();
+
+		system.stop(runtime);
+		AssertionUtils.assertEquals(new String[] { "stop.application",
+				"stop.environment" }, _tracker
+				.getEvents(Thread.currentThread()).toArray(new String[0]));
+
+	}
+
+	public void testCompositeWithWrongProvidedInfo() {
+		try {
+			Component<?> environment = new Environment();
+			Component<?> application = new Application();
+			Container system = new Container("all", new Component[] {
+					environment, application },
+					new ProvidedInterface[] { new DefaultProvidedInterface(
+							"float", Float.class) },
+					new DefaultRequiredInterface[0]);
+			system.validate();
+		} catch (SystemAssemblyException e) {
+			return;
+		}
+		fail();
+	}
+
+	public void testCompositeRequiredInterfaceNotProvided() {
+		try {
+			Component<?> environment = new Environment();
+			Component<?> application = new Application();
+			Container system = new Container("all", new Component[] {
+					environment, application }, new ProvidedInterface[0],
+					new RequiredInterface[] { new DefaultRequiredInterface(
+							"string", String.class) });
+			system.start();
+		} catch (SystemAssemblyException e) {
+			return;
+		}
+		fail();
+	}
+
+	public void testCompositeWithSuperfluousRequiredInfo() {
+		Component<?> environment = new Environment();
+		Component<?> application = new Application();
+		Container system = new Container("all", new Component[] { environment,
+				application }, new ProvidedInterface[0],
+				new RequiredInterface[] { new DefaultRequiredInterface("float",
+						Float.class) });
+		system.getRequiredInterfaces().get(0).setProvider(
+				new DefaultProvidedInterface("hallo", Float.class));
+		system.start();
+		List<RequiredInterface> required = system.getRequiredInterfaces();
+		assertEquals(1, required.size());
+		List<ProvidedInterface> provided = system.getProvidedInterfaces();
+		assertEquals(0, provided.size());
+	}
+
+	public void testCompositeWithExternalDependencesNotProvided() {
+		try {
+			Component<?> application = new Application();
+
+			Container system = new Container("all",
+					new Component[] { application }, new ProvidedInterface[0],
+					application.getRequiredInterfaces().toArray(
+							new RequiredInterface[0]));
+			system.start();
+		} catch (SystemAssemblyException e) {
+			return;
+		}
+		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() {
+
+		Component<?> environment = new Environment();
+		Component<?> application = new Application();
+		Container system = new Container("all",
+				new Component[] { application }, new ProvidedInterface[0],
+				application.getRequiredInterfaces().toArray(
+						new RequiredInterface[0]));
+		environment.start(new DefaultScope(new ProvidedInterface[0]));
+		system.getRequiredInterfaces().get(0).setProvider(
+				environment.getProvidedInterfaces().get(0));
+		system.getRequiredInterfaces().get(1).setProvider(
+				environment.getProvidedInterfaces().get(1));
+
+		system.start();
+		List<RequiredInterface> required = system.getRequiredInterfaces();
+		assertEquals(2, required.size());
+		List<ProvidedInterface> provided = system.getProvidedInterfaces();
+		assertEquals(0, provided.size());
+
+	}
+
+	public void testAmbiguousInterfaces() {
+		try {
+			Component<?> environment1 = new Environment();
+			Component<?> environment2 = new Environment();
+			Component<?> application = new Application();
+			Container container = new Container("root", new Component[] {
+					environment1, environment2, application },
+					new ProvidedInterface[0], new RequiredInterface[0]);
+			container.start();
+
+		} catch (SystemAssemblyException e) {
+			return;
+		}
+		fail();
+	}
+
+	public void testIncompleteRequirements() {
+		try {
+			Component<?> application = new Application();
+			Container system = new Container("all",
+					new Component[] { application }, new ProvidedInterface[0],
+					new RequiredInterface[0]);
+			system.start();
+		} catch (SystemAssemblyException e) {
+			return;
+		}
+		fail();
+	}
+
+	public void testEnvironmentApplicationRollbackOnException()
+			throws Exception {
+		IMocksControl control = EasyMock.createStrictControl();
+
+		Environment environment = new Environment(_tracker);
+		Application application = control.createMock(Application.class,
+				new ConstructorArgs(Application.class.getConstructor()),
+				Application.class.getDeclaredMethod("doStart", Scope.class));
+
+		application.doStart(EasyMockMatchers.anyObject(Scope.class));
+		EasyMock.expectLastCall().andThrow(new RuntimeException());
+		control.replay();
+
+		try {
+			Container container = new Container("root", new Component[] {
+					environment, application }, new ProvidedInterface[0],
+					new RequiredInterface[0]);
+
+			container.start();
+		} catch (RuntimeException e) {
+			AssertionUtils.assertEquals(new String[] { "start.environment",
+					"stop.environment" }, _tracker.getEvents(
+					Thread.currentThread()).toArray(new String[0]));
+			return;
+		}
+		fail();
+	}
+
+	public void testEnvironmentApplicationRollbackOnExceptionWithExceptionOnStop()
+			throws Exception {
+		IMocksControl control = EasyMock.createControl();
+
+		Environment environment = new Environment(_tracker);
+		// Application 1 will throw an exception while stopping.
+		Application application1 = control.createMock(Application.class,
+				new ConstructorArgs(Application.class.getConstructor()),
+				Application.class.getDeclaredMethod("doStop", Object.class));
+
+		application1.doStop(EasyMock.anyObject());
+		EasyMock.expectLastCall().andThrow(new RuntimeException());
+
+		// application 2 will throw an exception while starting
+		Application application2 = control.createMock(Application.class,
+				new ConstructorArgs(Application.class
+						.getConstructor(String.class), "application2"),
+				Application.class.getDeclaredMethod("doStart", Scope.class));
+
+		application2.doStart(EasyMockMatchers.anyObject(Scope.class));
+		EasyMock.expectLastCall().andThrow(new RuntimeException());
+
+		control.replay();
+
+		try {
+			Container container = new Container("root", new Component[] {
+					environment, application1, application2 },
+					new ProvidedInterface[0], new RequiredInterface[0]);
+
+			container.start();
+		} catch (RuntimeException e) {
+			AssertionUtils.assertEquals(new String[] { "start.environment",
+					"stop.environment" }, _tracker.getEvents(
+					Thread.currentThread()).toArray(new String[0]));
+			return;
+		}
+		fail();
+	}
+
+	public void testOptionalRequiredInterfaceProvidedOptionalInternal() {
+		Application application = new Application(true);
+		Container container = new Container("top",
+				new Component[] { application }, new ProvidedInterface[0],
+				Application.required(true));
+		Environment env = new Environment();
+		container.getRequiredInterfaces().get(0).setProvider(
+				env.getProvidedInterfaces().get(0));
+		container.getRequiredInterfaces().get(1).setProvider(
+				env.getProvidedInterfaces().get(1));
+		Scope external = new DefaultScope(env.getProvidedInterfaces());
+		env.start(external);
+
+		container.start(external);
+		assertSame(env.getProvidedInterfaces().get(0), container
+				.getRequiredInterfaces().get(0).getProvider());
+		assertSame(env.getProvidedInterfaces().get(1), container
+				.getRequiredInterfaces().get(1).getProvider());
+		assertSame(env.getProvidedInterfaces().get(0), application
+				.getRequiredInterfaces().get(0).getProvider());
+		assertSame(env.getProvidedInterfaces().get(1), application
+				.getRequiredInterfaces().get(1).getProvider());
+	}
+
+	public void testOptionalRequiredInterfaceNotProvidedOptionalInternal() {
+		Application application = new Application(true);
+		Container container = new Container("top",
+				new Component[] { application }, new ProvidedInterface[0],
+				Application.required(true));
+		Environment env = new Environment();
+		container.getRequiredInterfaces().get(0).setProvider(
+				env.getProvidedInterfaces().get(0));
+		Scope external = new DefaultScope(new ProvidedInterface[0]);
+		external.publishInterface(env.getProvidedInterfaces().get(0), env
+				.getString());
+		container.start(external);
+		assertSame(env.getProvidedInterfaces().get(0), container
+				.getRequiredInterfaces().get(0).getProvider());
+		assertNull(container.getRequiredInterfaces().get(1).getProvider());
+		assertSame(env.getProvidedInterfaces().get(0), application
+				.getRequiredInterfaces().get(0).getProvider());
+		assertNull(application.getRequiredInterfaces().get(1).getProvider());
+	}
+
+	public void testOptionalRequiredInterfaceProvidedMandatoryInternal() {
+		Application application = new Application();
+		Container container = new Container("top",
+				new Component[] { application }, new ProvidedInterface[0],
+				Application.required(true));
+		Environment env = new Environment();
+		container.getRequiredInterfaces().get(0).setProvider(
+				env.getProvidedInterfaces().get(0));
+		container.getRequiredInterfaces().get(1).setProvider(
+				env.getProvidedInterfaces().get(1));
+		try {
+			container.start();
+		} catch (SystemAssemblyException e) {
+			return;
+		}
+		fail();
+	}
+
+	public void testSealed() {
+		final Container container = new Container("xx");
+		assertFalse(container.isSealed());
+		container.start();
+		assertTrue(container.isSealed());
+
+		AssertionUtils.assertException(new AssertionUtils.ErroneousCode() {
+			@Override
+			public void run() throws Exception {
+				container.addComponent(new Application());
+			}
+		}, SystemAssemblyException.class);
+
+		AssertionUtils.assertException(new AssertionUtils.ErroneousCode() {
+			@Override
+			public void run() throws Exception {
+				container.connectRequiredProvided("x", "y", "a", "b");
+			}
+		}, SystemAssemblyException.class);
+		AssertionUtils.assertException(new AssertionUtils.ErroneousCode() {
+			@Override
+			public void run() throws Exception {
+				container.connectExternalRequired("x", "y", "a");
+			}
+		}, SystemAssemblyException.class);
+		AssertionUtils.assertException(new AssertionUtils.ErroneousCode() {
+			@Override
+			public void run() throws Exception {
+				container.connectExternalProvided("x", "y", "z");
+			}
+		}, SystemAssemblyException.class);
+		AssertionUtils.assertException(new AssertionUtils.ErroneousCode() {
+			@Override
+			public void run() throws Exception {
+				container.addProvidedInterface(new DefaultProvidedInterface(
+						"xx", String.class));
+			}
+		}, SystemAssemblyException.class);
+
+		AssertionUtils.assertException(new AssertionUtils.ErroneousCode() {
+			@Override
+			public void run() throws Exception {
+				container.addRequiredInterface(new DefaultRequiredInterface(
+						"xx", String.class));
+			}
+		}, SystemAssemblyException.class);
+	}
+
+	public void testRestriction() {
+		Environment env1 = new Environment("env1");
+		Environment env2 = new Environment("env2");
+		Application app = new Application("app");
+		Container container = new Container("top").addComponent(env1)
+				.addComponent(env2).addComponent(app);
+		container.connectRequiredProvided("app", null, "env1", null);
+		container.start();
+		assertEquals(env1.getString(), app.getString());
+		assertEquals(env1.getInteger(), app.getInteger());
+		assertFalse(env2.getString().equals(app.getString()));
+		assertFalse(env2.getInteger().equals(app.getInteger()));
+	}
+
+	public void testRestrictionWithFromAndToInterfaceName() {
+		Environment env1 = new Environment("env1");
+		Environment env2 = new Environment("env2");
+		Application app = new Application("app");
+		Container container = new Container("top").addComponent(env1)
+				.addComponent(env2).addComponent(app);
+		container.connectRequiredProvided("app", app.getRequiredInterfaces()
+				.get(0).getName(), "env1", env1.getProvidedInterfaces().get(0)
+				.getName());
+		container.connectRequiredProvided("app", app.getRequiredInterfaces()
+				.get(1).getName(), "env2", env2.getProvidedInterfaces().get(1)
+				.getName());
+		container.start();
+		assertEquals(env1.getString(), app.getString());
+		assertEquals(env2.getInteger(), app.getInteger());
+		assertFalse(env2.getString().equals(app.getString()));
+		assertFalse(env1.getInteger().equals(app.getInteger()));
+	}
+
+	public void testRestrictionWrongComponentNames() {
+		Environment env1 = new Environment("env1");
+		Environment env2 = new Environment("env2");
+		Application app = new Application("app");
+		final Container container = new Container("top").addComponent(env1)
+				.addComponent(env2).addComponent(app);
+		AssertionUtils.assertException(new AssertionUtils.ErroneousCode() {
+			@Override
+			public void run() throws Exception {
+				container.connectRequiredProvided("app2", null, "env1", null);
+			}
+		}, SystemAssemblyException.class);
+		AssertionUtils.assertException(new AssertionUtils.ErroneousCode() {
+			@Override
+			public void run() throws Exception {
+				container.connectRequiredProvided("app", null, "env3", null);
+			}
+		}, SystemAssemblyException.class);
+	}
+
+	public void testRestrictionWrongInterfaceNames() {
+		final Environment env1 = new Environment("env1");
+		Environment env2 = new Environment("env2");
+		final Application app = new Application("app");
+		final Container container = new Container("top").addComponent(env1)
+				.addComponent(env2).addComponent(app);
+		AssertionUtils.assertException(new AssertionUtils.ErroneousCode() {
+			@Override
+			public void run() throws Exception {
+				container.connectRequiredProvided("app", app
+						.getRequiredInterfaces().get(0).getName()
+						+ "xxx", "env1", null);
+			}
+		}, SystemAssemblyException.class);
+		AssertionUtils.assertException(new AssertionUtils.ErroneousCode() {
+			@Override
+			public void run() throws Exception {
+				container.connectRequiredProvided("app", null, "env1", env1
+						.getProvidedInterfaces().get(0).getName()
+						+ "yyy");
+			}
+		}, SystemAssemblyException.class);
+	}
+
+	public void testProvidedInDifferentScopes() {
+		// Scoping problem occurred. Externally and internally provided
+		// components clashed
+		// because unique id generation in the scope was wrong.
+
+		StringComponent str = new StringComponent("string");
+		Application app = new Application("app");
+		Container container = new Container("top").addComponent(str)
+				.addComponent(app);
+		container.addRequiredInterface(new DefaultRequiredInterface("integer",
+				Integer.class));
+
+		ProvidedInterface provided = new DefaultProvidedInterface("hallo",
+				Integer.class);
+		container.getRequiredInterfaces().get(0).setProvider(provided);
+
+		Scope external = new DefaultScope(new ProvidedInterface[0]);
+		external.publishInterface(provided, 100);
+		Scope scope = container.start(external);
+	}
+
+	public void testProvidedInterfaces() {
+		Environment env = new Environment(_tracker);
+		Container envcontainer = new Container("0").addComponent(env)
+				.addProvidedInterface(
+						new DefaultProvidedInterface("string", String.class))
+				.addProvidedInterface(
+						new DefaultProvidedInterface("integer", Integer.class));
+		Scope scope = envcontainer.start();
+
+		AssertionUtils.assertEquals(new String[] { "start.environment" },
+				_tracker.getEvents(Thread.currentThread()).toArray(
+						new String[0]));
+
+		envcontainer.stop(scope);
+	}
+
+	public void testCoupleTwoContainers() {
+		Environment env = new Environment(_tracker);
+		Container envcontainer = new Container("0").addComponent(env)
+				.addProvidedInterface(
+						new DefaultProvidedInterface("string", String.class))
+				.addProvidedInterface(
+						new DefaultProvidedInterface("integer", Integer.class));
+
+		Application app = new Application(_tracker);
+		Container appcontainer = new Container("1").addComponent(app)
+				.addRequiredInterface(
+						new DefaultRequiredInterface("string", String.class))
+				.addRequiredInterface(
+						new DefaultRequiredInterface("integer", Integer.class));
+
+		Container top = new Container("top");
+		top.addComponent(envcontainer).addComponent(appcontainer);
+
+		top.start();
+		AssertionUtils.assertEquals(new String[] { "start.environment",
+				"start.application" }, _tracker.getEvents(
+				Thread.currentThread()).toArray(new String[0]));
+
+	}
+
+	public void testNonUniqueRequiredInterface() {
+		final Container container = new Container("top");
+		container.addRequiredInterface(new DefaultRequiredInterface("i",
+				Integer.class));
+		container.addRequiredInterface(new DefaultRequiredInterface("x",
+				String.class));
+		container.addRequiredInterface(new DefaultRequiredInterface("y",
+				String.class));
+
+		Application app = new Application("1");
+		container.addComponent(app);
+
+		AssertionUtils.assertException(new AssertionUtils.ErroneousCode() {
+			@Override
+			public void run() throws Exception {
+				container.start();
+			}
+		}, SystemAssemblyException.class);
+
+		container.connectExternalRequired("1", app.getRequiredInterfaces().get(
+				0).getName(), "y");
+
+		ProvidedInterface i = new DefaultProvidedInterface("i", Integer.class);
+		ProvidedInterface x = new DefaultProvidedInterface("x", String.class);
+		ProvidedInterface y = new DefaultProvidedInterface("y", String.class);
+
+		Scope externalScope = new DefaultScope(new ProvidedInterface[0]);
+
+		externalScope.publishInterface(i, 100);
+		externalScope.publishInterface(x, "x-value");
+		externalScope.publishInterface(y, "y-value");
+
+		container.getRequiredInterfaces().get(0).setProvider(i);
+		container.getRequiredInterfaces().get(1).setProvider(x);
+		container.getRequiredInterfaces().get(2).setProvider(y);
+
+		Scope runtime = container.start(externalScope);
+
+		assertEquals("y-value", app.getString());
+
+	}
+
+	public void testNonUniqueRequiredInterfaceWrongNames() {
+		final Container container = new Container("top");
+		container.addRequiredInterface(new DefaultRequiredInterface("i",
+				Integer.class));
+		container.addRequiredInterface(new DefaultRequiredInterface("x",
+				String.class));
+		container.addRequiredInterface(new DefaultRequiredInterface("y",
+				String.class));
+
+		final Application app = new Application("1");
+		container.addComponent(app);
+
+		// wrong component name.
+		AssertionUtils.assertException(new AssertionUtils.ErroneousCode() {
+			@Override
+			public void run() throws Exception {
+				container.connectExternalRequired("2", "x", "y");
+			}
+		}, SystemAssemblyException.class);
+
+		// Wrong interface name of component.
+		AssertionUtils.assertException(new AssertionUtils.ErroneousCode() {
+			@Override
+			public void run() throws Exception {
+				container.connectExternalRequired("1", app
+						.getRequiredInterfaces().get(0).getName()
+						+ "xxx", "y");
+			}
+		}, SystemAssemblyException.class);
+
+		// Wrong external interface name of container
+		AssertionUtils.assertException(new AssertionUtils.ErroneousCode() {
+			@Override
+			public void run() throws Exception {
+				container.connectExternalRequired("1", app
+						.getRequiredInterfaces().get(0).getName(), "z");
+			}
+		}, SystemAssemblyException.class);
+	}
+
+	public void testNonUniqueProvidedInterface() {
+
+		final Container container = new Container("top")
+				.addProvidedInterface(new DefaultProvidedInterface("external",
+						String.class));
+		Environment env1 = new Environment("env1");
+		Environment env2 = new Environment("env2");
+
+		container.addComponent(env1);
+		container.addComponent(env2);
+
+		AssertionUtils.assertException(new AssertionUtils.ErroneousCode() {
+			@Override
+			public void run() throws Exception {
+				container.start();
+			}
+		}, SystemAssemblyException.class);
+
+		// now choose env2
+
+		container.connectExternalProvided(container.getProvidedInterfaces()
+				.get(0).getName(), env2.getName(), env2.getProvidedInterfaces()
+				.get(0).getName());
+
+		Scope scope = container.start();
+
+		// check the value of the provided interface of the container
+
+		String value = scope.getInterfaceImplementation(container
+				.getProvidedInterfaces().get(0), String.class);
+		assertNotNull(value);
+		assertEquals(value, env2.getString());
+		assertFalse(value.equals(env1.getString()));
+	}
+
+	public void testNonUniqueProvidedInterfaceWrongNames() {
+
+		final Container container = new Container("top")
+				.addProvidedInterface(new DefaultProvidedInterface("external",
+						String.class));
+		final Environment env1 = new Environment("env1");
+		final Environment env2 = new Environment("env2");
+
+		container.addComponent(env1);
+		container.addComponent(env2);
+
+		// Wrong external provided interface name
+		AssertionUtils.assertException(new AssertionUtils.ErroneousCode() {
+			@Override
+			public void run() throws Exception {
+				container.connectExternalProvided(container
+						.getProvidedInterfaces().get(0).getName()
+						+ "xx", "env1", env1.getProvidedInterfaces().get(0)
+						.getName());
+			}
+		}, SystemAssemblyException.class);
+
+		// Wrong provided interface name.
+		AssertionUtils.assertException(new AssertionUtils.ErroneousCode() {
+			@Override
+			public void run() throws Exception {
+				container.connectExternalProvided(container
+						.getProvidedInterfaces().get(0).getName(), "env1", env1
+						.getProvidedInterfaces().get(0).getName()
+						+ "xx");
+			}
+		}, SystemAssemblyException.class);
+
+		// Wrong provided component
+		AssertionUtils.assertException(new AssertionUtils.ErroneousCode() {
+			@Override
+			public void run() throws Exception {
+				container.connectExternalProvided(container
+						.getProvidedInterfaces().get(0).getName(), "env3", env1
+						.getProvidedInterfaces().get(0).getName());
+			}
+		}, SystemAssemblyException.class);
+	}
 }