KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > net > sf > anupam > csv > CSVParser


1 /*
2  * CSVParser.java
3  *
4  * Copyright (C) 2005 Anupam Sengupta (anupamsg@users.sourceforge.net)
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19  *
20  * Version: $Revision: 1.3 $
21  */

22 package net.sf.anupam.csv;
23
24 import net.sf.anupam.csv.formatters.CSVFieldFormatter;
25 import net.sf.anupam.csv.mapping.CSVBeanMapping;
26 import net.sf.anupam.csv.mapping.CSVFieldMapping;
27 import org.apache.commons.beanutils.BeanUtils;
28 import org.apache.commons.lang.builder.ToStringBuilder;
29 import org.apache.commons.logging.Log;
30 import org.apache.commons.logging.LogFactory;
31
32 import java.lang.reflect.InvocationTargetException JavaDoc;
33 import java.util.Iterator JavaDoc;
34 import java.util.List JavaDoc;
35
36 /**
37  * Parses CSV files and creates the mapped POJO objects. This is the primary
38  * interface into the CSV parsing framework.
39  * <p/>
40  * The class implements {@link Iterable Iterable} interface and can be
41  * used in the new <em>Tiger</em> for loops to iterate over all the CSV
42  * records in the file.
43  * </p>
44  * <p/>
45  * Configuration of the parser is performed via the <code>csv-mapping.xml</code>
46  * file. See the package description for more details.
47  * </p>
48  * <p/>
49  * Note that the class is not meant to be instantiated directly. Instead, the
50  * {@link CSVParserFactory CSVParserFactory} factory should be
51  * used for creation of instances.
52  * </p>
53  *
54  * @author Anupam Sengupta
55  * @version $Revision: 1.3 $
56  * @see CSVParserFactory
57  * @since 1.5
58  */

59 public class CSVParser implements Iterable JavaDoc<Object JavaDoc> {
60
61     /**
62      * The logger to use.
63      */

64     private static final Log LOG = LogFactory.getLog(CSVParser.class);
65
66     /**
67      * The CSV Reader to use for this parser.
68      */

69     private CSVReader reader;
70
71     /**
72      * The root bean mapping configuration for this parser.
73      */

74     private CSVBeanMapping rootBeanMapping;
75
76     /**
77      * Constructor for CSVParser. The constructor accepts the bean mapping to
78      * use as the starting CSV mapping configuration
79      * <em>(a.k.a the root bean mapping)</em> and the CSV reader/parser engine
80      * to use for actual parsing.
81      *
82      * @param rootBeanMapping the bean mapping to use as the starting configuration
83      * @param reader the CSV Reader object which will actually parse the CSV file
84      */

85     public CSVParser(final CSVBeanMapping rootBeanMapping,
86                      final CSVReader reader) {
87         super();
88         this.rootBeanMapping = rootBeanMapping;
89         this.reader = reader;
90     }
91
92     /**
93      * Dumps the root bean mapping configuration for this parser. This is meant
94      * for <strong>debugging</strong> only.
95      *
96      * @return the string representation of this parser
97      * @see Object#toString()
98      */

99     @Override JavaDoc
100     public String JavaDoc toString() {
101         return new ToStringBuilder(this).append("beanMapping", rootBeanMapping)
102                 .toString();
103     }
104
105     /**
106      * Finalizes this parser and closes the reader.
107      *
108      * @throws Throwable thrown if the finalization fails
109      * @see Object#finalize()
110      */

111     @Override JavaDoc
112     protected void finalize() throws Throwable JavaDoc {
113         super.finalize();
114         if (reader != null) {
115             reader.close();
116             reader = null;
117         }
118         rootBeanMapping = null;
119     }
120
121     /**
122      * The iterator to provide the Iterable interface to the parser.
123      */

124     private final class MappedObjectIterator implements Iterator JavaDoc<Object JavaDoc> {
125
126         /**
127          * The actual line iterator to use.
128          */

129         private Iterator JavaDoc<List JavaDoc<String JavaDoc>> csvLineIter;
130
131         /**
132          * The iterator constructor.
133          *
134          * @param csvLineIter The actual line iterator to use
135          */

136         MappedObjectIterator(final Iterator JavaDoc<List JavaDoc<String JavaDoc>> csvLineIter) {
137             super();
138             this.csvLineIter = csvLineIter;
139         }
140
141         /**
142          * Finalizes this iterator and nullifies all instance variables.
143          *
144          * @throws Throwable if the finalization fails
145          * @see Object#finalize()
146          */

147         @Override JavaDoc
148         protected final void finalize() throws Throwable JavaDoc {
149             super.finalize();
150             csvLineIter = null;
151         }
152
153         /**
154          * Indicates whether more parsed POJO beans exist.
155          *
156          * @return indicates whether there are any more parsed beans
157          * @see java.util.Iterator#hasNext()
158          */

159         public final boolean hasNext() {
160             return csvLineIter.hasNext();
161         }
162
163         /**
164          * Returns the parsed and mapped POJO bean corresponding to the current
165          * CSV line. Each subsequent invocation will parse and return the next
166          * parsed POJO, until end of the CSV stream is reached.
167          *
168          * @return the parsed bean
169          * @see java.util.Iterator#next()
170          */

171         public Object JavaDoc next() {
172             final List JavaDoc<String JavaDoc> csvLine = csvLineIter.next();
173             return getMappedBean(csvLine, getRootBeanMapping());
174         }
175
176         /**
177          * This operation is not supported.
178          *
179          * @see java.util.Iterator#remove()
180          */

181         public final void remove() {
182             csvLineIter.remove();
183         }
184
185         /**
186          * Applies the field formatters if present.
187          *
188          * @param csvFieldValue the field to format
189          * @param fieldMapping the field mapping from which the formatter should be used
190          * @return the formatted value
191          */

192         private String JavaDoc formatValue(final String JavaDoc csvFieldValue,
193                                    final CSVFieldMapping fieldMapping) {
194             final CSVFieldFormatter formatter = fieldMapping.getFormatter();
195             if (formatter == null) {
196                 return csvFieldValue;
197             }
198
199             return formatter.format(csvFieldValue);
200         }
201
202         /**
203          * Returns the mapped bean from the specified list of CSV values.
204          *
205          * @param csvLine the CSV line to parse
206          * @param beanMap the bean mapping to use
207          * @return the mapped bean
208          */

209         private Object JavaDoc getMappedBean(final List JavaDoc<String JavaDoc> csvLine,
210                                      final CSVBeanMapping beanMap) {
211
212             try {
213                 final Object JavaDoc bean = Class.forName(beanMap.getBeanClass())
214                         .newInstance();
215
216                 for (CSVFieldMapping fieldMapping : beanMap) {
217                     final Object JavaDoc formattedFieldValue;
218
219                     if (fieldMapping.getBeanReferenceName().equals("none")) {
220                         formattedFieldValue = getMappedField(csvLine,
221                                 fieldMapping);
222
223                     } else {
224                         // Recurse and get the value.
225
formattedFieldValue = getMappedBean(csvLine,
226                                 fieldMapping.getBeanReference());
227                     }
228
229                     try {
230                         BeanUtils.setProperty(bean, fieldMapping
231                                 .getAttributeName(), formattedFieldValue);
232                     } catch (final IllegalAccessException JavaDoc e) {
233                         LOG.warn(e);
234                     } catch (final InvocationTargetException JavaDoc e) {
235                         LOG.warn(e);
236                     }
237                 }
238                 return bean;
239
240             } catch (final ClassNotFoundException JavaDoc e) {
241                 LOG.warn("The Bean for class: " + beanMap.getClass()
242                         + " could not be instantiated", e);
243                 return null;
244
245             } catch (final IllegalAccessException JavaDoc e) {
246                 LOG.warn("The Bean for class: " + beanMap.getClass()
247                         + " could not be instantiated", e);
248                 return null;
249             } catch (final InstantiationException JavaDoc e) {
250                 LOG.warn("The Bean for class: " + beanMap.getClass()
251                         + " could not be instantiated", e);
252                 return null;
253             }
254         }
255
256         /**
257          * Returns the parsed field value.
258          *
259          * @param csvLine the CSV line to parse
260          * @param fieldMapping the field mapping to use
261          * @return the mapped field value
262          */

263         private Object JavaDoc getMappedField(final List JavaDoc<String JavaDoc> csvLine,
264                                       final CSVFieldMapping fieldMapping) {
265
266             final String JavaDoc csvFieldValue = csvLine.get(fieldMapping
267                     .getFieldPosition());
268             return formatValue(csvFieldValue, fieldMapping);
269
270         }
271
272     }
273
274     /**
275      * Returns the iterator for retrieving the parsed POJO beans.
276      *
277      * @return the iterator over the parsed beans
278      * @see Iterable#iterator()
279      */

280     public Iterator JavaDoc<Object JavaDoc> iterator() {
281
282         return new MappedObjectIterator(reader.iterator());
283     }
284
285     /**
286      * Returns the root bean mapping. The root bean mapping is the bean mapping
287      * with which the Parser is configured. "Child" bean mappings (which are not
288      * directly accessible) are the bean mapping configurations which may be
289      * present as references from the root mapping.
290      *
291      * @return Returns the root bean mapping.
292      */

293     private CSVBeanMapping getRootBeanMapping() {
294         return this.rootBeanMapping;
295     }
296
297 }
298
Popular Tags