org.eclipse.jubula.client.core.businessprocess.CompNamesBP.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipse.jubula.client.core.businessprocess.CompNamesBP.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.client.core.businessprocess;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.Validate;
import org.eclipse.jubula.client.core.businessprocess.ComponentNamesBP.CompNameCreationContext;
import org.eclipse.jubula.client.core.model.ICapPO;
import org.eclipse.jubula.client.core.model.ICompNamesPairPO;
import org.eclipse.jubula.client.core.model.IComponentNamePO;
import org.eclipse.jubula.client.core.model.IExecTestCasePO;
import org.eclipse.jubula.client.core.model.INodePO;
import org.eclipse.jubula.client.core.model.ISpecTestCasePO;
import org.eclipse.jubula.client.core.model.PoMaker;
import org.eclipse.jubula.client.core.persistence.IncompatibleTypeException;
import org.eclipse.jubula.client.core.persistence.NodePM;
import org.eclipse.jubula.client.core.persistence.PMException;
import org.eclipse.jubula.tools.constants.StringConstants;
import org.eclipse.jubula.tools.xml.businessmodell.Component;
import org.eclipse.jubula.tools.xml.businessmodell.ConcreteComponent;

/**
 * This business process performs the override and propagate operations on
 * component names on the test execution node level.
 * 
 * @author BREDEX GmbH
 * @created 08.09.2005
 */
public class CompNamesBP {
    /**
     * Interface for updates of overriden component names or propagations.
     */
    private interface IUpdater {
        /**
         * Updates the parent test execution node.
         * 
         * @param parentExec
         *            The parent test execution node
         * @param pair
         *            The component name pair
         */
        public void updateParentExecTestCase(IExecTestCasePO parentExec, ICompNamesPairPO pair);

        /**
         * Updates the component name pair
         * 
         * @param pair
         *            The component name pair
         * @return <code>true</code> if the pair has been updated,
         *         <code>false</code> otherwise
         */
        public boolean updateCompNamesPair(ICompNamesPairPO pair);
    }

    /**
     * Updates the propagated property of a component name pair.
     * 
     * {@inheritDoc}
     */
    private static class PropagatedUpdater implements IUpdater {
        /**
         * The propagated property
         */
        private boolean m_propagated;

        /**
         * Constructor
         * 
         * @param propagated
         *            The propagated property to update
         */
        public PropagatedUpdater(boolean propagated) {
            m_propagated = propagated;
        }

        /**
         * Updates the The propagated property and returns <code>true</code>
         * if the new property differs from the property of <code>pair</code>.
         * 
         * {@inheritDoc}
         */
        public boolean updateCompNamesPair(ICompNamesPairPO pair) {
            boolean oldValue = pair.isPropagated();
            pair.setPropagated(m_propagated);

            return oldValue != m_propagated;
        }

        /**
         * Removes the component name pair from the parent if it is not
         * propagated.
         * 
         * {@inheritDoc}
         *      org.eclipse.jubula.client.core.model.CompNamesPairPO)
         */
        public void updateParentExecTestCase(IExecTestCasePO parentExec, ICompNamesPairPO pair) {

            String name = pair.getSecondName();
            if (!m_propagated) {
                parentExec.removeCompNamesPair(name);
            }
        }
    }

    /**
     * Updates the second name (that means, the overriding name) of a component
     * name pair.
     */
    private static class SecondNameUpdater implements IUpdater {
        /**
         * The second name GUID.
         */
        private String m_secondNameGuid;

        /**
         * Constructor
         * 
         * @param secondName
         *            The second name
         */
        public SecondNameUpdater(String secondName) {
            m_secondNameGuid = secondName;
        }

        /**
         * Sets the second name into the <code>pair</code>. Returns
         * <code>true</code>.
         * 
         * {@inheritDoc}
         */
        public boolean updateCompNamesPair(ICompNamesPairPO pair) {
            pair.setSecondName(m_secondNameGuid);
            return true;
        }

        /**
         * Updates the parent node if it contains a component name pair that
         * overrides the second name of the passed <code>pair</code>.
         * 
         * {@inheritDoc}
         *      org.eclipse.jubula.client.core.model.CompNamesPairPO)
         */
        public void updateParentExecTestCase(IExecTestCasePO parentExec, ICompNamesPairPO pair) {

            Validate.noNullElements(new Object[] { parentExec, pair });
            ICompNamesPairPO parentPair = parentExec.getCompNamesPair(pair.getSecondName());
            if (parentPair != null) {
                parentExec.removeCompNamesPair(parentPair.getFirstName());
                final String type = parentExec.getCompNamesPair(pair.getFirstName()).getType();
                parentExec.addCompNamesPair(
                        PoMaker.createCompNamesPairPO(m_secondNameGuid, parentPair.getSecondName(), type));
            }
        }
    }

    /**
     * Adds all propagated component name pairs of the test execution node to
     * the map <code>pairs</code>.
     * 
     * @param pairs
     *            The map
     * @param execNode
     *            The test execution node
     */
    private void addPropagatedPairs(Map<String, ICompNamesPairPO> pairs, IExecTestCasePO execNode) {
        for (ICompNamesPairPO pair : execNode.getCompNamesPairs()) {
            if (pair.isPropagated()) {
                String name = pair.getSecondName();
                if (!pairs.containsKey(name)) {
                    String type = (pair.getType() == null || pair.getType().equals(StringConstants.EMPTY))
                            ? StringConstants.EMPTY
                            : pair.getType();
                    // ------------------------------------------------
                    if (pair.getType() == null) {
                        for (Object o : execNode.getSpecTestCase().getUnmodifiableNodeList()) {

                            INodePO node = (INodePO) o;
                            if (node instanceof ICapPO) {
                                ICapPO cap = (ICapPO) node;
                                if (cap.getComponentName().equals(pair.getName())) {

                                    type = cap.getComponentType();
                                    pair.setType(type);
                                    break;
                                }
                            }
                        }
                    }
                    pairs.put(name, PoMaker.createCompNamesPairPO(name, type));
                }
            }
        }
    }

    /**
     * Adds the component name of the passed test step to the map if the
     * component is not mapped by default.
     * 
     * @param pairs
     *            The map
     * @param capNode
     *            The test step
     */
    private void addCapComponentName(Map<String, ICompNamesPairPO> pairs, ICapPO capNode) {

        final Component component = capNode.getMetaComponentType();
        if (component instanceof ConcreteComponent && ((ConcreteComponent) component).hasDefaultMapping()) {
            return;
        }
        final String name = capNode.getComponentName();
        final String type = capNode.getComponentType();
        if (!pairs.containsKey(name)) {
            ICompNamesPairPO pair = PoMaker.createCompNamesPairPO(name, type);
            pairs.put(name, pair);
        }
    }

    /**
     * Gets all component name pairs of the passed test execution node. The list
     * contains all pairs of the passed node itself, and the propagated pairs of
     * the child test execution nodes, and the component names of the child test
     * steps.
     * 
     * @param execNode
     *            The test execution node
     * @return The list with all component name pairs that (directly or
     *         indirectly) belong to the passed node. The list is ordered by the
     *         first names in ascending order.
     */
    public List<ICompNamesPairPO> getAllCompNamesPairs(IExecTestCasePO execNode) {

        Map<String, ICompNamesPairPO> pairs = new HashMap<String, ICompNamesPairPO>();

        for (ICompNamesPairPO pair : execNode.getCompNamesPairs()) {
            pairs.put(pair.getFirstName(), pair);
        }

        ISpecTestCasePO specNode = execNode.getSpecTestCase();

        if (specNode != null) {
            for (Iterator it = specNode.getNodeListIterator(); it.hasNext();) {
                INodePO child = (INodePO) it.next();
                if (child instanceof IExecTestCasePO) {
                    addPropagatedPairs(pairs, (IExecTestCasePO) child);
                } else if (child instanceof ICapPO) {
                    addCapComponentName(pairs, (ICapPO) child);
                }
            }
        }

        List<ICompNamesPairPO> pairList = new ArrayList<ICompNamesPairPO>(pairs.values());
        // Sort the list by default
        Collections.sort(pairList, new Comparator<ICompNamesPairPO>() {
            public int compare(ICompNamesPairPO o1, ICompNamesPairPO o2) {
                return o1.getFirstName().compareTo(o2.getFirstName());
            }
        });

        return pairList;
    }

    /**
     * Finds all test execution nodes of the passed test specification node with
     * the following condition: The test execution node matches if one of its
     * children is the same as the passed execution node <code>execNode</code>.
     * 
     * @param specNode
     *            The specification node
     * @param execNode
     *            The execution node
     * @return The list of execution nodes
     */
    private List<IExecTestCasePO> findExecNodes(ISpecTestCasePO specNode, IExecTestCasePO execNode) {

        List<IExecTestCasePO> nodes = new ArrayList<IExecTestCasePO>();
        List<IExecTestCasePO> execTestCases = NodePM.getInternalExecTestCases(specNode.getGuid(),
                specNode.getParentProjectId());
        for (IExecTestCasePO execTc : execTestCases) {
            for (Iterator itNodes = execTc.getNodeListIterator(); itNodes.hasNext();) {

                INodePO child = (INodePO) itNodes.next();
                if (child == execNode) {
                    nodes.add(execTc);
                }
            }
        }
        return nodes;
    }

    /**
     * Updates the passed execution node and the passed component name pair
     * using the updater.
     * 
     * @param execNode
     *            The execution node to update
     * @param pair
     *            The component name pair to update
     * @param updater
     *            The updater
     * @return The result of
     *         {@link IUpdater#updateCompNamesPair(CompNamesPairPO)}
     */
    private boolean updateCompNamesPair(IExecTestCasePO execNode, ICompNamesPairPO pair, IUpdater updater) {

        final INodePO execParent = execNode.getParentNode();
        if (execParent instanceof ISpecTestCasePO) {
            ISpecTestCasePO parent = (ISpecTestCasePO) execParent;
            for (IExecTestCasePO parentExec : findExecNodes(parent, execNode)) {

                updater.updateParentExecTestCase(parentExec, pair);
            }
        }

        boolean update = updater.updateCompNamesPair(pair);
        if (update && execNode.getCompNamesPair(pair.getFirstName()) == null) {
            execNode.addCompNamesPair(pair);
        }
        return update;
    }

    /**
     * Updates the passed component name pair by setting the propagated
     * property. The method also updates the passed test execution node (by
     * adding the pair if required) and its parent execution nodes.
     * 
     * @param execNode
     *            The test execution node
     * @param pair
     *            The component name pair
     * @param propagated
     *            The property to update
     * @return <code>true</code> if the propagated property has been updated,
     *         <code>false</code> otherwise
     */
    public boolean updateCompNamesPair(IExecTestCasePO execNode, ICompNamesPairPO pair, boolean propagated) {
        return updateCompNamesPair(execNode, pair, new PropagatedUpdater(propagated));
    }

    /**
     * Updates the passed component name pair by setting the second name
     * property (that means, the overriding component name. The method also
     * updates the passed test execution node (by adding the pair if required)
     * and its parent execution nodes.
     * 
     * @param execNode The test execution node
     * @param pair The component name pair
     * @param secondCompName The second component name
     * @param compMapper business process for componentNames.    
     * @return <code>true</code> if the name property has been updated,
     *         <code>false</code> otherwise
     */
    public boolean updateCompNamesPair(IExecTestCasePO execNode, ICompNamesPairPO pair, String secondCompName,
            IWritableComponentNameMapper compMapper) throws IncompatibleTypeException, PMException {

        if (secondCompName == null || StringConstants.EMPTY.equals(secondCompName)) {
            return false;
        }
        String secondName = compMapper.getCompNameCache().getGuidForName(secondCompName);
        if (StringUtils.equals(secondName, pair.getSecondName())) {
            return false;
        }

        if (secondName == null) {
            final IComponentNamePO newComponentNamePO = compMapper.getCompNameCache()
                    .createComponentNamePO(secondCompName, pair.getType(), CompNameCreationContext.OVERRIDDEN_NAME);
            newComponentNamePO.setParentProjectId(execNode.getParentProjectId());
            secondName = newComponentNamePO.getGuid();
        }

        compMapper.changeReuse(pair, pair.getSecondName(), secondName);

        return updateCompNamesPair(execNode, pair, new SecondNameUpdater(secondName));
    }

    /**
     * @param pair the current compNamesPairPO
     * @param node the node to search comp type in
     * @return true, if comp type was found
     */
    public static boolean searchCompType(final ICompNamesPairPO pair, Object node) {
        if (node instanceof IExecTestCasePO) {
            ISpecTestCasePO specTc = ((IExecTestCasePO) node).getSpecTestCase();
            if (specTc == null) {
                // Referenced SpecTestCase does not exist
                return false;
            }
            for (Object childNode : specTc.getUnmodifiableNodeList()) {

                if (childNode instanceof IExecTestCasePO) {
                    IExecTestCasePO exec = (IExecTestCasePO) childNode;
                    for (ICompNamesPairPO cnp : exec.getCompNamesPairs()) {
                        if (cnp.getSecondName().equals(pair.getFirstName()) && cnp.isPropagated()) {

                            pair.setType(cnp.getType());
                            if (isValidCompNamePair(pair)) {
                                return true;
                            }
                            boolean retVal = searchCompType(cnp, exec);
                            pair.setType(cnp.getType());
                            return retVal;
                        }
                    }
                } else if (childNode instanceof ICapPO) {
                    ICapPO cap = (ICapPO) childNode;
                    if (cap.getComponentName() != null && cap.getComponentName().equals(pair.getFirstName())) {
                        pair.setType(cap.getComponentType());
                        return true;
                    }
                }
            }
        }
        return false;
    }

    /**
     * Finds the component name of the passed test step. The method searches for
     * the name in the passed tree path, which is exepected to be a top-down
     * path to the <code>capNode</code>. The <code>capNode</code> itself
     * may or may not be included as the last element of the list. Usually, the
     * tree path is determined by calling
     * {@link org.eclipse.jubula.client.core.utils.ITreeTraverserContext#getCurrentTreePath()}.
     * The result contains the component name and the node that is responsible
     * for defining the component name. This is the test step itself or the
     * execution node with the latest overriding. If a name is propagated
     * (overriden or not), the parent node is always responsible.
     * 
     * @param treePath
     *            The tree path
     * @param compNameDefiner
     *            The node that is using the component name
     * @param compNameCache
     *            The cache to use in order to resolve Component Name 
     *            references.
     * @param compNameGuid
     *            The GUID of the component name.
     * @return The result containing the component name and the responsible node
     */
    public CompNameResult findCompName(List<INodePO> treePath, INodePO compNameDefiner, String compNameGuid,
            IComponentNameCache compNameCache) {
        String currentName = compNameGuid;
        IComponentNamePO currentNamePo = compNameCache.getCompNamePo(currentName);
        if (currentNamePo != null) {
            currentName = currentNamePo.getGuid();
        }
        return findCompName(treePath, compNameCache, currentName, compNameDefiner);
    }

    /**
     * @param treePath
     *            The tree path
     * @param compNameCache
     *            The cache to use in order to resolve Component Name 
     *            references.
     * @param originalName
     *            The GUID of the component name.
     * @param originalCompNameDefiner
     *            The node that is using the component name
     * @return The result containing the component name and the responsible node
     */
    private CompNameResult findCompName(List<INodePO> treePath, IComponentNameCache compNameCache,
            String originalName, INodePO originalCompNameDefiner) {

        String currentName = originalName;
        INodePO compNameDefiner = originalCompNameDefiner;
        IComponentNamePO currentNamePo;
        ListIterator<INodePO> it = treePath.listIterator(treePath.size());
        while (it.hasPrevious()) {
            INodePO node = it.previous();
            if (node instanceof IExecTestCasePO) {
                IExecTestCasePO execNode = (IExecTestCasePO) node;
                ICompNamesPairPO pair = null;
                if (!StringUtils.isEmpty(currentName)) {
                    pair = execNode.getCompNamesPair(currentName);
                }
                if (pair != null) {
                    currentName = pair.getSecondName();
                    currentNamePo = compNameCache.getCompNamePo(currentName);
                    if (currentNamePo != null) {
                        currentName = currentNamePo.getGuid();
                    }
                    if (pair.isPropagated()) {
                        int index = it.previousIndex();
                        if (index > -1) {
                            compNameDefiner = treePath.get(index);
                        }
                    } else {
                        compNameDefiner = execNode;
                        break;
                    }
                }
            }
        }

        return new CompNameResult(currentName, compNameDefiner);
    }

    /**
     * Removes incorrect CompNamePairs from children of the given node.
     * 
     * @param node CompNamePairs for children of this node will be analyzed.
     */
    public static void removeIncorrectCompNamePairs(INodePO node) {
        for (Object o : node.getUnmodifiableNodeList()) {
            if (o instanceof IExecTestCasePO) {
                IExecTestCasePO exec = (IExecTestCasePO) o;
                // we need to iterate over a copy of the collection
                // because we are removing elements during iteration
                for (ICompNamesPairPO pair : new LinkedList<ICompNamesPairPO>(exec.getCompNamesPairs())) {
                    searchCompType(pair, exec);
                    if (!isValidCompNamePair(pair)) {
                        exec.removeCompNamesPair(pair.getFirstName());
                    }
                }
            }
        }
    }

    /**
     * @param pair the component name pair to check
     * @return true if the component name pair is valid
     */
    public static boolean isValidCompNamePair(ICompNamesPairPO pair) {
        return pair.getType().length() != 0;
    }

}