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 if io errors
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 when problems with servlet arise
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 for io problems
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 for io problems
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 for io problems
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 for io problems
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 IOException for io problems
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 for io problems
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 IOException for io problems
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 for io problems
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 if problems in SQL statement
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 for SQL problems
471         * @throws IOException for io problems
472         */
473        protected void loadVarchar(PreparedStatement stmt, int location, String value) throws SQLException, IOException
474        {
475                if (value == null)
476                {
477                        stmt.setNull(location, Types.VARCHAR );
478                }
479                else if (value.trim().length() == 0)
480                {
481                        stmt.setNull(location, Types.VARCHAR);
482                }
483                else
484                {
485                        stmt.setString(location, value);
486                }
487        }
488        /**
489         * Utility to aid in creating option lists for pull-down
490         * menus.
491         * @param value1 First string to be compared
492         * @param value2 Second string to be compared
493         * @return The word SELECTED if the two strings match, otherwise
494         *         a blank.
495         */
496        public static String matchValues(String value1, String value2)
497        {
498                if (value1 == null || value2 == null)
499                {
500                        return " ";
501                }
502                else if (value1.equalsIgnoreCase(value2))
503                {
504                        return " selected=\"selected\" ";
505                }
506                else
507                {
508                        return " ";
509                }
510        }
511        /**
512         * Obtains a value from a result set for use as the value attribute of a
513         * input element of type text.
514         * @param rs Result set
515         * @param name Name of column in result set
516         * @return Text string for value attribute.
517         */
518        public static String getTextValue(ResultSet rs, String name)
519        {
520                try {
521                        String working = rs.getString(name);
522                        if (rs.wasNull())
523                        {       return new String();    }
524                        else if (working.length() == 0)
525                        {       return new String();    }
526                        else 
527                        { return "value=\"" + StringHelpers.escapeHTML(working) + "\""; }
528                } catch (SQLException e)
529                { return new String();  }
530        }
531        /**
532         * Obtains a value from a result set for use as the starting value of a
533         * Textarea element.
534         * @see StringHelpers#escapeHTML(String, String)
535         * @param rs Result set
536         * @param name Name of column in result set
537         * @return Text string for Textarea tag.
538         */
539        public static String getTextareaValue(ResultSet rs, String name)
540        {
541                try 
542                {
543                        String working = rs.getString(name);
544                        if (rs.wasNull())
545                        { return new String(); }
546                        else if (working.trim().length() == 0)
547                        {  return new String(); }
548                        else 
549                        { return StringHelpers.escapeHTML(working, "TEXTAREA"); }
550                } 
551                catch (SQLException e)
552                { return new String(); }
553        }
554        /**
555         * Returns the string for a non-breaking space if a string
556         * column in a table is null or blank, otherwise returns an
557         * escaped string.
558         * @param rs Result set containing value
559         * @param name Name of column
560         * @return Processed string for insertion in web page
561         */
562        public static String getString(ResultSet rs, String name)
563        {
564                try
565                {
566                        String working = rs.getString(name);
567                        if (rs.wasNull())
568                        { return "&nbsp;"; }
569                        else if (working.trim().length() == 0)
570                        { return "&nbsp;"; }
571                        else
572                        { return StringHelpers.escapeHTML(working); }
573                }
574                catch (SQLException e)
575                {
576                        return new String(); 
577                }
578        }
579        /**
580         * Internal debugging aid for checking parseEscapeDate.
581         * @param value String to be parsed
582         * @see #parseEscapeDate(String)
583         */
584        protected static void innerTest(String value)
585        {
586                String test[] = parseEscapeDate(value);
587                System.out.print(value);
588                for (int i = 0; i < test.length; i++)
589                {
590                        System.out.print(" " + test[i]);
591                }
592                System.out.println();
593        }
594        /**
595         * This was inserted for testing of some of the internal static methods
596         * and is only for debugging purposes.
597         * 
598         * @param args Not used
599         */
600        public static void main(String args[])
601        {
602                String test[] = { "2009-09-09", "0000-00-00"};
603                for (int i = 0; i < test.length; i++)
604                { innerTest(test[i]); }
605        }
606}