2 * Copyright 2007 the original author or authors.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
16 package org.wamblee.system;
18 import java.util.ArrayList;
19 import java.util.Arrays;
20 import java.util.Collection;
21 import java.util.HashMap;
22 import java.util.HashSet;
23 import java.util.List;
27 import org.apache.commons.logging.Log;
28 import org.apache.commons.logging.LogFactory;
31 * Assembler to control multiple subsystems. It makes sure that all dependencies
32 * are met and controls the order in which systems are initialized.
34 * @author Erik Brakkee
36 public class SystemAssembler {
38 private static final Log LOG = LogFactory.getLog(SystemAssembler.class);
40 private static final String ROOT_CONTEXT_NAME = "root";
41 private String _context;
42 private Component[] _systems;
43 private ProvidedInterface[] _required;
45 public static RequiredInterface[] filterRequiredServices(
46 ProvidedInterface aProvided,
47 Collection<RequiredInterface> aDescriptors) {
48 List<RequiredInterface> required = new ArrayList<RequiredInterface>();
49 for (RequiredInterface descriptor : aDescriptors) {
50 if (descriptor.implementedBy(aProvided)) {
51 required.add(descriptor);
54 return required.toArray(new RequiredInterface[0]);
57 public static ProvidedInterface[] filterProvidedServices(
58 RequiredInterface aRequired,
59 Collection<ProvidedInterface> aProvided) {
60 List<ProvidedInterface> provided = new ArrayList<ProvidedInterface>();
61 for (ProvidedInterface descriptor : aProvided) {
62 if (aRequired.implementedBy(descriptor)) {
63 provided.add(descriptor);
66 return provided.toArray(new ProvidedInterface[0]);
70 * Constructs the assembler.
73 * Systems that must be assembled.
74 * @param aAvailableServices
75 * Available services from other systems outside of the systems
76 * that this assembler manages.
78 public SystemAssembler(Component[] aSystems,
79 ProvidedInterface[] aAvailableServices) {
80 this(ROOT_CONTEXT_NAME, aSystems, aAvailableServices);
84 * Constructs the assembler.
87 * Context (unique name) of the assembler.
89 * Systems that must be assembled.
90 * @param aAvailableServices
91 * Available services from other systems outside of the systems
92 * that this assembler manages.
94 public SystemAssembler(String aContext, Component[] aSystems,
95 ProvidedInterface[] aAvailableServices) {
98 _required = aAvailableServices;
103 * Determines if the systems are ordered appropriately so that all
104 * dependencies are met.
106 private void validate()
107 throws SystemAssemblyException {
109 List<ProvidedInterface> allProvided = new ArrayList<ProvidedInterface>();
110 for (ProvidedInterface descriptor : _required) {
111 allProvided.add(descriptor);
113 for (Component system : _systems) {
114 // Check if all required services are already provided by earlier
116 RequiredInterface[] required = system.getRequiredServices();
118 for (RequiredInterface descriptor : required) {
119 ProvidedInterface[] filtered = filterProvidedServices(
120 descriptor, allProvided);
122 if (filtered.length == 0) {
123 throw new SystemAssemblyException(
126 + "' required by system '"
128 + "' is not provided by systems that are started earlier");
130 if (filtered.length > 1) {
131 throw new SystemAssemblyException(
134 + "' required by system '"
136 + "' matches multiple services provided by other systems: " +
137 Arrays.asList(filtered));
141 // add all provided services
142 ProvidedInterface[] provided = system.getProvidedServices();
143 allProvided.addAll(Arrays.asList(provided));
148 * Starts the subsystems.
150 * @param aRequiredServices
151 * Services that are available from other systems that have been
154 public void start() {
155 LOG.info("Starting '" + _context + "'");
156 Set<ProvidedInterface> allProvided = new HashSet<ProvidedInterface>();
157 allProvided.addAll(Arrays.asList(_required));
159 for (Component system : _systems) {
161 // Compose a list of the required services required for the subsystem.
163 RequiredInterface[] descriptors = system
164 .getRequiredServices();
165 List<ProvidedInterface> services = new ArrayList<ProvidedInterface>();
166 for (RequiredInterface required : descriptors) {
167 ProvidedInterface[] provided = filterProvidedServices(
168 required, allProvided);
169 assert provided.length == 1;
170 services.add(provided[0]);
171 required.setProvider(provided[0]);
174 // Start the service.
175 system.start(_context);
177 // Add started services to the set of started services.
178 for (ProvidedInterface service : system.getProvidedServices()) {
179 allProvided.add(service);