001: /* ExcelDataTableAdapter.java
002: *
003: * DDSteps - Data Driven JUnit Test Steps
004: * Copyright (C) 2005 Jayway AB
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 version 2.1 as published by the Free Software Foundation.
009: *
010: * This library is distributed in the hope that it will be useful,
011: * but WITHOUT ANY WARRANTY; without even the implied warranty of
012: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
013: * Lesser General Public License for more details.
014: *
015: * You should have received a copy of the GNU Lesser General Public
016: * License along with this library; if not, visit
017: * http://www.opensource.org/licenses/lgpl-license.php
018: */
019: package org.ddsteps.dataset.excel;
020:
021: import java.util.Iterator;
022:
023: import jxl.Cell;
024: import jxl.Sheet;
025:
026: import org.apache.commons.collections.CollectionUtils;
027: import org.apache.commons.collections.Transformer;
028: import org.apache.commons.collections.iterators.FilterIterator;
029: import org.apache.commons.collections.iterators.IteratorChain;
030: import org.apache.commons.collections.iterators.ObjectArrayIterator;
031: import org.apache.commons.collections.iterators.TransformIterator;
032: import org.apache.commons.lang.StringUtils;
033: import org.apache.commons.lang.Validate;
034: import org.ddsteps.dataset.DataRow;
035: import org.ddsteps.dataset.DataTable;
036:
037: /**
038: * @author Adam
039: * @version $Id: ExcelDataTableAdapter.java,v 1.2 2005/12/15 21:53:54
040: * adamskogman Exp $
041: */
042: class ExcelDataTableAdapter implements DataTable {
043:
044: /**
045: * Transformer for converting from header cells to header names.
046: *
047: * @author Adam
048: * @version $Id: ExcelDataTableAdapter.java,v 1.2 2005/12/15 21:53:54
049: * adamskogman Exp $
050: */
051: class CellToStringTransformer implements Transformer {
052:
053: /**
054: * Get contents from a cell.
055: *
056: * @see org.apache.commons.collections.Transformer#transform(java.lang.Object)
057: */
058: public Object transform(Object arg0) {
059: Cell cell = (Cell) arg0;
060: return cell.getContents();
061: }
062: }
063:
064: /**
065: * Creates row adapters as it goes.
066: *
067: * @author Adam
068: * @version $Id: ExcelDataTableAdapter.java,v 1.2 2005/12/15 21:53:54
069: * adamskogman Exp $
070: */
071: class RowIterator implements Iterator {
072:
073: private int current = dataFirst - 1;
074:
075: /**
076: * @see java.util.Iterator#hasNext()
077: */
078: public boolean hasNext() {
079: return current < dataLast;
080: }
081:
082: /**
083: * @see java.util.Iterator#next()
084: */
085: public Object next() {
086: current++;
087: return createDataRowAdapter(ExcelDataTableAdapter.this ,
088: current);
089: }
090:
091: /**
092: * Not Supported.
093: *
094: * @see java.util.Iterator#remove()
095: */
096: public void remove() {
097: throw new UnsupportedOperationException(
098: "Cannot remove rows.");
099: }
100: }
101:
102: /**
103: * CONSTANT: Delimiter in excel sheet (three dashes): ---
104: */
105: public static final String DELIMITER = "---";
106:
107: /**
108: * Finds first cell with a label --- in it.
109: *
110: * @param column
111: * A column to look in.
112: * @param i
113: * The first row to look in.
114: * @return The row index of the delimiter
115: */
116: private static int findDelimiter(Cell[] column, int i) {
117:
118: for (int j = i; j < column.length; j++) {
119: Cell cell = column[j];
120: if (StringUtils.equals(DELIMITER, cell.getContents())) {
121: return cell.getRow();
122: }
123: }
124:
125: return -1;
126: }
127:
128: /**
129: * Index of the first row containing data.
130: */
131: final int dataFirst;
132:
133: /**
134: * Index of the last row containing data.
135: */
136: final int dataLast;
137:
138: /**
139: * First row containing headers
140: */
141: final int headerFirst;
142:
143: /**
144: * Last row containing headers.
145: */
146: final int headerLast;
147:
148: /**
149: * The sheet to get data and headers from.
150: */
151: final Sheet sheet;
152:
153: /**
154: * Create an adapter from a sheet.
155: *
156: * @param sheet
157: */
158: public ExcelDataTableAdapter(final Sheet sheet) {
159: super ();
160: this .sheet = sheet;
161:
162: // Count header and data rows
163: Cell[] column = sheet.getColumn(0);
164:
165: // First delimiter
166: int firstDelimiter = findDelimiter(column, 0);
167:
168: if (firstDelimiter < 0) {
169: throw new ExcelDataException(
170: "Could not find start delimiter in column A. Put a cell with '--- before the headers.");
171: }
172:
173: headerFirst = firstDelimiter + 1;
174: // Second delimiter
175: int secondDelimiter = findDelimiter(column, firstDelimiter + 1);
176:
177: if (secondDelimiter < 0) {
178: throw new ExcelDataException(
179: "Could not find delimiter between headers and data in column A. Put a cell with '--- after the headers.");
180: }
181:
182: headerLast = secondDelimiter - 1;
183: dataFirst = secondDelimiter + 1;
184:
185: // Third delimiter
186: int thirdDelimiter = findDelimiter(column, secondDelimiter + 1);
187:
188: if (thirdDelimiter < 0) {
189: throw new ExcelDataException(
190: "Could not find delimiter after data in column A. Put a cell with '--- after the data.");
191: }
192:
193: dataLast = thirdDelimiter - 1;
194:
195: }
196:
197: /**
198: * Counts headers.
199: *
200: * @return Header count
201: */
202: public int getHeaderCount() {
203: return CollectionUtils.size(headerCellsIterator());
204: }
205:
206: /**
207: * Number of data rows.
208: *
209: * @see org.ddsteps.dataset.DataTable#getRowCount()
210: */
211: public int getRowCount() {
212: return dataLast - dataFirst + 1;
213: }
214:
215: /**
216: * @return Returns the sheet.
217: */
218: public Sheet getSheet() {
219: return sheet;
220: }
221:
222: /**
223: * Iterate over headers.
224: *
225: * @return Iterator of String
226: */
227: public Iterator headerIterator() {
228:
229: // Provide a decorator that converts from the cell to a header name
230: return new TransformIterator(headerCellsIterator(),
231: new CellToStringTransformer());
232:
233: }
234:
235: /**
236: * Iterate over data rows.
237: *
238: * @see org.ddsteps.dataset.DataTable#rowIterator()
239: */
240: public Iterator rowIterator() {
241: return new RowIterator();
242: }
243:
244: /**
245: * Factory method.
246: *
247: * @param table
248: * @param row
249: * @return A ExcelDataRowAdapter.
250: */
251: protected DataRow createDataRowAdapter(ExcelDataTableAdapter table,
252: int row) {
253: return new ExcelDataRowAdapter(table, row);
254: }
255:
256: Iterator headerCellsIterator() {
257:
258: // First create an iterator over the header rows
259: IteratorChain chain = new IteratorChain();
260:
261: for (int i = headerFirst; i <= headerLast; i++) {
262: chain.addIterator(new ObjectArrayIterator(sheet.getRow(i)));
263: }
264:
265: // Then apply a filter that only returns labels
266: Iterator headerIter = new FilterIterator(chain,
267: HeaderPredicate.INSTANCE);
268:
269: return headerIter;
270:
271: }
272:
273: /**
274: * Gets name from sheet.
275: *
276: * @see org.ddsteps.dataset.DataTable#getName()
277: */
278: public String getName() {
279: return sheet.getName();
280: }
281:
282: /**
283: * @see org.ddsteps.dataset.DataTable#findRowById(java.lang.String)
284: */
285: public DataRow findRowById(String rowId) {
286:
287: Validate.notEmpty(rowId,
288: "Argument rowId must not be an empty String.");
289:
290: String rowNumber = StringUtils.stripStart(rowId, "Excel row ");
291:
292: int rowIndex = Integer.parseInt(rowNumber) - 1;
293:
294: return createDataRowAdapter(ExcelDataTableAdapter.this,
295: rowIndex);
296: }
297: }
|