001: package jimm.datavision.source.charsep;
002:
003: import jimm.datavision.Formula;
004: import jimm.datavision.ErrorHandler;
005: import jimm.datavision.source.DataCursor;
006: import jimm.datavision.source.Column;
007: import jimm.datavision.source.Query;
008: import java.util.*;
009: import java.io.IOException;
010: import java.text.SimpleDateFormat;
011: import java.text.ParseException;
012:
013: /**
014: * A concrete subclass of <code>DataCursor</code> that wraps a delimited file parser.
015: *
016: * @author Jim Menard, <a href="mailto:jimm@io.com">jimm@io.com</a>
017: */
018: public class CharSepRow extends DataCursor {
019:
020: protected CharSepSource source;
021: protected Query query;
022: protected Formula whereClauseFormula;
023: protected boolean noMoreData;
024: protected DelimParser parser;
025: protected HashMap dateParsers;
026: protected boolean dateParseErrorReported;
027:
028: CharSepRow(CharSepSource source, Query query) {
029: this .source = source;
030: this .query = query;
031: this .query.findSelectablesUsed(); // Needed so we can find columns later
032:
033: String script = query.getWhereClause();
034: if (script != null && script.length() > 0)
035: whereClauseFormula = new Formula(null, source.getReport(),
036: "", script);
037: }
038:
039: /**
040: * Returns the next row of data. If there is a where clause, use that to
041: * determine which rows we accept or reject.
042: */
043: public List readRowData() {
044: if (noMoreData)
045: return null;
046:
047: List data = null;
048:
049: boolean acceptRow;
050: do {
051: data = retrieveNextRow();
052: if (whereClauseFormula != null && data != null) {
053: // Run the Ruby script and retrive its boolean value. If true,
054: // accept the line. Else, reject it and move on to the next
055: // line.
056:
057: // First, save the existing current row and make the new data
058: // the current row. We need to do this because the formula we
059: // are about to evaluate may make use of data in the new
060: // current row.
061: List origCurrRowData = currRowData;
062: currRowData = data; // Need data available to formula
063:
064: // Evaulate the script and retrieve a boolean.
065: Object obj = whereClauseFormula.eval();
066: acceptRow = ((Boolean) obj).booleanValue();
067:
068: // Replace the original current row data (acutally the previous
069: // row, but we don't care).
070: currRowData = origCurrRowData;
071: } else
072: acceptRow = true;
073: } while (!acceptRow);
074:
075: return data;
076: }
077:
078: /**
079: * Retrieve the next row of data and return it as a list of column values.
080: *
081: * @return a list of column values
082: */
083: protected List retrieveNextRow() {
084: if (parser == null)
085: parser = new DelimParser(source.getReader(), source
086: .getSepChar());
087:
088: List data = null;
089: try {
090: data = parser.parse();
091: } catch (IOException ioe) {
092: ErrorHandler.error(ioe);
093: noMoreData = true;
094: return null;
095: }
096: if (data == null) {
097: noMoreData = true;
098: return null;
099: }
100:
101: int numColumnsInData = data.size();
102: int i = 0;
103: for (Iterator iter = source.columns(); iter.hasNext(); ++i) {
104: Column col = (Column) iter.next();
105:
106: if (i >= numColumnsInData) {
107: data.add(null);
108: continue;
109: }
110:
111: if (col.isNumeric()) {
112: String str = data.get(i).toString();
113: if (str == null || str.length() == 0)
114: data.set(i, new Integer(0));
115: else if (str.indexOf('.') == -1)
116: data.set(i, new Integer(str));
117: else
118: data.set(i, new Double(str));
119: } else if (col.isDate())
120: data.set(i, parseDate(col, data.get(i).toString()));
121: // else, it's a string; there is nothing to modify
122: }
123:
124: return data;
125: }
126:
127: protected Date parseDate(Column col, String dateString) {
128: String formatString = col.getDateParseFormat();
129:
130: // Find existing parser, if any
131: if (dateParsers == null)
132: dateParsers = new HashMap();
133: SimpleDateFormat parser = (SimpleDateFormat) dateParsers
134: .get(formatString);
135:
136: if (parser == null) {
137: parser = new SimpleDateFormat(formatString);
138: dateParsers.put(formatString, parser);
139: }
140:
141: try {
142: return parser.parse(dateString);
143: } catch (ParseException ex) {
144: if (!dateParseErrorReported) {
145: ErrorHandler.error("Parse format string = "
146: + formatString, ex);
147: dateParseErrorReported = true;
148: }
149: return null;
150: }
151: }
152:
153: public void close() {
154: source.closeReader();
155: }
156:
157: }
|