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 public class SystemAssembler {
19 private static final Log LOG = LogFactory.getLog(SystemAssembler.class);
21 private static final String ROOT_CONTEXT_NAME = "root";
22 private String _context;
23 private SubSystem[] _systems;
25 public static RequiredServiceDescriptor[] filterRequiredServices(
26 ProvidedServiceDescriptor aProvided,
27 Collection<RequiredServiceDescriptor> aDescriptors) {
28 List<RequiredServiceDescriptor> required = new ArrayList<RequiredServiceDescriptor>();
29 for (RequiredServiceDescriptor descriptor : aDescriptors) {
30 if (descriptor.implementedBy(aProvided)) {
31 required.add(descriptor);
34 return required.toArray(new RequiredServiceDescriptor[0]);
37 public static ProvidedServiceDescriptor[] filterProvidedServices(
38 RequiredServiceDescriptor aRequired,
39 Collection<ProvidedServiceDescriptor> aProvided) {
40 List<ProvidedServiceDescriptor> provided = new ArrayList<ProvidedServiceDescriptor>();
41 for (ProvidedServiceDescriptor descriptor : aProvided) {
42 if (aRequired.implementedBy(descriptor)) {
43 provided.add(descriptor);
46 return provided.toArray(new ProvidedServiceDescriptor[0]);
50 * Constructs the assembler.
53 * Systems that must be assembled.
54 * @param aAvailableServices
55 * Available services from other systems outside of the systems
56 * that this assembler manages.
58 public SystemAssembler(SubSystem[] aSystems,
59 ProvidedServiceDescriptor[] aAvailableServices) {
60 this(ROOT_CONTEXT_NAME, aSystems, aAvailableServices);
64 * Constructs the assembler.
67 * Context (unique name) of the assembler.
69 * Systems that must be assembled.
70 * @param aAvailableServices
71 * Available services from other systems outside of the systems
72 * that this assembler manages.
74 public SystemAssembler(String aContext, SubSystem[] aSystems,
75 ProvidedServiceDescriptor[] aAvailableServices) {
78 validate(aAvailableServices);
82 * Determines if the systems are ordered appropriately so that all
83 * dependencies are met.
85 private void validate(ProvidedServiceDescriptor[] aDescriptors)
86 throws SystemAssemblyException {
88 List<ProvidedServiceDescriptor> allProvided = new ArrayList<ProvidedServiceDescriptor>();
89 for (ProvidedServiceDescriptor descriptor : aDescriptors) {
90 allProvided.add(descriptor);
92 for (SubSystem system : _systems) {
93 // Check if all required services are already provided by earlier
95 RequiredServiceDescriptor[] required = system.getRequiredServices();
97 for (RequiredServiceDescriptor descriptor : required) {
98 ProvidedServiceDescriptor[] filtered = filterProvidedServices(
99 descriptor, allProvided);
101 if (filtered.length == 0) {
102 throw new SystemAssemblyException(
105 + "' required by system '"
107 + "' is not provided by systems that are started earlier");
109 if (filtered.length > 1) {
110 throw new SystemAssemblyException(
113 + "' required by system '"
115 + "' matches multiple services provided by other systems: " +
116 Arrays.asList(filtered));
120 // add all provided services
121 ProvidedServiceDescriptor[] provided = system.getProvidedServices();
122 allProvided.addAll(Arrays.asList(provided));
127 * Starts the subsystems.
130 * Service registry to which created services must be registered.
131 * @param aRequiredServices
132 * Services that are available from other systems that have been
135 public void start(ServiceRegistry aRegistry, Service[] aRequiredServices) {
136 LOG.info("Starting '" + _context + "'");
137 Map<ProvidedServiceDescriptor, Service> allProvided = new HashMap<ProvidedServiceDescriptor, Service>();
139 for (Service service : aRequiredServices) {
140 allProvided.put(service.getDescriptor(), service);
142 for (SubSystem system : _systems) {
144 // Compose a list of the required services required for the subsystem.
146 RequiredServiceDescriptor[] descriptors = system
147 .getRequiredServices();
148 List<Service> services = new ArrayList<Service>();
149 for (RequiredServiceDescriptor descriptor : descriptors) {
150 ProvidedServiceDescriptor[] provided = filterProvidedServices(
151 descriptor, allProvided.keySet());
152 services.add(allProvided.get(provided[0]));
155 // Start the service.
156 Service[] provided = system.start(_context, services
157 .toArray(new Service[0]));
159 // Add started services to the map of started services.
160 for (Service service : provided) {
161 allProvided.put(service.getDescriptor(), service);