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.HashSet;
22 import java.util.List;
25 import org.apache.commons.logging.Log;
26 import org.apache.commons.logging.LogFactory;
29 * Composite system consisting of multiple subsystems.
31 * @author Erik Brakkee
33 public class Container extends AbstractComponent {
35 private static final Log LOG = LogFactory.getLog(Container.class);
37 private Component[] _systems;
39 public static RequiredInterface[] filterRequiredServices(
40 ProvidedInterface aProvided,
41 Collection<RequiredInterface> aDescriptors) {
42 List<RequiredInterface> required = new ArrayList<RequiredInterface>();
43 for (RequiredInterface descriptor : aDescriptors) {
44 if (descriptor.implementedBy(aProvided)) {
45 required.add(descriptor);
48 return required.toArray(new RequiredInterface[0]);
51 public static ProvidedInterface[] filterProvidedServices(
52 RequiredInterface aRequired,
53 Collection<ProvidedInterface> aProvided) {
54 List<ProvidedInterface> provided = new ArrayList<ProvidedInterface>();
55 for (ProvidedInterface descriptor : aProvided) {
56 if (aRequired.implementedBy(descriptor)) {
57 provided.add(descriptor);
60 return provided.toArray(new ProvidedInterface[0]);
64 * Construcst the composite system.
65 * @param aName Name of the system.
66 * @param aRegistry Service registry.
67 * @param aSystems Subsystems.
68 * @param aProvided Provided services of the system.
69 * @param aRequired Required services by the system.
71 public Container(String aName, Component[] aSystems,
72 ProvidedInterface[] aProvided, RequiredInterface[] aRequired) {
73 super(aName, aProvided, aRequired);
79 * Validates the subsystems together to check that there are
80 * no required services not in the required list and
81 * no services in the provided list that cannot be provided.
82 * Also logs a warning in case of superfluous requirements.
84 private void validate(RequiredInterface[] aRequired) {
85 List<ProvidedInterface> provided = new ArrayList<ProvidedInterface>();
86 for (Component system : _systems) {
87 provided.addAll(Arrays.asList(system.getProvidedServices()));
90 List<RequiredInterface> required = new ArrayList<RequiredInterface>();
91 for (Component system : _systems) {
92 required.addAll(Arrays.asList(system.getRequiredServices()));
95 for (ProvidedInterface service : getProvidedServices()) {
96 if (!(provided.contains(service))) {
97 throw new SystemAssemblyException(getName() + ": Service '" + service
98 + "' is not provided by any of the subsystems");
102 for (RequiredInterface service : getRequiredServices()) {
103 if (!(required.contains(service))) {
106 + "' indicated as required is not actually required by any of the subsystems");
110 List<RequiredInterface> reallyRequired = new ArrayList<RequiredInterface>(
112 // Compute all required interfaces that are not provided
113 for (ProvidedInterface service : provided) {
114 List<RequiredInterface> fulfilled =
115 Arrays.asList(filterRequiredServices(service,
117 reallyRequired.removeAll(fulfilled);
119 // Now the remaining interfaces should be covered by the required
121 reallyRequired.removeAll(Arrays.asList(aRequired));
123 String missingRequired = "";
124 for (RequiredInterface service: reallyRequired) {
125 missingRequired += service + "\n";
127 if ( missingRequired.length() > 0 ) {
128 throw new SystemAssemblyException(getName() + ": missing required services\n" + missingRequired);
133 protected void doStart(String aContext) {
134 List<ProvidedInterface> provided = new ArrayList<ProvidedInterface>();
136 // all interfaces from the required list of this container are
137 // provided to the components inside it.
138 RequiredInterface[] required = getRequiredServices();
139 for (RequiredInterface intf: required) {
140 ProvidedInterface provider = intf.getProvider();
141 if ( provider == null ) {
142 throw new SystemAssemblyException(aContext + ": required interface '" + intf +"' is not provided");
144 provided.add(intf.getProvider());
151 * Starts the subsystems.
153 * @param aRequiredServices
154 * Services that are available from other systems that have been
157 private void startImpl() {
158 LOG.info("Starting '" + "'");
159 List<ProvidedInterface> allProvided = new ArrayList<ProvidedInterface>();
161 // Add the provides of all externally required interfaces to the list of available
163 for (RequiredInterface required: getRequiredServices()) {
164 allProvided.add(required.getProvider());
167 for (Component system : _systems) {
168 // Check if all required services are already provided by earlier
170 RequiredInterface[] required = system.getRequiredServices();
172 for (RequiredInterface descriptor : required) {
173 ProvidedInterface[] filtered = filterProvidedServices(
174 descriptor, allProvided);
176 if (filtered.length == 0) {
177 throw new SystemAssemblyException(
180 + "' required by system '"
182 + "' is not provided by systems that are started earlier");
184 if (filtered.length > 1) {
185 throw new SystemAssemblyException(
188 + "' required by system '"
190 + "' matches multiple services provided by other systems: " +
191 Arrays.asList(filtered));
193 descriptor.setProvider(filtered[0]);
196 // Start the service.
197 system.start(getQualifiedName());
199 // add all provided services
200 ProvidedInterface[] provided = system.getProvidedServices();
201 allProvided.addAll(Arrays.asList(provided));
207 protected void doStop() {
208 for (int i = _systems.length-1; i >= 0; i--) {
213 private void info(String aMsg) {
214 LOG.info(getName() + ": " + aMsg);