Implemented restrictions on component connections in the Container.
authorErik Brakkee <erik@brakkee.org>
Sat, 26 Apr 2008 20:22:02 +0000 (20:22 +0000)
committerErik Brakkee <erik@brakkee.org>
Sat, 26 Apr 2008 20:22:02 +0000 (20:22 +0000)
system/general/src/main/java/org/wamblee/system/core/Container.java
system/general/src/main/java/org/wamblee/system/core/DefaultProvidedInterface.java
system/general/src/test/java/org/wamblee/system/core/ContainerTest.java
system/general/src/test/java/org/wamblee/system/core/Environment.java

index 1eaebf432a0e1c239189e621e3d0a35b9275f1ed..8075abab3c7fcc703b5cbcdc9a22c2e105a58096 100644 (file)
@@ -25,6 +25,7 @@ import java.util.Set;
 
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
+import org.wamblee.general.Pair;
 
 /**
  * Container consisting of multiple components.
@@ -37,29 +38,23 @@ public class Container extends AbstractComponent<Scope> {
 
     private List<Component> _components;
     private Set<String> _componentNames;
+    private CompositeInterfaceRestriction _restriction; 
     private boolean _sealed;
 
-    public static RequiredInterface[] filterRequiredServices(
-            ProvidedInterface aProvided,
-            Collection<RequiredInterface> aDescriptors) {
-        List<RequiredInterface> required = new ArrayList<RequiredInterface>();
-        for (RequiredInterface descriptor : aDescriptors) {
-            if (descriptor.implementedBy(aProvided)) {
-                required.add(descriptor);
-            }
-        }
-        return required.toArray(new RequiredInterface[0]);
-    }
 
     public static ProvidedInterface[] filterProvidedServices(
-            RequiredInterface aRequired, Collection<ProvidedInterface> aProvided) {
-        List<ProvidedInterface> provided = new ArrayList<ProvidedInterface>();
-        for (ProvidedInterface descriptor : aProvided) {
-            if (aRequired.implementedBy(descriptor)) {
-                provided.add(descriptor);
+            Component aClient, RequiredInterface aRequired, Collection<Pair<ProvidedInterface,Component>> aProvided,
+            InterfaceRestriction aRestriction) {
+        List<ProvidedInterface> result = new ArrayList<ProvidedInterface>();
+        for (Pair<ProvidedInterface,Component> descriptor : aProvided) {
+            ProvidedInterface provided = descriptor.getFirst();
+            Component server = descriptor.getSecond();
+            if (aRequired.implementedBy(provided) && 
+                    !aRestriction.isViolated(aClient, aRequired, server, provided)) {
+                result.add(provided);
             }
         }
-        return provided.toArray(new ProvidedInterface[0]);
+        return result.toArray(new ProvidedInterface[0]);
     }
 
     /**
@@ -80,6 +75,7 @@ public class Container extends AbstractComponent<Scope> {
         _components = new ArrayList<Component>();
 
         _componentNames = new HashSet<String>();
+        _restriction = new CompositeInterfaceRestriction();
         _sealed = false;
         for (Component component : aComponents) {
             addComponent(component);
@@ -108,6 +104,18 @@ public class Container extends AbstractComponent<Scope> {
         aComponent.addContext(getQualifiedName());
         return this;
     }
+    
+    /**
+     * Adds an interface restriction for explicitly configuring the 
+     * relations between components. 
+     * @param aRestriction Restriction to add. 
+     * @return Reference to this to allow call chaining. 
+     */
+    public Container addRestriction(InterfaceRestriction aRestriction) {
+        checkSealed(); 
+        _restriction.add(aRestriction);
+        return this; 
+    }
 
     @Override
     public Container addProvidedInterface(ProvidedInterface aProvided) {
@@ -235,8 +243,8 @@ public class Container extends AbstractComponent<Scope> {
 
         Scope scope = new DefaultScope(getProvidedInterfaces(), aExternalScope);
 
-        List<ProvidedInterface> allProvided = new ArrayList<ProvidedInterface>();
-
+        List<Pair<ProvidedInterface,Component>> allProvided = new ArrayList<Pair<ProvidedInterface,Component>>();
+        
         addProvidersOfRequiredInterfaces(allProvided);
 
         List<Component> started = new ArrayList<Component>();
@@ -255,7 +263,9 @@ public class Container extends AbstractComponent<Scope> {
                 // add all provided services
                 ProvidedInterface[] provided = component
                         .getProvidedInterfaces();
-                allProvided.addAll(Arrays.asList(provided));
+                for (ProvidedInterface prov: provided) { 
+                    allProvided.add(new Pair<ProvidedInterface,Component>(prov, component));
+                }
             } catch (SystemAssemblyException e) {
                 throw e;
             } catch (RuntimeException e) {
@@ -269,14 +279,14 @@ public class Container extends AbstractComponent<Scope> {
     }
 
     private void addProvidersOfRequiredInterfaces(
-            List<ProvidedInterface> allProvided) {
+            List<Pair<ProvidedInterface,Component>> allProvided) {
         // 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);
+                allProvided.add(new Pair<ProvidedInterface,Component>(provider, null));
             } else {
                 if (!intf.isOptional()) {
                     throw new SystemAssemblyException(getQualifiedName()
@@ -314,15 +324,15 @@ public class Container extends AbstractComponent<Scope> {
      *            interfaces.
      */
     private void initializeProvidersForRequiredInterfaces(
-            List<ProvidedInterface> aAllProvided, Component aComponent,
+            List<Pair<ProvidedInterface,Component>> aAllProvided, Component aComponent,
             boolean aValidateOnly) {
         // Check if all required services are already provided by
         // earlier
         // systems.
 
         for (RequiredInterface descriptor : aComponent.getRequiredInterfaces()) {
-            ProvidedInterface[] filtered = filterProvidedServices(descriptor,
-                    aAllProvided);
+            ProvidedInterface[] filtered = filterProvidedServices(aComponent, descriptor,
+                    aAllProvided, _restriction);
             if (filtered.length == 1) {
                 if (!aValidateOnly) {
                     descriptor.setProvider(filtered[0]);
index 90c230dcc9bf23493fcba2dd629f14c7c880e665..3eb33ddc90c8a18bc2e9f5190c245c32fe8fe28a 100644 (file)
@@ -36,7 +36,7 @@ public class DefaultProvidedInterface implements ProvidedInterface {
                this(aName, new Class[] { aInterface }); 
        }
        
-       public DefaultProvidedInterface(String aName, Class[] aInterfaces) {
+       public DefaultProvidedInterface(String aName, Class[] aInterfaces) { 
                _name = aName; 
                _interfaces = Arrays.copyOf(aInterfaces, aInterfaces.length);
                _uniqueId = null; 
index 90723ed1c93c4f6271448cf19622ed0eb8166dbe..4c451337f7cbe027c03922687059e45f0ae88365 100644 (file)
@@ -17,421 +17,491 @@ package org.wamblee.system.core;
 
 import java.io.IOException;
 import java.io.Serializable;
+import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.List;
 
 import junit.framework.TestCase;
 
 import org.easymock.classextension.ConstructorArgs;
 import org.easymock.classextension.EasyMock;
 import org.easymock.classextension.IMocksControl;
+import org.wamblee.general.Pair;
 import org.wamblee.test.AssertionUtils;
 import org.wamblee.test.EasyMockMatchers;
 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
-               }
-       }
-
-       public void testFilterProvided() {
-               RequiredInterface req1 = new DefaultRequiredInterface("name",
-                               Runnable.class);
-               RequiredInterface req2 = new DefaultRequiredInterface("name",
-                               Serializable.class);
-               ProvidedInterface prov1 = new DefaultProvidedInterface("name",
-                               Runnable.class);
-               ProvidedInterface prov2 = new DefaultProvidedInterface("name",
-                               Serializable.class);
-               ProvidedInterface prov3 = new DefaultProvidedInterface("name",
-                               MyMultiple.class);
-
-               AssertionUtils.assertEquals(new RequiredInterface[] { req1 }, Container
-                               .filterRequiredServices(prov1, Arrays
-                                               .asList(new RequiredInterface[] { req1 })));
-               AssertionUtils.assertEquals(new RequiredInterface[] { req1 }, Container
-                               .filterRequiredServices(prov1, Arrays
-                                               .asList(new RequiredInterface[] { req1, req2 })));
-               AssertionUtils.assertEquals(new RequiredInterface[] { req1, req2 },
-                               Container.filterRequiredServices(prov3, Arrays
-                                               .asList(new RequiredInterface[] { req1, req2 })));
-
-               AssertionUtils.assertEquals(new ProvidedInterface[] { prov1 },
-                               Container.filterProvidedServices(req1, Arrays
-                                               .asList(new ProvidedInterface[] { prov1 })));
-               AssertionUtils.assertEquals(new ProvidedInterface[] { prov1 },
-                               Container.filterProvidedServices(req1, Arrays
-                                               .asList(new ProvidedInterface[] { prov1, prov2 })));
-               AssertionUtils.assertEquals(new ProvidedInterface[] { prov1, prov3 },
-                               Container.filterProvidedServices(req1, Arrays
-                                               .asList(new ProvidedInterface[] { prov1, prov3 })));
-       }
-
-       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().length);
-               
-               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().length);
-               
-               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();
-               RequiredInterface[] required = system.getRequiredInterfaces();
-               assertEquals(0, required.length);
-               ProvidedInterface[] provided = system.getProvidedInterfaces();
-               assertEquals(0, provided.length);
-
-               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()[0]
-                               .setProvider(new DefaultProvidedInterface("hallo", Float.class));
-               system.start();
-               RequiredInterface[] required = system.getRequiredInterfaces();
-               assertEquals(1, required.length);
-               ProvidedInterface[] provided = system.getProvidedInterfaces();
-               assertEquals(0, provided.length);
-       }
-
-       public void testCompositeWithExternalDependencesNotProvided() {
-               try {
-                       Component environment = new Environment();
-                       Component application = new Application();
-                       Container system = new Container("all",
-                                       new Component[] { application }, new ProvidedInterface[0],
-                                       application.getRequiredInterfaces());
-                       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());
-               environment.start(new DefaultScope(new ProvidedInterface[0]));
-               system.getRequiredInterfaces()[0].setProvider(environment
-                               .getProvidedInterfaces()[0]);
-               system.getRequiredInterfaces()[1].setProvider(environment
-                               .getProvidedInterfaces()[1]);
-
-               system.start();
-               RequiredInterface[] required = system.getRequiredInterfaces();
-               assertEquals(2, required.length);
-               ProvidedInterface[] provided = system.getProvidedInterfaces();
-               assertEquals(0, provided.length);
-
-       }
-
-       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()[0].setProvider(
-                               env.getProvidedInterfaces()[0]); 
-               container.getRequiredInterfaces()[1].setProvider(
-                               env.getProvidedInterfaces()[1]);
-               Scope external = new DefaultScope(env.getProvidedInterfaces());
-               env.start(external); 
-               
-           container.start(external);
-           assertSame(env.getProvidedInterfaces()[0], container.getRequiredInterfaces()[0].getProvider());
-           assertSame(env.getProvidedInterfaces()[1], container.getRequiredInterfaces()[1].getProvider());
-           assertSame(env.getProvidedInterfaces()[0], application.getRequiredInterfaces()[0].getProvider());
-           assertSame(env.getProvidedInterfaces()[1], application.getRequiredInterfaces()[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()[0].setProvider(
-                               env.getProvidedInterfaces()[0]);
-               Scope external = new DefaultScope(new ProvidedInterface[0]); 
-               external.publishInterface(env.getProvidedInterfaces()[0], env.getString());
-           container.start(external);
-           assertSame(env.getProvidedInterfaces()[0], container.getRequiredInterfaces()[0].getProvider());
-           assertNull(container.getRequiredInterfaces()[1].getProvider());
-           assertSame(env.getProvidedInterfaces()[0], application.getRequiredInterfaces()[0].getProvider());
-           assertNull(application.getRequiredInterfaces()[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()[0].setProvider(
-                               env.getProvidedInterfaces()[0]); 
-               container.getRequiredInterfaces()[1].setProvider(
-                               env.getProvidedInterfaces()[1]);
-           container.start();
-           assertSame(env.getProvidedInterfaces()[0], container.getRequiredInterfaces()[0].getProvider());
-           assertSame(env.getProvidedInterfaces()[1], container.getRequiredInterfaces()[1].getProvider());
-           assertSame(env.getProvidedInterfaces()[0], application.getRequiredInterfaces()[0].getProvider());
-           assertSame(env.getProvidedInterfaces()[1], application.getRequiredInterfaces()[1].getProvider());   
-       }
-       
-       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.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); 
-       }
+    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 testFilterProvided() {
+        RequiredInterface req1 = new DefaultRequiredInterface("name",
+                Runnable.class);
+        RequiredInterface req2 = new DefaultRequiredInterface("name",
+                Serializable.class);
+        ProvidedInterface prov1 = new DefaultProvidedInterface("name",
+                Runnable.class);
+        ProvidedInterface prov2 = new DefaultProvidedInterface("name",
+                Serializable.class);
+        ProvidedInterface prov3 = new DefaultProvidedInterface("name",
+                MyMultiple.class);
+        
+        Component client = new Application("client");
+        Component dummy = new Application("dummy");
+        
+        InterfaceRestriction noRestriction = new InterfaceRestriction() { 
+          @Override
+            public boolean isViolated(Component aClient,
+                    RequiredInterface aRequired, Component aServer,
+                    ProvidedInterface aProvided) {
+                return false;
+            }  
+        };
+
+        AssertionUtils.assertEquals(new ProvidedInterface[] { prov1 },
+                Container.filterProvidedServices(client, req1, 
+                        createProvidedInput(new ProvidedInterface[] { prov1 }, dummy), noRestriction));
+        AssertionUtils.assertEquals(new ProvidedInterface[] { prov1 },
+                Container.filterProvidedServices(client, req1, 
+                        createProvidedInput(new ProvidedInterface[] { prov1, prov2 }, dummy), noRestriction));
+        AssertionUtils.assertEquals(new ProvidedInterface[] { prov1, prov3 },
+                Container.filterProvidedServices(client, req1, 
+                        createProvidedInput(new ProvidedInterface[] { prov1, prov3 }, dummy), noRestriction));
+        
+        InterfaceRestriction everything = new InterfaceRestriction() { 
+            @Override
+            public boolean isViolated(Component aClient,
+                    RequiredInterface aRequired, Component aServer,
+                    ProvidedInterface aProvided) {
+                return true;
+            }
+        };
+        AssertionUtils.assertEquals(new ProvidedInterface[0],
+                Container.filterProvidedServices(client, req1, 
+                        createProvidedInput(new ProvidedInterface[] { prov1, prov3 }, dummy), everything));
+        
+    }
+
+    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().length);
+
+        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().length);
+
+        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();
+        RequiredInterface[] required = system.getRequiredInterfaces();
+        assertEquals(0, required.length);
+        ProvidedInterface[] provided = system.getProvidedInterfaces();
+        assertEquals(0, provided.length);
+
+        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()[0]
+                .setProvider(new DefaultProvidedInterface("hallo", Float.class));
+        system.start();
+        RequiredInterface[] required = system.getRequiredInterfaces();
+        assertEquals(1, required.length);
+        ProvidedInterface[] provided = system.getProvidedInterfaces();
+        assertEquals(0, provided.length);
+    }
+
+    public void testCompositeWithExternalDependencesNotProvided() {
+        try {
+            Component environment = new Environment();
+            Component application = new Application();
+            Container system = new Container("all",
+                    new Component[] { application }, new ProvidedInterface[0],
+                    application.getRequiredInterfaces());
+            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());
+        environment.start(new DefaultScope(new ProvidedInterface[0]));
+        system.getRequiredInterfaces()[0].setProvider(environment
+                .getProvidedInterfaces()[0]);
+        system.getRequiredInterfaces()[1].setProvider(environment
+                .getProvidedInterfaces()[1]);
+
+        system.start();
+        RequiredInterface[] required = system.getRequiredInterfaces();
+        assertEquals(2, required.length);
+        ProvidedInterface[] provided = system.getProvidedInterfaces();
+        assertEquals(0, provided.length);
+
+    }
+
+    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()[0].setProvider(env
+                .getProvidedInterfaces()[0]);
+        container.getRequiredInterfaces()[1].setProvider(env
+                .getProvidedInterfaces()[1]);
+        Scope external = new DefaultScope(env.getProvidedInterfaces());
+        env.start(external);
+
+        container.start(external);
+        assertSame(env.getProvidedInterfaces()[0], container
+                .getRequiredInterfaces()[0].getProvider());
+        assertSame(env.getProvidedInterfaces()[1], container
+                .getRequiredInterfaces()[1].getProvider());
+        assertSame(env.getProvidedInterfaces()[0], application
+                .getRequiredInterfaces()[0].getProvider());
+        assertSame(env.getProvidedInterfaces()[1], application
+                .getRequiredInterfaces()[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()[0].setProvider(env
+                .getProvidedInterfaces()[0]);
+        Scope external = new DefaultScope(new ProvidedInterface[0]);
+        external.publishInterface(env.getProvidedInterfaces()[0], env
+                .getString());
+        container.start(external);
+        assertSame(env.getProvidedInterfaces()[0], container
+                .getRequiredInterfaces()[0].getProvider());
+        assertNull(container.getRequiredInterfaces()[1].getProvider());
+        assertSame(env.getProvidedInterfaces()[0], application
+                .getRequiredInterfaces()[0].getProvider());
+        assertNull(application.getRequiredInterfaces()[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()[0].setProvider(env
+                .getProvidedInterfaces()[0]);
+        container.getRequiredInterfaces()[1].setProvider(env
+                .getProvidedInterfaces()[1]);
+        container.start();
+        assertSame(env.getProvidedInterfaces()[0], container
+                .getRequiredInterfaces()[0].getProvider());
+        assertSame(env.getProvidedInterfaces()[1], container
+                .getRequiredInterfaces()[1].getProvider());
+        assertSame(env.getProvidedInterfaces()[0], application
+                .getRequiredInterfaces()[0].getProvider());
+        assertSame(env.getProvidedInterfaces()[1], application
+                .getRequiredInterfaces()[1].getProvider());
+    }
+
+    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.addRestriction(new InterfaceRestriction() {
+                    @Override
+                    public boolean isViolated(Component aClient,
+                            RequiredInterface aRequired, Component aServer,
+                            ProvidedInterface aProvided) {
+                        return false;
+                    }
+                });
+            }
+        }, 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.addRestriction(new DefaultInterfaceRestriction("app", null,
+                "env1", null));
+        container.start();
+        assertEquals(env1.getString(), app.getString());
+        assertFalse(env2.getString().equals(app.getString()));
+    }
 }
index f176d4aa748e2fa3a5c731bd9e3c2960fdfccf28..c08f456d117ff6358c7e4cbe0b018038c8f1f320 100644 (file)
@@ -59,7 +59,7 @@ public class Environment extends AbstractComponent {
        }
 
        public String getString() {
-               return "Hello";
+               return getName() + ".hello";
        }
 
        @Override