/*******************************************************************************
* 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.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.eclipse.jubula.client.core.model.ICapPO;
import org.eclipse.jubula.client.core.model.IExecTestCasePO;
import org.eclipse.jubula.client.core.model.INodePO;
import org.eclipse.jubula.client.core.model.IParamDescriptionPO;
import org.eclipse.jubula.client.core.model.IParamNodePO;
import org.eclipse.jubula.client.core.model.IParameterInterfacePO;
import org.eclipse.jubula.client.core.model.ISpecTestCasePO;
import org.eclipse.jubula.client.core.model.ITDManager;
import org.eclipse.jubula.client.core.model.TDCell;
import org.eclipse.jubula.client.core.persistence.NodePM;
import org.eclipse.jubula.client.core.utils.GuiParamValueConverter;
import org.eclipse.jubula.client.core.utils.ModelParamValueConverter;
import org.eclipse.jubula.toolkit.common.xml.businessprocess.ComponentBuilder;
import org.eclipse.jubula.tools.internal.xml.businessmodell.Action;
import org.eclipse.jubula.tools.internal.xml.businessmodell.CompSystem;
import org.eclipse.jubula.tools.internal.xml.businessmodell.Component;
import org.eclipse.jubula.tools.internal.xml.businessmodell.Param;
/**
* This is the business process for all parameter value operations on
* a parameter node like test steps, specification and execution test cases.
* The BP performs all required operations that result in the removing
* or adding of parameter references, e.g. <code>=FOO</code>. This includes
* checks to ensure that the operations are valid.
*
* {@inheritDoc}
*
* @author BREDEX GmbH
* @created 22.08.2005
*/
public class TestCaseParamBP extends AbstractParamInterfaceBP<ISpecTestCasePO> {
/** {@inheritDoc} */
protected void updateParam(GuiParamValueConverter conv,
IParamNameMapper mapper, int row) {
checkRemoveExternalDataFile(conv.getCurrentNode());
if (conv.getCurrentNode() instanceof IExecTestCasePO) {
IExecTestCasePO exTc = (IExecTestCasePO)conv.getCurrentNode();
exTc.resolveTDReference();
}
INodePO parent = NodePM.getSpecTestCaseParent(
(INodePO)conv.getCurrentNode());
if (parent instanceof ISpecTestCasePO) {
ISpecTestCasePO parentSpecTc = (ISpecTestCasePO)parent;
for (String refName : conv.getParametersToAdd(parentSpecTc)) {
addParameter(refName,
conv.getDesc().getType(), parentSpecTc, mapper);
}
}
writeTestDataEntry(conv, row);
}
/**
* finds all Params where a parameter is actually used. Since this is
* used for type checking only there is only one representative for a
* possible group of uses stored in the set.
* @param node node to check
* @param paramGUID the parameter to check
* @return a possibly empty set of usage points.
*/
public static Set<Param> getValuesForParameter(IParamNodePO node,
String paramGUID) {
Set<Param> result = new HashSet<Param>();
if (paramGUID != null) { // can happen when a dataset is deleted
getValuesForParameterImp(node, paramGUID, true, result);
}
return result;
}
/**
* finds all Params where a parameter is actually used. Since this is
* used for type checking only there is only one representative for a
* possible group of uses stored in the set.
* @param node node to check
* @param paramGUID the parameter to check
* @param isFirstCall true if called for the first time, false on all
* recursive calls
* @param result storage for results, owned by caller
*/
private static void getValuesForParameterImp(IParamNodePO node,
String paramGUID, boolean isFirstCall,
Set<Param> result) {
if (node instanceof ISpecTestCasePO) {
Iterator<INodePO> it = node.getNodeListIterator();
while (it.hasNext()) {
INodePO next = it.next();
if (next instanceof IParamNodePO) {
IParamNodePO n = (IParamNodePO) next;
getValuesForParameterImp(n, paramGUID,
false, result);
}
}
} else if (node instanceof IExecTestCasePO) {
IExecTestCasePO execTC = (IExecTestCasePO)node;
if (execTC.getSpecTestCase() != null) {
if (isFirstCall) {
getValuesForParameterImp(execTC.getSpecTestCase(),
paramGUID, false, result);
} else {
Set<String> subst = findSubstitutes(execTC, paramGUID);
for (String p : subst) {
getValuesForParameterImp(execTC.getSpecTestCase(), p,
false, result);
}
}
}
} else if (node instanceof ICapPO) {
ICapPO cap = (ICapPO)node;
final CompSystem compSystem = ComponentBuilder.getInstance()
.getCompSystem();
for (IParamDescriptionPO pd : cap.getParameterList()) {
try {
String pID =
cap.getDataManager().getCell(0, pd);
if ((pID != null) // check for unset data
&& pID.endsWith(paramGUID)) {
Component c = compSystem.findComponent(cap
.getComponentType());
Action a = c.findAction(cap.getActionName());
result.add(a.findParam(pd.getUniqueId()));
}
} catch (IndexOutOfBoundsException e) {
// Cell for the given row and column does not exist
// Do nothing
}
}
}
}
/**
* @param node ExecTC from which the data is chosen
* @param paramGUID check in the data set for usage of this GUID
* @return a possibly empty Set of parameter GUIDs which are the parameters
* which are substituted by paramGUID
*/
private static Set<String> findSubstitutes(IExecTestCasePO node,
String paramGUID) {
Set<String> result = new HashSet<String>();
for (IParamDescriptionPO paramDesc : node.getParameterList()) {
for (int rowNum = 0; rowNum < node.getDataManager()
.getDataSetCount(); rowNum++) {
try {
String value = node.getDataManager().getCell(rowNum,
paramDesc);
if ((value != null) && value.endsWith(paramGUID)) {
result.add(paramDesc.getUniqueId());
}
} catch (IndexOutOfBoundsException ioob) {
// this is a legal state: see ticket #3354
}
}
}
return result;
}
/**
* @param refName name for new parameter
* @param type of parameter to create
* @param node which get the new parameter
* @param mapper to resolve param names
*/
public void addParameter(String refName, String type,
ISpecTestCasePO node, IParamNameMapper mapper) {
node.addParameter(type, refName, mapper);
}
/**
* @param desc of parameter to remove
* @param specTc with parameter to remove
*/
public void removeParameter(IParamDescriptionPO desc,
ISpecTestCasePO specTc) {
specTc.removeParameter(desc.getUniqueId());
removeReferences(desc, specTc.getAllNodeIter());
}
/**
* @param desc desc of removed parameter of specTc
* @param childrenIt the Iterator of the children which References are to
* remove.
*/
private void removeReferences(IParamDescriptionPO desc,
Iterator<? extends INodePO> childrenIt) {
while (childrenIt.hasNext()) {
INodePO node = childrenIt.next();
if (node instanceof IParamNodePO) {
final IParamNodePO child = (IParamNodePO)node;
final ITDManager mgr = child.getDataManager();
final Iterator<TDCell> refIt =
child.getParamReferencesIterator();
while (refIt.hasNext()) {
final TDCell cell = refIt.next();
final String guid = mgr.getUniqueIds().get(cell.getCol());
final IParamDescriptionPO childDesc =
child.getParameterForUniqueId(guid);
final ModelParamValueConverter conv =
new ModelParamValueConverter(cell.getTestData(), child,
childDesc);
if (conv.containsReferences()) {
final boolean isModified = conv.removeReference(
desc.getUniqueId());
if (isModified) {
cell.setTestData(conv.getModelString());
}
}
}
}
}
}
/**
* Change the usage of the given old parameter to the new parameter GUID
* in all child execution Test Cases of the given specification Test Case.
* @param specTc The specification Test Case for changing the usage at.
* {@inheritDoc}
*/
public void changeUsageParameter(ISpecTestCasePO specTc,
IParamDescriptionPO desc, String newGuid,
ParamNameBPDecorator mapper) {
changeUsageReferences(
specTc.getAllNodeIter(), desc, newGuid, mapper);
}
/**
* @param childrenIt the Iterator of the children which References are to
* remove.
* @param desc The old parameter description, which have to be changed.
* @param newGuid The new GUID to change the reference to.
* @param mapper The parameter name mapping used here to persist test data.
*/
private void changeUsageReferences(Iterator childrenIt,
IParamDescriptionPO desc, String newGuid,
ParamNameBPDecorator mapper) {
while (childrenIt.hasNext()) {
final IParamNodePO child = (IParamNodePO)childrenIt.next();
final ITDManager mgr = child.getDataManager();
final Iterator<TDCell> refIt =
child.getParamReferencesIterator();
while (refIt.hasNext()) {
final TDCell cell = refIt.next();
final String guid = mgr.getUniqueIds().get(cell.getCol());
final IParamDescriptionPO childDesc =
child.getParameterForUniqueId(guid);
final String testData = cell.getTestData();
final ModelParamValueConverter conv =
new ModelParamValueConverter(testData, child,
childDesc);
if (conv.containsReferences()) {
Map<String, String> map = new HashMap<String, String>();
map.put(desc.getUniqueId(), newGuid);
if (conv.replaceUuidsInReferences(map)) {
cell.setTestData(conv.getModelString());
}
}
}
}
}
/**
* Gets a List of IExecTestCasePO with unused TestData of the given
* ISpecTestCasePO.
* @param nodePO An INodePO.
* @return a List of IExecTestCasePO with unused TestData of the given
* ISpecTestCasePO or an empty List.
*/
public static final List<IExecTestCasePO> getExecTcWithUnusedTestData(
INodePO nodePO) {
List<IExecTestCasePO> unusedTDExecList =
new LinkedList<IExecTestCasePO>();
for (Iterator nodeIt = nodePO.getNodeListIterator();
nodeIt.hasNext();) {
final INodePO childNode = (INodePO)nodeIt.next();
if (childNode instanceof IExecTestCasePO) {
final IExecTestCasePO execTc = (IExecTestCasePO)childNode;
if (execTc.getDataManager() != null
&& execTc.checkHasUnusedTestData()) {
unusedTDExecList.add(execTc);
}
}
}
return unusedTDExecList;
}
/**
* Removes the External-Data-File of the given IParamNodePO if it has no
* parameter. Otherwise it does nothing
* @param paramnode the IParamNodePO to check
* @return true if the External-Data-File has been removed, false otherwise.
*/
private boolean checkRemoveExternalDataFile(
IParameterInterfacePO paramnode) {
if (paramnode.getParameterList().isEmpty()) {
paramnode.setDataFile(null);
return true;
}
return false;
}
/**
* Sets the Interface (Parameters) of the given isInterfaceLocked to the
* given locked status.
* @param specTC an ISpecTestCasePO.
* @param locked true if locked, false otherwise.
*/
public static final void setInterfaceLocked(ISpecTestCasePO specTC,
boolean locked) {
specTC.setInterfaceLocked(locked);
}
/**
* Returns true, if the given IParamNodePO allowes References as data values.
* @param paramNode an IParamNodePO
* @return true if References are allowed, false otherwise.
*/
public static final boolean isReferenceValueAllowed(
IParameterInterfacePO paramNode) {
if (paramNode instanceof ISpecTestCasePO) {
return false;
}
if (paramNode instanceof IExecTestCasePO
|| paramNode instanceof ICapPO) {
// FIXME zeb assuming that the preceding instanceof checks imply
// that the object is an INodePO
final INodePO parentNode = NodePM.getSpecTestCaseParent(
((INodePO)paramNode));
if (parentNode instanceof ISpecTestCasePO) {
return !((ISpecTestCasePO)parentNode).isInterfaceLocked();
}
}
return true;
}
}