001: /*
002: * (c) Copyright 2007 by Volker Bergmann. All rights reserved.
003: *
004: * Redistribution and use in source and binary forms, with or without
005: * modification, is permitted under the terms of the
006: * GNU General Public License.
007: *
008: * For redistributing this software or a derivative work under a license other
009: * than the GPL-compatible Free Software License as defined by the Free
010: * Software Foundation or approved by OSI, you must first obtain a commercial
011: * license to this software product from Volker Bergmann.
012: *
013: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
014: * WITHOUT A WARRANTY OF ANY KIND. ALL EXPRESS OR IMPLIED CONDITIONS,
015: * REPRESENTATIONS AND WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF
016: * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE
017: * HEREBY EXCLUDED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
018: * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
019: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
020: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
021: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
022: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
023: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
024: * POSSIBILITY OF SUCH DAMAGE.
025: */
026:
027: package org.databene.platform.dbunit;
028:
029: import org.databene.model.data.EntityDescriptor;
030: import org.databene.script.ScriptUtil;
031: import org.databene.commons.Context;
032: import org.databene.commons.HeavyweightIterator;
033: import org.databene.commons.IOUtil;
034: import org.databene.commons.ArrayFormat;
035: import org.databene.commons.ArrayUtil;
036: import org.w3c.dom.*;
037: import org.apache.commons.logging.LogFactory;
038: import org.apache.commons.logging.Log;
039:
040: import java.io.IOException;
041: import java.util.List;
042: import java.util.ArrayList;
043:
044: /**
045: * Iterates the rows defined an a DBUnit dataset file. It supports the normal format as well as the flat format.<br/>
046: * <br/>
047: * Created: 05.08.2007 07:43:36
048: * @author Volker Bergmann
049: */
050: public class DbUnitEntityIterator implements
051: HeavyweightIterator<org.databene.model.data.Entity> {
052:
053: private static final Log logger = LogFactory
054: .getLog(DbUnitEntityIterator.class);
055:
056: private Context context;
057:
058: private List<Row> rows;
059:
060: private int nextRowNum;
061:
062: public DbUnitEntityIterator(String uri, Context context,
063: String defaultScriptEngine) throws IOException {
064: this .context = context;
065: this .rows = new ArrayList<Row>();
066: Document document = readDocument(uri);
067: if (isFlatDataset(document))
068: parseFlatDataset(document);
069: else
070: parseDataset(document);
071: processScripts(defaultScriptEngine);
072: this .nextRowNum = 0;
073: }
074:
075: // HeavyweightIterator interface implementation --------------------------------------------------------------------
076:
077: public boolean hasNext() {
078: return nextRowNum < rows.size();
079: }
080:
081: public org.databene.model.data.Entity next() {
082: if (nextRowNum < rows.size()) {
083: Row row = rows.get(nextRowNum);
084: String[] rowValues = row.getValues();
085: org.databene.model.data.Entity result = new org.databene.model.data.Entity(
086: new EntityDescriptor(row.getTableName(), false));
087: for (int i = 0; i < rowValues.length; i++)
088: result.setComponent(row.getColumnName(i), rowValues[i]);
089: nextRowNum++;
090: return result;
091: } else
092: return null;
093: }
094:
095: public void remove() {
096: throw new UnsupportedOperationException();
097: }
098:
099: public void close() {
100: // This is not implemented, so why make the class a Heavyweight?
101: // Because we might need to process very long files one day and
102: // don't want to change the contract for that
103: }
104:
105: // private helpers -------------------------------------------------------------------------------------------------
106:
107: private void processScripts(String defaultScriptEngine) {
108: for (Row row : rows) {
109: String[] cells = row.getValues();
110: for (int i = 0; i < cells.length; i++) {
111: cells[i] = ScriptUtil.render(cells[i], context,
112: defaultScriptEngine);
113: }
114: }
115: }
116:
117: private boolean isFlatDataset(Document document) {
118: return document.getDocumentElement().getElementsByTagName(
119: "table").getLength() == 0;
120: }
121:
122: private Document readDocument(String uri) throws IOException {
123: return IOUtil.parseXML(uri);
124: }
125:
126: private void parseDataset(Document document) {
127: Element documentElement = document.getDocumentElement();
128: // parse tableNodes
129: NodeList tableNodes = documentElement
130: .getElementsByTagName("table");
131: // this.tables = new Table[tableNodes.getLength()];
132: for (int tablenum = 0; tablenum < tableNodes.getLength(); tablenum++) {
133: Element tableNode = (Element) tableNodes.item(tablenum);
134: String tableName = tableNode.getAttribute("name");
135: // parse columns
136: NodeList columns = tableNode.getElementsByTagName("column");
137: String[] columnNames = new String[columns.getLength()];
138: for (int colnum = 0; colnum < columns.getLength(); colnum++) {
139: Element column = (Element) columns.item(colnum);
140: columnNames[colnum] = column.getTextContent();
141: }
142: Table table = new Table(tableName, columnNames);
143: // this.tables[tablenum] = table;
144: // parse rows
145: NodeList rows = tableNode.getElementsByTagName("row");
146: for (int rownum = 0; rownum < rows.getLength(); rownum++) {
147: Element row = (Element) rows.item(rownum);
148: NodeList cellNodes = row.getElementsByTagName("value");
149: String[] values = new String[cellNodes.getLength()];
150: for (int cellnum = 0; cellnum < cellNodes.getLength(); cellnum++) {
151: Element cell = (Element) cellNodes.item(cellnum);
152: values[cellnum] = cell.getTextContent();
153: }
154: this .rows.add(new Row(tableName,
155: table.getColumnNames(), values));
156: }
157: }
158: }
159:
160: private void parseFlatDataset(Document document) {
161: Element documentElement = document.getDocumentElement();
162: // parse tableNodes
163: NodeList rowNodes = documentElement.getChildNodes();
164: for (int rownum = 0; rownum < rowNodes.getLength(); rownum++) {
165: Node node = rowNodes.item(rownum);
166: if (node instanceof Element) {
167: Element tableNode = (Element) node;
168: String tableName = tableNode.getNodeName();
169: NamedNodeMap attributes = tableNode.getAttributes();
170: String[] columnNames = new String[attributes
171: .getLength()];
172: String[] values = new String[attributes.getLength()];
173: for (int childnum = 0; childnum < attributes
174: .getLength(); childnum++) {
175: Attr attNode = (Attr) attributes.item(childnum);
176: columnNames[childnum] = attNode.getNodeName();
177: values[childnum] = attNode.getValue();
178: }
179: Row row = new Row(tableName, columnNames, values);
180: logger.debug("parsed row " + row);
181: rows.add(row);
182: }
183: }
184: }
185:
186: private static class Table {
187: private String name;
188: private String[] columnNames;
189:
190: public Table(String name, String[] columns) {
191: this .name = name;
192: this .columnNames = columns;
193: }
194:
195: public String getName() {
196: return name;
197: }
198:
199: public int getColumnCount() {
200: return columnNames.length;
201: }
202:
203: public String getColumn(int i) {
204: return columnNames[i];
205: }
206:
207: public String toString() {
208: return name + '[' + ArrayFormat.format(columnNames) + ']';
209: }
210:
211: public int getColumnIndex(String columnName) {
212: return ArrayUtil.indexOf(columnName, columnNames);
213: }
214:
215: public String[] getColumnNames() {
216: return columnNames;
217: }
218: }
219:
220: private static class Row {
221:
222: // private Table table;
223: private String tableName;
224: private String[] columnNames;
225: private String[] values;
226:
227: public Row(String tableName, String[] columnNames,
228: String[] values) {
229: this .tableName = tableName;
230: this .columnNames = columnNames;
231: this .values = values;
232: }
233:
234: public String getTableName() {
235: return tableName;
236: }
237:
238: public String[] getValues() {
239: return values;
240: }
241:
242: public String getColumnName(int i) {
243: return columnNames[i];
244: }
245:
246: public String toString() {
247: return tableName + '[' + ArrayFormat.format(values) + ']';
248: }
249: }
250: }
|