package org.wamblee.system; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import org.apache.commons.logging.Log; 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. */ public class SystemAssembler { private static final Log LOG = LogFactory.getLog(SystemAssembler.class); private static final String ROOT_CONTEXT_NAME = "root"; private String _context; private SubSystem[] _systems; /** * 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) { 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. */ public SystemAssembler(String aContext, SubSystem[] aSystems, ServiceDescriptor[] 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 { List allProvided = new ArrayList(); for (ServiceDescriptor descriptor: aDescriptors) { allProvided.add(descriptor); } for (SubSystem 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))) { throw new SystemAssemblyException( "Service '" + descriptor + "' required by system '" + system + "' is not provided by systems that are started earlier"); } } // add all provided services ServiceDescriptor[] provided = system.getProvidedServices(); for (ServiceDescriptor descriptor : provided) { allProvided.add(descriptor); } } } /** * 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. */ public void start(ServiceRegistry aRegistry, Service[] aRequiredServices) { LOG.info("Starting '" + _context + "'"); Map allProvided = new HashMap(); for (Service service : aRequiredServices) { allProvided.put(service.getDescriptor(), service); } for (SubSystem system : _systems) { ServiceDescriptor[] descriptors = system.getRequiredServices(); List services = new ArrayList(); 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); } Service[] provided = system.start(_context, aRegistry, services .toArray(new Service[0])); for (Service service : provided) { allProvided.put(service.getDescriptor(), service); } } } }