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.core;
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);
75 for (Component component: aSystems) {
76 component.addContext(getQualifiedName());
82 * Validates the subsystems together to check that there are
83 * no required services not in the required list and
84 * no services in the provided list that cannot be provided.
85 * Also logs a warning in case of superfluous requirements.
87 private void validate(RequiredInterface[] aRequired) {
88 List<ProvidedInterface> provided = new ArrayList<ProvidedInterface>();
89 for (Component system : _systems) {
90 provided.addAll(Arrays.asList(system.getProvidedInterfaces()));
93 List<RequiredInterface> required = new ArrayList<RequiredInterface>();
94 for (Component system : _systems) {
95 required.addAll(Arrays.asList(system.getRequiredInterfaces()));
98 for (ProvidedInterface service : getProvidedInterfaces()) {
99 if (!(provided.contains(service))) {
100 throw new SystemAssemblyException(getName() + ": Service '" + service
101 + "' is not provided by any of the subsystems");
105 for (RequiredInterface service : getRequiredInterfaces()) {
106 if (!(required.contains(service))) {
109 + "' indicated as required is not actually required by any of the subsystems");
113 List<RequiredInterface> reallyRequired = new ArrayList<RequiredInterface>(
115 // Compute all required interfaces that are not provided
116 for (ProvidedInterface service : provided) {
117 List<RequiredInterface> fulfilled =
118 Arrays.asList(filterRequiredServices(service,
120 reallyRequired.removeAll(fulfilled);
122 // Now the remaining interfaces should be covered by the required
124 reallyRequired.removeAll(Arrays.asList(aRequired));
126 String missingRequired = "";
127 for (RequiredInterface service: reallyRequired) {
128 missingRequired += service + "\n";
130 if ( missingRequired.length() > 0 ) {
131 throw new SystemAssemblyException(getName() + ": missing required services\n" + missingRequired);
136 protected void doStart() {
137 List<ProvidedInterface> provided = new ArrayList<ProvidedInterface>();
139 // all interfaces from the required list of this container are
140 // provided to the components inside it.
141 RequiredInterface[] required = getRequiredInterfaces();
142 for (RequiredInterface intf: required) {
143 ProvidedInterface provider = intf.getProvider();
144 if ( provider == null ) {
145 throw new SystemAssemblyException(getQualifiedName() + ": required interface '" + intf +"' is not provided");
147 provided.add(intf.getProvider());
154 * Starts the subsystems.
156 * @param aRequiredServices
157 * Services that are available from other systems that have been
160 private void startImpl() {
161 LOG.info("Starting '" + getQualifiedName() + "'");
162 List<ProvidedInterface> allProvided = new ArrayList<ProvidedInterface>();
164 // Add the provides of all externally required interfaces to the list of available
166 for (RequiredInterface required: getRequiredInterfaces()) {
167 allProvided.add(required.getProvider());
170 for (Component system : _systems) {
171 // Check if all required services are already provided by earlier
173 RequiredInterface[] required = system.getRequiredInterfaces();
175 for (RequiredInterface descriptor : required) {
176 ProvidedInterface[] filtered = filterProvidedServices(
177 descriptor, allProvided);
179 if (filtered.length == 0) {
180 throw new SystemAssemblyException(
183 + "' required by system '"
185 + "' is not provided by systems that are started earlier");
187 if (filtered.length > 1) {
188 throw new SystemAssemblyException(
191 + "' required by system '"
193 + "' matches multiple services provided by other systems: " +
194 Arrays.asList(filtered));
196 descriptor.setProvider(filtered[0]);
199 // Start the service.
202 // add all provided services
203 ProvidedInterface[] provided = system.getProvidedInterfaces();
204 allProvided.addAll(Arrays.asList(provided));
210 protected void doStop() {
211 for (int i = _systems.length-1; i >= 0; i--) {
216 private void info(String aMsg) {
217 LOG.info(getName() + ": " + aMsg);