RowFilterTable.java

  1. /*
  2.  *
  3.  * The DbUnit Database Testing Framework
  4.  * Copyright (C)2002-2004, DbUnit.org
  5.  *
  6.  * This library is free software; you can redistribute it and/or
  7.  * modify it under the terms of the GNU Lesser General Public
  8.  * License as published by the Free Software Foundation; either
  9.  * version 2.1 of the License, or (at your option) any later version.
  10.  *
  11.  * This library is distributed in the hope that it will be useful,
  12.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  14.  * Lesser General Public License for more details.
  15.  *
  16.  * You should have received a copy of the GNU Lesser General Public
  17.  * License along with this library; if not, write to the Free Software
  18.  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  19.  *
  20.  */
  21. package org.dbunit.dataset;

  22. import java.util.ArrayList;
  23. import java.util.List;

  24. import org.dbunit.dataset.filter.IRowFilter;
  25. import org.slf4j.Logger;
  26. import org.slf4j.LoggerFactory;

  27. /**
  28.  * Filters table rows by using arbitrary column values of the table to check if a row should be filtered or not.
  29.  * <br>
  30.  * Implemented as a decorator for {@link ITable}.
  31.  *
  32.  * See dbunit feature request at <a href="https://sourceforge.net/tracker/index.php?func=detail&aid=1959771&group_id=47439&atid=449494">#1959771</a>
  33.  *
  34.  * @author gommma
  35.  * @author Last changed by: $Author$
  36.  * @version $Revision$ $Date$
  37.  * @since 2.3.0
  38.  */
  39. public class RowFilterTable implements ITable, IRowValueProvider {

  40.    
  41.     /**
  42.      * reference to the original table being wrapped
  43.      */
  44.     private final ITable originalTable;
  45.     /** mapping of filtered rows, i.e, each entry on this list has the value of
  46.             the index on the original table corresponding to the desired index.
  47.             For instance, if the original table is:
  48.             row   PK  Value
  49.             0     pk1  v1
  50.             1     pk2  v2
  51.             2     pk3  v3
  52.             3     pk4  v4
  53.             And the allowed PKs are pk2 and pk4, the new table should be:
  54.             row   PK  Value
  55.             0     pk2  v2
  56.             1     pk4  v4
  57.             Consequently, the mapping will be {1, 3}
  58.      */
  59.     private final List filteredRowIndexes;
  60.     /**
  61.      * logger
  62.      */
  63.     private final Logger logger = LoggerFactory.getLogger(RowFilterTable.class);
  64.     /**
  65.      * The row that is currently checked for filtering. Used in the implementation of {@link IRowValueProvider}
  66.      */
  67.     private int currentRowIdx;

  68.     /**
  69.      * Creates a new {@link ITable} where some rows can be filtered out from the original table
  70.      * @param table The table to be wrapped
  71.      * @param rowFilter The row filter that checks for every row whether or not it should be filtered
  72.      * @throws DataSetException
  73.      */
  74.     public RowFilterTable(ITable table, IRowFilter rowFilter) throws DataSetException {
  75.         if ( table == null || rowFilter == null ) {
  76.             throw new IllegalArgumentException( "Constructor cannot receive null arguments" );
  77.         }
  78.         this.originalTable = table;
  79.         // sets the rows for the new table
  80.         // NOTE: this conversion might be an issue for long tables, as it iterates for
  81.         // all values of the original table and that might take time and memory leaks.
  82.         // So, this mapping mechanism is a candidate for improvement: another alternative
  83.         // would be to calculate the mapping on the fly, as getValue() is called (and in
  84.         // this case, getRowCount() would be simply the size of allowedPKs)
  85.         this.filteredRowIndexes = setRows(rowFilter);
  86.     }

  87.     private List setRows(IRowFilter rowFilter) throws DataSetException {

  88.         ITableMetaData tableMetadata = this.originalTable.getTableMetaData();
  89.         this.logger.debug("Setting rows for table {}",  tableMetadata.getTableName() );

  90.         int fullSize = this.originalTable.getRowCount();
  91.         List filteredRowIndexes = new ArrayList();

  92.         for ( int row=0; row<fullSize; row++ ) {
  93.             this.currentRowIdx = row;
  94.             if(rowFilter.accept(this)) {
  95.                 this.logger.debug("Adding row {}", row);
  96.                 filteredRowIndexes.add(row);
  97.             } else {
  98.                 this.logger.debug("Discarding row {}", row);
  99.             }
  100.         }
  101.         return filteredRowIndexes;  
  102.     }


  103.     // ITable methods

  104.     public ITableMetaData getTableMetaData() {
  105.         logger.debug("getTableMetaData() - start");

  106.         return this.originalTable.getTableMetaData();
  107.     }

  108.     public int getRowCount() {
  109.         logger.debug("getRowCount() - start");

  110.         return this.filteredRowIndexes.size();
  111.     }

  112.     public Object getValue(int row, String column) throws DataSetException
  113.     {
  114.         if(logger.isDebugEnabled())
  115.             logger.debug("getValue(row={}, columnName={}) - start", Integer.toString(row), column);

  116.         int max = this.filteredRowIndexes.size();
  117.         if ( row < max ) {
  118.             int realRow = ((Integer) this.filteredRowIndexes.get( row )).intValue();
  119.             Object value = this.originalTable.getValue(realRow, column);
  120.             return value;
  121.         } else {
  122.             throw new RowOutOfBoundsException( "tried to access row " + row +
  123.                     " but rowCount is " + max );
  124.         }
  125.     }


  126.     /**
  127.      * Returns the column value for the column with the given name of the currently processed row
  128.      * @throws DataSetException
  129.      * @see org.dbunit.dataset.IRowValueProvider#getColumnValue(java.lang.String)
  130.      */
  131.     public Object getColumnValue(String columnName) throws DataSetException {
  132.         Object valueOfCol = this.originalTable.getValue(this.currentRowIdx, columnName);
  133.         return valueOfCol;
  134.     }


  135. }