/*******************************************************************************
* Copyright (c) 2004, 2013 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.functions;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import org.eclipse.jubula.client.core.ClientTest;
import org.eclipse.jubula.client.core.businessprocess.ITestExecutionEventListener;
import org.eclipse.jubula.client.core.businessprocess.TestDataCubeBP;
import org.eclipse.jubula.client.core.businessprocess.TestExecutionEvent;
import org.eclipse.jubula.client.core.businessprocess.TestExecutionEvent.State;
import org.eclipse.jubula.client.core.model.IParamDescriptionPO;
import org.eclipse.jubula.client.core.model.ITDManager;
import org.eclipse.jubula.client.core.model.ITestDataCubePO;
import org.eclipse.jubula.client.core.persistence.GeneralStorage;
import org.eclipse.jubula.client.core.utils.ExecObject;
import org.eclipse.jubula.client.core.utils.GuiParamValueConverter;
import org.eclipse.jubula.client.core.utils.NullValidator;
import org.eclipse.jubula.tools.internal.exception.InvalidDataException;
import org.eclipse.jubula.tools.internal.messagehandling.MessageIDs;
/**
* This function returns the String value of a cell of a central central test
* data set. Therefore you need to define an unique key for this central test
* data set. You can get the cell value using the parameters DATA_SET_NAME,
* ENTRY_KEY, COLUMN_NAME.
*
* @author BREDEX GmbH
*/
public class CentralTestDataSetValueFunctionEvaluator
extends AbstractFunctionEvaluator {
/**
* a map of the data cubes
*/
private static final Map<String, ITestDataCubePO> DATA_CUBES =
new HashMap<String, ITestDataCubePO>();
/**
* the parameter descriptions
*/
private static final Map<ITestDataCubePO,
Map<String, IParamDescriptionPO>> PARAM_DESCRIPTIONS =
new HashMap<ITestDataCubePO, Map<String, IParamDescriptionPO>>();
/**
* the unique key map
*/
private static final Map<IParamDescriptionPO,
Map<String, Integer>> UNIQUE_KEYS =
new HashMap<IParamDescriptionPO, Map<String, Integer>>();
/**
* Add listener that refresh the caching of central test data sets every time the test
* execution starts
*/
static {
ClientTest.instance()
.addTestExecutionEventListener(new ITestExecutionEventListener() {
public void stateChanged(TestExecutionEvent event) {
if (event.getState() == State.TEST_EXEC_RESULT_TREE_READY) {
registerDataCubes();
PARAM_DESCRIPTIONS.clear();
UNIQUE_KEYS.clear();
}
}
public void endTestExecution() {
PARAM_DESCRIPTIONS.clear();
UNIQUE_KEYS.clear();
}
@Override
public void receiveExecutionNotification(String notification) {
// nothing
}
});
}
/**
* Register all central test data sets that are available and create a cache with the
* name of the central test data set as key
*/
private static void registerDataCubes() {
DATA_CUBES.clear();
ITestDataCubePO[] allTestDataCubesFor = TestDataCubeBP
.getAllTestDataCubesFor(GeneralStorage.getInstance()
.getProject());
for (ITestDataCubePO testDataCubePO : allTestDataCubesFor) {
DATA_CUBES.put(testDataCubePO.getName(), testDataCubePO);
}
}
/**
* Register all columns in a central test data set and create a cache with the name of
* the column as key
*
* @param dataSet
* the data table, that has different columns
* @return a map with all columns for this central test data sets
*/
private static Map<String, IParamDescriptionPO> registerParamDescription(
ITestDataCubePO dataSet) {
Map<String, IParamDescriptionPO> paramDescriptionsForOneDataSet =
new HashMap<String, IParamDescriptionPO>();
for (IParamDescriptionPO description : dataSet.getParameterList()) {
paramDescriptionsForOneDataSet.put(description.getName(),
description);
}
PARAM_DESCRIPTIONS.put(dataSet, paramDescriptionsForOneDataSet);
return paramDescriptionsForOneDataSet;
}
/**
* Register all key values for a key column of a specific central test data set.
*
* @param dataSet
* central test data set that contains keys and columns
* @param keyColumn
* Column where the key is stored
* @return a map specific for the column containing the row number for a
* given key
* @throws InvalidDataException
*/
private static Map<String, Integer> registerUniqueKeyMap(
ITestDataCubePO dataSet, IParamDescriptionPO keyColumn)
throws InvalidDataException {
Map<String, Integer> keyMap;
keyMap = new HashMap<String, Integer>();
ITDManager dataManager = dataSet.getDataManager();
for (int i = 0; i < dataManager.getDataSetCount(); i++) {
String cellValue = dataManager.getCell(i, keyColumn);
if (keyMap.get(cellValue) != null) {
throw new InvalidDataException("The key '" + cellValue //$NON-NLS-1$
+ "' for column '" + keyColumn.getName() //$NON-NLS-1$
+ "' is not unique in central test data set '" + dataSet.getName() //$NON-NLS-1$
+ "'!", MessageIDs.E_FUNCTION_EVAL_ERROR); //$NON-NLS-1$
}
keyMap.put(cellValue, i);
}
UNIQUE_KEYS.put(keyColumn, keyMap);
return keyMap;
}
/** {@inheritDoc} */
public String evaluate(String[] arguments) throws InvalidDataException {
validateParamCount(arguments, 4);
ITestDataCubePO dataSet = validateDataSetName(arguments[0]);
IParamDescriptionPO keyColumn = validateColumnName(dataSet,
arguments[1]);
int entryKey = validateEntryKey(dataSet, keyColumn, arguments[2]);
IParamDescriptionPO column = validateColumnName(dataSet, arguments[3]);
return getDataSetValue(dataSet, entryKey, column);
}
/**
* return the value of a central test data set cell identified by the given parameters
*
* @param dataSet
* where the value is stored
* @param row
* number of the given row
* @param column
* descriptor for the column
* @return value as a string, if it is another function it would be
* validated too
* @throws InvalidDataException
*/
private static String getDataSetValue(ITestDataCubePO dataSet, int row,
IParamDescriptionPO column)
throws InvalidDataException {
String dataSetValue = dataSet.getDataManager().getCell(row, column);
return new GuiParamValueConverter(dataSetValue, dataSet, null,
new NullValidator()).getExecutionString(
new ArrayList<ExecObject>());
}
/**
* Validate and return descriptor of a central test data set column. Cache will be used
* if available. After resolving any key from the given central test data set, all
* columns in this set should be cached.
*
* @param dataSet
* that contains value
* @param columnName
* unique name of the column in this central test data set
* @return descriptor for this column
* @throws InvalidDataException
*/
private static IParamDescriptionPO validateColumnName(
ITestDataCubePO dataSet, String columnName)
throws InvalidDataException {
Map<String, IParamDescriptionPO> map = PARAM_DESCRIPTIONS
.get(dataSet);
if (map == null) {
map = registerParamDescription(dataSet);
}
IParamDescriptionPO column = map.get(columnName);
if (column != null) {
return column;
}
throw new InvalidDataException("Column '" + columnName //$NON-NLS-1$
+ "' is not available in central test data set '" + dataSet.getName() + "'!", //$NON-NLS-1$ //$NON-NLS-2$
MessageIDs.E_FUNCTION_EVAL_ERROR);
}
/**
* Validates if a given key is available in a central test data set and returns the row
* number. This method uses keys from a cache if available. If not the key
* will be load and put to cache.
*
* @param dataSet
* that contains key
* @param keyColumn
* that contains key
* @param key
* unique key
* @return row number
* @throws InvalidDataException
*/
private static int validateEntryKey(ITestDataCubePO dataSet,
IParamDescriptionPO keyColumn, String key)
throws InvalidDataException {
Map<String, Integer> keyMap = UNIQUE_KEYS.get(keyColumn);
if (keyMap == null) {
keyMap = registerUniqueKeyMap(dataSet, keyColumn);
}
Integer row = keyMap.get(key);
if (row != null) {
return row;
}
throw new InvalidDataException("Key '" + key //$NON-NLS-1$
+ "' is not available in column '" + keyColumn.getName() //$NON-NLS-1$
+ "' in central test data set '" //$NON-NLS-1$
+ dataSet.getName() + "'!", //$NON-NLS-1$
MessageIDs.E_FUNCTION_EVAL_ERROR);
}
/**
* Returns a given central test data set using the cache if central test data set exists
*
* @param dataSetName
* unique name of the central test data set
* @return central test data set with the given name
* @throws InvalidDataException
*/
private static ITestDataCubePO validateDataSetName(String dataSetName)
throws InvalidDataException {
ITestDataCubePO dataCube = DATA_CUBES.get(dataSetName);
if (dataCube != null) {
return dataCube;
}
throw new InvalidDataException("Central test data set '" + dataSetName //$NON-NLS-1$
+ "' is not available!", MessageIDs.E_FUNCTION_EVAL_ERROR); //$NON-NLS-1$
}
}