001: /*
002: *
003: * The DbUnit Database Testing Framework
004: * Copyright (C)2005, DbUnit.org
005: *
006: * This library is free software; you can redistribute it and/or
007: * modify it under the terms of the GNU Lesser General Public
008: * License as published by the Free Software Foundation; either
009: * version 2.1 of the License, or (at your option) any later version.
010: *
011: * This library is distributed in the hope that it will be useful,
012: * but WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * Lesser General Public License for more details.
015: *
016: * You should have received a copy of the GNU Lesser General Public
017: * License along with this library; if not, write to the Free Software
018: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
019: *
020: */
021:
022: package org.dbunit.database;
023:
024: import java.util.ArrayList;
025: import java.util.List;
026: import java.util.Set;
027:
028: import org.slf4j.Logger;
029: import org.slf4j.LoggerFactory;
030: import org.dbunit.dataset.DataSetException;
031: import org.dbunit.dataset.ITable;
032: import org.dbunit.dataset.ITableMetaData;
033: import org.dbunit.dataset.RowOutOfBoundsException;
034:
035: /**
036: * This class is a wrapper for another table with the condition that only a subset
037: * of the original table will be available - the subset is defined by the set of
038: * primary keys that are allowed in the new table.
039: *
040: * @author Felipe Leme <dbunit@felipeal.net>
041: * @version $Revision: 554 $
042: * @since Sep 9, 2005
043: */
044: public class PrimaryKeyFilteredTableWrapper implements ITable {
045:
046: /** reference to the original table being wrapped */
047: private final ITable originalTable;
048: /** mapping of filtered rows, i.e, each entry on this list has the value of
049: the index on the original table corresponding to the desired index.
050: For instance, if the original table is:
051: row PK Value
052: 0 pk1 v1
053: 1 pk2 v2
054: 2 pk3 v3
055: 3 pk4 v4
056: And the allowed PKs are pk2 and pk4, the new table should be:
057: row PK Value
058: 0 pk2 v2
059: 1 pk4 v4
060: Consequently, the mapping will be {1, 3}
061:
062: */
063: private final List filteredRowsMapping;
064: /** logger */
065: protected final Logger logger = LoggerFactory.getLogger(getClass());
066:
067: /**
068: * Creates a PKFilteredTable given an original table and the allowed primary keys
069: * for that table.
070: * @param table original table
071: * @param allowedPKs primary keys allowed on the new table
072: * @throws DataSetException if something happened while getting the information
073: */
074: public PrimaryKeyFilteredTableWrapper(ITable table, Set allowedPKs)
075: throws DataSetException {
076: if (table == null || allowedPKs == null) {
077: throw new IllegalArgumentException(
078: "Constructor cannot receive null arguments");
079: }
080: this .originalTable = table;
081: // sets the rows for the new table
082: // NOTE: this conversion might be an issue for long tables, as it iterates for
083: // all values of the original table and that might take time and memory leaks.
084: // So, this mapping mechanism is a candidate for improvement: another alternative
085: // would be to calculate the mapping on the fly, as getValue() is called (and in
086: // this case, getRowCount() would be simply the sise of allowedPKs)
087: this .filteredRowsMapping = setRows(allowedPKs);
088: }
089:
090: /**
091: * This method is used to calculate the mapping between the rows of the original
092: * and the filtered tables.
093: * @param allowedPKs primary keys allowed in the new table
094: * @return list of rows for the new table
095: * @throws DataSetException
096: */
097: private List setRows(Set allowedPKs) throws DataSetException {
098: if (this .logger.isDebugEnabled()) {
099: this .logger.debug("Setting rows for table "
100: + this .originalTable.getTableMetaData()
101: .getTableName());
102: }
103: int allowedSize = allowedPKs.size();
104: int fullSize = this .originalTable.getRowCount();
105: List mapping = new ArrayList(allowedSize);
106: // TODO: support multi-columns PKs
107: String pkColumn = this .originalTable.getTableMetaData()
108: .getPrimaryKeys()[0].getColumnName();
109: for (int row = 0; row < fullSize; row++) {
110: Object pk = this .originalTable.getValue(row, pkColumn);
111: if (allowedPKs.contains(pk)) {
112: if (this .logger.isDebugEnabled()) {
113: this .logger.debug("Adding row " + row + " (pk="
114: + pk + ")");
115: }
116: mapping.add(new Integer(row));
117: } else {
118: if (this .logger.isDebugEnabled()) {
119: this .logger.debug("Discarding row " + row + " (pk="
120: + pk + ")");
121: }
122: }
123: }
124: return mapping;
125: }
126:
127: // ITable methods
128:
129: public ITableMetaData getTableMetaData() {
130: logger.debug("getTableMetaData() - start");
131:
132: return this .originalTable.getTableMetaData();
133: }
134:
135: public int getRowCount() {
136: logger.debug("getRowCount() - start");
137:
138: return this .filteredRowsMapping.size();
139: }
140:
141: public Object getValue(int row, String column)
142: throws DataSetException {
143: logger.debug("getValue(row=" + row + ", column=" + column
144: + ") - start");
145:
146: int max = this .filteredRowsMapping.size();
147: if (row < max) {
148: int realRow = ((Integer) this .filteredRowsMapping.get(row))
149: .intValue();
150: Object value = this .originalTable.getValue(realRow, column);
151: return value;
152: } else {
153: throw new RowOutOfBoundsException("tried to access row "
154: + row + " but rowCount is " + max);
155: }
156: }
157:
158: }
|