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;
10 import org.apache.commons.logging.Log;
11 import org.apache.commons.logging.LogFactory;
14 * Assembler to control multiple subsystems. It makes sure that all dependencies
15 * are met and controls the order in which systems are initialized.
17 * @author Erik Brakkee
19 public class SystemAssembler {
21 private static final Log LOG = LogFactory.getLog(SystemAssembler.class);
23 private static final String ROOT_CONTEXT_NAME = "root";
24 private String _context;
25 private Component[] _systems;
27 public static RequiredInterfaceDescriptor[] filterRequiredServices(
28 ProvidedInterfaceDescriptor aProvided,
29 Collection<RequiredInterfaceDescriptor> aDescriptors) {
30 List<RequiredInterfaceDescriptor> required = new ArrayList<RequiredInterfaceDescriptor>();
31 for (RequiredInterfaceDescriptor descriptor : aDescriptors) {
32 if (descriptor.implementedBy(aProvided)) {
33 required.add(descriptor);
36 return required.toArray(new RequiredInterfaceDescriptor[0]);
39 public static ProvidedInterfaceDescriptor[] filterProvidedServices(
40 RequiredInterfaceDescriptor aRequired,
41 Collection<ProvidedInterfaceDescriptor> aProvided) {
42 List<ProvidedInterfaceDescriptor> provided = new ArrayList<ProvidedInterfaceDescriptor>();
43 for (ProvidedInterfaceDescriptor descriptor : aProvided) {
44 if (aRequired.implementedBy(descriptor)) {
45 provided.add(descriptor);
48 return provided.toArray(new ProvidedInterfaceDescriptor[0]);
52 * Constructs the assembler.
55 * Systems that must be assembled.
56 * @param aAvailableServices
57 * Available services from other systems outside of the systems
58 * that this assembler manages.
60 public SystemAssembler(Component[] aSystems,
61 ProvidedInterfaceDescriptor[] aAvailableServices) {
62 this(ROOT_CONTEXT_NAME, aSystems, aAvailableServices);
66 * Constructs the assembler.
69 * Context (unique name) of the assembler.
71 * Systems that must be assembled.
72 * @param aAvailableServices
73 * Available services from other systems outside of the systems
74 * that this assembler manages.
76 public SystemAssembler(String aContext, Component[] aSystems,
77 ProvidedInterfaceDescriptor[] aAvailableServices) {
80 validate(aAvailableServices);
84 * Determines if the systems are ordered appropriately so that all
85 * dependencies are met.
87 private void validate(ProvidedInterfaceDescriptor[] aDescriptors)
88 throws SystemAssemblyException {
90 List<ProvidedInterfaceDescriptor> allProvided = new ArrayList<ProvidedInterfaceDescriptor>();
91 for (ProvidedInterfaceDescriptor descriptor : aDescriptors) {
92 allProvided.add(descriptor);
94 for (Component system : _systems) {
95 // Check if all required services are already provided by earlier
97 RequiredInterfaceDescriptor[] required = system.getRequiredServices();
99 for (RequiredInterfaceDescriptor descriptor : required) {
100 ProvidedInterfaceDescriptor[] filtered = filterProvidedServices(
101 descriptor, allProvided);
103 if (filtered.length == 0) {
104 throw new SystemAssemblyException(
107 + "' required by system '"
109 + "' is not provided by systems that are started earlier");
111 if (filtered.length > 1) {
112 throw new SystemAssemblyException(
115 + "' required by system '"
117 + "' matches multiple services provided by other systems: " +
118 Arrays.asList(filtered));
122 // add all provided services
123 ProvidedInterfaceDescriptor[] provided = system.getProvidedServices();
124 allProvided.addAll(Arrays.asList(provided));
129 * Starts the subsystems.
132 * Service registry to which created services must be registered.
133 * @param aRequiredServices
134 * Services that are available from other systems that have been
137 public void start(ServiceRegistry aRegistry, Service[] aRequiredServices) {
138 LOG.info("Starting '" + _context + "'");
139 Map<ProvidedInterfaceDescriptor, Service> allProvided = new HashMap<ProvidedInterfaceDescriptor, Service>();
141 for (Service service : aRequiredServices) {
142 allProvided.put(service.getDescriptor(), service);
144 for (Component system : _systems) {
146 // Compose a list of the required services required for the subsystem.
148 RequiredInterfaceDescriptor[] descriptors = system
149 .getRequiredServices();
150 List<Service> services = new ArrayList<Service>();
151 for (RequiredInterfaceDescriptor descriptor : descriptors) {
152 ProvidedInterfaceDescriptor[] provided = filterProvidedServices(
153 descriptor, allProvided.keySet());
154 services.add(allProvided.get(provided[0]));
157 // Start the service.
158 Service[] provided = system.start(_context, services
159 .toArray(new Service[0]));
161 // Add started services to the map of started services.
162 for (Service service : provided) {
163 allProvided.put(service.getDescriptor(), service);