001 package com.mockrunner.jdbc;
002
003 import java.io.File;
004 import java.io.FileNotFoundException;
005 import java.util.HashMap;
006 import java.util.List;
007 import java.util.Map;
008
009 import com.mockrunner.mock.jdbc.MockResultSet;
010 import com.mockrunner.util.common.FileUtil;
011 import com.mockrunner.util.common.StringUtil;
012
013 /**
014 * Can be used to create a <code>ResultSet</code> based on
015 * a table specified in a CSV file. You can specify the delimiter
016 * of the columns (default is <code>;</code>). Furthermore you can specify if the first line
017 * contains the column names (default is <code>false</code>) and if
018 * the column entries should be trimmed (default is <code>true</code>).
019 * With {@link #setUseTemplates} you can enable template replacement in the
020 * files (default is <code>false</code>, i.e. templates are disabled).
021 * The file can be specified directly or by its name. The class
022 * tries to find the file in the absolut or relative path and
023 * (if not found) by calling <code>getResource</code>. Note that the
024 * file must exist in the local file system and cannot be loaded from
025 * inside a jar archive.
026 */
027 public class FileResultSetFactory implements ResultSetFactory
028 {
029 private File file = null;
030 private String delimiter = ";";
031 private boolean firstLineContainsColumnNames = false;
032 private boolean trim = true;
033 private boolean useTemplates = false;
034 private String templateMarker = null;
035 private Map templates = null;
036
037 public FileResultSetFactory(String fileName)
038 {
039 this(new File(fileName));
040 }
041
042 public FileResultSetFactory(File file)
043 {
044 this.file = file;
045 setDefaultTemplateConfiguration();
046 }
047
048 /**
049 * Get the <code>File</code> being used to read in the
050 * <code>ResultSet</code>. Throws a <code>RuntimeException</code>
051 * if the file does not exist.
052 * @return the file
053 */
054 public File getFile()
055 {
056 if (file.exists() && file.isFile())
057 {
058 return file;
059 }
060 else
061 {
062 try
063 {
064 file = FileUtil.findFile(file.getPath());
065 return file;
066 }
067 catch (FileNotFoundException exc)
068 {
069 throw new RuntimeException("Could not find: " + file.getPath());
070 }
071 }
072 }
073
074 /**
075 * Set the delimiter. Default is <i>";"</i>.
076 * @param delimiter the delimiter
077 */
078 public void setDelimiter(String delimiter)
079 {
080 this.delimiter = delimiter;
081 }
082
083 /**
084 * Set if the first line contains the column names.
085 * Default is <code>false</code>.
086 */
087 public void setFirstLineContainsColumnNames(boolean firstLineContainsColumnNames)
088 {
089 this.firstLineContainsColumnNames = firstLineContainsColumnNames;
090 }
091
092 /**
093 * Set if the column entries should be trimmed.
094 * Default is <code>true</code>.
095 */
096 public void setTrim(boolean trim)
097 {
098 this.trim = trim;
099 }
100
101 /**
102 * Set this to <code>true</code> to allow the use of templates
103 * in data files. A template is identified by a marker followed
104 * by a label. The template is replaced by a predefined string in
105 * the corresponding data file. E.g. with the default configuration,
106 * <code>$defaultString</code> is replaced by an empty string
107 * in the file.
108 * The default configuration which is automatically set uses
109 * <code>$</code> as a marker. See {@link #setDefaultTemplateConfiguration}
110 * for details. You can also set a custom template configuration using
111 * {@link #setTemplateConfiguration(String, Map)}.
112 * Default is <code>false</code>, i.e. templates are disabled.
113 * @param useTemplates set <code>true</code> to enable templates.
114 */
115 public void setUseTemplates(boolean useTemplates)
116 {
117 this.useTemplates = useTemplates;
118 }
119
120 /**
121 * This method sets a custom template configuration. See
122 * {@link #setUseTemplates} for an explanation how templates work.
123 * <code>marker + map key</code> is replaced by the corresponding <code>map
124 * value</code> in the data files.
125 * Please use {@link #setDefaultTemplateConfiguration} to set a
126 * default configuration.
127 * @param marker the custom marker replacing the default <code>$</code>
128 * @param templates the custom template map
129 */
130 public void setTemplateConfiguration(String marker, Map templates)
131 {
132 this.templates = templates;
133 this.templateMarker = marker;
134 }
135
136 /**
137 * This method sets the default template configuration. See
138 * {@link #setUseTemplates} for an explanation how templates work.
139 * The default marker is <code>$</code> and the default templates are:<br><br>
140 * <code>$defaultString</code> is replaced by an empty string<br>
141 * <code>$defaultDate</code> is replaced by <code>1970-01-01</code><br>
142 * <code>$defaultInteger</code> is replaced by <code>0</code><br><br>
143 * Please use {@link #setTemplateConfiguration(String, Map)} to set a
144 * custom marker and custom templates.
145 */
146 public void setDefaultTemplateConfiguration()
147 {
148 Map templates = new HashMap();
149 templates.put("defaultString", "");
150 templates.put("defaultDate", "1970-01-01");
151 templates.put("defaultInteger", "0");
152 setTemplateConfiguration("$", templates);
153 }
154
155 public MockResultSet create(String id)
156 {
157 MockResultSet resultSet = new MockResultSet(id);
158 File fileToRead = getFile();
159 List lines = FileUtil.getLinesFromFile(fileToRead);
160
161 int firstLineNumber = 0;
162 if(firstLineContainsColumnNames)
163 {
164 String firstLine = (String)lines.get(firstLineNumber);
165 firstLineNumber++;
166 String[] names = StringUtil.split(firstLine, delimiter, trim);
167 for(int ii = 0; ii < names.length; ii++)
168 {
169 resultSet.addColumn(names[ii]);
170 }
171 }
172 for(int ii = firstLineNumber; ii < lines.size(); ii++)
173 {
174 String line = (String)lines.get(ii);
175 String[] values = StringUtil.split(line, delimiter, trim);
176 if(useTemplates)
177 {
178 for(int yy = 0; yy < values.length; yy++)
179 {
180 if(null != values[yy])
181 {
182 if(values[yy].startsWith(templateMarker) && templates.containsKey(values[yy].substring(1)))
183 {
184 values[yy] = (String)templates.get(values[yy].substring(1));
185 }
186 }
187 }
188 }
189 resultSet.addRow(values);
190 }
191 return resultSet;
192 }
193 }