org.eclipse.jubula.tools.internal.xml.businessmodell.CompSystem.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipse.jubula.tools.internal.xml.businessmodell.CompSystem.java

Source

/*******************************************************************************
 * Copyright (c) 2004, 2010 BREDEX GmbH.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *     BREDEX GmbH - initial API and implementation and/or initial documentation
 *******************************************************************************/
package org.eclipse.jubula.tools.internal.xml.businessmodell;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.Validate;
import org.apache.commons.lang.builder.ToStringBuilder;
import org.eclipse.jubula.tools.internal.constants.StringConstants;
import org.eclipse.jubula.tools.internal.constants.ToolkitConstants;
import org.eclipse.jubula.tools.internal.exception.ConfigXmlException;
import org.eclipse.jubula.tools.internal.i18n.CompSystemI18n;
import org.eclipse.jubula.tools.internal.messagehandling.MessageIDs;
import org.eclipse.jubula.tools.internal.objects.event.TestErrorEvent;
import org.eclipse.jubula.tools.internal.xml.businessprocess.ConfigVersion;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * This class represents a container for all components which can be tested by
 * Jubula.
 * @author BREDEX GmbH
 * @created 18.07.2005
 */
public class CompSystem {
    /** The logger */
    private static Logger log = LoggerFactory.getLogger(CompSystem.class);

    /** The list of all components. */
    private List<Component> m_components;

    /** fast lookup */
    private Map<String, Component> m_componentsByType;

    /** fast lookup */
    private Map<String, Component> m_componentsByTypeLowerCase;

    /** The list of abstract components. */
    private List<AbstractComponent> m_abstractComponents;

    /** The list of concrete components. */
    private List<ConcreteComponent> m_concreteComponents;

    /** The List of Event Types. */
    private Map<String, Integer> m_eventTypes;

    /** The most abstract component in the hierarchy */
    private Component m_mostAbstractComponent;

    /**
     * Map of {@link ToolkitDescriptor}
     * Key: id of toolkit, value: ToolkitDescriptor
     */
    private Map<String, ToolkitDescriptor> m_toolkitDescriptors;

    /** Stores whether the component is initialized. */
    private boolean m_initialized = false;

    /** <code>m_configVersion</code> version for clientConfig.xml */
    private ConfigVersion m_configVersion = null;

    /** A List of all DataTypes */
    private Set<String> m_dataTypes = null;

    /** Set of all parameter */
    private Set<Param> m_parameter = null;

    /** Default constructor */
    public CompSystem() {
        init();
    }

    /**  */
    private void init() {
        if (m_components == null) {
            m_components = new ArrayList<Component>();
        }
        if (m_componentsByType == null) {
            m_componentsByType = new HashMap<String, Component>(1001);
        }
        if (m_componentsByTypeLowerCase == null) {
            m_componentsByTypeLowerCase = new HashMap<String, Component>(1001);
        }
        if (m_abstractComponents == null) {
            m_abstractComponents = new ArrayList<AbstractComponent>();
        }
        if (m_concreteComponents == null) {
            m_concreteComponents = new ArrayList<ConcreteComponent>();
        }
        if (m_eventTypes == null) {
            m_eventTypes = new HashMap<String, Integer>(4);
        }
        if (m_toolkitDescriptors == null) {
            m_toolkitDescriptors = new HashMap<String, ToolkitDescriptor>();
        }
        // FIXME Achim only hard coded EventTypes so far
        m_eventTypes.put(TestErrorEvent.ID.ACTION_ERROR, new Integer(7));
        m_eventTypes.put(TestErrorEvent.ID.COMPONENT_NOT_FOUND, new Integer(7));
        m_eventTypes.put(TestErrorEvent.ID.CONFIGURATION_ERROR, new Integer(1));
        m_eventTypes.put(TestErrorEvent.ID.VERIFY_FAILED, new Integer(1));
        m_initialized = true;
    }

    /**
     * Gets the list with all components of all installed Toolkit-Plugins.
     * @return List A <code>List</code> object.
     */
    public List<Component> getComponents() {
        return m_components;
    }

    /**
     * @param toolkitId the unique toolkit id <br>
     * This information is available at the Project!
     * @param addReferencedToolkits <code>true</code> if components from toolkits 
     *                            that are "include"ed or "depend"ed on by
     *                            the given toolkitId should
     *                            be included in the list
     * @return a List with toolkit specific components of the given toolkit
     * (and its included Toolkit if <code>addIncludedToolkits</code> is 
     * <code>true</code>).
     */
    public List<Component> getComponents(String toolkitId, boolean addReferencedToolkits) {
        final List<Component> toolkitComponents = new ArrayList<Component>();
        final ToolkitDescriptor currDescriptor = getToolkitDescriptor(toolkitId);
        String includesToolkit = currDescriptor.getIncludes();
        final ToolkitDescriptor includesDescriptor = getToolkitDescriptor(includesToolkit);
        if (includesDescriptor != null) {
            final String includesLevel = includesDescriptor.getLevel();
            if (!ToolkitConstants.LEVEL_TOOLKIT.equals(includesLevel)) {
                includesToolkit = ToolkitConstants.NO_VALID_INCLUDE_TOOLKIT;
            }
        } else {
            includesToolkit = ToolkitConstants.NO_VALID_INCLUDE_TOOLKIT;
        }
        final List<String> dependsToolkits = getDependsToolkitIds(toolkitId);
        for (Component component : getComponents()) {
            final String compToolkitId = component.getToolkitDesriptor().getToolkitID();
            if (toolkitId.equals(compToolkitId) || (includesToolkit.equals(compToolkitId) && addReferencedToolkits)
                    || (dependsToolkits.contains(compToolkitId) && addReferencedToolkits)) {

                toolkitComponents.add(component);
            }
        }
        return toolkitComponents;
    }

    /**
     * @return Returns the abstractComponents.
     */
    public List<AbstractComponent> getAbstractComponents() {
        return m_abstractComponents;
    }

    /**
     * @return Returns the concreteComponents.
     */
    public List<ConcreteComponent> getConcreteComponents() {
        return m_concreteComponents;
    }

    /**
     * Gets a List of all includes toolkits (the whole hierarchy) of the given
     * toolkit and the given toolkit itself.
     * 
     * @param toolkitId
     *            the id of a toolkit whose include hierarchy is wanted.
     * @param toolkits
     *            an empty List.
     * @return the given toolkits List
     */
    private List<String> getIncludesToolkits(String toolkitId, List<String> toolkits) {
        toolkits.add(toolkitId);
        final ToolkitDescriptor toolkitPluginDescriptor = getToolkitDescriptor(toolkitId);
        if (toolkitPluginDescriptor != null) {
            final String includes = toolkitPluginDescriptor.getIncludes();
            if (!ToolkitConstants.EMPTY_EXTPOINT_ENTRY.equals(includes)) {
                getIncludesToolkits(includes, toolkits);
            }
        }
        return toolkits;
    }

    /**
     * @param toolkitId
     *            a Toolkit id
     * @return a List of toolkit names which depends on the given toolkit id.
     */
    private List<String> getDependsToolkitIds(String toolkitId) {
        final List<String> dependsToolkits = new ArrayList<String>();
        for (String tkId : m_toolkitDescriptors.keySet()) {
            final ToolkitDescriptor tkDescr = m_toolkitDescriptors.get(tkId);
            if (toolkitId.equals(tkDescr.getDepends())) {
                dependsToolkits.add(tkId);
            }
        }
        return dependsToolkits;
    }

    /**
     * Gets all Component-Types of the given toolkit, its "Includes-Toolkits"
     * and "Depends-Toolkits".
     * @param toolkitId a toolkit id
     * @return A List of Component-Types
     */
    public String[] getComponentTypes(String toolkitId) {
        final List<String> compTypes = new ArrayList<String>();
        List<String> toolkits = new ArrayList<String>();
        toolkits = getIncludesToolkits(toolkitId, toolkits);
        toolkits.addAll(getDependsToolkitIds(toolkitId));
        for (Component comp : getComponents()) {

            final String compToolkitId = comp.getToolkitDesriptor().getToolkitID();
            if (!comp.isExtender() && toolkits.contains(compToolkitId)) {
                compTypes.add(comp.getType());
            }
        }
        return compTypes.toArray(new String[compTypes.size()]);
    }

    /**
     * 
     * @return a <code>String</code> Array of Event Types.
     */
    public Map<String, Integer> getEventTypes() {
        return m_eventTypes;
    }

    /**
     * Checks if there are multiple components with the same type.
     * 
     * @param component
     *            A
     *            <code>org.eclipse.jubula.tools.internal.xml.businessmodell.Component</code>
     *            object
     * 
     */
    private void check(Component component) {
        for (Component current : getComponents()) {
            if (current.getType().equals(component.getType())) {
                final String msg = "multiple definition of component type " //$NON-NLS-1$
                        + component.getType();
                log.error(msg);
                throw new ConfigXmlException(msg, MessageIDs.E_MULTIPLE_COMPONENT);
            }
        }
    }

    /**
     * Adds all passed components to <code>m_components</code>. The method
     * <code>check()</code> is called for each component in the list.
     * 
     * @param components
     *            The components to add
     */
    private void addAll(List components) {
        for (Iterator it = components.iterator(); it.hasNext();) {
            Component component = (Component) it.next();
            check(component);
            getComponents().add(component);
            m_componentsByType.put(component.getType(), component);
            m_componentsByTypeLowerCase.put(component.getType().toLowerCase(), component);
        }
    }

    /**
     * Adds an Event Type to the List.
     * @param eventType a <code>String</code> object which describes the Event Type.
     * @param reentryProp The re-entry property (<code>Integer</code> object).
     * 
     */
    public void addEventType(String eventType, Integer reentryProp) {
        m_eventTypes.put(eventType, reentryProp);
    }

    /**
     * 
     * @param toolkitId the id of the toolkit
     * @param descriptor the {@link ToolkitDescriptor}
     */
    public void addToolkitPluginDescriptor(String toolkitId, ToolkitDescriptor descriptor) {

        if (m_toolkitDescriptors == null) {
            m_toolkitDescriptors = new HashMap<String, ToolkitDescriptor>();
        }
        m_toolkitDescriptors.put(toolkitId, descriptor);
    }

    /**
     * 
     * @param toolkitId
     *            the id of the toolkit
     * @return the {@link ToolkitDescriptor} for the given toolkit ID, or
     *         <code>null</code> if the given toolkit ID does not have a
     *         corresponding active plugin.
     */
    public ToolkitDescriptor getToolkitDescriptor(String toolkitId) {
        if (m_toolkitDescriptors == null) {
            m_toolkitDescriptors = new HashMap<String, ToolkitDescriptor>();
        }
        return m_toolkitDescriptors.get(toolkitId);
    }

    /**
     * @return the {@link ToolkitDescriptor}s of all toolkits
     */
    public List<ToolkitDescriptor> getAllToolkitDescriptors() {
        if (m_toolkitDescriptors == null) {
            m_toolkitDescriptors = new HashMap<String, ToolkitDescriptor>();
        }
        return new ArrayList<ToolkitDescriptor>(m_toolkitDescriptors.values());
    }

    /**
     * @param level Only Toolkits with this level will be returned. May be
     *              <code>null</code>, in which case independent toolkits
     *              for all levels will be returned.
     * @return the {@link ToolkitDescriptor}s of all independent 
     *         toolkits with the given level.
     */
    public List<ToolkitDescriptor> getIndependentToolkitDescriptors(String level) {
        final String emptyStr = StringConstants.EMPTY;

        List<ToolkitDescriptor> toolkitDesriptors = getAllToolkitDescriptors();

        Collections.sort(toolkitDesriptors);

        Iterator<ToolkitDescriptor> descIt = toolkitDesriptors.iterator();

        // Remove all non-independent and invalid toolkits
        while (descIt.hasNext()) {
            ToolkitDescriptor desc = descIt.next();

            final String includes = desc.getIncludes();
            String toolkitID = desc.getToolkitID();

            boolean removeDueToToolkitLevel = level != null && !level.equals(desc.getLevel());
            if (removeDueToToolkitLevel
                    || (!ToolkitConstants.LEVEL_ABSTRACT.equals(level) && (emptyStr.equals(includes)
                            || ToolkitConstants.EMPTY_EXTPOINT_ENTRY.equals(includes.toLowerCase())
                            || emptyStr.equals(toolkitID)
                            || ToolkitConstants.EMPTY_EXTPOINT_ENTRY.equals(toolkitID.toLowerCase())))) {

                descIt.remove();
            }

        }

        return toolkitDesriptors;
    }

    /**
     * @return A List of all DataTypes of the Actions.
     */
    public Set<String> getAllDataTypes() {
        if (m_dataTypes != null && !m_dataTypes.isEmpty()) {
            return m_dataTypes;
        }
        m_dataTypes = new HashSet<String>();
        final List<Component> components = getComponents();
        for (Component component : components) {
            for (Action action : component.getActions()) {
                for (Param param : action.getParams()) {
                    m_dataTypes.add(param.getType());
                }
            }
        }
        return m_dataTypes;
    }

    /**
     * @return a set of all action parameters.
     */
    public Set<Param> getAllParameter() {
        if (m_parameter != null && !m_parameter.isEmpty()) {
            return m_parameter;
        }
        m_parameter = new HashSet<Param>();
        final List<Component> components = getComponents();
        for (Component component : components) {
            for (Action action : component.getActions()) {
                for (Param param : action.getParams()) {
                    m_parameter.add(param);
                }
            }
        }
        return m_parameter;
    }

    /**
     * Returns the component with the specified typeName.
     * 
     * @param typeName
     *            Name of the specified component (the I18N key).
     * @return the specified Component.
     */
    public Component findComponent(String typeName) {
        Validate.notNull(typeName);

        if (StringConstants.EMPTY.equals(typeName)) {
            if (log.isDebugEnabled()) {
                log.debug("CompSystem.findComponent(...) called with empty String. Returning InvalidComponent."); //$NON-NLS-1$
            }
            return new InvalidComponent();
        }

        Component comp = m_componentsByType.get(typeName);
        if (comp != null) {
            return comp;
        }

        if (log.isDebugEnabled()) {
            String translatedName = CompSystemI18n.getString(typeName, true);
            String message = "Component " + translatedName + " does not exist"; //$NON-NLS-1$ //$NON-NLS-2$
            log.debug(message);
        }

        return new InvalidComponent();
    }

    /**
     * Returns the components with the specified typeName.
     * 
     * @param typeName
     *            Name of the specified component (the I18N key).
     * @return the specified Components.
     */
    public List<Component> findComponents(String typeName) {
        Validate.notNull(typeName);
        List<Component> comps = new LinkedList<Component>();
        if (StringConstants.EMPTY.equals(typeName)) {
            if (log.isDebugEnabled()) {
                log.debug("CompSystem.findComponent(...) called with empty String. Returning InvalidComponent."); //$NON-NLS-1$
            }
            comps.add(new InvalidComponent());
            return comps;
        }

        for (Component comp : getComponents()) {
            if (comp instanceof ConcreteComponent) {
                ConcreteComponent ccomp = (ConcreteComponent) comp;
                if (typeName.equals(ccomp.getComponentClass().getName())) {
                    comps.add(ccomp);
                }
            }
        }
        if (!(comps.isEmpty())) {
            return comps;
        }

        if (log.isDebugEnabled()) {
            String translatedName = CompSystemI18n.getString(typeName, true);
            String message = "Component " + translatedName + " does not exist"; //$NON-NLS-1$ //$NON-NLS-2$
            log.debug(message);
        }
        comps.add(new InvalidComponent());
        return comps;
    }

    /**
     * Returns a string representation of the component system object.
     * 
     * @return String
     */
    public String toString() {
        return new ToStringBuilder(this).append("Abstract comps", m_abstractComponents) //$NON-NLS-1$
                .append("Concrete comps", m_concreteComponents) //$NON-NLS-1$
                .toString();
    }

    /**
     * Adds all Components of the given CompSystem to this CompSystem
     * @param compSystem the CompSystem to merge
     */
    public void merge(CompSystem compSystem) {
        if (!m_initialized) {
            init();
        }
        if (compSystem.m_abstractComponents != null) {
            m_abstractComponents.addAll(compSystem.m_abstractComponents);
        }
        if (compSystem.m_concreteComponents != null) {
            m_concreteComponents.addAll(compSystem.m_concreteComponents);
        }
        if (compSystem.m_toolkitDescriptors != null) {
            m_toolkitDescriptors.putAll(compSystem.m_toolkitDescriptors);
        }
    }

    /**
     * make all Actions available at all realizing (derived) Components; build
     * the lists of components (realizing concrete Components)
     * 
     */
    public void postProcess() {
        if (!m_initialized) {
            init();
        }
        addAll(m_concreteComponents);
        addAll(m_abstractComponents);

        for (Component component : getComponents()) {
            component.completeActions(this);
            handleRealizer(component);
            handleExtender(component);
            handleDepender(component);
        }
        validateComponents();
        for (Component component : getAbstractComponents()) {
            if (component.getRealized().isEmpty()) {
                m_mostAbstractComponent = component;
                break;
            }
        }
    }

    /**
     * Handles independent Components (no realizer, no extender) which are added
     * via user plugin to an existing plugin.
     * Those Components are added to the depending toolkit.
     * @param component A Component.
     */
    private void handleDepender(Component component) {
        final ToolkitDescriptor toolkitDesriptor = component.getToolkitDesriptor();
        final String depends = toolkitDesriptor.getDepends();
        if (!component.isExtender() && !component.isRealizer()
                && !ToolkitConstants.EMPTY_EXTPOINT_ENTRY.equals(depends) && toolkitDesriptor.isUserToolkit()) {

            final ToolkitDescriptor dependsDescr = m_toolkitDescriptors.get(depends);
            if (dependsDescr != null) {
                component.setToolkitDesriptor(dependsDescr);
            }

        }
    }

    /**
     * Validates the Components.
     */
    private void validateComponents() {
        for (AbstractComponent ac : m_abstractComponents) {
            if (ac.getRealizers().isEmpty()) {
                String message = "AbstractComponent " + ac.getType() //$NON-NLS-1$
                        + " has no realizing concreteComponents"; //$NON-NLS-1$
                if (ac.isVisible()) {
                    log.error("visible " + message); //$NON-NLS-1$
                    throw new ConfigXmlException("visible " + message, //$NON-NLS-1$
                            MessageIDs.E_NO_ABSTRACT_COMPONENT);
                }
                log.warn(message);
            }
        }
        for (ConcreteComponent cc : m_concreteComponents) {
            if (cc.isExtender() && !StringUtils.isBlank(cc.getComponentClass().getName())) {
                // extender must not have a componentClass!
                final String msg = "Extending ConcreteComponent '" //$NON-NLS-1$
                        + cc.getType() + "' must not have a componentClass!"; //$NON-NLS-1$
                log.error(msg);
                throw new ConfigXmlException(msg, MessageIDs.E_GENERAL_COMPONENT_ERROR);
            }
        }
    }

    /**
     * Resolves the "realized" relation.
     * @param component a Component.
     */
    private void handleRealizer(Component component) {
        final boolean isConcrete = component.isConcrete();
        Set<Component> realizedSet = component.getAllRealized();
        for (Component realized : realizedSet) {
            if (isConcrete) {
                realized.addRealizer((ConcreteComponent) component);
            }
            realized.addAllRealizer(component);
        }
        if (isConcrete) {
            component.addRealizer((ConcreteComponent) component);
        }
        component.addAllRealizer(component);
    }

    /**
     * Handles a Component which extends another Component and adds its Actions
     * and its tester class to the extended Component.
     * @param component the extending Component.
     */
    private void handleExtender(Component component) {
        if (component.isExtender()) {
            final List<Action> extenderActions = component.getActions();
            final List<String> extendedTypes = component.getExtendedTypes();
            final boolean isExtenderVisible = component.isVisible();
            for (String extendedType : extendedTypes) {
                final Component extendedComponent = findComponent(extendedType);
                if (!extendedComponent.isVisible()) {
                    extendedComponent.setVisible(isExtenderVisible);
                }
                for (Action extenderAction : extenderActions) {
                    extendedComponent.addAction(extenderAction);
                    if (component instanceof ConcreteComponent && extendedComponent instanceof ConcreteComponent) {

                        final ConcreteComponent extender = (ConcreteComponent) component;
                        final ConcreteComponent extended = (ConcreteComponent) extendedComponent;

                        extended.setTesterClass(extender.getTesterClass());
                    }
                }
            }
        }
    }

    /**
     * @return Returns the configVersion.
     */
    public ConfigVersion getConfigVersion() {
        return m_configVersion;
    }

    /**
     * @param type a Component Type.
     * @return The Component of the given Component Type or null if no 
     * Component was found.
     */
    public Component getComponentForType(String type) {
        return m_componentsByTypeLowerCase.get(type.toLowerCase());
    }

    /**
     * @return The most abstract component in the hierarchy.
     */
    public final Component getMostAbstractComponent() {
        return m_mostAbstractComponent;
    }

    /**
     * 
     * @param type1 a Component Type.
     * @param type2 a Component Type.
     * @return the more concrete Component Type or null if the given 
     * Component Types are incompatible.
     */
    public final String getMoreConcreteType(String type1, String type2) {
        final Component comp1 = getComponentForType(type1);
        final Component comp2 = getComponentForType(type2);
        final Component moreConcreteComp = getMoreConcreteComponent(comp1, comp2);

        return moreConcreteComp != null ? moreConcreteComp.getType() : null;
    }

    /**
     * 
     * @param components The Components to check. May be empty but may not be 
     *                   <code>null</code>.
     * @return the most concrete of the given components, or <code>null</code>
     *         if any of the given components are incompatible or if 
     *         <code>components</code> is empty.
     */
    public final Component getMostConcrete(Component[] components) {
        Component mostConcrete = null;
        if (components.length > 0) {
            mostConcrete = components[0];
        }
        for (int i = 1; i < components.length && mostConcrete != null; i++) {
            mostConcrete = getMoreConcreteComponent(mostConcrete, components[i]);
        }

        return mostConcrete;
    }

    /**
     * 
     * @param comp1 a Component
     * @param comp2 a Component
     * @return the more concrete Component or null if the given Components are 
     * incompatible.
     */
    private Component getMoreConcreteComponent(Component comp1, Component comp2) {

        return getMoreConcreteComponentImpl(comp1, comp2, true);
    }

    /**
     * 
     * @param comp1 a Component
     * @param comp2 a Component
     * @param isFirstCall caller should set this to true always!
     * @return the more concrete Component or null if the given Components are 
     * incompatible.
     */
    private Component getMoreConcreteComponentImpl(Component comp1, Component comp2, boolean isFirstCall) {

        if (comp1 == null || comp2 == null) {
            return null;
        }
        if (comp1.equals(comp2)) {
            return comp1;
        }
        final String comp2Type = comp2.getType();
        for (Component realizer : comp1.getAllRealizers()) {
            if (realizer.getType().equals(comp2Type)) {
                return realizer;
            }
        }
        // if comp2 is not more concrete than comp1, try inverted search:
        return isFirstCall ? getMoreConcreteComponentImpl(comp2, comp1, false) : null;
    }

    /**
     * Checks if the given realizingType is realizing the give realizedType.
     * @param realizingType the realizingType to check.
     * @param realizedType the realizedType.
     * @return true if the realizingType is realizing the realizedType, false 
     * otherwise.
     */
    public final boolean isRealizing(String realizingType, String realizedType) {
        if (realizingType.equals(realizedType)) {
            return true;
        }
        final Component realizer = findComponent(realizingType);
        return realizer.isRealizing(realizedType);
    }

    /**
     * @param toolkitLevel
     *            true if only toolkits with level "toolkit" are wanted, false
     *            if all toolkits are wanted.
     * @return a List of I18N names of the toolkits or a List of toolkit IDs.
     */
    public List<ToolkitDescriptor> getIndependentToolkitDescriptors(boolean toolkitLevel) {
        String level = toolkitLevel ? ToolkitConstants.LEVEL_TOOLKIT : null;
        return getIndependentToolkitDescriptors(level);
    }

    /**
     * 
     * @param componentClassName The FQN (fully qualified name) of the 
     *                           supported class for the Component. 
     * @param availableComponents Components through which to search.
     * @return The Component from the provided collection that supports the
     *         given class name, or <code>null</code> if no such Component
     *         is found.
     */
    public static String getComponentType(String componentClassName, Collection<Component> availableComponents) {

        Validate.notNull(componentClassName);
        Validate.allElementsOfType(availableComponents, Component.class);

        for (Component currentComp : availableComponents) {
            if (currentComp instanceof ConcreteComponent
                    && componentClassName.equals(((ConcreteComponent) currentComp).getComponentClass().getName())) {

                return currentComp.getType();
            }
        }

        return null;
    }
}