package org.wamblee.system;
import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.commons.logging.LogFactory;
/**
- * Assembler to control multiple subsystems. It makes sure that
- * all dependencies are met and controls the order in which systems
- * are initialized.
+ * Assembler to control multiple subsystems. It makes sure that all dependencies
+ * are met and controls the order in which systems are initialized.
+ *
+ * @author Erik Brakkee
*/
public class SystemAssembler {
private static final String ROOT_CONTEXT_NAME = "root";
private String _context;
- private SubSystem[] _systems;
+ private Component[] _systems;
+
+ public static RequiredInterfaceDescriptor[] filterRequiredServices(
+ ProvidedInterfaceDescriptor aProvided,
+ Collection<RequiredInterfaceDescriptor> aDescriptors) {
+ List<RequiredInterfaceDescriptor> required = new ArrayList<RequiredInterfaceDescriptor>();
+ for (RequiredInterfaceDescriptor descriptor : aDescriptors) {
+ if (descriptor.implementedBy(aProvided)) {
+ required.add(descriptor);
+ }
+ }
+ return required.toArray(new RequiredInterfaceDescriptor[0]);
+ }
+
+ public static ProvidedInterfaceDescriptor[] filterProvidedServices(
+ RequiredInterfaceDescriptor aRequired,
+ Collection<ProvidedInterfaceDescriptor> aProvided) {
+ List<ProvidedInterfaceDescriptor> provided = new ArrayList<ProvidedInterfaceDescriptor>();
+ for (ProvidedInterfaceDescriptor descriptor : aProvided) {
+ if (aRequired.implementedBy(descriptor)) {
+ provided.add(descriptor);
+ }
+ }
+ return provided.toArray(new ProvidedInterfaceDescriptor[0]);
+ }
/**
- * Constructs the assembler.
- * @param aSystems Systems that must be assembled.
- * @param aAvailableServices Available services from other systems
- * outside of the systems that this assembler manages.
+ * Constructs the assembler.
+ *
+ * @param aSystems
+ * Systems that must be assembled.
+ * @param aAvailableServices
+ * Available services from other systems outside of the systems
+ * that this assembler manages.
*/
- public SystemAssembler(SubSystem[] aSystems, ServiceDescriptor[] aAvailableServices) {
+ public SystemAssembler(Component[] aSystems,
+ ProvidedInterfaceDescriptor[] aAvailableServices) {
this(ROOT_CONTEXT_NAME, aSystems, aAvailableServices);
}
/**
- * Constructs the assembler.
- * @param aContext Context (unique name) of the assembler.
- * @param aSystems Systems that must be assembled.
- * @param aAvailableServices Available services from other systems
- * outside of the systems that this assembler manages.
+ * Constructs the assembler.
+ *
+ * @param aContext
+ * Context (unique name) of the assembler.
+ * @param aSystems
+ * Systems that must be assembled.
+ * @param aAvailableServices
+ * Available services from other systems outside of the systems
+ * that this assembler manages.
*/
- public SystemAssembler(String aContext, SubSystem[] aSystems,
- ServiceDescriptor[] aAvailableServices) {
+ public SystemAssembler(String aContext, Component[] aSystems,
+ ProvidedInterfaceDescriptor[] aAvailableServices) {
_context = aContext;
_systems = aSystems;
validate(aAvailableServices);
* Determines if the systems are ordered appropriately so that all
* dependencies are met.
*/
- private void validate(ServiceDescriptor[] aDescriptors) throws SystemAssemblyException {
+ private void validate(ProvidedInterfaceDescriptor[] aDescriptors)
+ throws SystemAssemblyException {
- List<ServiceDescriptor> allProvided = new ArrayList<ServiceDescriptor>();
- for (ServiceDescriptor descriptor: aDescriptors) {
+ List<ProvidedInterfaceDescriptor> allProvided = new ArrayList<ProvidedInterfaceDescriptor>();
+ for (ProvidedInterfaceDescriptor descriptor : aDescriptors) {
allProvided.add(descriptor);
}
- for (SubSystem system : _systems) {
+ for (Component system : _systems) {
// Check if all required services are already provided by earlier
// systems.
- ServiceDescriptor[] required = system.getRequiredServices();
- for (ServiceDescriptor descriptor : required) {
- if (!(allProvided.contains(descriptor))) {
+ RequiredInterfaceDescriptor[] required = system.getRequiredServices();
+
+ for (RequiredInterfaceDescriptor descriptor : required) {
+ ProvidedInterfaceDescriptor[] filtered = filterProvidedServices(
+ descriptor, allProvided);
+
+ if (filtered.length == 0) {
throw new SystemAssemblyException(
"Service '"
+ descriptor
+ system
+ "' is not provided by systems that are started earlier");
}
+ if (filtered.length > 1) {
+ throw new SystemAssemblyException(
+ "Service '"
+ + descriptor
+ + "' required by system '"
+ + system
+ + "' matches multiple services provided by other systems: " +
+ Arrays.asList(filtered));
+ }
}
// add all provided services
- ServiceDescriptor[] provided = system.getProvidedServices();
- for (ServiceDescriptor descriptor : provided) {
- allProvided.add(descriptor);
- }
+ ProvidedInterfaceDescriptor[] provided = system.getProvidedServices();
+ allProvided.addAll(Arrays.asList(provided));
}
}
/**
* Starts the subsystems.
- * @param aRegistry Service registry to which created services must be registered.
- * @param aRequiredServices Services that are available from
- * other systems that have been started before.
+ *
+ * @param aRegistry
+ * Service registry to which created services must be registered.
+ * @param aRequiredServices
+ * Services that are available from other systems that have been
+ * started before.
*/
public void start(ServiceRegistry aRegistry, Service[] aRequiredServices) {
LOG.info("Starting '" + _context + "'");
- Map<ServiceDescriptor, Service> allProvided = new HashMap<ServiceDescriptor, Service>();
+ Map<ProvidedInterfaceDescriptor, Service> allProvided = new HashMap<ProvidedInterfaceDescriptor, Service>();
for (Service service : aRequiredServices) {
allProvided.put(service.getDescriptor(), service);
}
- for (SubSystem system : _systems) {
- ServiceDescriptor[] descriptors = system.getRequiredServices();
+ for (Component system : _systems) {
+
+ // Compose a list of the required services required for the subsystem.
+
+ RequiredInterfaceDescriptor[] descriptors = system
+ .getRequiredServices();
List<Service> services = new ArrayList<Service>();
- for (ServiceDescriptor descriptor : descriptors) {
- Service required = allProvided.get(descriptor);
- if (required == null) {
- throw new SystemAssemblyException("Service '" + descriptor
- + "' required by '" + system + "' is null.");
- }
- services.add(required);
+ for (RequiredInterfaceDescriptor descriptor : descriptors) {
+ ProvidedInterfaceDescriptor[] provided = filterProvidedServices(
+ descriptor, allProvided.keySet());
+ services.add(allProvided.get(provided[0]));
}
+
+ // Start the service.
Service[] provided = system.start(_context, services
.toArray(new Service[0]));
+
+ // Add started services to the map of started services.
for (Service service : provided) {
allProvided.put(service.getDescriptor(), service);
}