1 package org.wamblee.system;
3 import java.util.ArrayList;
4 import java.util.Arrays;
5 import java.util.Collection;
6 import java.util.HashMap;
7 import java.util.HashSet;
12 import org.apache.commons.logging.Log;
13 import org.apache.commons.logging.LogFactory;
16 * Assembler to control multiple subsystems. It makes sure that all dependencies
17 * are met and controls the order in which systems are initialized.
19 * @author Erik Brakkee
21 public class SystemAssembler {
23 private static final Log LOG = LogFactory.getLog(SystemAssembler.class);
25 private static final String ROOT_CONTEXT_NAME = "root";
26 private String _context;
27 private Component[] _systems;
28 private ProvidedInterface[] _required;
30 public static RequiredInterface[] filterRequiredServices(
31 ProvidedInterface aProvided,
32 Collection<RequiredInterface> aDescriptors) {
33 List<RequiredInterface> required = new ArrayList<RequiredInterface>();
34 for (RequiredInterface descriptor : aDescriptors) {
35 if (descriptor.implementedBy(aProvided)) {
36 required.add(descriptor);
39 return required.toArray(new RequiredInterface[0]);
42 public static ProvidedInterface[] filterProvidedServices(
43 RequiredInterface aRequired,
44 Collection<ProvidedInterface> aProvided) {
45 List<ProvidedInterface> provided = new ArrayList<ProvidedInterface>();
46 for (ProvidedInterface descriptor : aProvided) {
47 if (aRequired.implementedBy(descriptor)) {
48 provided.add(descriptor);
51 return provided.toArray(new ProvidedInterface[0]);
55 * Constructs the assembler.
58 * Systems that must be assembled.
59 * @param aAvailableServices
60 * Available services from other systems outside of the systems
61 * that this assembler manages.
63 public SystemAssembler(Component[] aSystems,
64 ProvidedInterface[] aAvailableServices) {
65 this(ROOT_CONTEXT_NAME, aSystems, aAvailableServices);
69 * Constructs the assembler.
72 * Context (unique name) of the assembler.
74 * Systems that must be assembled.
75 * @param aAvailableServices
76 * Available services from other systems outside of the systems
77 * that this assembler manages.
79 public SystemAssembler(String aContext, Component[] aSystems,
80 ProvidedInterface[] aAvailableServices) {
83 _required = aAvailableServices;
88 * Determines if the systems are ordered appropriately so that all
89 * dependencies are met.
91 private void validate()
92 throws SystemAssemblyException {
94 List<ProvidedInterface> allProvided = new ArrayList<ProvidedInterface>();
95 for (ProvidedInterface descriptor : _required) {
96 allProvided.add(descriptor);
98 for (Component system : _systems) {
99 // Check if all required services are already provided by earlier
101 RequiredInterface[] required = system.getRequiredServices();
103 for (RequiredInterface descriptor : required) {
104 ProvidedInterface[] filtered = filterProvidedServices(
105 descriptor, allProvided);
107 if (filtered.length == 0) {
108 throw new SystemAssemblyException(
111 + "' required by system '"
113 + "' is not provided by systems that are started earlier");
115 if (filtered.length > 1) {
116 throw new SystemAssemblyException(
119 + "' required by system '"
121 + "' matches multiple services provided by other systems: " +
122 Arrays.asList(filtered));
126 // add all provided services
127 ProvidedInterface[] provided = system.getProvidedServices();
128 allProvided.addAll(Arrays.asList(provided));
133 * Starts the subsystems.
135 * @param aRequiredServices
136 * Services that are available from other systems that have been
139 public void start() {
140 LOG.info("Starting '" + _context + "'");
141 Set<ProvidedInterface> allProvided = new HashSet<ProvidedInterface>();
142 allProvided.addAll(Arrays.asList(_required));
144 for (Component system : _systems) {
146 // Compose a list of the required services required for the subsystem.
148 RequiredInterface[] descriptors = system
149 .getRequiredServices();
150 List<ProvidedInterface> services = new ArrayList<ProvidedInterface>();
151 for (RequiredInterface required : descriptors) {
152 ProvidedInterface[] provided = filterProvidedServices(
153 required, allProvided);
154 assert provided.length == 1;
155 services.add(provided[0]);
156 required.setProvider(provided[0]);
159 // Start the service.
160 system.start(_context);
162 // Add started services to the set of started services.
163 for (ProvidedInterface service : system.getProvidedServices()) {
164 allProvided.add(service);