View Javadoc
1   /*
2    * ObjectLab, http://www.objectlab.co.uk/open is supporting FlatPack.
3    *
4    * Based in London, we are world leaders in the design and development
5    * of bespoke applications for the securities financing markets.
6    *
7    * <a href="http://www.objectlab.co.uk/open">Click here to learn more</a>
8    *           ___  _     _           _   _          _
9    *          / _ \| |__ (_) ___  ___| |_| |    __ _| |__
10   *         | | | | '_ \| |/ _ \/ __| __| |   / _` | '_ \
11   *         | |_| | |_) | |  __/ (__| |_| |__| (_| | |_) |
12   *          \___/|_.__// |\___|\___|\__|_____\__,_|_.__/
13   *                   |__/
14   *
15   *                     www.ObjectLab.co.uk
16   *
17   * $Id: ColorProvider.java 74 2006-10-24 22:19:05Z benoitx $
18   *
19   * Copyright 2006 the original author or authors.
20   *
21   * Licensed under the Apache License, Version 2.0 (the "License"); you may not
22   * use this file except in compliance with the License. You may obtain a copy of
23   * the License at
24   *
25   * http://www.apache.org/licenses/LICENSE-2.0
26   *
27   * Unless required by applicable law or agreed to in writing, software
28   * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
29   * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
30   * License for the specific language governing permissions and limitations under
31   * the License.
32   */
33  package net.sf.flatpack;
34  
35  import java.math.BigDecimal;
36  import java.text.ParseException;
37  import java.text.SimpleDateFormat;
38  import java.time.LocalDate;
39  import java.time.format.DateTimeFormatter;
40  import java.util.ArrayList;
41  import java.util.Collections;
42  import java.util.Date;
43  import java.util.List;
44  import java.util.Optional;
45  import java.util.Properties;
46  import java.util.function.DoubleSupplier;
47  import java.util.function.IntSupplier;
48  import java.util.function.LongSupplier;
49  import java.util.function.Supplier;
50  
51  import net.sf.flatpack.ordering.OrderBy;
52  import net.sf.flatpack.structure.ColumnMetaData;
53  import net.sf.flatpack.structure.Row;
54  import net.sf.flatpack.util.FPException;
55  import net.sf.flatpack.util.FPInvalidUsageException;
56  import net.sf.flatpack.util.ParserUtils;
57  import net.sf.flatpack.xml.MetaData;
58  
59  /**
60   * @author Benoit Xhenseval
61   * @author Paul Zepernick
62   *
63   */
64  public class DefaultDataSet implements DataSet {
65      private static final String NEW_LINE = System.lineSeparator();
66  
67      private final List<Row> rows = new ArrayList<>();
68  
69      private final List<DataError> errors = new ArrayList<>();
70  
71      private Properties pzConvertProps = null;
72  
73      /** Pointer for the current row in the array we are on */
74      private int pointer = -1;
75  
76      /** flag to indicate if data should be pulled as lower case */
77      private boolean lowerCase = false;
78  
79      /** flag to indicate if data should be pulled as upper case */
80      private boolean upperCase = false;
81      private String[] columns = null;
82  
83      /**
84       * flag to indicate if a strict parse should be used when getting doubles
85       * and ints
86       */
87      private boolean strictNumericParse = false;
88  
89      private MetaData metaData;
90  
91      private final Parser parser;
92  
93      private Record currentRecord;
94  
95      public DefaultDataSet(final MetaData pzMetaData, final Parser pzparser) {
96          this.metaData = pzMetaData;
97          this.parser = pzparser;
98      }
99  
100     public void addRow(final Row row) {
101         rows.add(row);
102     }
103 
104     public void addError(final DataError dataError) {
105         errors.add(dataError);
106     }
107 
108     /*
109      * (non-Javadoc)
110      *
111      * @see net.sf.flatpack.DataSet#getColumns()
112      */
113     @Override
114     public String[] getColumns() {
115 
116         if (columns == null && metaData != null) {
117             final List<ColumnMetaData> cmds = metaData.getColumnsNames();
118             columns = new String[cmds.size()];
119             for (int i = 0; i < cmds.size(); i++) {
120                 final ColumnMetaData column = cmds.get(i);
121                 columns[i] = column.getColName();
122             }
123         }
124 
125         return columns;
126     }
127 
128     /*
129      * (non-Javadoc)
130      *
131      * @see net.sf.flatpack.DataSet#getColumns(java.lang.String)
132      */
133     @Override
134     public String[] getColumns(final String recordID) {
135         String[] array = null;
136 
137         if (metaData != null) {
138             final List<ColumnMetaData> cmds = ParserUtils.getColumnMetaData(recordID, metaData);
139             array = new String[cmds.size()];
140             for (int i = 0; i < cmds.size(); i++) {
141                 final ColumnMetaData column = cmds.get(i);
142                 array[i] = column.getColName();
143             }
144         }
145 
146         return array;
147     }
148 
149     @Override
150     public Date getDate(final String column) throws ParseException {
151         return currentRecord.getDate(column);
152     }
153 
154     @Override
155     public Date getDate(final String column, final SimpleDateFormat sdf) throws ParseException {
156         return currentRecord.getDate(column, sdf);
157     }
158 
159     @Override
160     public double getDouble(final String column) {
161         return currentRecord.getDouble(column);
162     }
163 
164     @Override
165     public BigDecimal getBigDecimal(final String column) {
166         return currentRecord.getBigDecimal(column);
167     }
168 
169     @Override
170     public Object getObject(final String column, final Class<?> classToConvertTo) {
171         return currentRecord.getObject(column, classToConvertTo);
172     }
173 
174     @Override
175     public BigDecimal getBigDecimal(final String column, final Supplier<BigDecimal> defaultSupplier) {
176         return currentRecord.getBigDecimal(column, defaultSupplier);
177     }
178 
179     @Override
180     public Date getDate(final String column, final SimpleDateFormat sdf, final Supplier<Date> defaultSupplier) throws ParseException {
181         return currentRecord.getDate(column, sdf, defaultSupplier);
182     }
183 
184     @Override
185     public Date getDate(final String column, final Supplier<Date> defaultSupplier) throws ParseException {
186         return currentRecord.getDate(column, defaultSupplier);
187     }
188 
189     @Override
190     public double getDouble(final String column, final DoubleSupplier defaultSupplier) {
191         return currentRecord.getDouble(column, defaultSupplier);
192     }
193 
194     @Override
195     public int getInt(final String column, final IntSupplier defaultSupplier) {
196         return currentRecord.getInt(column, defaultSupplier);
197     }
198 
199     @Override
200     public long getLong(final String column, final LongSupplier defaultSupplier) {
201         return currentRecord.getLong(column, defaultSupplier);
202     }
203 
204     @Override
205     public String getString(final String column, final Supplier<String> defaultSupplier) {
206         return currentRecord.getString(column, defaultSupplier);
207     }
208 
209     /*
210      * (non-Javadoc)
211      *
212      * @see net.sf.flatpack.DataSet#getErrorCount()
213      */
214     @Override
215     public int getErrorCount() {
216         if (getErrors() != null) {
217             return getErrors().size();
218         }
219 
220         return 0;
221     }
222 
223     /*
224      * (non-Javadoc)
225      *
226      * @see net.sf.flatpack.DataSet#getErrors()
227      */
228     @Override
229     public List<DataError> getErrors() {
230         return errors;
231     }
232 
233     /*
234      * (non-Javadoc)
235      *
236      * @see net.sf.flatpack.DataSet#getIndex()
237      */
238     @Override
239     public int getIndex() {
240         return pointer;
241     }
242 
243     @Override
244     public int getInt(final String column) {
245         return currentRecord.getInt(column);
246     }
247 
248     @Override
249     public long getLong(final String column) {
250         return currentRecord.getLong(column);
251     }
252 
253     /*
254      * (non-Javadoc)
255      *
256      * @see net.sf.flatpack.DataSet#getRowCount()
257      */
258     @Override
259     public int getRowCount() {
260         return rows.size();
261     }
262 
263     /*
264      * (non-Javadoc)
265      *
266      * @see net.sf.flatpack.DataSet#getRowNo()
267      */
268     @Override
269     public int getRowNo() {
270         return currentRecord.getRowNo();
271     }
272 
273     /*
274      * (non-Javadoc)
275      *
276      * @see net.sf.flatpack.DataSet#getString(java.lang.String)
277      */
278     @Override
279     public String getString(final String column) {
280         return currentRecord.getString(column);
281     }
282 
283     @Override
284     public void setValue(final String column, final String value) {
285         final Row row = rows.get(pointer);
286         final int colIndex = ParserUtils.getColumnIndex(row.getMdkey(), metaData, column, parser.isColumnNamesCaseSensitive());
287 
288         row.setValue(colIndex, value);
289     }
290 
291     /*
292      * (non-Javadoc)
293      *
294      * @see net.sf.flatpack.DataSet#goBottom()
295      */
296     @Override
297     public void goBottom() {
298         pointer = rows.size() - 1;
299     }
300 
301     /*
302      * (non-Javadoc)
303      *
304      * @see net.sf.flatpack.DataSet#goTop()
305      */
306     @Override
307     public void goTop() {
308         pointer = -1;
309     }
310 
311     /*
312      * (non-Javadoc)
313      *
314      * @see net.sf.flatpack.DataSet#isAnError(int)
315      */
316     @Override
317     public boolean isAnError(final int lineNo) {
318         for (int i = 0; i < errors.size(); i++) {
319             if (errors.get(i).getLineNo() == lineNo && errors.get(i).getErrorLevel() > 1) {
320                 return true;
321             }
322         }
323         return false;
324     }
325 
326     /*
327      * (non-Javadoc)
328      *
329      * @see net.sf.flatpack.DataSet#next()
330      */
331     @Override
332     public boolean next() {
333         if (pointer < rows.size() && pointer + 1 != rows.size()) {
334             pointer++;
335             currentRecord = new RowRecord(rows.get(pointer), metaData, parser.isColumnNamesCaseSensitive(), pzConvertProps, strictNumericParse,
336                     upperCase, lowerCase, parser.isNullEmptyStrings());
337             return true;
338         }
339         currentRecord = null;
340         return false;
341     }
342 
343     @Override
344     public Optional<Record> getRecord() {
345         return Optional.ofNullable(currentRecord);
346     }
347 
348     /*
349      * (non-Javadoc)
350      *
351      * @see net.sf.flatpack.DataSet#orderRows(net.sf.flatpack.ordering.OrderBy)
352      */
353     @Override
354     public void orderRows(final OrderBy ob) {
355         if (ob != null) {
356             ob.setMetaData(getMetaData());
357             ob.setParser(parser);
358             Collections.sort(rows, ob);
359             goTop();
360         }
361     }
362 
363     /*
364      * (non-Javadoc)
365      *
366      * @see net.sf.flatpack.DataSet#previous()
367      */
368     @Override
369     public boolean previous() {
370         if (pointer <= 0) {
371             currentRecord = null;
372             return false;
373         }
374         pointer--;
375         currentRecord = new RowRecord(rows.get(pointer), metaData, parser.isColumnNamesCaseSensitive(), pzConvertProps, strictNumericParse, upperCase,
376                 lowerCase, parser.isNullEmptyStrings());
377         return true;
378     }
379 
380     /**
381      * Sets data in the DataSet to lowercase
382      */
383     @Override
384     public void setLowerCase() {
385         upperCase = false;
386         lowerCase = true;
387     }
388 
389     /**
390      * Sets data in the DataSet to uppercase
391      */
392     @Override
393     public void setUpperCase() {
394         upperCase = true;
395         lowerCase = false;
396     }
397 
398     /**
399      * Checks to see if the row has the given &lt;RECORD&gt; id
400      *
401      * @param recordID record to check
402      * @return boolean true if current record is of recordID
403      */
404     @Override
405     public boolean isRecordID(final String recordID) {
406         return currentRecord.isRecordID(recordID);
407     }
408 
409     @Override
410     public String getRecordID() {
411         return currentRecord.getRecordID();
412     }
413 
414     /**
415      * Sets the absolute position of the record pointer
416      *
417      * @param localPointer
418      *            - int
419      * @exception IndexOutOfBoundsException if wrong index
420      */
421     @Override
422     public void absolute(final int localPointer) {
423         if (localPointer < 0 || localPointer >= rows.size()) {
424             throw new IndexOutOfBoundsException("INVALID POINTER LOCATION: " + localPointer);
425         }
426 
427         pointer = localPointer;
428         currentRecord = new RowRecord(rows.get(pointer), metaData, parser.isColumnNamesCaseSensitive(), pzConvertProps, strictNumericParse, upperCase,
429                 lowerCase, parser.isNullEmptyStrings());
430     }
431 
432     /**
433      * Setting this to True will parse text as is and throw a
434      * NumberFormatException. Setting to false, which is the default, will
435      * remove any non numeric charcter from the field. The remaining numeric
436      * chars's will be returned. If it is an empty string,or there are no
437      * numeric chars, 0 will be returned for getInt() and getDouble()
438      *
439      * @param strictNumericParse
440      *            The strictNumericParse to set.
441      */
442     @Override
443     public void setStrictNumericParse(final boolean strictNumericParse) {
444         this.strictNumericParse = strictNumericParse;
445     }
446 
447     /*
448      * (non-Javadoc)
449      *
450      * @see net.sf.flatpack.DataSet#remove()
451      */
452     @Override
453     public void remove() {
454         rows.remove(pointer);
455         pointer--;
456     }
457 
458     @Override
459     public void setPZConvertProps(final Properties props) {
460         this.pzConvertProps = props;
461     }
462 
463     /**
464      * @param pointer
465      *            the pointer to set
466      */
467     protected void setPointer(final int pointer) {
468         this.pointer = pointer;
469     }
470 
471     @Override
472     public void clearRows() {
473         pointer = -1; // set the pointer back to -1 directly just in case this
474         // instance is a BuffReaderDataSet.
475         rows.clear();
476     }
477 
478     @Override
479     public void clearAll() {
480         clearRows();
481         clearErrors();
482     }
483 
484     @Override
485     public void clearErrors() {
486         errors.clear();
487     }
488 
489     public MetaData getMetaData() {
490         return metaData;
491     }
492 
493     public void setMetaData(final MetaData metaData) {
494         this.metaData = metaData;
495         this.columns = null;
496     }
497 
498     @Override
499     public String toString() {
500         final StringBuilder buf = new StringBuilder();
501         buf.append("Errors:").append(errors.size()).append(NEW_LINE);
502         buf.append("Rows:").append(rows.size()).append(NEW_LINE);
503         buf.append("Position:").append(pointer).append(NEW_LINE);
504         buf.append("Conversion Props:").append(pzConvertProps).append(NEW_LINE);
505         buf.append("MetaData:").append(metaData).append(NEW_LINE);
506         return buf.toString();
507     }
508 
509     @Override
510     public boolean contains(final String column) {
511         if (pointer == -1) {
512             throw new IndexOutOfBoundsException("dataset on invalid row. need to call next()");
513         }
514         return currentRecord.contains(column);
515     }
516 
517     /**
518      * @throws FPInvalidUsageException
519      *             Parser.isFlagEmptyRows() must be set to true before using
520      *             this
521      * @throws FPException
522      *             if cursor is on an invalid row
523      */
524     @Override
525     public boolean isRowEmpty() {
526         if (!parser.isFlagEmptyRows()) {
527             // flag empty rows needs to be set for this functionality
528             // throw an exception
529             throw new FPInvalidUsageException("Parser.isFlagEmptyRows(true) must be set before using isRowEmpty()");
530         }
531 
532         if (pointer < 0) {
533             throw new FPException("Cursor on invalid row..  Make sure next() is called and returns true");
534         }
535 
536         return rows.get(pointer).isEmpty();
537     }
538 
539     /**
540      * @throws FPInvalidUsageException
541      * @throws FPException
542      *             if cursor is on an invalid row
543      */
544     @Override
545     public String getRawData() {
546         if (!parser.isStoreRawDataToDataSet()) {
547             // option needs to be set for this functionality
548             // throw an exception
549             throw new FPInvalidUsageException("Parser.isStoreRawDataToDataSet(true) must be set before using getRawData()");
550         }
551 
552         if (pointer < 0) {
553             throw new FPException("Cursor on invalid row.. Make sure next() is called and returns true");
554         }
555 
556         return rows.get(pointer).getRawData();
557     }
558 
559     @Override
560     public LocalDate getLocalDate(final String column, final Supplier<LocalDate> defaultSupplier) throws ParseException {
561         return currentRecord.getLocalDate(column, defaultSupplier);
562     }
563 
564     @Override
565     public LocalDate getLocalDate(final String column) throws ParseException {
566         return currentRecord.getLocalDate(column);
567     }
568 
569     @Override
570     public LocalDate getLocalDate(final String column, DateTimeFormatter dtf) throws ParseException {
571         return currentRecord.getLocalDate(column, dtf);
572     }
573 
574     @Override
575     public LocalDate getLocalDate(final String column, final String dateFormat, final Supplier<LocalDate> defaultSupplier) throws ParseException {
576         return currentRecord.getLocalDate(column, dateFormat, defaultSupplier);
577     }
578 
579     @Override
580     public LocalDate getLocalDate(final String column, final String dateFormat) throws ParseException {
581         return currentRecord.getLocalDate(column, dateFormat);
582     }
583 }