[Bugfix] fixed bug where controllers aren't properly stopped
- this occurred for controllers which had dependencies of other dependencies
This commit is contained in:
parent
6eb6f8d503
commit
b731be86e3
|
@ -52,6 +52,8 @@ public class ComponentContainerImpl implements ComponentContainer {
|
||||||
private StrolchConfiguration strolchConfiguration;
|
private StrolchConfiguration strolchConfiguration;
|
||||||
private ComponentState state;
|
private ComponentState state;
|
||||||
|
|
||||||
|
private ComponentContainerStateHandler containerStateHandler;
|
||||||
|
|
||||||
public ComponentContainerImpl(StrolchAgent agent) {
|
public ComponentContainerImpl(StrolchAgent agent) {
|
||||||
this.agent = agent;
|
this.agent = agent;
|
||||||
this.state = ComponentState.UNDEFINED;
|
this.state = ComponentState.UNDEFINED;
|
||||||
|
@ -151,103 +153,6 @@ public class ComponentContainerImpl implements ComponentContainer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void initialize(Set<ComponentController> controllers) {
|
|
||||||
|
|
||||||
// initialize each component
|
|
||||||
for (ComponentController controller : controllers) {
|
|
||||||
if (controller.getState() == ComponentState.INITIALIZED)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
StrolchComponent component = controller.getComponent();
|
|
||||||
String componentName = component.getName();
|
|
||||||
ComponentConfiguration componentConfiguration = this.strolchConfiguration
|
|
||||||
.getComponentConfiguration(componentName);
|
|
||||||
|
|
||||||
String msg = "Initializing component {0}..."; //$NON-NLS-1$
|
|
||||||
logger.info(MessageFormat.format(msg, componentName));
|
|
||||||
component.initialize(componentConfiguration);
|
|
||||||
}
|
|
||||||
|
|
||||||
// initialize direct downstream components
|
|
||||||
Set<ComponentController> dependencies = this.dependencyAnalyzer
|
|
||||||
.collectDirectDownstreamDependencies(controllers);
|
|
||||||
if (!dependencies.isEmpty())
|
|
||||||
initialize(dependencies);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void start(Set<ComponentController> controllers) {
|
|
||||||
|
|
||||||
// Start each component
|
|
||||||
for (ComponentController controller : controllers) {
|
|
||||||
if (controller.getState() == ComponentState.STARTED)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
StrolchComponent component = controller.getComponent();
|
|
||||||
String msg = "Starting component {0}..."; //$NON-NLS-1$
|
|
||||||
String componentName = component.getName();
|
|
||||||
logger.info(MessageFormat.format(msg, componentName));
|
|
||||||
component.start();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Start direct downstream components
|
|
||||||
Set<ComponentController> dependencies = this.dependencyAnalyzer
|
|
||||||
.collectDirectDownstreamDependencies(controllers);
|
|
||||||
if (!dependencies.isEmpty())
|
|
||||||
start(dependencies);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void stop(Set<ComponentController> controllers) {
|
|
||||||
|
|
||||||
// Stop each component
|
|
||||||
for (ComponentController controller : controllers) {
|
|
||||||
if (controller.getState() == ComponentState.STOPPED)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
StrolchComponent component = controller.getComponent();
|
|
||||||
String msg = "Stopping component {0}..."; //$NON-NLS-1$
|
|
||||||
String componentName = component.getName();
|
|
||||||
logger.info(MessageFormat.format(msg, componentName));
|
|
||||||
try {
|
|
||||||
component.stop();
|
|
||||||
} catch (Exception e) {
|
|
||||||
msg = "Failed to stop component {0} due to {1}"; //$NON-NLS-1$
|
|
||||||
msg = MessageFormat.format(msg, componentName, e.getMessage());
|
|
||||||
logger.error(msg, e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Stop direct upstream components
|
|
||||||
Set<ComponentController> dependencies = this.dependencyAnalyzer.collectDirectUpstreamDependencies(controllers);
|
|
||||||
if (!dependencies.isEmpty())
|
|
||||||
stop(dependencies);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void destroy(Set<ComponentController> controllers) {
|
|
||||||
|
|
||||||
// Destroy each component
|
|
||||||
for (ComponentController controller : controllers) {
|
|
||||||
if (controller.getState() == ComponentState.DESTROYED)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
StrolchComponent component = controller.getComponent();
|
|
||||||
String msg = "Destroying component {0}..."; //$NON-NLS-1$
|
|
||||||
String componentName = component.getName();
|
|
||||||
logger.info(MessageFormat.format(msg, componentName));
|
|
||||||
try {
|
|
||||||
component.destroy();
|
|
||||||
} catch (Exception e) {
|
|
||||||
msg = "Failed to destroy component {0} due to {1}"; //$NON-NLS-1$
|
|
||||||
msg = MessageFormat.format(msg, componentName, e.getMessage());
|
|
||||||
logger.error(msg, e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Destroy direct upstream components
|
|
||||||
Set<ComponentController> dependencies = this.dependencyAnalyzer.collectDirectUpstreamDependencies(controllers);
|
|
||||||
if (!dependencies.isEmpty())
|
|
||||||
destroy(dependencies);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setup(StrolchConfiguration strolchConfiguration) {
|
public void setup(StrolchConfiguration strolchConfiguration) {
|
||||||
|
|
||||||
// set the application locale
|
// set the application locale
|
||||||
|
@ -278,68 +183,84 @@ public class ComponentContainerImpl implements ComponentContainer {
|
||||||
this.controllerMap = controllerMap;
|
this.controllerMap = controllerMap;
|
||||||
this.strolchConfiguration = strolchConfiguration;
|
this.strolchConfiguration = strolchConfiguration;
|
||||||
|
|
||||||
|
// and configure the state handler
|
||||||
|
this.containerStateHandler = new ComponentContainerStateHandler(this.dependencyAnalyzer,
|
||||||
|
this.strolchConfiguration);
|
||||||
|
|
||||||
this.state = this.state.validateStateChange(ComponentState.SETUP);
|
this.state = this.state.validateStateChange(ComponentState.SETUP);
|
||||||
String msg = "Strolch Container setup with {0} components."; //$NON-NLS-1$
|
String msg = "{0}:{1} Strolch Container setup with {2} components."; //$NON-NLS-1$
|
||||||
logger.info(MessageFormat.format(msg, this.componentMap.size()));
|
logger.info(MessageFormat.format(msg, getAgent().getApplicationName(), getAgent().getStrolchConfiguration()
|
||||||
|
.getRuntimeConfiguration().getEnvironment(), this.componentMap.size()));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void initialize(StrolchConfiguration strolchConfiguration) {
|
public void initialize(StrolchConfiguration strolchConfiguration) {
|
||||||
|
|
||||||
// now we can initialize the components
|
// now we can initialize the components
|
||||||
logger.info("Initializing strolch components..."); //$NON-NLS-1$
|
String msg = "{0}:{1} Initializing {2} Strolch Components..."; //$NON-NLS-1$
|
||||||
|
logger.info(MessageFormat.format(msg, getAgent().getApplicationName(), getAgent().getStrolchConfiguration()
|
||||||
|
.getRuntimeConfiguration().getEnvironment(), this.controllerMap.size()));
|
||||||
|
|
||||||
Set<ComponentController> rootUpstreamComponents = this.dependencyAnalyzer.findRootUpstreamComponents();
|
Set<ComponentController> rootUpstreamComponents = this.dependencyAnalyzer.findRootUpstreamComponents();
|
||||||
initialize(rootUpstreamComponents);
|
containerStateHandler.initialize(rootUpstreamComponents);
|
||||||
this.state = this.state.validateStateChange(ComponentState.INITIALIZED);
|
this.state = this.state.validateStateChange(ComponentState.INITIALIZED);
|
||||||
|
|
||||||
String msg = "All {0} Strolch Components have been initialized."; //$NON-NLS-1$
|
msg = "{0}:{1} All {2} Strolch Components have been initialized."; //$NON-NLS-1$
|
||||||
logger.info(MessageFormat.format(msg, this.controllerMap.size()));
|
logger.info(MessageFormat.format(msg, getAgent().getApplicationName(), getAgent().getStrolchConfiguration()
|
||||||
|
.getRuntimeConfiguration().getEnvironment(), this.controllerMap.size()));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void start() {
|
public void start() {
|
||||||
|
|
||||||
logger.info("Starting strolch components..."); //$NON-NLS-1$
|
String msg = "{0}:{1} Starting {2} Strolch Components..."; //$NON-NLS-1$
|
||||||
|
logger.info(MessageFormat.format(msg, getAgent().getApplicationName(), getAgent().getStrolchConfiguration()
|
||||||
|
.getRuntimeConfiguration().getEnvironment(), this.controllerMap.size()));
|
||||||
|
|
||||||
Set<ComponentController> rootUpstreamComponents = this.dependencyAnalyzer.findRootUpstreamComponents();
|
Set<ComponentController> rootUpstreamComponents = this.dependencyAnalyzer.findRootUpstreamComponents();
|
||||||
start(rootUpstreamComponents);
|
containerStateHandler.start(rootUpstreamComponents);
|
||||||
this.state = this.state.validateStateChange(ComponentState.STARTED);
|
this.state = this.state.validateStateChange(ComponentState.STARTED);
|
||||||
|
|
||||||
String msg = "All {0} Strolch Components started. {1}:{2} is now ready to be used. Have fun =))"; //$NON-NLS-1$
|
msg = "{0}:{1} All {2} Strolch Components started. Strolch is now ready to be used. Have fun =))"; //$NON-NLS-1$
|
||||||
logger.info(MessageFormat.format(msg, this.controllerMap.size(), getAgent().getApplicationName(), getAgent()
|
logger.info(MessageFormat.format(msg, getAgent().getApplicationName(), getAgent().getStrolchConfiguration()
|
||||||
.getStrolchConfiguration().getRuntimeConfiguration().getEnvironment()));
|
.getRuntimeConfiguration().getEnvironment(), this.controllerMap.size()));
|
||||||
logger.info(MessageFormat.format("System: {0}", SystemHelper.asString())); //$NON-NLS-1$
|
logger.info(MessageFormat.format("System: {0}", SystemHelper.asString())); //$NON-NLS-1$
|
||||||
logger.info(MessageFormat.format("Memory: {0}", SystemHelper.getMemorySummary())); //$NON-NLS-1$
|
logger.info(MessageFormat.format("Memory: {0}", SystemHelper.getMemorySummary())); //$NON-NLS-1$
|
||||||
}
|
}
|
||||||
|
|
||||||
public void stop() {
|
public void stop() {
|
||||||
|
|
||||||
logger.info("Stopping strolch components..."); //$NON-NLS-1$
|
String msg = "{0}:{1} Stopping {2} Strolch Components..."; //$NON-NLS-1$
|
||||||
|
logger.info(MessageFormat.format(msg, getAgent().getApplicationName(), getAgent().getStrolchConfiguration()
|
||||||
|
.getRuntimeConfiguration().getEnvironment(), this.controllerMap.size()));
|
||||||
|
|
||||||
if (this.dependencyAnalyzer == null) {
|
if (this.dependencyAnalyzer == null) {
|
||||||
logger.info("Strolch Components have been stopped."); //$NON-NLS-1$
|
logger.info("Strolch was not yet setup, nothing to stop"); //$NON-NLS-1$
|
||||||
} else {
|
} else {
|
||||||
Set<ComponentController> rootUpstreamComponents = this.dependencyAnalyzer.findRootDownstreamComponents();
|
Set<ComponentController> rootUpstreamComponents = this.dependencyAnalyzer.findRootDownstreamComponents();
|
||||||
stop(rootUpstreamComponents);
|
containerStateHandler.stop(rootUpstreamComponents);
|
||||||
this.state = this.state.validateStateChange(ComponentState.STOPPED);
|
this.state = this.state.validateStateChange(ComponentState.STOPPED);
|
||||||
|
|
||||||
String msg = "All {0} Strolch Components have been stopped."; //$NON-NLS-1$
|
msg = "{0}:{1} All {2} Strolch Components have been stopped."; //$NON-NLS-1$
|
||||||
logger.info(MessageFormat.format(msg, this.controllerMap.size()));
|
logger.info(MessageFormat.format(msg, getAgent().getApplicationName(), getAgent().getStrolchConfiguration()
|
||||||
|
.getRuntimeConfiguration().getEnvironment(), this.controllerMap.size()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void destroy() {
|
public void destroy() {
|
||||||
|
|
||||||
logger.info("Destroying strolch components..."); //$NON-NLS-1$
|
String msg = "{0}:{1} Destroying {2} Strolch Components..."; //$NON-NLS-1$
|
||||||
|
logger.info(MessageFormat.format(msg, getAgent().getApplicationName(), getAgent().getStrolchConfiguration()
|
||||||
|
.getRuntimeConfiguration().getEnvironment(), this.controllerMap.size()));
|
||||||
|
|
||||||
if (this.dependencyAnalyzer == null) {
|
if (this.dependencyAnalyzer == null) {
|
||||||
logger.info("Strolch Components have been destroyed."); //$NON-NLS-1$
|
logger.info("Strolch was not yet setup, nothing to destroy"); //$NON-NLS-1$
|
||||||
} else {
|
} else {
|
||||||
Set<ComponentController> rootUpstreamComponents = this.dependencyAnalyzer.findRootDownstreamComponents();
|
Set<ComponentController> rootUpstreamComponents = this.dependencyAnalyzer.findRootDownstreamComponents();
|
||||||
destroy(rootUpstreamComponents);
|
containerStateHandler.destroy(rootUpstreamComponents);
|
||||||
this.state = this.state.validateStateChange(ComponentState.DESTROYED);
|
this.state = this.state.validateStateChange(ComponentState.DESTROYED);
|
||||||
|
|
||||||
String msg = "All {0} Strolch Components have been destroyed!"; //$NON-NLS-1$
|
msg = "{0}:{1} All {2} Strolch Components have been destroyed!"; //$NON-NLS-1$
|
||||||
logger.info(MessageFormat.format(msg, this.controllerMap.size()));
|
logger.info(MessageFormat.format(msg, getAgent().getApplicationName(), getAgent().getStrolchConfiguration()
|
||||||
|
.getRuntimeConfiguration().getEnvironment(), this.controllerMap.size()));
|
||||||
this.controllerMap.clear();
|
this.controllerMap.clear();
|
||||||
this.componentMap.clear();
|
this.componentMap.clear();
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,140 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2013 Robert von Burg <eitch@eitchnet.ch>
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package li.strolch.agent.impl;
|
||||||
|
|
||||||
|
import java.text.MessageFormat;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import li.strolch.agent.api.ComponentState;
|
||||||
|
import li.strolch.agent.api.StrolchComponent;
|
||||||
|
import li.strolch.runtime.configuration.ComponentConfiguration;
|
||||||
|
import li.strolch.runtime.configuration.StrolchConfiguration;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Robert von Burg <eitch@eitchnet.ch>
|
||||||
|
*/
|
||||||
|
public class ComponentContainerStateHandler {
|
||||||
|
|
||||||
|
private static final Logger logger = LoggerFactory.getLogger(ComponentContainerStateHandler.class);
|
||||||
|
private ComponentDependencyAnalyzer dependencyAnalyzer;
|
||||||
|
private StrolchConfiguration strolchConfiguration;
|
||||||
|
|
||||||
|
public ComponentContainerStateHandler(ComponentDependencyAnalyzer dependencyAnalyzer,
|
||||||
|
StrolchConfiguration strolchConfiguration) {
|
||||||
|
this.dependencyAnalyzer = dependencyAnalyzer;
|
||||||
|
this.strolchConfiguration = strolchConfiguration;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void initialize(Set<ComponentController> controllers) {
|
||||||
|
|
||||||
|
// initialize each component
|
||||||
|
for (ComponentController controller : controllers) {
|
||||||
|
if (controller.getState() == ComponentState.INITIALIZED)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
StrolchComponent component = controller.getComponent();
|
||||||
|
String componentName = component.getName();
|
||||||
|
ComponentConfiguration componentConfiguration = this.strolchConfiguration
|
||||||
|
.getComponentConfiguration(componentName);
|
||||||
|
|
||||||
|
String msg = "Initializing component {0}..."; //$NON-NLS-1$
|
||||||
|
logger.info(MessageFormat.format(msg, componentName));
|
||||||
|
component.initialize(componentConfiguration);
|
||||||
|
}
|
||||||
|
|
||||||
|
// initialize direct downstream components
|
||||||
|
Set<ComponentController> dependencies = this.dependencyAnalyzer
|
||||||
|
.collectDirectDownstreamDependencies(controllers);
|
||||||
|
if (!dependencies.isEmpty())
|
||||||
|
initialize(dependencies);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void start(Set<ComponentController> controllers) {
|
||||||
|
|
||||||
|
// Start each component
|
||||||
|
for (ComponentController controller : controllers) {
|
||||||
|
if (controller.getState() == ComponentState.STARTED)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
StrolchComponent component = controller.getComponent();
|
||||||
|
String msg = "Starting component {0}..."; //$NON-NLS-1$
|
||||||
|
String componentName = component.getName();
|
||||||
|
logger.info(MessageFormat.format(msg, componentName));
|
||||||
|
component.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start direct downstream components
|
||||||
|
Set<ComponentController> dependencies = this.dependencyAnalyzer
|
||||||
|
.collectDirectDownstreamDependencies(controllers);
|
||||||
|
if (!dependencies.isEmpty())
|
||||||
|
start(dependencies);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void stop(Set<ComponentController> controllers) {
|
||||||
|
|
||||||
|
// Stop each component
|
||||||
|
for (ComponentController controller : controllers) {
|
||||||
|
if (controller.getState() == ComponentState.STOPPED)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
StrolchComponent component = controller.getComponent();
|
||||||
|
String msg = "Stopping component {0}..."; //$NON-NLS-1$
|
||||||
|
String componentName = component.getName();
|
||||||
|
logger.info(MessageFormat.format(msg, componentName));
|
||||||
|
try {
|
||||||
|
component.stop();
|
||||||
|
} catch (Exception e) {
|
||||||
|
msg = "Failed to stop component {0} due to {1}"; //$NON-NLS-1$
|
||||||
|
msg = MessageFormat.format(msg, componentName, e.getMessage());
|
||||||
|
logger.error(msg, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Stop direct upstream components
|
||||||
|
Set<ComponentController> dependencies = this.dependencyAnalyzer.collectDirectUpstreamDependencies(controllers);
|
||||||
|
if (!dependencies.isEmpty())
|
||||||
|
stop(dependencies);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void destroy(Set<ComponentController> controllers) {
|
||||||
|
|
||||||
|
// Destroy each component
|
||||||
|
for (ComponentController controller : controllers) {
|
||||||
|
if (controller.getState() == ComponentState.DESTROYED)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
StrolchComponent component = controller.getComponent();
|
||||||
|
String msg = "Destroying component {0}..."; //$NON-NLS-1$
|
||||||
|
String componentName = component.getName();
|
||||||
|
logger.info(MessageFormat.format(msg, componentName));
|
||||||
|
try {
|
||||||
|
component.destroy();
|
||||||
|
} catch (Exception e) {
|
||||||
|
msg = "Failed to destroy component {0} due to {1}"; //$NON-NLS-1$
|
||||||
|
msg = MessageFormat.format(msg, componentName, e.getMessage());
|
||||||
|
logger.error(msg, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Destroy direct upstream components
|
||||||
|
Set<ComponentController> dependencies = this.dependencyAnalyzer.collectDirectUpstreamDependencies(controllers);
|
||||||
|
if (!dependencies.isEmpty())
|
||||||
|
destroy(dependencies);
|
||||||
|
}
|
||||||
|
}
|
|
@ -45,6 +45,10 @@ public class ComponentController {
|
||||||
return this.component;
|
return this.component;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getComponentName() {
|
||||||
|
return this.component.getName();
|
||||||
|
}
|
||||||
|
|
||||||
public Set<ComponentController> getUpstreamDependencies() {
|
public Set<ComponentController> getUpstreamDependencies() {
|
||||||
return new HashSet<>(this.upstreamDependencies);
|
return new HashSet<>(this.upstreamDependencies);
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,7 +17,6 @@ package li.strolch.agent.impl;
|
||||||
|
|
||||||
import java.text.MessageFormat;
|
import java.text.MessageFormat;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Iterator;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
|
@ -62,6 +61,15 @@ public class ComponentDependencyAnalyzer {
|
||||||
return controllers;
|
return controllers;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Set<ComponentController> collectAllUpstreamDependencies(ComponentController controller) {
|
||||||
|
Set<ComponentController> upstreamDependencies = new HashSet<>(controller.getUpstreamDependencies());
|
||||||
|
for (ComponentController upstream : upstreamDependencies) {
|
||||||
|
upstreamDependencies.addAll(collectAllUpstreamDependencies(upstream));
|
||||||
|
}
|
||||||
|
|
||||||
|
return upstreamDependencies;
|
||||||
|
}
|
||||||
|
|
||||||
public Set<ComponentController> collectDirectUpstreamDependencies(Set<ComponentController> controllers) {
|
public Set<ComponentController> collectDirectUpstreamDependencies(Set<ComponentController> controllers) {
|
||||||
|
|
||||||
Set<ComponentController> directUpstreamDependencies = new HashSet<>();
|
Set<ComponentController> directUpstreamDependencies = new HashSet<>();
|
||||||
|
@ -72,27 +80,25 @@ public class ComponentDependencyAnalyzer {
|
||||||
directUpstreamDependencies.addAll(upstreamDependencies);
|
directUpstreamDependencies.addAll(upstreamDependencies);
|
||||||
}
|
}
|
||||||
|
|
||||||
// prune dependencies which are a dependency of any of these dependencies
|
// prune any controllers which are an upstream dependency of any of these dependencies
|
||||||
for (ComponentController controller : controllers) {
|
Set<ComponentController> tmp = new HashSet<>(directUpstreamDependencies);
|
||||||
Set<ComponentController> upstreamDependencies = controller.getUpstreamDependencies();
|
for (ComponentController controller : tmp) {
|
||||||
|
Set<ComponentController> upstreamDeps = collectAllUpstreamDependencies(controller);
|
||||||
for (ComponentController upstream : upstreamDependencies) {
|
directUpstreamDependencies.removeAll(upstreamDeps);
|
||||||
|
|
||||||
Iterator<ComponentController> iter = directUpstreamDependencies.iterator();
|
|
||||||
while (iter.hasNext()) {
|
|
||||||
ComponentController possibleTransitiveDependency = iter.next();
|
|
||||||
if (upstream.hasUpstreamDependency(possibleTransitiveDependency))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (possibleTransitiveDependency.hasTransitiveUpstreamDependency(upstream))
|
|
||||||
iter.remove();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return directUpstreamDependencies;
|
return directUpstreamDependencies;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Set<ComponentController> collectAllDownstreamDependencies(ComponentController controller) {
|
||||||
|
Set<ComponentController> downstreamDependencies = new HashSet<>(controller.getDownstreamDependencies());
|
||||||
|
for (ComponentController downstream : downstreamDependencies) {
|
||||||
|
downstreamDependencies.addAll(collectAllDownstreamDependencies(downstream));
|
||||||
|
}
|
||||||
|
|
||||||
|
return downstreamDependencies;
|
||||||
|
}
|
||||||
|
|
||||||
public Set<ComponentController> collectDirectDownstreamDependencies(Set<ComponentController> controllers) {
|
public Set<ComponentController> collectDirectDownstreamDependencies(Set<ComponentController> controllers) {
|
||||||
|
|
||||||
Set<ComponentController> directDownstreamDependencies = new HashSet<>();
|
Set<ComponentController> directDownstreamDependencies = new HashSet<>();
|
||||||
|
@ -103,22 +109,11 @@ public class ComponentDependencyAnalyzer {
|
||||||
directDownstreamDependencies.addAll(downstreamDependencies);
|
directDownstreamDependencies.addAll(downstreamDependencies);
|
||||||
}
|
}
|
||||||
|
|
||||||
// prune dependencies which are a dependency of any of these dependencies
|
// prune any controllers which are a downstream dependency of any of these dependencies
|
||||||
for (ComponentController controller : controllers) {
|
Set<ComponentController> tmp = new HashSet<>(directDownstreamDependencies);
|
||||||
Set<ComponentController> downstreamDependencies = controller.getDownstreamDependencies();
|
for (ComponentController controller : tmp) {
|
||||||
|
Set<ComponentController> downstreamDeps = collectAllDownstreamDependencies(controller);
|
||||||
for (ComponentController downstream : downstreamDependencies) {
|
directDownstreamDependencies.removeAll(downstreamDeps);
|
||||||
|
|
||||||
Iterator<ComponentController> iter = directDownstreamDependencies.iterator();
|
|
||||||
while (iter.hasNext()) {
|
|
||||||
ComponentController possibleTransitiveDependency = iter.next();
|
|
||||||
if (downstream.hasUpstreamDependency(possibleTransitiveDependency))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (possibleTransitiveDependency.hasTransitiveDownstreamDependency(downstream))
|
|
||||||
iter.remove();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return directDownstreamDependencies;
|
return directDownstreamDependencies;
|
||||||
|
@ -141,17 +136,17 @@ public class ComponentDependencyAnalyzer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
logDependencies(0, findRootUpstreamComponents());
|
logDependencies(1, findRootUpstreamComponents());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param components
|
* @param components
|
||||||
*/
|
*/
|
||||||
private void logDependencies(int depth, Set<ComponentController> components) {
|
private void logDependencies(int depth, Set<ComponentController> components) {
|
||||||
if (depth == 0) {
|
if (depth == 1) {
|
||||||
logger.info("Dependency tree:"); //$NON-NLS-1$
|
logger.info("Dependency tree:"); //$NON-NLS-1$
|
||||||
}
|
}
|
||||||
String inset = StringHelper.normalizeLength(" ", depth * 2, false, ' '); //$NON-NLS-1$
|
String inset = StringHelper.normalizeLength("", depth * 2, false, ' '); //$NON-NLS-1$
|
||||||
for (ComponentController controller : components) {
|
for (ComponentController controller : components) {
|
||||||
logger.info(inset + controller.getComponent().getName() + ": "
|
logger.info(inset + controller.getComponent().getName() + ": "
|
||||||
+ controller.getComponent().getClass().getName());
|
+ controller.getComponent().getClass().getName());
|
||||||
|
|
|
@ -20,13 +20,16 @@ import static org.junit.Assert.assertFalse;
|
||||||
import static org.junit.Assert.assertTrue;
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
import java.util.Collection;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
|
import li.strolch.agent.api.ComponentState;
|
||||||
import li.strolch.agent.api.StrolchComponent;
|
import li.strolch.agent.api.StrolchComponent;
|
||||||
import li.strolch.agent.impl.ComponentContainerImpl;
|
import li.strolch.agent.impl.ComponentContainerImpl;
|
||||||
|
import li.strolch.agent.impl.ComponentContainerStateHandler;
|
||||||
import li.strolch.agent.impl.ComponentController;
|
import li.strolch.agent.impl.ComponentController;
|
||||||
import li.strolch.agent.impl.ComponentDependencyAnalyzer;
|
import li.strolch.agent.impl.ComponentDependencyAnalyzer;
|
||||||
|
|
||||||
|
@ -169,9 +172,6 @@ public class ControllerDependencyTest {
|
||||||
|
|
||||||
//
|
//
|
||||||
|
|
||||||
File rootPathF = new File("src/test/resources/configtest");
|
|
||||||
this.strolchConfiguration = ConfigurationParser.parseConfiguration("dev", rootPathF);
|
|
||||||
|
|
||||||
this.controllerMap = new HashMap<>();
|
this.controllerMap = new HashMap<>();
|
||||||
|
|
||||||
this.controllerMap.put("2", this.con2);
|
this.controllerMap.put("2", this.con2);
|
||||||
|
@ -195,6 +195,16 @@ public class ControllerDependencyTest {
|
||||||
this.controllerMap.put("C2", this.conC2);
|
this.controllerMap.put("C2", this.conC2);
|
||||||
this.controllerMap.put("D2", this.conD2);
|
this.controllerMap.put("D2", this.conD2);
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
|
File rootPathF = new File("src/test/resources/configtest");
|
||||||
|
this.strolchConfiguration = ConfigurationParser.parseConfiguration("dev", rootPathF);
|
||||||
|
for (ComponentController controller : this.controllerMap.values()) {
|
||||||
|
ComponentConfiguration componentConfiguration = new ComponentConfiguration(
|
||||||
|
this.strolchConfiguration.getRuntimeConfiguration(), controller.getComponentName(), null, null,
|
||||||
|
null, null);
|
||||||
|
this.strolchConfiguration.addConfiguration(controller.getComponentName(), componentConfiguration);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void assertModel() {
|
private void assertModel() {
|
||||||
|
@ -568,4 +578,43 @@ public class ControllerDependencyTest {
|
||||||
assertTrue(transitiveUpstreamDependency2.hasTransitiveDownstreamDependency(controller));
|
assertTrue(transitiveUpstreamDependency2.hasTransitiveDownstreamDependency(controller));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shouldRunThroughModelStates() {
|
||||||
|
|
||||||
|
ComponentDependencyAnalyzer dependencyAnalyzer = new ComponentDependencyAnalyzer(this.strolchConfiguration,
|
||||||
|
this.controllerMap);
|
||||||
|
ComponentContainerStateHandler stateHandler = new ComponentContainerStateHandler(dependencyAnalyzer,
|
||||||
|
strolchConfiguration);
|
||||||
|
|
||||||
|
for (ComponentController controller : this.controllerMap.values()) {
|
||||||
|
assertEquals(ComponentState.UNDEFINED, controller.getState());
|
||||||
|
|
||||||
|
ComponentConfiguration componentConfiguration = this.strolchConfiguration
|
||||||
|
.getComponentConfiguration(controller.getComponentName());
|
||||||
|
controller.getComponent().setup(componentConfiguration);
|
||||||
|
}
|
||||||
|
|
||||||
|
Set<ComponentController> rootUpstreamComponents = dependencyAnalyzer.findRootUpstreamComponents();
|
||||||
|
|
||||||
|
assertState(ComponentState.SETUP, this.controllerMap.values());
|
||||||
|
|
||||||
|
stateHandler.initialize(rootUpstreamComponents);
|
||||||
|
assertState(ComponentState.INITIALIZED, this.controllerMap.values());
|
||||||
|
|
||||||
|
stateHandler.start(rootUpstreamComponents);
|
||||||
|
assertState(ComponentState.STARTED, this.controllerMap.values());
|
||||||
|
|
||||||
|
Set<ComponentController> rootDownstreamComponents = dependencyAnalyzer.findRootDownstreamComponents();
|
||||||
|
stateHandler.stop(rootDownstreamComponents);
|
||||||
|
assertState(ComponentState.STOPPED, this.controllerMap.values());
|
||||||
|
|
||||||
|
stateHandler.destroy(rootDownstreamComponents);
|
||||||
|
assertState(ComponentState.DESTROYED, this.controllerMap.values());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void assertState(ComponentState expectedState, Collection<ComponentController> collection) {
|
||||||
|
for (ComponentController controller : collection) {
|
||||||
|
assertEquals(expectedState, controller.getState());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue