001package bradleyross.j2ee.servlets; 002import bradleyross.library.helpers.StringHelpers; 003import java.io.Serializable; 004import java.io.IOException; 005import javax.servlet.ServletConfig; 006import javax.servlet.http.HttpServlet; 007import javax.servlet.http.HttpServletRequest; 008import javax.servlet.http.HttpServletResponse; 009import javax.servlet.ServletException; 010import java.sql.Date; 011import java.sql.PreparedStatement; 012import java.sql.ResultSet; 013import java.sql.SQLException; 014import java.sql.Types; 015import java.text.NumberFormat; 016/** 017 * Superclass for servlets. 018 * 019 * @author Bradley Ross 020 * @see bradleyross.library.helpers.ServletHelpers 021 * 022 */ 023public abstract class Servlet extends HttpServlet 024{ 025 /** 026 * Inserted for debugging; 027 */ 028 public Servlet() 029 { ; } 030 /** 031 * This class is placed here so that the programmer can subclass either 032 * Servlet.ThisPage or bradleyross.library.servlets.ThisPage. 033 * 034 * @author Bradley Ross 035 * 036 */ 037 public class ThisPage extends bradleyross.j2ee.servlets.ThisPage 038 { 039 /** 040 * Constructor provided to allow subclassing. 041 */ 042 public ThisPage() 043 { ; } 044 /** 045 * Initializes the object with information about the HTTP transaction. 046 * @param request HttpServletRequest object 047 * @param response HttpServletResponse object 048 * @param config ServletConfig object 049 * @throws IOException 050 */ 051 public ThisPage(HttpServletRequest request, HttpServletResponse response, ServletConfig config) 052 throws IOException 053 { 054 super(request, response, config); 055 } 056 } 057 /** 058 * Added to satisfy Serializable interface. 059 * @see Serializable 060 */ 061 private static final long serialVersionUID = 1L; 062 /** 063 * Information on the configuration of the servlet. 064 * 065 * <p>This is used to pass information from the {@link #init(ServletConfig) } method to the 066 * other methods in the class.</p> 067 */ 068 private ServletConfig config = null; 069 /** 070 * Called when initializing the object for handling HTTP 071 * transactions. 072 * @param configValue Servlet configuration object 073 * @throws ServletException 074 */ 075 public void init(ServletConfig configValue) throws ServletException 076 { 077 config = configValue; 078 } 079 /** 080 * Obtains servlet configuration information. 081 * @return servlet configuration object 082 */ 083 public ServletConfig getConfig() 084 { 085 return config; 086 } 087 /** 088 * Carries out processing for a HTTP transaction. 089 * 090 * @see #starter(ThisPage) 091 * @see #processor(ThisPage) 092 * @see #ender(ThisPage) 093 * 094 * @param requestValue Request object 095 * @param responseValue Response object 096 * @throws IOException 097 */ 098 public void service (HttpServletRequest requestValue, HttpServletResponse responseValue) 099 throws IOException 100 { 101 ThisPage thisPage = new ThisPage (requestValue, responseValue, getConfig()); 102 starter(thisPage); 103 if (thisPage.getTerminateRequest()) 104 { return; } 105 processor(thisPage); 106 if (thisPage.getTerminateRequest()) 107 { return; } 108 ender(thisPage); 109 if (thisPage.getTerminateRequest()) 110 { return; } 111 String address = thisPage.getRedirectAddress(); 112 if (address != null) 113 { 114 thisPage.getResponse().sendRedirect(thisPage.getResponse().encodeRedirectURL(address)); 115 } 116 } 117 /** 118 * Processing before calling processor method. 119 * 120 * <p>This method can be overridden in subclasses to provide a class 121 * that carries out the desired operation for a group of classes.</p> 122 * 123 * @see #processor(ThisPage) 124 * @param thisPage Information on this HTTP transaction 125 * @throws IOException 126 */ 127 public void starter(ThisPage thisPage) throws IOException 128 { 129 if (thisPage != null) 130 { 131 thisPage.addMessage("Running Servlet.starter(ThisPage)"); 132 thisPage.addMessage("This is a dummy stub that doesn't do any work"); 133 } 134 } 135 /** 136 * Processing after calling processor method. 137 * 138 * <p>This method can be overridden in subclasses to provide a class 139 * that carries out the desired operation for a group of classes.</p> 140 * 141 * @see #processor(ThisPage) 142 * @param thisPage Information on this HTTP transaction 143 * @throws IOException 144 */ 145 public void ender(ThisPage thisPage) throws IOException 146 { 147 if (thisPage != null) 148 { 149 thisPage.addMessage("Running Servlet.ender"); 150 thisPage.addMessage("This is a dummy stub that doesn't do any work"); 151 } 152 } 153 /** 154 * Class specific processing for this class. 155 * 156 * @param thisPage Information on this HTTP transaction 157 * @throws IOException 158 */ 159 protected abstract void processor(ThisPage thisPage) throws IOException; 160 /** 161 * Construct an SQL date using the year, month, and day 162 * @param yearValue Year (4 digit) 163 * @param monthValue Number of Month (January = 1) 164 * @param dayValue Day of month 165 * @return SQL date 166 */ 167 protected Date buildDate(String yearValue, String monthValue, String dayValue) 168 { 169 int year = -1; 170 int month = -1; 171 int day = -1; 172 Date working = null; 173 try 174 { 175 year = Integer.parseInt(yearValue.trim()); 176 month = Integer.parseInt(monthValue.trim()); 177 day = Integer.parseInt(dayValue.trim()); 178 working = buildDate(year, month, day); 179 } 180 catch (NumberFormatException e) 181 { 182 throw new IllegalArgumentException ("buildDate unable to process " + yearValue + ":" + monthValue + ":" + dayValue); 183 } 184 return working; 185 } 186 /** 187 * Construct an SQL date using the year, month, and day 188 * @param year Year (4 digit) 189 * @param month Number of month (January = 1) 190 * @param day Day of month 191 * @return SQL date 192 */ 193 protected Date buildDate(int year, int month, int day) 194 { 195 NumberFormat format2 = NumberFormat.getIntegerInstance(); 196 NumberFormat format4 = NumberFormat.getIntegerInstance(); 197 format2.setMinimumIntegerDigits(2); 198 format2.setGroupingUsed(false); 199 format4.setMinimumIntegerDigits(4); 200 format4.setGroupingUsed(false); 201 return Date.valueOf(format4.format(year) + "-" + format2.format(month) + "-" + format2.format(day)); 202 } 203 /** 204 * Obtain date range from HTTP request. 205 * @see Date 206 * @param instance Object containing information for this HTTP request 207 */ 208 protected void setDateRange(ThisPage instance) 209 { 210 HttpServletRequest req = instance.getRequest(); 211 212 /* 213 * For the constructor for GregorianCalendar, January is 214 * month 0. 215 */ 216 Date start = buildDate 217 (req.getParameter("START_YEAR"), 218 req.getParameter("START_MONTH"), 219 req.getParameter("START_DAY")); 220 Date end = buildDate 221 (req.getParameter("END_YEAR"), 222 req.getParameter("END_MONTH"), 223 req.getParameter("END_DAY")); 224 instance.setStartDate(start); 225 instance.setEndDate(end); 226 } 227 /** 228 * Build a date in the java.sql.Date escape format. 229 * @param year Year as an integer 230 * @param month Month as an integer from 1 to 12 231 * @param day Day of month as an integer from 1 to 31 232 * @return Date in escape format 233 * @see Date#toString() 234 * <p>It appears that SQL Server is unable to handle dates before the 235 * year 1900.</p> 236 * @throws SQLException 237 */ 238 public static String buildEscapeDate(int year, int month, int day) throws IOException 239 { 240 if (year < 50) 241 { 242 year = year + 2000; 243 } 244 else if (year < 100) 245 { 246 year = year + 1900; 247 } 248 if (year < 1900 || year > 3000 || month < 1 || month > 12 || day < 1 || day > 31) 249 { 250 throw new IOException("Unable to convert year=" + 251 Integer.toString(year) + " month=" + 252 Integer.toString(month) + " day=" + Integer.toString(day) + 253 " java.sql.Date escape format"); 254 } 255 NumberFormat format2 = NumberFormat.getIntegerInstance(); 256 NumberFormat format4 = NumberFormat.getIntegerInstance(); 257 format2.setMinimumIntegerDigits(2); 258 format2.setGroupingUsed(false); 259 format4.setMinimumIntegerDigits(4); 260 format4.setGroupingUsed(false); 261 return format4.format(year) + "-" + format2.format(month) + "-" + format2.format(day); 262 } 263 /** 264 * Build a date in the java.sql.Date escape format. 265 * @param year String containing the year as an integer 266 * @param month String containing the month as an integer from 1 to 12 267 * @param day String containing the day of month as an integer from 1 to 31 268 * @return Date in escape format 269 * @see Date#toString() 270 * @throws IOException 271 */ 272 public static String buildEscapeDate(String year, String month, String day) throws IOException 273 { 274 if (year == null) 275 { 276 throw new IOException("No parameter for year value"); 277 } 278 if (month == null) 279 { 280 throw new IOException("No parameter for month value"); 281 } 282 if (day == null) 283 { 284 throw new IOException("No parameter for day value"); 285 } 286 if (year.trim().length() == 0 && month.trim().length() == 0 && day.trim().length() == 0) 287 { 288 return "0000-00-00"; 289 } 290 int yearValue = -1; 291 int monthValue = -1; 292 int dayValue = -1; 293 try 294 { 295 yearValue = Integer.parseInt(year.trim()); 296 monthValue = Integer.parseInt(month.trim()); 297 dayValue = Integer.parseInt(day.trim()); 298 } 299 catch (Exception e) 300 { 301 throw new IOException("Unable to convert year=" + 302 year + " month=" + 303 month + " day=" + day + 304 " java.sql.Date escape format"); 305 } 306 return buildEscapeDate(yearValue, monthValue, dayValue); 307 } 308 /** 309 * Generate an SQL escape date. 310 * @param date SQL date 311 * @return SQL escape date 312 */ 313 public static String buildEscapeDate(java.sql.Date date) 314 { 315 if (date == null) 316 { 317 return "0000-00-00"; 318 } 319 else 320 { 321 return date.toString(); 322 } 323 } 324 /** 325 * Build a date in the java.sql.Date escape format. 326 * @param year Year as an integer 327 * @param month Month as an integer from 1 to 12 328 * @param day Day of month as an integer from 1 to 31 329 * @param defaultDate Date to use if error in processing 330 * @return Date in escape format 331 * @see Date#toString() 332 * <p>It appears that SQL Server is unable to handle dates before the 333 * year 1900.</p> 334 * @throws SQLException 335 */ 336 public static String buildEscapeDate(int year, int month, int day, String defaultDate) throws IOException 337 { 338 if (year < 50) 339 { 340 year = year + 2000; 341 } 342 else if (year < 100) 343 { 344 year = year + 1900; 345 } 346 if (year < 1900 || year > 3000 || month < 1 || month > 12 || day < 1 || day > 31) 347 { 348 return defaultDate; 349 } 350 NumberFormat format2 = NumberFormat.getIntegerInstance(); 351 NumberFormat format4 = NumberFormat.getIntegerInstance(); 352 format2.setMinimumIntegerDigits(2); 353 format2.setGroupingUsed(false); 354 format4.setMinimumIntegerDigits(4); 355 format4.setGroupingUsed(false); 356 return format4.format(year) + "-" + format2.format(month) + "-" + format2.format(day); 357 } 358 /** 359 * Build a date in the java.sql.Date escape format. 360 * @param year String containing the year as an integer 361 * @param month String containing the month as an integer from 1 to 12 362 * @param day String containing the day of month as an integer from 1 to 31 363 * @param defaultDate Date to use if error in processing 364 * @return Date in escape format 365 * @see Date#toString() 366 * @throws IOException 367 */ 368 public static String buildEscapeDate(String year, String month, String day, String defaultDate) throws IOException 369 { 370 if (year == null || month == null || day == null) 371 { 372 return defaultDate; 373 } 374 if (year.trim().length() == 0 || month.trim().length() == 0 || day.trim().length() == 0) 375 { 376 return defaultDate; 377 } 378 int yearValue = -1; 379 int monthValue = -1; 380 int dayValue = -1; 381 try 382 { 383 yearValue = Integer.parseInt(year.trim()); 384 monthValue = Integer.parseInt(month.trim()); 385 dayValue = Integer.parseInt(day.trim()); 386 } 387 catch (Exception e) 388 { 389 return defaultDate; 390 } 391 return buildEscapeDate(yearValue, monthValue, dayValue); 392 } 393 /** 394 * Break a java.sql.Date escape format date into a set of 395 * string objects for the year, month, and day portions. 396 * @see Date#toString() 397 * @param escapeDate Date to be parsed 398 * @return Array of strings 399 */ 400 public static String[] parseEscapeDate(String escapeDate) 401 { 402 String working[] = new String[3]; 403 if (escapeDate == null) 404 { 405 working[0] = new String(); 406 working[1] = new String(); 407 working[2] = new String(); 408 } 409 else if (escapeDate.equals("0000-00-00")) 410 { 411 working[0] = " value=\" \" "; 412 working[1] = " value=\" \" "; 413 working[2] = " value=\" \" "; 414 } 415 416 else if (escapeDate.trim().length() < 10) 417 { 418 working[0] = new String(); 419 working[1] = new String(); 420 working[2] = new String(); 421 } 422 else 423 { 424 working[0] = " value=\"" + escapeDate.substring(0, 4) + "\" "; 425 working[1] = " value=\"" + escapeDate.substring(5, 7) + "\" "; 426 working[2] = " value=\"" + escapeDate.substring(8) + "\" "; 427 } 428 return working; 429 } 430 431 432 433 /** 434 * Utility method for setting parameters in Prepared Statements. 435 * <p>For CHAR data types.</p> 436 * @param stmt PreparedStatement object 437 * @param location Number of parameter 438 * @param value Value to be loaded in parameter 439 * @throws SQLException 440 */ 441 protected void loadChar(PreparedStatement stmt, int location, String value) throws SQLException 442 { 443 if (stmt == null) 444 { 445 throw new SQLException("PreparedStatement object has null value"); 446 } 447 if (location < 0) 448 { 449 throw new SQLException("Negative number for parameter number in prepared statement"); 450 } 451 if (value == null) 452 { 453 stmt.setNull(location, Types.CHAR ); 454 } 455 else if (value.trim().length() == 0) 456 { 457 stmt.setNull(location, Types.CHAR); 458 } 459 else 460 { 461 stmt.setString(location, value); 462 } 463 } 464 /** 465 * Utility method for setting parameters in Prepared Statements. 466 * <p>For VARCHAR data types.</p> 467 * @param stmt PreparedStatement object 468 * @param location Number of parameter 469 * @param value Value to be loaded in parameter 470 * @throws SQLException 471 */ 472 protected void loadVarchar(PreparedStatement stmt, int location, String value) throws SQLException 473 { 474 if (value == null) 475 { 476 stmt.setNull(location, Types.VARCHAR ); 477 } 478 else if (value.trim().length() == 0) 479 { 480 stmt.setNull(location, Types.VARCHAR); 481 } 482 else 483 { 484 stmt.setString(location, value); 485 } 486 } 487 /** 488 * Utility to aid in creating option lists for pull-down 489 * menus. 490 * @param value1 First string to be compared 491 * @param value2 Second string to be compared 492 * @return The word SELECTED if the two strings match, otherwise 493 * a blank. 494 */ 495 public static String matchValues(String value1, String value2) 496 { 497 if (value1 == null || value2 == null) 498 { 499 return " "; 500 } 501 else if (value1.equalsIgnoreCase(value2)) 502 { 503 return " selected=\"selected\" "; 504 } 505 else 506 { 507 return " "; 508 } 509 } 510 /** 511 * Obtains a value from a result set for use as the value attribute of a 512 * input element of type text. 513 * @param rs Result set 514 * @param name Name of column in result set 515 * @return Text string for value attribute. 516 */ 517 public static String getTextValue(ResultSet rs, String name) 518 { 519 try { 520 String working = rs.getString(name); 521 if (rs.wasNull()) 522 { return new String(); } 523 else if (working.length() == 0) 524 { return new String(); } 525 else 526 { return "value=\"" + StringHelpers.escapeHTML(working) + "\""; } 527 } catch (SQLException e) 528 { return new String(); } 529 } 530 /** 531 * Obtains a value from a result set for use as the starting value of a 532 * Textarea element. 533 * @see StringHelpers#escapeHTML(String, String) 534 * @param rs Result set 535 * @param name Name of column in result set 536 * @return Text string for Textarea tag. 537 */ 538 public static String getTextareaValue(ResultSet rs, String name) 539 { 540 try 541 { 542 String working = rs.getString(name); 543 if (rs.wasNull()) 544 { return new String(); } 545 else if (working.trim().length() == 0) 546 { return new String(); } 547 else 548 { return StringHelpers.escapeHTML(working, "TEXTAREA"); } 549 } 550 catch (SQLException e) 551 { return new String(); } 552 } 553 /** 554 * Returns the string for a non-breaking space if a string 555 * column in a table is null or blank, otherwise returns an 556 * escaped string. 557 * @param rs Result set containing value 558 * @param name Name of column 559 * @return Processed string for insertion in web page 560 */ 561 public static String getString(ResultSet rs, String name) 562 { 563 try 564 { 565 String working = rs.getString(name); 566 if (rs.wasNull()) 567 { return " "; } 568 else if (working.trim().length() == 0) 569 { return " "; } 570 else 571 { return StringHelpers.escapeHTML(working); } 572 } 573 catch (SQLException e) 574 { 575 return new String(); 576 } 577 } 578 /** 579 * Internal debugging aid for checking parseEscapeDate. 580 * @param value String to be parsed 581 * @see #parseEscapeDate(String) 582 */ 583 protected static void innerTest(String value) 584 { 585 String test[] = parseEscapeDate(value); 586 System.out.print(value); 587 for (int i = 0; i < test.length; i++) 588 { 589 System.out.print(" " + test[i]); 590 } 591 System.out.println(); 592 } 593 /** 594 * This was inserted for testing of some of the internal static methods 595 * and is only for debugging purposes. 596 * 597 * @param args Not used 598 */ 599 public static void main(String args[]) 600 { 601 String test[] = { "2009-09-09", "0000-00-00"}; 602 for (int i = 0; i < test.length; i++) 603 { innerTest(test[i]); } 604 } 605}