/* * 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 java.util.ArrayList; import java.util.Arrays; import java.util.HashSet; import java.util.List; import java.util.Set; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; /** * Abstract subsystem class making it easy to implement new subsystems. */ public abstract class AbstractComponent implements Component { private static final Log LOG = LogFactory.getLog(AbstractComponent.class); private ThreadLocal> _remaining; private String _context; private String _name; private List _provided; private List _required; /** * 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) { _remaining = new ThreadLocal>(); _context = null; _name = aName; _provided = new ArrayList(); _provided.addAll(Arrays.asList(aProvided)); _required = new ArrayList(); _required.addAll(Arrays.asList(aRequired)); } protected AbstractComponent(String aName) { this(aName, new ProvidedInterface[0], new RequiredInterface[0]); } public AbstractComponent addProvidedInterface(ProvidedInterface aProvided) { _provided.add(aProvided); return this; } public AbstractComponent addRequiredInterface(RequiredInterface aRequired) { _required.add(aRequired); return this; } @Override public final String getName() { return _name; } @Override public void addContext(String aContext) { if (_context == null) { _context = aContext; } else { _context = aContext + "." + _context; } } @Override public String getContext() { return _context; } @Override public String getQualifiedName() { if (_context == null) { return getName(); } return _context + "." + getName(); } @Override public final ProvidedInterface[] getProvidedInterfaces() { return _provided.toArray(new ProvidedInterface[0]); } @Override public final RequiredInterface[] getRequiredInterfaces() { return _required.toArray(new RequiredInterface[0]); } @Override public final Type start(Scope aScope) { LOG.info("Initializing '" + getQualifiedName() + "'"); List oldRemaining = _remaining.get(); _remaining.set(new ArrayList(Arrays.asList(getProvidedInterfaces()))); try { Type runtime = doStart(aScope); checkNotStartedInterfaces(); return runtime; } finally { _remaining.set(oldRemaining); } } 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 #addService(Service)} for each service that is started. * * @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. */ protected final void addInterface(ProvidedInterface aDescriptor, Object aService, Scope aScope) { LOG.info("Interface '" + getQualifiedName() + "." + aDescriptor.getName() + "' started."); _remaining.get().remove(aDescriptor); aScope.publishInterface(aDescriptor, aService); } @Override public void stop(Type aRuntime) { doStop(aRuntime); } protected abstract void doStop(Type aRuntime); @Override public String toString() { return getQualifiedName(); } }