001: /*
002: * CSVParserFactory.java
003: *
004: * Copyright (C) 2005 Anupam Sengupta (anupamsg@users.sourceforge.net)
005: *
006: * This program is free software; you can redistribute it and/or
007: * modify it under the terms of the GNU General Public License
008: * as published by the Free Software Foundation; either version 2
009: * of the License, or (at your option) any later version.
010: *
011: * This program is distributed in the hope that it will be useful,
012: * but WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
014: * GNU General Public License for more details.
015: *
016: * You should have received a copy of the GNU General Public License
017: * along with this program; if not, write to the Free Software
018: * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
019: *
020: * Version: $Revision: 1.3 $
021: */
022: package net.sf.anupam.csv;
023:
024: import net.sf.anupam.csv.formatters.CSVFieldFormatter;
025: import net.sf.anupam.csv.formatters.CSVFormatterFactory;
026: import net.sf.anupam.csv.mapping.CSVBeanMapping;
027: import net.sf.anupam.csv.mapping.CSVFieldMapping;
028: import net.sf.anupam.csv.mapping.CSVMappingParser;
029: import net.sf.anupam.csv.exceptions.CSVOException;
030: import org.apache.commons.lang.StringUtils;
031: import org.apache.commons.logging.Log;
032: import org.apache.commons.logging.LogFactory;
033:
034: import java.io.FileNotFoundException;
035: import java.io.FileReader;
036: import java.io.InputStream;
037: import java.io.InputStreamReader;
038: import java.io.Reader;
039: import java.util.HashMap;
040: import java.util.Map;
041:
042: /**
043: * Singleton factory for creating the {@link CSVParser CSVParser} parser objects
044: * for clients' of the framework. This factory uses the
045: * <code>csv-mapping.xml</code> mapping configuration to create CSV parsers
046: * customized for the POJO bean to parse. This is the first interface for
047: * clients of the framework.
048: *
049: * @author Anupam Sengupta
050: * @version $Revision: 1.3 $
051: * @see CSVParser
052: * @since 1.5
053: */
054: public final class CSVParserFactory {
055:
056: /**
057: * The Mapping file name.
058: */
059: private static final String MAPPING_FILE_NAME = "csv-mapping.xml";
060:
061: /**
062: * The logger to use.
063: */
064: private static final Log LOG = LogFactory
065: .getLog(CSVParserFactory.class);
066:
067: /**
068: * The singleton factory instance.
069: */
070: private static CSVParserFactory singleton;
071:
072: private static final CSVFormatterFactory FORMATTER_FACTORY = CSVFormatterFactory
073: .getSingleton();
074:
075: /**
076: * The CSV to POJO mapping repository.
077: */
078: private Map<String, CSVBeanMapping> beanMappings;
079:
080: static {
081:
082: }
083:
084: /**
085: * Constructor for CSVParserFactory. Private as this is a singleton.
086: */
087: private CSVParserFactory() {
088: super ();
089: beanMappings = new HashMap<String, CSVBeanMapping>();
090: }
091:
092: /**
093: * Returns the singleton instance of this factory.
094: *
095: * @return the singleton parser factory
096: * @throws CSVOException thrown if the singleton cannot be created
097: */
098: public synchronized static CSVParserFactory getSingleton()
099: throws CSVOException {
100: if (singleton == null) {
101: // Create the singleton at startup.
102: singleton = new CSVParserFactory();
103: singleton.loadMappings();
104: LOG.info("Created the Singleton for: "
105: + CSVParserFactory.class);
106: }
107: return singleton;
108: }
109:
110: /**
111: * Loads the bean mapping configuration from the XML mapping file.
112: *
113: * @throws CSVOException thrown if the mapping cannot be loaded
114: */
115: private void loadMappings() throws CSVOException {
116: final CSVMappingParser parser = new CSVMappingParser();
117: beanMappings
118: .putAll(parser.getMappings(MAPPING_FILE_NAME, true));
119:
120: for (String beanNames : beanMappings.keySet()) {
121: final CSVBeanMapping currentBeanMapping = beanMappings
122: .get(beanNames);
123: for (CSVFieldMapping currentFieldMapping : currentBeanMapping) {
124: createFormattersFor(currentFieldMapping);
125: resolveBeanReferencesFor(currentFieldMapping);
126: }
127: }
128: LOG.debug("Loaded the CSV Mapping configuration from "
129: + MAPPING_FILE_NAME);
130: }
131:
132: /**
133: * Creates any necessary field formatters for the specified field mapping.
134: *
135: * @param fieldMapping the field for which formatters should be created
136: * @throws net.sf.anupam.csv.exceptions.CSVOException
137: * thrown if the specified formatters cannot be created
138: */
139: private void createFormattersFor(final CSVFieldMapping fieldMapping)
140: throws CSVOException {
141:
142: final CSVFieldFormatter formatter = FORMATTER_FACTORY
143: .createFormatterFor(fieldMapping.getReformatterName());
144: fieldMapping.setFormatter(formatter);
145:
146: }
147:
148: /**
149: * Resolves bean references for the specified field, and sets the bean
150: * mapping hierarchy accordingly.
151: *
152: * @param fieldMapping the field for which references need to be resolved
153: */
154: private void resolveBeanReferencesFor(
155: final CSVFieldMapping fieldMapping) {
156:
157: final String beanRefName = fieldMapping.getBeanReferenceName();
158: if (!beanRefName.equalsIgnoreCase("none")) {
159: final CSVBeanMapping referencedBean = getBeanMapping(beanRefName);
160:
161: if (referencedBean != null) {
162: fieldMapping.setBeanReference(referencedBean);
163: } else {
164: LOG.warn("For field " + fieldMapping
165: + " the referenced bean does not exist");
166: fieldMapping.setBeanReferenceName("none");
167: }
168: }
169:
170: }
171:
172: /**
173: * Returns the requested bean mapping configuration.
174: *
175: * @param beanName the POJO bean for which the mapping is to be returned
176: * @return the CSV bean mapping, or <code>null</code> if not found
177: */
178: public CSVBeanMapping getBeanMapping(final String beanName) {
179: return beanMappings.get(beanName);
180: }
181:
182: /**
183: * Returns a new CSV file parser for the specified mapping, and the
184: * specified CSV file.
185: *
186: * @param mappingName the CSV mapping to for which the parser should be created
187: * @param csvFileName the CSV file to be parsed
188: * @param inClassPath indicates whether the CSV file is in the classpath
189: * @return the CSV Parser, or <code>null</code> if not found
190: * @throws FileNotFoundException thrown if the specified CSV file cannot be found
191: * @see #getCSVParser(String,java.io.Reader)
192: */
193: public CSVParser getCSVParser(final String mappingName,
194: final String csvFileName, final boolean inClassPath)
195: throws FileNotFoundException {
196:
197: if (StringUtils.isEmpty(csvFileName)) {
198: LOG.warn("The specified CSV Filename is empty");
199: throw new IllegalArgumentException("File Name is empty");
200: }
201:
202: final Reader reader;
203:
204: try {
205: if (inClassPath) {
206: final InputStream is = ClassLoader
207: .getSystemResourceAsStream(csvFileName);
208: if (is == null) {
209: throw new FileNotFoundException("The CSV File: "
210: + csvFileName
211: + " was not found in the classpath");
212: }
213: reader = new InputStreamReader(is);
214: } else {
215: reader = new FileReader(csvFileName);
216:
217: }
218: LOG.debug("Successfully read the CSV file");
219: } catch (final FileNotFoundException e) {
220: LOG.warn("The specified CSV File: " + csvFileName
221: + " was not found", e);
222: throw e;
223: }
224:
225: return getCSVParser(mappingName, reader);
226: }
227:
228: /**
229: * Returns a new CSV file parser for the specified mapping and the specified
230: * CSV reader stream.
231: *
232: * @param mappingName the CSV mapping for which the parser should be returned
233: * @param csvReader the CSV stream to parse
234: * @return the CSV Parser, or <code>null</code> if not found
235: * @see #getCSVParser(String,String,boolean)
236: */
237: public CSVParser getCSVParser(final String mappingName,
238: final Reader csvReader) {
239:
240: final CSVBeanMapping beanMapping = getBeanMapping(mappingName);
241:
242: if (beanMapping == null) {
243: LOG.warn("Specified bean mapping was not found");
244: throw new IllegalArgumentException(
245: "Specified bean mapping was not found");
246: }
247:
248: if (csvReader == null) {
249: LOG.warn("Specified CSV IO Reader was null");
250: throw new IllegalArgumentException(
251: "Specified CSV IO Reader was null");
252: }
253:
254: final CSVReader reader = new CSVReader(csvReader, beanMapping
255: .isCsvHeaderPresent());
256:
257: return new CSVParser(beanMapping, reader);
258: }
259: }
|