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 }