PrimaryKeyFilteredTableWrapper.java

  1. /*
  2.  *
  3.  * The DbUnit Database Testing Framework
  4.  * Copyright (C)2005, 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.database;

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

  25. import org.slf4j.Logger;
  26. import org.slf4j.LoggerFactory;
  27. import org.dbunit.dataset.DataSetException;
  28. import org.dbunit.dataset.ITable;
  29. import org.dbunit.dataset.ITableMetaData;
  30. import org.dbunit.dataset.RowOutOfBoundsException;

  31. /**
  32.  * This class is a wrapper for another table with the condition that only a subset
  33.  * of the original table will be available - the subset is defined by the set of
  34.  * primary keys that are allowed in the new table.
  35.  *
  36.  * @author Felipe Leme (dbunit@felipeal.net)
  37.  * @version $Revision$
  38.  * @since Sep 9, 2005
  39.  */
  40. public class PrimaryKeyFilteredTableWrapper implements ITable {
  41.  
  42.   /** reference to the original table being wrapped */
  43.   private final ITable originalTable;
  44.   /** mapping of filtered rows, i.e, each entry on this list has the value of
  45.       the index on the original table corresponding to the desired index.
  46.       For instance, if the original table is:
  47.       row   PK  Value
  48.       0     pk1  v1
  49.       1     pk2  v2
  50.       2     pk3  v3
  51.       3     pk4  v4
  52.       And the allowed PKs are pk2 and pk4, the new table should be:
  53.       row   PK  Value
  54.       0     pk2  v2
  55.       1     pk4  v4
  56.       Consequently, the mapping will be {1, 3}
  57.      
  58.    */
  59.   private final List filteredRowsMapping;  
  60.   /** logger */
  61.   protected final Logger logger = LoggerFactory.getLogger(getClass());
  62.  
  63.   /**
  64.    * Creates a PKFilteredTable given an original table and the allowed primary keys
  65.    * for that table.
  66.    * @param table original table
  67.    * @param allowedPKs primary keys allowed on the new table
  68.    * @throws DataSetException if something happened while getting the information
  69.    */
  70.   public PrimaryKeyFilteredTableWrapper(ITable table, Set allowedPKs) throws DataSetException {
  71.     if ( table == null || allowedPKs == null ) {
  72.       throw new IllegalArgumentException( "Constructor cannot receive null arguments" );
  73.     }
  74.     this.originalTable = table;
  75.     // sets the rows for the new table
  76.     // NOTE: this conversion might be an issue for long tables, as it iterates for
  77.     // all values of the original table and that might take time and memory leaks.
  78.     // So, this mapping mechanism is a candidate for improvement: another alternative
  79.     // would be to calculate the mapping on the fly, as getValue() is called (and in
  80.     // this case, getRowCount() would be simply the sise of allowedPKs)
  81.     this.filteredRowsMapping = setRows( allowedPKs );
  82.   }

  83.   /**
  84.    * This method is used to calculate the mapping between the rows of the original
  85.    * and the filtered tables.
  86.    * @param allowedPKs primary keys allowed in the new table
  87.    * @return list of rows for the new table
  88.    * @throws DataSetException
  89.    */
  90.   private List setRows(Set allowedPKs) throws DataSetException {
  91.     if ( this.logger.isDebugEnabled() ) {
  92.       this.logger.debug( "Setting rows for table " +
  93.           this.originalTable.getTableMetaData().getTableName() );
  94.     }
  95.     int allowedSize = allowedPKs.size();
  96.     int fullSize = this.originalTable.getRowCount();
  97.     List mapping = new ArrayList( allowedSize );
  98.     // TODO: support multi-columns PKs
  99.     String pkColumn = this.originalTable.getTableMetaData().getPrimaryKeys()[0].getColumnName();
  100.     for ( int row=0; row<fullSize; row++ ) {
  101.       Object pk = this.originalTable.getValue( row, pkColumn );
  102.       if ( allowedPKs.contains(pk) ) {
  103.         if ( this.logger.isDebugEnabled() ) {
  104.           this.logger.debug( "Adding row " + row + " (pk=" + pk + ")" );
  105.         }
  106.         mapping.add(row);
  107.       } else {
  108.         if ( this.logger.isDebugEnabled() ) {
  109.           this.logger.debug("Discarding row " + row + " (pk=" + pk + ")" );        
  110.         }
  111.       }
  112.     }
  113.     return mapping;  
  114.   }
  115.  
  116.   // ITable methods

  117.   public ITableMetaData getTableMetaData() {
  118.     return this.originalTable.getTableMetaData();
  119.   }

  120.   public int getRowCount() {
  121.     return this.filteredRowsMapping.size();
  122.   }

  123.   public Object getValue(int row, String column) throws DataSetException
  124.   {
  125.       if(logger.isDebugEnabled())
  126.           logger.debug("getValue(row={}, columnName={}) - start", Integer.toString(row), column);

  127.     int max = this.filteredRowsMapping.size();
  128.     if ( row < max ) {
  129.       int realRow = ((Integer) this.filteredRowsMapping.get( row )).intValue();
  130.       Object value = this.originalTable.getValue(realRow, column);
  131.       return value;
  132.     } else {
  133.       throw new RowOutOfBoundsException( "tried to access row " + row +
  134.           " but rowCount is " + max );
  135.     }
  136.   }

  137. }