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 org.apache.commons.logging.Log;
19 import org.apache.commons.logging.LogFactory;
21 import java.util.ArrayList;
22 import java.util.Arrays;
23 import java.util.Collections;
24 import java.util.List;
28 * Abstract subsystem class making it easy to implement new subsystems.
30 * @param <Type> DOCUMENT ME!
32 public abstract class AbstractComponent<Type> implements Component<Type> {
36 private static final Log LOG = LogFactory.getLog(AbstractComponent.class);
41 private ThreadLocal<List<ProvidedInterface>> remaining;
46 private String context;
56 private List<ProvidedInterface> provided;
61 private List<RequiredInterface> required;
64 * Constructs the subsystem.
73 protected AbstractComponent(String aName,
74 List<ProvidedInterface> aProvided, List<RequiredInterface> aRequired) {
75 remaining = new ThreadLocal<List<ProvidedInterface>>();
78 provided = new ArrayList<ProvidedInterface>(aProvided);
79 required = new ArrayList<RequiredInterface>(aRequired);
83 * Constructs the subsystem.
92 protected AbstractComponent(String aName, ProvidedInterface[] aProvided,
93 RequiredInterface[] aRequired) {
94 this(aName, Arrays.asList(aProvided), Arrays.asList(aRequired));
98 * Creates a new AbstractComponent object.
100 * @param aName DOCUMENT ME!
102 protected AbstractComponent(String aName) {
103 this(aName, new ProvidedInterface[0], new RequiredInterface[0]);
109 * @param aProvided DOCUMENT ME!
111 * @return DOCUMENT ME!
113 public AbstractComponent<Type> addProvidedInterface(
114 ProvidedInterface aProvided) {
115 provided.add(aProvided);
123 * @param aRequired DOCUMENT ME!
125 * @return DOCUMENT ME!
127 public AbstractComponent<Type> addRequiredInterface(
128 RequiredInterface aRequired) {
129 required.add(aRequired);
137 * @return DOCUMENT ME!
140 public final String getName() {
147 * @param aContext DOCUMENT ME!
150 public void addContext(String aContext) {
151 if (context == null) {
154 context = aContext + "." + context;
161 * @return DOCUMENT ME!
164 public String getContext() {
171 * @return DOCUMENT ME!
174 public String getQualifiedName() {
175 if (context == null) {
179 return context + "." + getName();
185 * @return DOCUMENT ME!
188 public final List<ProvidedInterface> getProvidedInterfaces() {
189 return Collections.unmodifiableList(provided);
195 * @return DOCUMENT ME!
198 public final List<RequiredInterface> getRequiredInterfaces() {
199 return Collections.unmodifiableList(required);
205 * @param aScope DOCUMENT ME!
207 * @return DOCUMENT ME!
210 public final Type start(Scope aScope) {
211 LOG.info("Initialization starting '" + getQualifiedName() + "'");
213 List<ProvidedInterface> oldRemaining = remaining.get();
214 remaining.set(new ArrayList<ProvidedInterface>(getProvidedInterfaces()));
217 Type runtime = doStart(aScope);
218 checkNotStartedInterfaces();
219 LOG.info("Initialization finished '" + getQualifiedName() + "'");
223 remaining.set(oldRemaining);
230 private void checkNotStartedInterfaces() {
231 if (remaining.get().size() > 0) {
232 String notProvided = "";
234 for (ProvidedInterface provided : remaining.get()) {
235 notProvided += ("\nComponent " + getQualifiedName()
236 + " did not start interface " + provided);
239 throw new SystemAssemblyException(notProvided);
244 * Must be implemented for initializing the subsystem. The
245 * implementation must call {@link #addInterface(ProvidedInterface,
246 * Object, Scope)} for each service that is started.
248 * @param aScope DOCUMENT ME!
250 * @return Returns the runtime of the component.
252 protected abstract Type doStart(Scope aScope);
255 * Implementations must call this method to indicate that a new
256 * service has been started.
258 * @param aDescriptor Provided interface.
259 * @param aService Implementation of the interface.
260 * @param aScope scope in which to publish the implementation.
262 * @throws SystemAssemblyException DOCUMENT ME!
264 protected final void addInterface(ProvidedInterface aDescriptor,
265 Object aService, Scope aScope) {
266 LOG.info("Interface '" + getQualifiedName() + "."
267 + aDescriptor.getName() + "' started.");
269 if (!remaining.get().remove(aDescriptor)) {
270 throw new SystemAssemblyException("Component '"
271 + getQualifiedName() + "' started an unexpected interface '"
273 + "' that was not registerd as a provided interface before");
276 aScope.publishInterface(aDescriptor, aService);
282 * @param aRuntime DOCUMENT ME!
285 public void stop(Type aRuntime) {
286 LOG.info("Stopping initiated '" + getQualifiedName() + "'");
288 LOG.info("Stopping completed '" + getQualifiedName() + "'");
294 * @param aRuntime DOCUMENT ME!
296 protected abstract void doStop(Type aRuntime);
301 * @return DOCUMENT ME!
304 public String toString() {
305 return getQualifiedName();
311 * @param aName DOCUMENT ME!
313 * @return DOCUMENT ME!
315 public ProvidedInterface findProvidedInterface(String aName) {
316 for (ProvidedInterface provided : getProvidedInterfaces()) {
317 if (provided.getName().equals(aName)) {
328 * @param aName DOCUMENT ME!
330 * @return DOCUMENT ME!
332 public RequiredInterface findRequiredInterface(String aName) {
333 for (RequiredInterface required : getRequiredInterfaces()) {
334 if (required.getName().equals(aName)) {