+ /**
+ * DOCUMENT ME!
+ */
+ private static final Log LOG = LogFactory.getLog(AbstractComponent.class);
+
+ /**
+ * DOCUMENT ME!
+ */
+ private ThreadLocal<List<ProvidedInterface>> remaining;
+
+ /**
+ * DOCUMENT ME!
+ */
+ private String context;
+
+ /**
+ * DOCUMENT ME!
+ */
+ private String name;
+
+ /**
+ * DOCUMENT ME!
+ */
+ private List<ProvidedInterface> provided;
+
+ /**
+ * DOCUMENT ME!
+ */
+ private List<RequiredInterface> required;
+
+/**
+ * Constructs the subsystem.
+ *
+ * @param aName
+ * Name of the system.
+ * @param aProvided
+ * Provided services.
+ * @param aRequired
+ * Required services.
+ */
+ protected AbstractComponent(String aName,
+ List<ProvidedInterface> aProvided, List<RequiredInterface> aRequired) {
+ remaining = new ThreadLocal<List<ProvidedInterface>>();
+ context = null;
+ name = aName;
+ provided = new ArrayList<ProvidedInterface>(aProvided);
+ required = new ArrayList<RequiredInterface>(aRequired);
+ }
+
+/**
+ * Constructs the subsystem.
+ *
+ * @param aName
+ * Name of the system.
+ * @param aProvided
+ * Provided services.
+ * @param aRequired
+ * Required services.
+ */
+ protected AbstractComponent(String aName, ProvidedInterface[] aProvided,
+ RequiredInterface[] aRequired) {
+ this(aName, Arrays.asList(aProvided), Arrays.asList(aRequired));
+ }
+
+ /**
+ * Creates a new AbstractComponent object.
+ *
+ * @param aName DOCUMENT ME!
+ */
+ protected AbstractComponent(String aName) {
+ this(aName, new ProvidedInterface[0], new RequiredInterface[0]);
+ }
+
+ /**
+ * DOCUMENT ME!
+ *
+ * @param aProvided DOCUMENT ME!
+ *
+ * @return DOCUMENT ME!
+ */
+ public AbstractComponent<Type> addProvidedInterface(
+ ProvidedInterface aProvided) {
+ provided.add(aProvided);
+
+ return this;
+ }
+
+ /**
+ * DOCUMENT ME!
+ *
+ * @param aRequired DOCUMENT ME!
+ *
+ * @return DOCUMENT ME!
+ */
+ public AbstractComponent<Type> addRequiredInterface(
+ RequiredInterface aRequired) {
+ required.add(aRequired);
+
+ return this;
+ }
+
+ /**
+ * DOCUMENT ME!
+ *
+ * @return DOCUMENT ME!
+ */
+ @Override
+ public final String getName() {
+ return name;
+ }
+
+ /**
+ * DOCUMENT ME!
+ *
+ * @param aContext DOCUMENT ME!
+ */
+ @Override
+ public void addContext(String aContext) {
+ if (context == null) {
+ context = aContext;
+ } else {
+ context = aContext + "." + context;
+ }
+ }
+
+ /**
+ * DOCUMENT ME!
+ *
+ * @return DOCUMENT ME!
+ */
+ @Override
+ public String getContext() {
+ return context;
+ }
+
+ /**
+ * DOCUMENT ME!
+ *
+ * @return DOCUMENT ME!
+ */
+ @Override
+ public String getQualifiedName() {
+ if (context == null) {
+ return getName();
+ }
+
+ return context + "." + getName();
+ }
+
+ /**
+ * DOCUMENT ME!
+ *
+ * @return DOCUMENT ME!
+ */
+ @Override
+ public final List<ProvidedInterface> getProvidedInterfaces() {
+ return Collections.unmodifiableList(provided);
+ }
+
+ /**
+ * DOCUMENT ME!
+ *
+ * @return DOCUMENT ME!
+ */
+ @Override
+ public final List<RequiredInterface> getRequiredInterfaces() {
+ return Collections.unmodifiableList(required);
+ }
+
+ /**
+ * DOCUMENT ME!
+ *
+ * @param aScope DOCUMENT ME!
+ *
+ * @return DOCUMENT ME!
+ */
+ @Override
+ public final Type start(Scope aScope) {
+ LOG.info("Initialization starting '" + getQualifiedName() + "'");
+
+ List<ProvidedInterface> oldRemaining = remaining.get();
+ remaining.set(new ArrayList<ProvidedInterface>(getProvidedInterfaces()));
+
+ try {
+ Type runtime = doStart(aScope);
+ checkNotStartedInterfaces();
+ LOG.info("Initialization finished '" + getQualifiedName() + "'");
+
+ return runtime;
+ } finally {
+ remaining.set(oldRemaining);
+ }
+ }
+
+ /**
+ * DOCUMENT ME!
+ */
+ private void checkNotStartedInterfaces() {
+ if (remaining.get().size() > 0) {
+ String notProvided = "";
+
+ for (ProvidedInterface provided : remaining.get()) {
+ notProvided += ("\nComponent " + getQualifiedName()
+ + " did not start interface " + provided);
+ }
+
+ throw new SystemAssemblyException(notProvided);
+ }
+ }
+
+ /**
+ * Must be implemented for initializing the subsystem. The
+ * implementation must call {@link #addInterface(ProvidedInterface,
+ * Object, Scope)} for each service that is started.
+ *
+ * @param aScope DOCUMENT ME!
+ *
+ * @return Returns the runtime of the component.
+ */
+ protected abstract Type doStart(Scope aScope);
+
+ /**
+ * Implementations must call this method to indicate that a new
+ * service has been started.
+ *
+ * @param aDescriptor Provided interface.
+ * @param aService Implementation of the interface.
+ * @param aScope scope in which to publish the implementation.
+ *
+ * @throws SystemAssemblyException DOCUMENT ME!
+ */
+ protected final void addInterface(ProvidedInterface aDescriptor,
+ Object aService, Scope aScope) {
+ LOG.info("Interface '" + getQualifiedName() + "."
+ + aDescriptor.getName() + "' started.");
+
+ if (!remaining.get().remove(aDescriptor)) {
+ throw new SystemAssemblyException("Component '"
+ + getQualifiedName() + "' started an unexpected interface '"
+ + aDescriptor
+ + "' that was not registerd as a provided interface before");
+ }
+
+ aScope.publishInterface(aDescriptor, aService);
+ }
+
+ /**
+ * DOCUMENT ME!
+ *
+ * @param aRuntime DOCUMENT ME!
+ */
+ @Override
+ public void stop(Type aRuntime) {
+ LOG.info("Stopping initiated '" + getQualifiedName() + "'");
+ doStop(aRuntime);
+ LOG.info("Stopping completed '" + getQualifiedName() + "'");
+ }
+
+ /**
+ * DOCUMENT ME!
+ *
+ * @param aRuntime DOCUMENT ME!
+ */
+ protected abstract void doStop(Type aRuntime);
+
+ /**
+ * DOCUMENT ME!
+ *
+ * @return DOCUMENT ME!
+ */
+ @Override
+ public String toString() {
+ return getQualifiedName();
+ }
+
+ /**
+ * DOCUMENT ME!
+ *
+ * @param aName DOCUMENT ME!
+ *
+ * @return DOCUMENT ME!
+ */
+ public ProvidedInterface findProvidedInterface(String aName) {
+ for (ProvidedInterface provided : getProvidedInterfaces()) {
+ if (provided.getName().equals(aName)) {
+ return provided;
+ }
+ }
+
+ return null;
+ }