/******************************************************************************* * 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.Collections; import java.util.List; import javax.persistence.Basic; import javax.persistence.CascadeType; import javax.persistence.CollectionTable; import javax.persistence.Column; import javax.persistence.ElementCollection; import javax.persistence.Entity; import javax.persistence.EntityListeners; import javax.persistence.EntityManager; import javax.persistence.FetchType; import javax.persistence.GeneratedValue; import javax.persistence.Id; import javax.persistence.JoinColumn; import javax.persistence.OneToMany; import javax.persistence.OrderColumn; import javax.persistence.Query; import javax.persistence.Table; import javax.persistence.Transient; import javax.persistence.Version; import org.apache.commons.lang.Validate; import org.eclipse.jubula.client.core.businessprocess.progress.ElementLoadedProgressListener; import org.eclipse.jubula.client.core.i18n.Messages; import org.eclipse.jubula.client.core.utils.NativeSQLUtils; import org.eclipse.jubula.tools.internal.constants.StringConstants; import org.eclipse.persistence.annotations.BatchFetch; import org.eclipse.persistence.annotations.BatchFetchType; import org.eclipse.persistence.annotations.Index; /** * class to link parameter description to values or references <br> * provides methods for handling of testdata * * @author BREDEX GmbH * @created 08.12.2004 * */ @Entity @Table(name = "TD_MANAGER") @EntityListeners(value = { ElementLoadedProgressListener.class }) class TDManagerPO implements ITDManager { /** Persistence (JPA / EclipseLink) OID */ private transient Long m_id = null; /** * <code>m_dataTable</code> list with DataSetPO objects inside <br> * <li>index of list corresponds to dataset number</li> * <li>listWrapper object contains the reference to a list with testdata * objects * <li>constraint: the order of entries in this referenced list must * correspond to the order of parameters in parameterList of paramNode</li> * <br> * */ private List<IDataSetPO> m_dataTable = new ArrayList<IDataSetPO>(); /** * unique id of each parameter to get the assignment between parameter and its testdata */ private List<String> m_uniqueIds = new ArrayList<String>(); /** The ID of the parent project */ private Long m_parentProjectId = null; /** Persistence (JPA / EclipseLink) version id */ private transient Integer m_version = null; /** * @param node * corresponding node to TDManagerPO */ TDManagerPO(IParameterInterfacePO node) { Validate.notNull(node); createUniqueIds(node); } /** * @param node corresponding node to TDManagerPO * @param uniqueIds the uniqueIds */ TDManagerPO(IParameterInterfacePO node, List<String> uniqueIds) { Validate.notNull(node); setUniqueIds(uniqueIds); } /** * private constructor only for Persistence (JPA / EclipseLink) */ TDManagerPO() { // nothing so far } /** * create the list with ids of all parameters * * @param node The Parameter Interface from which Parameters are determined. */ private void createUniqueIds(IParameterInterfacePO node) { List<IParamDescriptionPO> params = node.getParameterList(); for (IParamDescriptionPO param : params) { getUniqueIds().add(param.getUniqueId()); } } /** * * @return Id */ @Id @GeneratedValue public Long getId() { return m_id; } /** * @param id The id to set. */ @SuppressWarnings("unused") private void setId(Long id) { m_id = id; } /** * * {@inheritDoc} */ @Transient public Long getParentProjectId() { return getHbmParentProjectId(); } /** * * {@inheritDoc} */ public void setParentProjectId(Long projectId) { setHbmParentProjectId(projectId); for (IDataSetPO lWrapperPO : getDataTable()) { lWrapperPO.setParentProjectId(projectId); } } /** * * @return the ID of the Project to which the receiver belongs. */ @Basic @Column(name = "PARENT_PROJ") @Index(name = "PI_TD_MANAGER_PARENT_PROJ") private Long getHbmParentProjectId() { return m_parentProjectId; } /** * * @param projectId The ID of the Project to which the receiver belongs. */ private void setHbmParentProjectId(Long projectId) { m_parentProjectId = projectId; } /** * Only use this method for internal purposes!</b> * * @return Returns the dataTable. */ @OneToMany(cascade = CascadeType.ALL, orphanRemoval = true, targetEntity = DataSetPO.class, fetch = FetchType.EAGER) @OrderColumn(name = "IDX") @BatchFetch(value = BatchFetchType.JOIN) public List<IDataSetPO> getDataTable() { return m_dataTable; } /** * Removes the Data Sets * @param sess the session */ private void removeDataSets(EntityManager sess) { if (m_dataTable.isEmpty()) { return; } Query q = sess.createNativeQuery("delete from TD_MANAGER_TEST_DATA_LIST where TDMANAGERPO_ID = ?1"); //$NON-NLS-1$ q.setParameter(1, getId()); q.executeUpdate(); String list = NativeSQLUtils.getIdList(m_dataTable); q = sess.createNativeQuery("delete from TEST_DATA_CELL where FK_DATASET_ID in " + list); //$NON-NLS-1$ q.executeUpdate(); q = sess.createNativeQuery("delete from TEST_DATA_LIST where ID in " + list); //$NON-NLS-1$ q.executeUpdate(); } /** * * @param dataTable The dataTable to set. */ @SuppressWarnings("unused") private void setDataTable(List<IDataSetPO> dataTable) { m_dataTable = dataTable; } /** * deletes the dataset with specified number from datatable shifts all * following datasets to the next lower number * * @param number * number of dataset to delete */ public void removeDataSet(int number) { getDataTable().remove(number); } /** * Deletes the values for the parameter with the given id * in all rows. If the data set rows are empty after this operation, they * will be deleted too. * * @param uniqueId * The unique id of the parameter the data to delete */ public void removeColumn(String uniqueId) { int index = findColumnForParam(uniqueId); if (index >= 0) { for (IDataSetPO dataSet : getDataSets()) { dataSet.removeColumn(index); } if (getColumnCount() == 0) { getDataTable().clear(); } } } /** * Creates new rows with empty test data. * @param row The new row count */ private void expandRows(int row) { int colCount = getColumnCount(); while (row >= getDataTable().size()) { List <String> columns = new ArrayList <String> (colCount); for (int i = 0; i < colCount; i++) { columns.add(""); //$NON-NLS-1$ } IDataSetPO listW = PoMaker.createListWrapperPO(columns); getDataTable().add(listW); listW.setParentProjectId(getParentProjectId()); } } /** * * {@inheritDoc} */ public void insertDataSet(int position) { int colCount = getColumnCount(); List <String> columns = new ArrayList <String> (colCount); for (int i = 0; i < colCount; i++) { columns.add(""); //$NON-NLS-1$ } insertDataSet(PoMaker.createListWrapperPO(columns), position); } /** * * {@inheritDoc} */ public void insertDataSet(IDataSetPO dataSet, int position) { Validate.notNull(dataSet); dataSet.setParentProjectId(getParentProjectId()); if (position > getDataTable().size()) { // add empty columns up to the position where the given // Data Set will be inserted expandRows(position - 1); } getDataTable().add(position, dataSet); } /** * Creates new columns in all rows with empty test data. * * @param column * The new column count */ private void expandColumns(int column) { while (column >= getColumnCount()) { for (IDataSetPO dataSet : getDataSets()) { dataSet.addColumn(""); //$NON-NLS-1$ } } } /** * reads a single testdata object with value or reference for a specified * dataset row and the parameter name. * * @param dataSetRow * dataSetRow of dataset * @param uniqueId * unique id of parameter, which is wanted the value/reference for * @return testdata object for parameter in specified dataset or null, if no * testdata object is available * @throws IllegalArgumentException * If the parameter with the userdefined name * <code>paramName</code> doesn't exist */ private String getCell(int dataSetRow, String uniqueId) throws IllegalArgumentException { int index = getUniqueIds().indexOf(uniqueId); if (index == -1) { throw new IndexOutOfBoundsException(Messages.ParameterWithUniqueId + StringConstants.SPACE + uniqueId + StringConstants.SPACE + Messages.IsNotAvailable + StringConstants.DOT); } return getCell(dataSetRow, index); } /** * Gets a test data entry at the specified row and column indices. * * @param row * The row * @param column * The column * @return The test data */ private String getCell(int row, int column) { return getDataSet(row).getValueAt(column); } /** * {@inheritDoc} */ public String getCell(int dataSetRow, IParamDescriptionPO parameter) throws IllegalArgumentException { return getCell(dataSetRow, parameter.getUniqueId()); } /** * reads a single dataset with specified dataSetRow <br> * <p> * <b>usage: </b> <br> * for restore of a single dataset * * @param dataSetRow * dataSetRow of wanted dataset * @return the list with testdata objects for specified dataset or null */ public IDataSetPO getDataSet(int dataSetRow) { return getDataTable().get(dataSetRow); } /** * Reads all datasets of a node. * * @return The list of data sets or an empty list if the manager is empty. */ @Transient public List<IDataSetPO> getDataSets() { return Collections.unmodifiableList(getDataTable()); } /** * Updates the test data at the specified row and column. The data in the * passed test data instance are copied into the test data in the specified * cell. If the row and/or column are greater than the existing row/column * count, new rows/columns are created automatically. * * @param testData * The test data to update * @param row * The row * @param column * The column */ public void updateCell(String testData, int row, int column) { expandRows(row); expandColumns(column); getDataSet(row).setValueAt(column, testData); } /** * Updates the test data at the specified row and parameter name. The data * in the passed test data instance are copied into the test data in the * specified cell. If the row and/or column are greater than the existing * row/column count, new rows/columns are created automatically. * * @param testData * The test data to update * @param row * The row * @param uniqueId * uniqueId of the parameter */ public void updateCell(String testData, int row, String uniqueId) { int index = getUniqueIds().indexOf(uniqueId); if (index > -1) { updateCell(testData, row, index); } } /** * @return number of datasets */ @Transient public int getDataSetCount() { return getDataTable().size(); } /** * @return The number of columns */ @Transient public int getColumnCount() { int columns = 0; try { List<IDataSetPO> dataTable = getDataTable(); if (dataTable.size() > 0) { IDataSetPO listW = dataTable.get(0); columns = listW.getColumnCount(); } } catch (IndexOutOfBoundsException e) { // NOPMD by al on 3/19/07 1:37 PM // Nothing to be done } return columns; } /** * Copies the data of this TDManager to the given TDManager * @param tdMan the TDManager to copy the data to * @return the given TDManager with the new data. */ public ITDManager deepCopy(ITDManager tdMan) { for (String uniqueId : getUniqueIds()) { tdMan.addUniqueId(uniqueId); } tdMan.clear(); for (IDataSetPO dataSet : getDataSets()) { int columncount = dataSet.getColumnCount(); List<String> newRow = new ArrayList<String> (columncount); for (int i = 0; i < columncount; i++) { newRow.add(dataSet.getValueAt(i)); } tdMan.insertDataSet(PoMaker.createListWrapperPO(newRow), tdMan.getDataSetCount()); } return tdMan; } /** * Clears this TDManager. Removes all TestData! */ public void clear() { getDataTable().clear(); } /** * * {@inheritDoc} */ @Version public Integer getVersion() { return m_version; } /** * * @param version The version number to set for JPA optimistic-locking. */ @SuppressWarnings("unused") private void setVersion(Integer version) { m_version = version; } /** * * {@inheritDoc} */ @Transient public String getName() { return toString(); } /** * * @return the uniqueIds */ @ElementCollection(fetch = FetchType.EAGER) @CollectionTable(name = "TD_MANAGER_PARAM_ID", indexes = {@javax.persistence.Index( name = "TDMPO_IDX", columnList = "TDManagerPO_ID")}) @Column(name = "UNIQUE_ID") @OrderColumn(name = "IDX") @JoinColumn(name = "FK_TD_MANAGER") @BatchFetch(value = BatchFetchType.EXISTS) public List<String> getUniqueIds() { return m_uniqueIds; } /** * Removes the entries from the collection table * @param sess the session */ private void removeLinksToParams(EntityManager sess) { Query q = sess.createNativeQuery("delete from TD_MANAGER_PARAM_ID where TDMANAGERPO_ID = ?1"); //$NON-NLS-1$ q.setParameter(1, getId()).executeUpdate(); } /** * @param uniqueId unique id of parameter to find the column in datatable * @return the column contains values for given parameter or -1, if param is not contained in datatable */ public int findColumnForParam(String uniqueId) { return getUniqueIds().indexOf(uniqueId); } /** * @param uniqueIds the uniqueIds to set */ private void setUniqueIds(List<String> uniqueIds) { m_uniqueIds = uniqueIds; } /** * @param uniqueId uniqueId of a new parameter (independent of display order) */ public void addUniqueId(String uniqueId) { getUniqueIds().add(uniqueId); } /** * clears the unique ids list */ public void clearUniqueIds() { getUniqueIds().clear(); } /** * removes the parameter id and its testdata * @param uniqueId id of parameter to remove */ public void removeUniqueId(String uniqueId) { if (getUniqueIds().contains(uniqueId)) { removeColumn(uniqueId); getUniqueIds().remove(uniqueId); } } /** {@inheritDoc} */ public void goingToBeDeleted(EntityManager sess) { removeDataSets(sess); removeLinksToParams(sess); } }