/* * Copyright 2007 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.wamblee.system.core; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; /** * Abstract subsystem class making it easy to implement new subsystems. * * @param DOCUMENT ME! */ public abstract class AbstractComponent implements Component { /** * DOCUMENT ME! */ private static final Log LOG = LogFactory.getLog(AbstractComponent.class); /** * DOCUMENT ME! */ private ThreadLocal> remaining; /** * DOCUMENT ME! */ private String context; /** * DOCUMENT ME! */ private String name; /** * DOCUMENT ME! */ private List provided; /** * DOCUMENT ME! */ private List required; /** * Constructs the subsystem. * * @param aName * Name of the system. * @param aProvided * Provided services. * @param aRequired * Required services. */ protected AbstractComponent(String aName, List aProvided, List aRequired) { remaining = new ThreadLocal>(); context = null; name = aName; provided = new ArrayList(aProvided); required = new ArrayList(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 addProvidedInterface( ProvidedInterface aProvided) { provided.add(aProvided); return this; } /** * DOCUMENT ME! * * @param aRequired DOCUMENT ME! * * @return DOCUMENT ME! */ public AbstractComponent 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 getProvidedInterfaces() { return Collections.unmodifiableList(provided); } /** * DOCUMENT ME! * * @return DOCUMENT ME! */ @Override public final List 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 oldRemaining = remaining.get(); remaining.set(new ArrayList(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; } /** * DOCUMENT ME! * * @param aName DOCUMENT ME! * * @return DOCUMENT ME! */ public RequiredInterface findRequiredInterface(String aName) { for (RequiredInterface required : getRequiredInterfaces()) { if (required.getName().equals(aName)) { return required; } } return null; } }