/*******************************************************************************
* 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.model;
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.List;
import java.util.ListIterator;
import java.util.Map;
import java.util.Set;
import javax.persistence.Basic;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.DiscriminatorValue;
import javax.persistence.Entity;
import javax.persistence.EntityManager;
import javax.persistence.FetchType;
import javax.persistence.JoinColumn;
import javax.persistence.MapKeyColumn;
import javax.persistence.OneToMany;
import javax.persistence.Query;
import javax.persistence.Transient;
import org.apache.commons.lang.ObjectUtils;
import org.eclipse.jubula.client.core.businessprocess.ProjectNameBP;
import org.eclipse.jubula.client.core.i18n.Messages;
import org.eclipse.jubula.client.core.persistence.NodePM;
import org.eclipse.jubula.client.core.persistence.ProjectPM;
import org.eclipse.jubula.tools.internal.constants.StringConstants;
import org.eclipse.jubula.tools.internal.exception.JBException;
import org.eclipse.osgi.util.NLS;
import org.eclipse.persistence.annotations.BatchFetch;
import org.eclipse.persistence.annotations.BatchFetchType;
import org.eclipse.persistence.annotations.Index;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* class only relevant for test execution
*
* @author BREDEX GmbH
* @created 12.10.2004
*/
@Entity
@DiscriminatorValue(value = "E")
class ExecTestCasePO extends TestCasePO implements
IEventHandlerContainer, IExecTestCasePO {
/** the logger */
private static final Logger LOG =
LoggerFactory.getLogger(ExecTestCasePO.class);
/**
* reference to SpecTestCasePO from specification tree
*/
private transient ISpecTestCasePO m_cachedSpecTestCase = null;
/**
* <code>m_hasReferencedTD</code> determines, if the execTC has own testdata
* or referenced testdata from corresponding specTestCase
*/
private boolean m_hasReferencedTD = true;
/**
* <code>m_refEventTcMap</code> manages the flags to signal, if an event-
* handler for a given eventType is overwritten or not
* key: eventType, value: flag
*/
private Map<String, Boolean> m_refEventTcMap =
new HashMap<String, Boolean>(
IEventHandlerContainer.MAX_NUMBER_OF_EVENT_HANDLER);
/**
* <code>m_compNameMap</code> manages the mapping between old component name
* and new (overwritten) component name
*/
private Map<String, ICompNamesPairPO> m_compNamesMap;
/** GUID of the parent project */
private String m_projectGuid;
/** GUID of the referenced test case */
private String m_specTestCaseGuid;
/**
* only for Persistence (JPA / EclipseLink)
*/
ExecTestCasePO() {
// only for Persistence (JPA / EclipseLink)
m_compNamesMap = new HashMap<String, ICompNamesPairPO>();
}
/**
* constructor
* @param specTestCase reference to specified testcase
* @param isGenerated indicates whether this node has been generated
*/
ExecTestCasePO(ISpecTestCasePO specTestCase, boolean isGenerated) {
super(null, isGenerated); // null is correct, do not set a name here!
setSpecTestCase(specTestCase);
m_compNamesMap = new HashMap<String, ICompNamesPairPO>();
}
/**
* constructor when the GUID is already assigned
* @param specTestCase reference to specified testcase
* @param guid the GUID for this exec test case
* @param isGenerated indicates whether this node has been generated
*/
ExecTestCasePO(ISpecTestCasePO specTestCase, String guid,
boolean isGenerated) {
super(null, guid, isGenerated); // null is correct,
// do not set a name here!
setSpecTestCase(specTestCase);
m_compNamesMap = new HashMap<String, ICompNamesPairPO>();
}
/**
* constructor when the GUID is already assigned and the referenced testcase
* was not imported with this exec testcase
* @param specTestCaseGuid GUID reference to specified testcase
* @param projectGuid GUID reference to specified testcase's parent project
* @param guid the GUID for this exec test case
* @param isGenerated indicates whether this node has been generated
*/
ExecTestCasePO(String specTestCaseGuid, String projectGuid, String guid,
boolean isGenerated) {
super(null, guid, isGenerated); // null is correct,
// do not set a name here!
setSpecTestCaseGuid(specTestCaseGuid);
setProjectGuid(projectGuid);
m_compNamesMap = new HashMap<String, ICompNamesPairPO>();
}
/**
* constructor when a new GUID must be assigned and the referenced testcase
* was not imported with this exec testcase
* @param specTestCaseGuid GUID reference to specified testcase
* @param projectGuid GUID reference to specified testcase's parent project
* @param isGenerated indicates whether this node has been generated
*/
ExecTestCasePO(String specTestCaseGuid, String projectGuid,
boolean isGenerated) {
super(null, isGenerated); // null is correct, do not set a name here!
setSpecTestCaseGuid(specTestCaseGuid);
setProjectGuid(projectGuid);
m_compNamesMap = new HashMap<String, ICompNamesPairPO>();
}
/**
* Gets the name of this node or, if na name is set,
* gets the name of the SpecTestCase.
* {@inheritDoc}
* @return
*/
@Transient
public String getName() {
String name = super.getName();
if (name == null || name.equals(StringConstants.EMPTY)) {
if (getSpecTestCase() != null) {
return getSpecTestCase().getName();
}
String reusedProjectName =
ProjectNameBP.getInstance().getName(m_projectGuid);
if (reusedProjectName != null && reusedProjectName.length() != 0) {
return NLS.bind(
Messages.ExecTestCasePOMissingReferenceWithProjectName,
reusedProjectName);
}
return Messages.ExecTestCasePOMissingReference;
}
return name;
}
/**
* Gets the comment of this node or, if no comment is set,
* gets the comment of the SpecTestCase.
* {@inheritDoc}
* @return
*/
@Transient
public String getComment() {
String comment = super.getComment();
if ((comment == null || comment.equals(StringConstants.EMPTY))
&& getSpecTestCase() != null) {
return getSpecTestCase().getComment();
}
return comment;
}
/**
* {@inheritDoc}
* @return
*/
@Transient
public String getDataFile() {
String dataFile = super.getDataFile();
if ((dataFile == null || dataFile.equals(StringConstants.EMPTY))
&& getSpecTestCase() != null) {
return getSpecTestCase().getDataFile();
}
return dataFile;
}
/**
*
* {@inheritDoc}
*/
@Transient
public ISpecTestCasePO getSpecTestCase() {
if (m_cachedSpecTestCase != null) {
return m_cachedSpecTestCase;
}
ISpecTestCasePO specTc = null;
// Search by GUID
try {
if (getParentProjectId() != null) {
if (getProjectGuid() == null
|| getProjectGuid().equals(
ProjectPM.getGuidOfProjectId(
getParentProjectId()))) {
// Referenced TC is in the same project
specTc = NodePM.getSpecTestCase(getParentProjectId(),
getSpecTestCaseGuid());
} else {
// Referenced TC is in a different project
Set<IReusedProjectPO> reusedProjects =
new HashSet<IReusedProjectPO>();
reusedProjects
.addAll(
ProjectPM.loadReusedProjectsRO(
getParentProjectId()));
specTc = NodePM.getSpecTestCase(
reusedProjects, getProjectGuid(),
getSpecTestCaseGuid());
}
}
} catch (JBException e) {
LOG.warn("Could not retrieve referenced Test Case.", e); //$NON-NLS-1$
}
m_cachedSpecTestCase = specTc;
return specTc;
}
/**
*
* {@inheritDoc}
*/
public void setSpecTestCase(ISpecTestCasePO specTestCase) {
if (specTestCase != null) {
if (getId() == null) {
// New ExecTestCase. If it's being imported, then we won't find
// the RefSpecTestCase in the database, so we have to cache it.
m_cachedSpecTestCase = specTestCase;
}
setSpecTestCaseGuid(specTestCase.getGuid());
if (specTestCase.getParentProjectId() != getParentProjectId()) {
try {
setProjectGuid(ProjectPM.loadProjectById(
specTestCase.getParentProjectId()).getGuid());
} catch (JBException e) {
// FIXME zeb Error occurred while trying to set project guid for exec tc
}
} else {
setProjectGuid(null);
}
}
}
/**
* {@inheritDoc}
* ExecTestCasePO doesn't have an own parameter list
* it uses generally the parameter from associated specTestCase
*/
@Transient
public List<IParamDescriptionPO> getParameterList() {
if (getSpecTestCase() != null) {
return getSpecTestCase().getParameterList();
}
return new ArrayList<IParamDescriptionPO>();
}
/**
* {@inheritDoc}
*/
@Transient
public ListIterator<IParamDescriptionPO> getParameterListIter() {
if (getSpecTestCase() != null) {
return getSpecTestCase().getParameterListIter();
}
List<IParamDescriptionPO> emptyList = Collections.emptyList();
return emptyList.listIterator();
}
/**
* {@inheritDoc}
*/
@Transient
public int getParameterListSize() {
if (getSpecTestCase() != null) {
return getSpecTestCase().getParameterListSize();
}
return 0;
}
/**
* {@inheritDoc}
* @return the TDManagerPO from the depending SpecTestCasePO or the own if
* TestData are overwritten.
*/
@Transient
public ITDManager getDataManager() {
if (getReferencedDataCube() == null
&& getHasReferencedTD() && getSpecTestCase() != null) {
return getSpecTestCase().getDataManager();
}
return super.getDataManager();
}
/**
* {@inheritDoc}
*/
public boolean hasReferencedTestData() {
return super.hasReferencedTestData()
|| (getHasReferencedTD() && getSpecTestCase() != null);
}
/**
* {@inheritDoc}
*/
@Transient
public IParameterInterfacePO getReferencedDataCube() {
if ((getHasReferencedTD() && getSpecTestCase() != null)) {
return getSpecTestCase().getReferencedDataCube();
}
return super.getReferencedDataCube();
}
/**
* @return the DataManager of this ExecTestCase even if getHasReferencedID()
* returns true.
*/
@Transient
private ITDManager getOwnDataManager() {
return super.getDataManager();
}
/**
* Sets the data manager and changes the <code>hasReferencedTD</code> flag
* to <code>false</code>, so that {@link #getHasReferencedTD()} will
* return <code>false</code> after this call.
*
* {@inheritDoc}
*/
public void setDataManager(ITDManager dataManager) {
super.setDataManager(dataManager);
setHasReferencedTD(false);
}
/**
* {@inheritDoc}
*/
public void setParentProjectId(Long projectId) {
super.setParentProjectId(projectId);
for (ICompNamesPairPO compNamesPair : getCompNamesPairs()) {
compNamesPair.setParentProjectId(projectId);
}
}
/**
* Resolves the reference to the test data manager of the associated
* specification test case node. This method creates a deep copy of the test
* data manager an sets it as it's own manager.
*
* @return The new test data manager
*/
public ITDManager resolveTDReference() {
if (getHasReferencedTD()) {
final ITDManager specTDMan = getSpecTestCase().getDataManager();
final ITDManager execTDMan = super.getHbmDataManager();
final ITDManager modifiedExecTDMan = specTDMan.deepCopy(
execTDMan);
this.setDataManager(modifiedExecTDMan);
}
return getDataManager();
}
/** {@inheritDoc} */
@Transient
public Iterator<INodePO> getNodeListIterator() {
ISpecTestCasePO specTestCase = getSpecTestCase();
if (specTestCase != null) {
return specTestCase.getNodeListIterator();
}
List<INodePO> emptyList = Collections.emptyList();
return emptyList.iterator();
}
/** {@inheritDoc} */
@Transient
public Iterator<INodePO> getAllNodeIter() {
ISpecTestCasePO specTestCase = getSpecTestCase();
if (specTestCase != null) {
return specTestCase.getAllNodeIter();
}
List<INodePO> emptyList = Collections.emptyList();
return emptyList.iterator();
}
/** {@inheritDoc} */
@Transient
public int getNodeListSize() {
if (getSpecTestCase() != null) {
return getSpecTestCase().getNodeListSize();
}
return 0;
}
/**
* only for Persistence (JPA / EclipseLink)
*
* @return Returns the m_hasReferencedTD.
*/
@Basic
@Column(name = "REF_FLAG")
@Index(name = "PI_NODE_REF_FLAG")
public boolean getHasReferencedTD() {
return m_hasReferencedTD;
}
/**
* only for Persistence (JPA / EclipseLink)
* @param hasReferencedTD The m_hasReferencedTD to set.
*/
public void setHasReferencedTD(boolean hasReferencedTD) {
m_hasReferencedTD = hasReferencedTD;
}
/**
* public getter for unmodifiable map of eventExecTestCases
* @return map ov eventExecTestCases
*/
@Transient
public Map<String, IEventExecTestCasePO> getEventMap() {
return Collections.unmodifiableMap(
getSpecTestCase().getEventExecTcMap());
}
/**
* {@inheritDoc}
*/
public IEventExecTestCasePO getEventExecTC(String eventType) {
return (getFlagForRefEventTc(eventType))
? getSpecTestCase().getEventExecTC(eventType)
: getEventExecTC(eventType);
}
/**
* only for Persistence (JPA / EclipseLink)
* @return Returns the refEventTcMap.
*/
@Transient
private Map<String, Boolean> getRefEventTcMap() {
return m_refEventTcMap;
}
/**
* only for Persistence (JPA / EclipseLink)
* @param refEventTcMap The refEventTcMap to set.
*/
@SuppressWarnings("unused")
private void setRefEventTcMap(Map<String, Boolean> refEventTcMap) {
m_refEventTcMap = refEventTcMap;
}
/**
* @param eventType eventType, for which to set the flag
* @param flag signals, if the associated eventhandler for given eventType
* will be reused (flag = true) or overwritten (flag = false)
*/
public void setFlagForRefEventTc(String eventType, boolean flag) {
getRefEventTcMap().put(eventType, Boolean.valueOf(flag));
}
/**
* @param eventType eventType, for which to get the flag
* @return flag, which signals, if the eventhandler for given eventType is
* referenced from associated specTestCase or overwritten
*/
public boolean getFlagForRefEventTc(String eventType) {
Boolean value = m_refEventTcMap.get(eventType);
return (value == null) ? true : value.booleanValue();
}
/**
* only for Persistence (JPA / EclipseLink)
*
* @return Returns the compNameMap.
*/
@OneToMany(cascade = CascadeType.ALL, orphanRemoval = true,
fetch = FetchType.EAGER, targetEntity = CompNamesPairPO.class)
@MapKeyColumn(name = "MK_EXECTC_COMPNAMES")
@JoinColumn(name = "FK_EXECTC")
@BatchFetch(value = BatchFetchType.JOIN)
private Map<String, ICompNamesPairPO> getHbmCompNamesMap() {
return m_compNamesMap;
}
/**
* Removes Comp Names Pairs
* @param sess the session
*/
private void removeCompNamesPairs(EntityManager sess) {
Query q = sess.createNativeQuery("delete from COMP_NAME_PAIRS where FK_EXECTC = ?1"); //$NON-NLS-1$
q.setParameter(1, getId()).executeUpdate();
}
/**
* only for Persistence (JPA / EclipseLink)
*
* @param compNameMap The compNameMap to set.
*/
@SuppressWarnings("unused")
private void setHbmCompNamesMap(Map<String, ICompNamesPairPO> compNameMap) {
m_compNamesMap = compNameMap;
}
/**
* Adds the component name pair to the internal map if the pair doesn't
* exist.
*
* @param pair
* The component name pair
*/
public void addCompNamesPair(ICompNamesPairPO pair) {
String key = pair.getFirstName();
if (!getHbmCompNamesMap().containsKey(key)) {
getHbmCompNamesMap().put(key, pair);
pair.setParentProjectId(getParentProjectId());
}
}
/**
* Removes the component name pair with the passed first name from the
* internal map.
*
* @param firstName
* The first name
*/
public void removeCompNamesPair(String firstName) {
getHbmCompNamesMap().remove(firstName);
}
/**
* Gets the component name pair with the past first name.
*
* @param firstName
* The first name
* @return The component name pair or <code>null</code>, if the internal
* map doesn't contain a component name pair with the passed first
* name
*/
public ICompNamesPairPO getCompNamesPair(String firstName) {
return getHbmCompNamesMap().get(firstName);
}
/**
* @return An unmodifyable list of all component name pairs
*/
@Transient
public Collection<ICompNamesPairPO> getCompNamesPairs() {
return Collections.unmodifiableCollection(
getHbmCompNamesMap().values());
}
/**
* {@inheritDoc}
* @return
*/
@Transient
public String getRealName() {
return super.getName();
}
/**
*
* @return the GUID of the parent Project of the referenced Test Case, or
* <code>null</code> if the referenced Test Case has the same parent
* Project as the receiver.
*/
@Basic
@Column(name = "PARENT_PROJ_GUID")
@Index(name = "PI_NODE_PARENT_PROJECT_GUID")
public String getProjectGuid() {
return m_projectGuid;
}
/**
*
* @return the GUID of the referenced test case.
*/
@Basic
@Column(name = "SPEC_TC_GUID")
@Index(name = "PI_NODE_SPEC_TC_GUID")
public String getSpecTestCaseGuid() {
return m_specTestCaseGuid;
}
/**
* For Persistence (JPA / EclipseLink).
* @param projectGuid The GUID of the parent project of the referenced test case.
*/
private void setProjectGuid(String projectGuid) {
m_projectGuid = projectGuid;
}
/**
* For Persistence (JPA / EclipseLink).
* @param testCaseGuid The GUID of the referenced test case.
*/
private void setSpecTestCaseGuid(String testCaseGuid) {
m_specTestCaseGuid = testCaseGuid;
}
/**
* {@inheritDoc}
*/
@Transient
public String getToolkitLevel() {
return getSpecTestCase().getToolkitLevel();
}
/**
* {@inheritDoc}
*/
public void setToolkitLevel(String toolkitLevel) {
final ISpecTestCasePO specTestCase = getSpecTestCase();
if (specTestCase != null) {
specTestCase.setToolkitLevel(toolkitLevel);
}
}
/**
* {@inheritDoc}
*/
public void clearCachedSpecTestCase() {
m_cachedSpecTestCase = null;
}
/**
* {@inheritDoc}
*/
public void setCachedSpecTestCase(ISpecTestCasePO spec) {
if (ObjectUtils.equals(getSpecTestCaseGuid(), spec.getGuid())) {
m_cachedSpecTestCase = spec;
}
}
/**
* {@inheritDoc}
*/
public boolean isTestDataComplete() {
if (getSpecTestCase() == null) { // missing referenced Test Case
return false;
}
return super.isTestDataComplete();
}
/**
*
* {@inheritDoc}
*/
public IParamDescriptionPO getParameterForName(String paramName) {
if (getSpecTestCase() != null) {
return getSpecTestCase().getParameterForName(paramName);
}
return null;
}
/**
*
* {@inheritDoc}
*/
public IParamDescriptionPO getParameterForUniqueId(String uniqueId) {
if (getSpecTestCase() != null) {
return getSpecTestCase().getParameterForUniqueId(uniqueId);
}
return null;
}
/** {@inheritDoc}
* @see org.eclipse.jubula.client.core.model.ITDManager#synchronizeParameterIDs()
*/
public void synchronizeParameterIDs() {
if (getReferencedDataCube() == null) {
ITDManager tdMan = getDataManager();
List<IParamDescriptionPO> params = getParameterList();
List<String> origParamIDs = new ArrayList<String>();
List<String> header = new ArrayList<String>(tdMan.getUniqueIds());
for (IParamDescriptionPO param : params) {
origParamIDs.add(param.getUniqueId());
}
// add ids for new parameters
for (String origId : origParamIDs) {
if (!header.contains(origId)) {
tdMan.addUniqueId(origId);
}
}
// remove ids of deleted parameters inclusive data
header = new ArrayList<String>(tdMan.getUniqueIds());
for (String tdManParamId : header) {
if (!origParamIDs.contains(tdManParamId)) {
tdMan.removeUniqueId(tdManParamId);
}
}
}
}
/**
* Checks if there are unused Test Data in this TDManagerPO
* (Data column without a parameter).
* @return true if there are unused Test Data in this TDManagerPO.,
* false otherwise.
*/
public boolean checkHasUnusedTestData() {
if (getReferencedDataCube() == null) {
for (String colId : getDataManager().getUniqueIds()) {
boolean hasColIdParam = false;
for (ListIterator<IParamDescriptionPO> paramListIter =
getParameterListIter(); paramListIter.hasNext();) {
IParamDescriptionPO paramDescr = paramListIter.next();
if (colId.equals(paramDescr.getUniqueId())) {
hasColIdParam = true;
break;
}
}
if (!hasColIdParam) {
return true;
}
}
}
return false;
}
/** {@inheritDoc} */
public void goingToBeDeleted(EntityManager sess) {
super.goingToBeDeleted(sess);
removeCompNamesPairs(sess);
}
}