001 /*
002 * CSVFormatterFactory.java
003 *
004 * Copyright (C) 2005 Anupam Sengupta ([email protected])
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.formatters;
023
024 import net.sf.anupam.csv.exceptions.CSVOException;
025 import org.apache.commons.logging.Log;
026 import org.apache.commons.logging.LogFactory;
027
028 import java.util.HashMap;
029 import java.util.Map;
030
031 /**
032 * A singleton factory which creates and caches the
033 * {@link CSVFieldFormatter csv field formatters}. The factory
034 * maintains a cache of CSV formatters that are reentrant (i.e.,
035 * the formatters that do not maintain any instance specific state).
036 *
037 * @author Anupam Sengupta
038 * @version $Revision: 1.3 $
039 * @see CSVFieldFormatter
040 * @since 1.5
041 */
042 public final class CSVFormatterFactory {
043
044 /**
045 * The CSV formatter mapping file name. This file assumed to be present in the
046 * classpath.
047 */
048 private static final String FMT_MAPPING_FILE_NAME = "net/sf/anupam/csv/formatters/csv-formatter-config.xml";
049
050 /**
051 * The singleton instance of the factory.
052 */
053 private static CSVFormatterFactory singleton;
054
055 /**
056 * The generic NO-OP formatter which is used when no explicit formatter is
057 * defined.
058 */
059 private static final CSVFieldFormatter DO_NOTHING_FORMATTER = new DoNothingFormatter();
060
061 /**
062 * The logger to use.
063 */
064 private static final Log LOG = LogFactory
065 .getLog(CSVFormatterFactory.class);
066
067 /**
068 * Mapping of the formatter name and the configuration.
069 */
070 private Map<String, FormatterConfiguration> formatterLookupMap;
071
072 /**
073 * The cached formatters.
074 */
075 private Map<String, CSVFieldFormatter> formatterCache;
076
077
078 /**
079 * Constructor for CSVFormatterFactory. Private to prevent direct
080 * instantiation.
081 */
082 private CSVFormatterFactory() {
083 super();
084 formatterLookupMap = new HashMap<String, FormatterConfiguration>();
085 formatterCache = new HashMap<String, CSVFieldFormatter>();
086 }
087
088 /**
089 * Returns the singleton instance of this factory.
090 *
091 * @return the singleton instance
092 */
093 public synchronized static CSVFormatterFactory getSingleton() {
094 if (singleton == null) {
095 singleton = new CSVFormatterFactory();
096 singleton.loadMappings();
097 LOG.info("Created the CSVFormatter Factory");
098 }
099 return singleton;
100 }
101
102 /**
103 * Loads all mappings from the formatter configuration file.
104 */
105 private void loadMappings() {
106 final CSVFormatterConfigParser parser = CSVFormatterConfigParser.getConfigParser();
107 final FormatterConfiguration doNothingConfiguration = new FormatterConfiguration();
108 doNothingConfiguration.setFormatterName("none");
109 doNothingConfiguration.setFormatterClass("net.sf.anupam.csv.formatters.DoNothingFormatter");
110 doNothingConfiguration.setConstructionNeeded(false);
111 formatterLookupMap.put("none", doNothingConfiguration);
112 formatterLookupMap.putAll(parser.getFormatMappings(FMT_MAPPING_FILE_NAME,
113 true));
114 createCache();
115 LOG.debug("Loaded the CSV Mapping configuration from "
116 + FMT_MAPPING_FILE_NAME);
117 }
118
119 /**
120 * Creates the cached formatters for the ones which do not need special
121 * construction.
122 */
123 private void createCache() {
124 for (String formatterName : formatterLookupMap.keySet()) {
125 final FormatterConfiguration currentFormatter = formatterLookupMap
126 .get(formatterName);
127 // If the formatter does not require special construction,
128 // then create it one time and cache it.
129 if (!currentFormatter.isConstructionNeeded()) {
130
131 final CSVFieldFormatter formatter = createFormatterForClass(currentFormatter
132 .getFormatterClass());
133
134 formatterCache.put(formatterName, formatter);
135 }
136 }
137 }
138
139 /**
140 * Creates a formatter from the specified class.
141 *
142 * @param className the formatter class
143 * @return the created formatter
144 */
145 private CSVFieldFormatter createFormatterForClass(final String className) {
146
147 Object formatter;
148 try {
149 formatter = Class.forName(className.trim()).newInstance();
150 } catch (final InstantiationException e) {
151 LOG.warn("Could not create formatter for class: "
152 + className, e);
153 formatter = DO_NOTHING_FORMATTER;
154 } catch (final IllegalAccessException e) {
155 LOG.warn("Could not create formatter for class: "
156 + className, e);
157 formatter = DO_NOTHING_FORMATTER;
158 } catch (final ClassNotFoundException e) {
159 LOG.warn("Could not create formatter for class: "
160 + className, e);
161 formatter = DO_NOTHING_FORMATTER;
162 }
163 return (CSVFieldFormatter) formatter;
164
165 }
166
167 /**
168 * Creates a new instance of the specified formatter. The cache is used
169 * whenever possible.
170 *
171 * @param formatterName the formatter to return
172 * @return the requested formatter
173 * @throws CSVOException thrown if the formatter cannot be created
174 */
175 public CSVFieldFormatter createFormatterFor(final String formatterName)
176 throws CSVOException {
177
178 // If a cache hit, then return the cached formatter
179 if (formatterCache.containsKey(formatterName)) {
180 return formatterCache.get(formatterName);
181 } else {
182 LOG.warn("Formatter: " + formatterName + " not found");
183 throw new CSVOException("Formatter: " + formatterName + " not found");
184 }
185
186 }
187 }