now allowing components and interfaces to be added after construction.
[utils] / system / general / src / main / java / org / wamblee / system / core / Container.java
index df92c0d099dcb4a61e219bb6047a7b5bea672783..a4b0620fccc589ab5fd48796aa3ca8ba34d17768 100644 (file)
@@ -29,11 +29,12 @@ import org.apache.commons.logging.LogFactory;
  * 
  * @author Erik Brakkee
  */
-public class Container extends AbstractComponent {
+public class Container extends AbstractComponent<Scope> {
 
        private static final Log LOG = LogFactory.getLog(Container.class);
 
-       private Component[] _components;
+       private List<Component> _components;
+       private boolean _sealed; 
 
        public static RequiredInterface[] filterRequiredServices(
                        ProvidedInterface aProvided,
@@ -59,7 +60,7 @@ public class Container extends AbstractComponent {
        }
 
        /**
-        * Construcst the container
+        * Constructs the container
         * 
         * @param aName
         *            Name of the container
@@ -73,20 +74,46 @@ public class Container extends AbstractComponent {
        public Container(String aName, Component[] aComponents,
                        ProvidedInterface[] aProvided, RequiredInterface[] aRequired) {
                super(aName, aProvided, aRequired);
-               _components = aComponents;
+               _components = new ArrayList<Component>(Arrays.asList(aComponents));
                for (Component component : aComponents) {
                        component.addContext(getQualifiedName());
                }
+               _sealed = false; 
                validate();
        }
+       
+       public Container(String aName) {
+           this(aName, new Component[0], new ProvidedInterface[0], new RequiredInterface[0]);
+       }
+       
+       public Container addComponent(Component aComponent) {
+               checkSealed(); 
+               _components.add(aComponent);
+               return this; 
+       }
 
+       @Override
+       protected Container addProvidedInterface(ProvidedInterface aProvided) {
+               checkSealed();
+               super.addProvidedInterface(aProvided);
+               return this; 
+       }
+       
+       @Override
+       protected Container addRequiredInterface(RequiredInterface aRequired) {
+               checkSealed(); 
+               super.addRequiredInterface(aRequired);
+               return this; 
+       }
+       
        /**
         * Validates the components together to check that there are no required
         * services not in the required list and no services in the provided list
         * that cannot be provided. Also logs a warning in case of superfluous
         * requirements.
+        * @throws SystemAssemblyException in case of any validation problems. 
         */
-       private void validate() {
+       public void validate() {
                List<ProvidedInterface> provided = new ArrayList<ProvidedInterface>();
                for (Component component : _components) {
                        provided.addAll(Arrays.asList(component.getProvidedInterfaces()));
@@ -176,10 +203,42 @@ public class Container extends AbstractComponent {
                        }
                }
        }
+       
+       /**
+        * Starts the container. After the container is started, the container becomes sealed
+        * meaning that no further components, required or provided interfaces may be added. 
+        * @return Scope. 
+        */
+       public Scope start() {
+               checkSealed();
+               validate();
+           Scope scope = super.start(new DefaultScope(new ProvidedInterface[0]));
+           seal();
+           return scope; 
+       }
+       
+       /**
+        * Seal the container, meaning that no further components or interfaces may be added. 
+        */
+       public void seal() { 
+               _sealed = true; 
+       }
+
+       /**
+        * Checks if the container is sealed. 
+        * @return True iff the container is sealed. 
+        */
+       public boolean isSealed() {
+               return _sealed;
+       }
 
        @Override
-       protected void doStart() {
+       protected Scope doStart(Scope aExternalScope) {
                LOG.info("Starting '" + getQualifiedName() + "'");
+               
+               Scope scope = new DefaultScope(getProvidedInterfaces(), 
+                               aExternalScope);
+               
                List<ProvidedInterface> allProvided = new ArrayList<ProvidedInterface>();
 
                // all interfaces from the required list of this container are
@@ -203,7 +262,8 @@ public class Container extends AbstractComponent {
                                checkAllRequiredServicesAlreadyProvided(allProvided, component);
 
                                // Start the service.
-                               component.start();
+                               Object runtime = component.start(scope);
+                               scope.addRuntime(component, runtime); 
                                started.add(component);
 
                                // add all provided services
@@ -214,19 +274,19 @@ public class Container extends AbstractComponent {
                        } catch (RuntimeException e) {
                                LOG.error(getQualifiedName() + ": could not start '"
                                                + component.getQualifiedName() + "'", e);
-                               stopAlreadyStartedComponents(started);
+                               stopAlreadyStartedComponents(started, scope);
                                throw e; 
                        }
                }
-
+               return scope; 
        }
 
-       private void stopAlreadyStartedComponents(List<Component> aStarted) {
+       private void stopAlreadyStartedComponents(List<Component> aStarted, Scope aScope) {
                // an exception occurred, stop the successfully started
                // components
                for (int i = aStarted.size() - 1; i >= 0; i--) {
                        try {
-                               aStarted.get(i).stop();
+                               aStarted.get(i).stop(aScope);
                        } catch (Throwable t) {
                                LOG.error(getQualifiedName() + ": error stopping "
                                                + aStarted.get(i).getQualifiedName());
@@ -268,9 +328,11 @@ public class Container extends AbstractComponent {
        }
 
        @Override
-       protected void doStop() {
-               for (int i = _components.length - 1; i >= 0; i--) {
-                       _components[i].stop();
+       protected void doStop(Scope aScope) {
+               for (int i = _components.size() - 1; i >= 0; i--) {
+                       Component component = _components.get(i);
+                       Object runtime = aScope.getRuntime(component);
+                       component.stop(runtime);
                }
        }
 
@@ -309,4 +371,10 @@ public class Container extends AbstractComponent {
                }
                return clients; 
        }
+       
+       private void checkSealed() { 
+               if ( _sealed ) { 
+                       throw new SystemAssemblyException("Container is sealed");
+               }
+       }
 }