001package bradleyross.j2ee.servlets; 002import java.io.*; 003import java.sql.Types; 004import javax.servlet.*; 005import javax.servlet.http.*; 006/** 007* Serves as a template for writing servlets that 008* display the contains of a java.sql.ResultSet object 009* as a CSV (comma separated values) page. 010* <p>The methods getResultSet and makeConnection are 011* abstract and will need to be overridden before 012* this class can be used. The user may also wish to 013* override several of the methods for formatting 014* information.</p> 015* <p>This is the class that is currently used by 016* com.amtrak.eng.servlets.downloadDataServlet and 017* com.amtrak.eng.tests.testServlet. After 018* bradleyross.library.servlets.csvWriter is modified 019* to make the variables local to the service method, 020* the classes in com.amtrak.eng should be modified to 021* make use of that version.</p> 022* @author Bradley Ross 023* @deprecated 024*/ 025public abstract class csvWriter2 extends HttpServlet 026 { 027 /** 028 * 029 */ 030 private static final long serialVersionUID = 1L; 031/** 032 * File name to be used when creating file. File will be 033 * suffixed with .csv. 034 * <p>Changes to this field can be placed in the method 035 * getResultSet.</p> 036 * @see #getResultSet(javax.servlet.http.HttpServletRequest) 037 */ 038 protected String outputFilename = "default"; 039 /** 040 * String to be placed in CSV file as the first line in the file. 041 * <p>Changes to this field can be placed in the method 042 * getResultSet.</p> 043 * @see #getResultSet(javax.servlet.http.HttpServletRequest) 044 */ 045 protected String message = null; 046 /** 047 * Object containing database connection information. 048 * <p>This field is set by the makeConnection method.</p> 049 * @see #makeConnection() 050 */ 051 protected bradleyross.library.database.DatabaseProperties data = null; 052 /** 053 * Object containing the result set. 054 * <p>This object is created by the getResultMethod method which 055 * is called by the service method. 056 */ 057 protected java.sql.ResultSet rs = null; 058 /** 059 * Object containing meta data on result set. 060 * <p>This object is created by the service method after the 061 * execution of the getResultSet method and before the 062 * execution of the printHeader method.</p> 063 */ 064 protected java.sql.ResultSetMetaData rsmd = null; 065 /** 066 * Object representing the output to the HTTP response. 067 */ 068 protected java.io.PrintWriter output = null; 069 /** 070 * Number of columns in result set 071 */ 072 protected int columnCount; 073 /** 074 * ServletConfig object as passed to the init method. 075 */ 076 protected ServletConfig config = null; 077 public void init(ServletConfig configIn) throws ServletException 078 { 079 super.init(configIn); 080 config = configIn; 081 } 082 public void destroy() 083 { super.destroy(); } 084 /** 085 * @param req Object containing request information 086 * @param res Object containing response information 087 */ 088 public void service (HttpServletRequest req, 089 HttpServletResponse res) throws IOException 090 { 091 try 092 { 093 data = makeConnection(); 094 data.connect(); 095 output = res.getWriter(); 096 rs = getResultSet(req); 097 res.setContentType("text/csv"); 098 res.setHeader("Content-Disposition", "attachment;filename=" + 099 outputFilename + ".csv"); 100 rsmd = rs.getMetaData(); 101 if (message != null) 102 { output.print(message + "\r\n"); } 103 columnCount = rsmd.getColumnCount(); 104 if (rs == null) 105 { 106 output.print("No result set provided\r\n"); 107 return; 108 } 109 boolean moreRecords = rs.next(); 110 if (!moreRecords) 111 { 112 output.print("Result set is empty\r\n"); 113 return; 114 } 115 else 116 { printHeader(); } 117 while (true) 118 { 119 printLine(); 120 moreRecords = rs.next(); 121 if (!moreRecords) { break; } 122 } 123 rs.close(); 124 data.close(); 125 } 126 catch (java.io.IOException e) 127 { throw new java.io.IOException("Error in processing file: " + 128 e.getClass().getName() + " : " + e.getMessage()); } 129 catch (java.sql.SQLException e) 130 { 131 System.out.println("SQL error in processing CSV file"); 132 throw new java.io.IOException("SQL error: " + e.getClass().getName() + 133 " : " + e.getMessage()); 134 } 135 } 136 /** 137 * Obtain the database connection information. 138 */ 139 protected abstract bradleyross.library.database.DatabaseProperties 140 makeConnection() throws IOException; 141 /** 142 * Will be overridden with the method for obtaining the SQL 143 * result set. 144 * <p>Changes to fields such as message and outputFilename can go in this 145 * method.</p> 146 * @param req Request information 147 * @return Result set 148 * @see #message 149 * @see #outputFilename 150 */ 151 protected abstract java.sql.ResultSet getResultSet(HttpServletRequest req) 152 throws java.io.IOException; 153 /** 154 * Will print header line for CSV file. 155 */ 156 protected void printHeader () 157 throws java.io.IOException 158 { 159 try 160 { 161 for (int i = 1; i <= columnCount; i++) 162 { 163 if (i != 1) { output.print(","); } 164 output.print(rsmd.getColumnName(i)); 165 } 166 output.print("\r\n"); 167 } 168 catch (Exception e) 169 { throw new java.io.IOException("Error detected: " + e.getClass().getName() + 170 " : " + e.getMessage()); } 171 } 172 /** 173 * Will print one line of CSV file. 174 * <p>This method will be changed at a later time to allow the 175 * specification of overriding methods for formatting timestamps, 176 * integers, floating point numbers, character strings, etc.</p> 177 */ 178 protected void printLine () 179 throws java.io.IOException 180 { 181 for (int i = 1; i <= columnCount; i++) 182 { 183 try 184 { 185 if (i != 1) { output.print(","); } 186 int columnType = rsmd.getColumnType(i); 187 if (columnType == Types.VARCHAR || columnType == Types.CHAR || 188 columnType == Types.LONGVARCHAR) 189 { 190 String working = rs.getString(i); 191 if (rs.wasNull()) { working = new String(); } 192 output.print(formatString(working, i)); 193 } 194 else if (columnType == Types.FLOAT || columnType == Types.REAL || 195 columnType == Types.DOUBLE) 196 { 197 double working = rs.getDouble(i); 198 if (rs.wasNull()) 199 { output.print(new String()); } 200 else 201 { output.print(formatDouble(working)); } 202 } 203 else if (columnType == Types.TINYINT || columnType == Types.SMALLINT || 204 columnType == Types.INTEGER || columnType == Types.BIGINT) 205 { 206 int working = rs.getInt(i); 207 if (rs.wasNull()) 208 { output.print(new String()); } 209 else 210 { output.print(formatInteger(working)); } 211 } 212 else if (columnType == Types.TIMESTAMP) 213 { 214 java.sql.Timestamp working = rs.getTimestamp(i); 215 if (rs.wasNull()) 216 { output.print(new String()); } 217 else 218 { 219 java.util.Date date = new java.util.Date(working.getTime()); 220 output.print(formatDateTime(date)); 221 } 222 } 223 else 224 /* 225 ** Haven't decided how to handle Types.DECIMAL and 226 ** TYPES.GENERIC. However, this may be academic as I don't 227 ** think that these will occur in the databases 228 ** that I will be using. 229 */ 230 { 231 String working = rs.getString(i); 232 if (rs.wasNull()) 233 { output.print(new String()); } 234 else 235 { output.print(working); } 236 } 237 } 238 catch (Exception e) 239 { throw new java.io.IOException("Error detected in column " + 240 Integer.toString(i) + ":" + 241 e.getClass().getName() + " : " + 242 e.getMessage()); } 243 } 244 try 245 { output.print("\r\n"); } 246 catch (Exception e) 247 { throw new java.io.IOException("Error detected: " + 248 e.getClass().getName() + " : " + 249 e.getMessage()); } 250 } 251 /** 252 * Method of calling formatString when it doesn't 253 * depend on the column in the result set. 254 * @param valueIn String to be processed 255 * @return Processed string 256 */ 257 protected String formatString(String valueIn) 258 { return formatString(valueIn, 1); } 259 /** 260 * Double up on all double quotes in string and surround the string with 261 * double quotes so that it will be in the proper format for the CSV file. 262 * @param valueIn String to be processed 263 * @param column Column number of item (not used unless method overriden) 264 * @return Processed string 265 */ 266 protected String formatString(String valueIn, int column) 267 { 268 String working = null; 269 if (valueIn == null) 270 { working = " "; } 271 else if (valueIn.length() == 0) 272 { working = " "; } 273 else 274 { 275 java.util.regex.Pattern pattern = java.util.regex.Pattern.compile("\\\""); 276 java.util.regex.Matcher matcher = pattern.matcher(valueIn); 277 working = matcher.replaceAll("\"\""); 278 } 279 if (working == null) { working = " "; } 280 return "\"" + working + "\""; 281 } 282 /** 283 * Alternate calling sequence, leaving out the column number. 284 * @param valueIn Floating point number to be formatted 285 * @return Formatted string 286 */ 287 protected String formatDouble (double valueIn) 288 { return formatDouble (valueIn, 1); } 289 /** 290 * Formatter for floating point numbers. 291 * <p>This method can be overridden to control printing of 292 * the values in the CSV file.</p> 293 * @param valueIn Floating point number to be processed 294 * @param column Column number 295 * @return Formatted string 296 */ 297 protected String formatDouble (double valueIn, int column) 298 { return Double.toString(valueIn); } 299 /** 300 * Alternate calling sequence, omitting the column number. 301 * @param valueIn Integer value to be formatted 302 * @return Formatted string 303 */ 304 protected String formatInteger (int valueIn) 305 { return formatInteger(valueIn, 1); } 306 /** 307 * Formatter for integer values. 308 * <p>This method can be overridden to control printing of 309 * the values in the CSV file.</p> 310 * @param valueIn Integer to be formatted 311 * @param column Column number 312 * @return Formatted string 313 */ 314 protected String formatInteger (int valueIn, int column) 315 { return Integer.toString(valueIn); } 316 /** 317 * Alternate calling sequence, leaving out the column number 318 * @param valueIn java.util.Date object containing date and time 319 * @return Formatted string 320 */ 321 protected String formatDateTime (java.util.Date valueIn) 322 { return formatDateTime(valueIn, 1); } 323 /** 324 * Formatter for values involving date and time. 325 * <p>This method can be overridden to control printing of 326 * the values in the CSV file.</p> 327 * @param valueIn java.util.Date object containing date and time 328 * @param column Column number 329 * @return Formatted string 330 */ 331 protected String formatDateTime (java.util.Date valueIn, int column) 332 { 333 java.text.SimpleDateFormat format = new java.text.SimpleDateFormat("MM/dd/yyyy HH:mm"); 334 return format.format(valueIn); 335 } 336 }