classes/hirondelle/web4j/readconfig/Config.java
changeset 0 3060119b1292
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/classes/hirondelle/web4j/readconfig/Config.java	Wed Dec 04 17:00:31 2013 +0100
@@ -0,0 +1,597 @@
+package hirondelle.web4j.readconfig;
+
+import hirondelle.web4j.database.ConnectionSource;
+import hirondelle.web4j.database.TxIsolationLevel;
+import hirondelle.web4j.util.Util;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Calendar;
+import java.util.Collections;
+import java.util.LinkedHashMap;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Set;
+import java.util.StringTokenizer;
+import java.util.TimeZone;
+import java.util.regex.Pattern;
+
+/**
+ (UNPUBLISHED) Access the config values needed by the framework.
+ 
+ <P>Assumptions:
+ <ul> 
+  <li><tt>init</tt> is called only once, upon startup, when the system is in single-threaded mode
+  <li>there is no re-init or reload mechanism
+  <li>after <tt>init</tt> is called, the data will never change, and this class is safe to be used 
+  in a multi-threaded environment
+  <li>all data returned by the getXXX methods is immutable, or a defensive copy is passed
+ </ul>  
+ 
+ <P>The typical user of this class is simple:
+<pre>Config config = new Config();
+  String blah = config.getBlah;
+</pre>
+ The caller usually has no need to store the data in their own static private field.
+ 
+  <P>The hard-coding in this class is desirable and necessary. Note that it makes no 
+  sense to add config items at runtime, since no code will be able to talk to it. 
+  
+  <P>Default values are defined internally by this class. Callers performing tests 
+  may use default values, or they may override any number of default values by calling <tt>init</tt>.
+  There is no method to revert to the original defaults.
+  
+  <P>
+   When an app as a whole is reloaded, it's a full reload, with new classes/classloaders.
+   When the Deployment Descriptor (DD) is touched, often the app reloads partially, with the same classes/classloaders, 
+   but a new Servlet object. (This depends on the Container.) 
+   Thus, static blocks are not re-executed in that case.
+    
+   <P>This means that classes should not copy/store data from Config in a static block, since that static block
+   will not see partial reloads (tweaks to the DD). This is a bit tricky.
+   As well, any 'first-use-initialization' logic in class X cannot talk to the config, since it will not be executed on a partial reload.
+   
+   <P>If all the parsing/caching is done by this class, then callers don't have to worry about partial reloads, and whether or 
+   not they are out of date. In addition, if the syntax is the same, then the parsing is centralized here.
+*/
+public final class Config {
+
+  /** Value - {@value} - special value for some settings, denoting an absent value. */
+  public static final String NONE = "NONE";
+  
+   /* NOTE: Most of this code was generated by a one-off script. */
+  
+  /**
+   Must be called once and only once, upon startup, when the system is in 
+   single-threaded mode. Throws an exception if a problem with the syntax is detected.
+   
+   <P>Note than this takes a generic map, not <tt>ServletContext</tt>. That's important, 
+   since it allows this Config to be used in any context, not just a servlet container.
+   <P>The key is case-sensitive.
+  */
+  public static void init(Map<String, String> aKeyValuePairs){
+    initAllItems(aKeyValuePairs);
+  }
+
+  /** 
+   Confirm that database settings in <tt>web.xml</tt> are known to {@link ConnectionSource}.
+   Order dependency: this method is called after <tt>init</tt>, since it needs to know the database names, 
+   which in turn requires a call to BuildImpl.init.   
+  */
+  public static void checkDbNamesInSettings(Set<String> aValidDbNames){
+    Set<String> namesInSettings = new LinkedHashSet<String>(); 
+    
+    namesInSettings.addAll(fHasAutoGeneratedKeys.getDbNames());
+    namesInSettings.addAll(fSqlFetcherDefaultTxIsolationLevel.getDbNames());
+    namesInSettings.addAll(fSqlEditorDefaultTxIsolationLevel.getDbNames());
+    namesInSettings.addAll(fErrorCodeForDuplicateKey.getDbNames());
+    namesInSettings.addAll(fErrorCodeForForeignKey.getDbNames());
+    namesInSettings.addAll(fMaxRows.getDbNames());
+    namesInSettings.addAll(fFetchSize.getDbNames());
+    namesInSettings.addAll(fIsSQLPrecompilationAttempted.getDbNames());
+    namesInSettings.addAll(fDateTimeFormatForPassingParamsToDb.getDbNames());
+    
+    Set<String> unknownNames = new LinkedHashSet<String>();
+    for(String name: namesInSettings){
+      if(Util.textHasContent(name) && ! aValidDbNames.contains(name)){
+        unknownNames.add(name);
+      }
+    }
+    
+    if(! unknownNames.isEmpty() ) {
+       throw new IllegalArgumentException("Web.xml contains settings that refer to databases that are not known to your implementation of ConnectionSource.getDatabaseNames(). Please check spelling and case for : " + Util.logOnePerLine(unknownNames));
+    }
+  }
+  
+  /** Intended for logging and trouble tickets. */
+  public Map<String, String> getRawMap(){
+    return Collections.unmodifiableMap(fMap);
+  }
+  
+  public Boolean isTesting(){
+    return fIsTesting;
+  }
+  
+  /** Value is present, and is not 'NONE'. */
+  public boolean isEnabled(String aValue){
+    return Util.textHasContent(aValue) && ! NONE.equalsIgnoreCase(aValue);
+  }
+  
+  public String getWebmaster(){
+    return fWebmaster;
+  }
+  
+  public String getImplicitMappingRemoveBasePackage(){
+    return fImplicitMappingRemoveBasePackage;
+  }
+  
+  public String getMailServerConfig(){
+    return fMailServerConfig;
+  }
+
+  public String getMailServerCredentials(){
+    return fMailServerCredentials;
+  }
+
+  public String getLoggingDirectory (){
+    return fLoggingDirectory;
+  }
+
+  public List<String> getLoggingLevels(){
+    return fLoggingLevels;
+  }
+
+  public List<String> getTroubleTicketMailingList(){
+    return Collections.unmodifiableList(fTroubleTicketMailingList);
+  }
+  
+  public Long getMinimumIntervalBetweenTroubleTickets(){
+    return fMinimumIntervalBetweenTroubleTickets;
+  }
+
+  /** Returns the value in nanos, not seconds. */
+  public Long getPoorPerformanceThreshold(){
+    long NANOSECONDS_PER_SECOND = 1000 *1000 * 1000;
+    return fPoorPerformanceThreshold  * NANOSECONDS_PER_SECOND;
+  }
+
+  public Long getMaxHttpRequestSize(){
+    return fMaxHttpRequestSize;
+  }
+
+  public Long getMaxFileUploadRequestSize(){
+    return fMaxFileUploadRequestSize;
+  }
+
+  public Long getMaxRequestParamValueSize(){
+    return fMaxRequestParamValueSize;
+  }
+
+  public Boolean getSpamDetectionInFirewall(){
+    return fSpamDetectionInFirewall;
+  }
+
+  public Boolean getFullyValidateFileUploads(){
+    return fFullyValidateFileUploads;
+  }
+
+  public Boolean getAllowStringAsBuildingBlock(){
+    return fAllowStringAsBuildingBlock;
+  }
+
+  public Map<String, List<String>> getUntrustedProxyForUserId(){
+    return fUntrustedProxyForUserId;
+  }
+
+  public String getCharacterEncoding(){
+    return fCharacterEncoding;
+  }
+
+  public Locale getDefaultLocale(){
+    return fDefaultLocale;
+  }
+
+  public TimeZone getDefaultUserTimeZone(){
+    return TimeZone.getTimeZone(fDefaultUserTimeZone.getID()); //mutable class
+  }
+
+  public Boolean hasTimeZoneHint(){ 
+    return fTimeZoneHint != null;
+  }
+  
+  public Calendar getTimeZoneHint(){
+    Calendar result = null;
+    if( hasTimeZoneHint() ) {
+      result = Calendar.getInstance(fTimeZoneHint);
+    }
+    return result;
+  }
+
+  //this could be deleted ? - no callers
+  public String getDecimalSeparator(){
+    return fDecimalSeparator;
+  }
+  
+  public Pattern getDecimalInputPattern(){
+    return fDecimalInputPattern; //derived from decimal separator
+  }
+
+  public String getBigDecimalDisplayFormat(){
+    return fBigDecimalDisplayFormat;
+  }
+
+  public String getBooleanTrueDisplayFormat(){
+    return fBooleanTrueDisplayFormat;
+  }
+
+  public String getBooleanFalseDisplayFormat(){
+    return fBooleanFalseDisplayFormat;
+  }
+
+  public String getEmptyOrNullDisplayFormat(){
+    return fEmptyOrNullDisplayFormat;
+  }
+
+  public String getIntegerDisplayFormat(){
+    return fIntegerDisplayFormat;
+  }
+
+  public String getIgnorableParamValue(){
+    return fIgnorableParamValue;
+  }
+
+  public Boolean getIsSQLPrecompilationAttempted(String aDbName){
+    return asBoolean(fIsSQLPrecompilationAttempted.getValue(aDbName));
+  }
+
+  public Integer getMaxRows(String aDbName){
+    return asInteger(fMaxRows.getValue(aDbName));
+  }
+
+  public Integer getFetchSize(String aDbName){
+    return asInteger(fFetchSize.getValue(aDbName));
+  }
+
+  public Boolean getHasAutoGeneratedKeys(String aDbName){
+    return asBoolean(fHasAutoGeneratedKeys.getValue(aDbName));
+  }
+
+  public List<Integer> getErrorCodesForDuplicateKey(String aDbName){
+    return asIntegerList(fErrorCodeForDuplicateKey.getValue(aDbName));
+  }
+
+  public List<Integer> getErrorCodesForForeignKey(String aDbName){
+    return asIntegerList(fErrorCodeForForeignKey.getValue(aDbName));
+  }
+
+  public TxIsolationLevel getSqlFetcherDefaultTxIsolationLevel(String aDbName){
+    return TxIsolationLevel.valueOf(fSqlFetcherDefaultTxIsolationLevel.getValue(aDbName));
+  }
+
+  public TxIsolationLevel getSqlEditorDefaultTxIsolationLevel(String aDbName){
+    return TxIsolationLevel.valueOf(fSqlEditorDefaultTxIsolationLevel.getValue(aDbName));
+  }
+
+  public String getDateFormat(String aDbName){
+    return asDateTimeFormat(fDateTimeFormatForPassingParamsToDb.getValue(aDbName), 0);
+  }
+  
+  public String getTimeFormat(String aDbName){
+    return asDateTimeFormat(fDateTimeFormatForPassingParamsToDb.getValue(aDbName), 1);
+  }
+  
+  public String getDateTimeFormat(String aDbName){
+    return asDateTimeFormat(fDateTimeFormatForPassingParamsToDb.getValue(aDbName), 2);
+  }
+
+  // PRIVATE 
+  
+  private static List<String> fErrors = new ArrayList<String>();
+  
+  private static void initAllItems(Map<String, String> aKeyValuePairs) {
+    fMap = aKeyValuePairs;
+    
+    fWebmaster = initThisStringNoDefault("Webmaster", aKeyValuePairs);
+    fImplicitMappingRemoveBasePackage = initThisStringNoDefault("ImplicitMappingRemoveBasePackage", aKeyValuePairs);
+    
+    if (hasValue("MailServerConfig", aKeyValuePairs)) {
+      fMailServerConfig = initThisString("MailServerConfig", aKeyValuePairs);
+    }
+    if (hasValue("MailServerCredentials", aKeyValuePairs)) {
+      fMailServerCredentials = initThisString("MailServerCredentials", aKeyValuePairs);
+    }
+    if (hasValue("LoggingDirectory", aKeyValuePairs)) {
+      fLoggingDirectory = initThisString("LoggingDirectory", aKeyValuePairs);
+    }
+    if (hasValue("LoggingLevels", aKeyValuePairs)) {
+      fLoggingLevels = initThisStringList("LoggingLevels", aKeyValuePairs);
+    }
+    if (hasValueNotNone("TroubleTicketMailingList", aKeyValuePairs)) {
+      fTroubleTicketMailingList = initThisStringList("TroubleTicketMailingList", aKeyValuePairs);
+    }
+    if (hasValue("MinimumIntervalBetweenTroubleTickets", aKeyValuePairs)) {
+      fMinimumIntervalBetweenTroubleTickets = initThisLong("MinimumIntervalBetweenTroubleTickets", aKeyValuePairs);
+    }
+    if (hasValue("PoorPerformanceThreshold", aKeyValuePairs)) {
+      fPoorPerformanceThreshold = initThisLong("PoorPerformanceThreshold", aKeyValuePairs);
+    }
+    if (hasValue("MaxHttpRequestSize", aKeyValuePairs)) {
+      fMaxHttpRequestSize = initThisLong("MaxHttpRequestSize", aKeyValuePairs);
+      checkTooLow(fMaxHttpRequestSize, 1000L, "MaxHttpRequestSize");
+    }
+    if (hasValue("MaxFileUploadRequestSize", aKeyValuePairs)) {
+      fMaxFileUploadRequestSize = initThisLong("MaxFileUploadRequestSize", aKeyValuePairs);
+      checkTooLow(fMaxFileUploadRequestSize, 1000L, "MaxFileUploadRequestSize");
+    }
+    if (hasValue("MaxRequestParamValueSize", aKeyValuePairs)) {
+      fMaxRequestParamValueSize = initThisLong("MaxRequestParamValueSize", aKeyValuePairs);
+      checkTooLow(fMaxRequestParamValueSize, 1000L, "MaxRequestParamValueSize");
+    }
+    if (hasValue("SpamDetectionInFirewall", aKeyValuePairs)) {
+      fSpamDetectionInFirewall = initThisBoolean("SpamDetectionInFirewall", aKeyValuePairs);
+    }
+    if (hasValue("FullyValidateFileUploads", aKeyValuePairs)) {
+      fFullyValidateFileUploads = initThisBoolean("FullyValidateFileUploads", aKeyValuePairs);
+    }
+    if (hasValue("AllowStringAsBuildingBlock", aKeyValuePairs)) {
+      fAllowStringAsBuildingBlock = initThisBoolean("AllowStringAsBuildingBlock", aKeyValuePairs);
+    }
+    if (hasValue("UntrustedProxyForUserId", aKeyValuePairs)) {
+      ParseUntrustedProxy untrusted = new ParseUntrustedProxy();
+      fUntrustedProxyForUserId = untrusted.parse(aKeyValuePairs.get("UntrustedProxyForUserId"));
+    }
+    if (hasValue("CharacterEncoding", aKeyValuePairs)) {
+      fCharacterEncoding = initThisString("CharacterEncoding", aKeyValuePairs);
+    }
+    if (hasValue("DefaultLocale", aKeyValuePairs)) {
+      fDefaultLocale = initThisLocale("DefaultLocale", aKeyValuePairs);
+    }
+    if (hasValue("DefaultUserTimeZone", aKeyValuePairs)) {
+      fDefaultUserTimeZone = initThisTimeZone("DefaultUserTimeZone", aKeyValuePairs);
+    }
+    if (hasValueNotNone("TimeZoneHint", aKeyValuePairs)) {
+      fTimeZoneHint = initThisTimeZone("TimeZoneHint", aKeyValuePairs);
+    }
+    if (hasValue("DecimalSeparator", aKeyValuePairs)) {
+      fDecimalSeparator = initThisString("DecimalSeparator", aKeyValuePairs);
+      fDecimalInputPattern = fDecimalParser.getDecimalFormatPattern(fDecimalSeparator);
+    }
+    if (hasValue("BigDecimalDisplayFormat", aKeyValuePairs)) {
+      fBigDecimalDisplayFormat = initThisString("BigDecimalDisplayFormat", aKeyValuePairs);
+    }
+    if (hasValue("BooleanTrueDisplayFormat", aKeyValuePairs)) {
+      fBooleanTrueDisplayFormat = initThisString("BooleanTrueDisplayFormat", aKeyValuePairs);
+    }
+    if (hasValue("BooleanFalseDisplayFormat", aKeyValuePairs)) {
+      fBooleanFalseDisplayFormat = initThisString("BooleanFalseDisplayFormat", aKeyValuePairs);
+    }
+    if (hasValue("EmptyOrNullDisplayFormat", aKeyValuePairs)) {
+      fEmptyOrNullDisplayFormat = initThisString("EmptyOrNullDisplayFormat", aKeyValuePairs);
+    }
+    if (hasValue("IntegerDisplayFormat", aKeyValuePairs)) {
+      fIntegerDisplayFormat = initThisString("IntegerDisplayFormat", aKeyValuePairs);
+    }
+    if (hasValue("IgnorableParamValue", aKeyValuePairs)) {
+      fIgnorableParamValue = initThisString("IgnorableParamValue", aKeyValuePairs);
+    }
+    if (hasValue("IsSQLPrecompilationAttempted", aKeyValuePairs)) {
+      fIsSQLPrecompilationAttempted = initThisDbConfig("IsSQLPrecompilationAttempted", aKeyValuePairs);
+    }
+    if (hasValue("MaxRows", aKeyValuePairs)) {
+      fMaxRows = initThisDbConfig("MaxRows", aKeyValuePairs);
+    }
+    if (hasValue("FetchSize", aKeyValuePairs)) {
+      fFetchSize = initThisDbConfig("FetchSize", aKeyValuePairs);
+    }
+    if (hasValue("HasAutoGeneratedKeys", aKeyValuePairs)) {
+      fHasAutoGeneratedKeys = initThisDbConfig("HasAutoGeneratedKeys", aKeyValuePairs);
+    }
+    if (hasValue("ErrorCodeForDuplicateKey", aKeyValuePairs)) {
+      fErrorCodeForDuplicateKey = initThisDbConfig("ErrorCodeForDuplicateKey", aKeyValuePairs);
+    }
+    if (hasValue("ErrorCodeForForeignKey", aKeyValuePairs)) {
+      fErrorCodeForForeignKey = initThisDbConfig("ErrorCodeForForeignKey", aKeyValuePairs);
+    }
+    if (hasValue("SqlFetcherDefaultTxIsolationLevel", aKeyValuePairs)) {
+      fSqlFetcherDefaultTxIsolationLevel = initThisDbConfig("SqlFetcherDefaultTxIsolationLevel", aKeyValuePairs);
+    }
+    if (hasValue("SqlEditorDefaultTxIsolationLevel", aKeyValuePairs)) {
+      fSqlEditorDefaultTxIsolationLevel = initThisDbConfig("SqlEditorDefaultTxIsolationLevel", aKeyValuePairs);
+    }
+    if (hasValue("DateTimeFormatForPassingParamsToDb", aKeyValuePairs)) {
+      fDateTimeFormatForPassingParamsToDb = initThisDbConfig("DateTimeFormatForPassingParamsToDb", aKeyValuePairs);
+    }
+    if (hasValue("IsTesting", aKeyValuePairs)) {
+      fIsTesting = initThisBoolean("IsTesting", aKeyValuePairs);
+    }
+    
+    if (! fErrors.isEmpty()){
+      throw new RuntimeException("Errors in config data: " + fErrors);
+    }
+  }
+  
+  private static boolean hasValue(String aName,  Map<String, String> aKeyValuePairs){
+    return Util.textHasContent(aKeyValuePairs.get(aName));    
+  }
+  
+  private static boolean hasValueNotNone(String aName,  Map<String, String> aKeyValuePairs){
+    String value = aKeyValuePairs.get(aName);
+    return Util.textHasContent(value) && (! NONE.equalsIgnoreCase(value));    
+  }
+
+  private static String initThisString(String aName, Map<String, String> aKeyValuePairs){
+    return aKeyValuePairs.get(aName);
+  }
+  
+  private static Long initThisLong(String aName, Map<String, String> aKeyValuePairs){
+    return asLong(aKeyValuePairs.get(aName));
+  }
+  
+  private static TimeZone initThisTimeZone(String aName, Map<String, String> aKeyValuePairs){
+    return asTimeZone(aKeyValuePairs.get(aName));
+  }
+  
+  private static List<String> initThisStringList(String aName, Map<String, String> aKeyValuePairs){
+    return asStringListWithNone(aKeyValuePairs.get(aName));
+  }
+  
+  private static String initThisStringNoDefault(final String aName, final Map<String, String> aKeyValuePairs){
+    String result = aKeyValuePairs.get(aName);
+    if (! Util.textHasContent(result)){
+      fErrors.add(aName + " has no value set.");
+    }
+    return result;
+  }
+  
+  private static Boolean initThisBoolean(String aName, Map<String, String> aKeyValuePairs){
+    String value = aKeyValuePairs.get(aName);
+    return Util.parseBoolean(value);
+  }
+  
+  private static DbConfigParser initThisDbConfig(String aName, Map<String, String> aKeyValuePairs){
+    return new DbConfigParser(aKeyValuePairs.get(aName));
+  }
+
+  private static Locale initThisLocale(String aName, Map<String, String> aKeyValuePairs){
+    return asLocale(aKeyValuePairs.get(aName));
+  }
+  
+  /* These declares define the default value of each item, if any. */
+
+  //used for iteration over raw values (logging)
+  private static Map<String, String> fMap;
+  
+  private static String fWebmaster = ""; //no default
+  private static String fImplicitMappingRemoveBasePackage  = ""; //no default
+  
+  private static String fMailServerConfig = "NONE";
+  private static String fMailServerCredentials = "NONE";
+  private static String fLoggingDirectory = "NONE";
+  private static List<String> fLoggingLevels = Arrays.asList("hirondelle.web4j.level=CONFIG");
+  private static List<String> fTroubleTicketMailingList = Collections.emptyList();
+  private static Long fMinimumIntervalBetweenTroubleTickets = Long.valueOf(30);
+  private static Long fPoorPerformanceThreshold = 20L;
+  private static Long fMaxHttpRequestSize = 51200L;
+  private static Long fMaxFileUploadRequestSize = 51200L;
+  private static Long fMaxRequestParamValueSize = 51200L;
+  private static Boolean fSpamDetectionInFirewall = Boolean.FALSE;
+  private static Boolean fFullyValidateFileUploads = Boolean.FALSE;
+  private static Boolean fAllowStringAsBuildingBlock = Boolean.FALSE;
+  private static Map<String, List<String>> fUntrustedProxyForUserId =  new LinkedHashMap<String, List<String>>();
+  private static String fCharacterEncoding = "UTF-8";
+  private static Locale fDefaultLocale = Util.buildLocale("en");
+  private static TimeZone fDefaultUserTimeZone = TimeZone.getTimeZone("GMT");
+  private static TimeZone fTimeZoneHint; //default is null in this case
+  
+  // these 3 are related to each other
+  private static String fDecimalSeparator = "PERIOD";
+  private static ParseDecimalFormat fDecimalParser = new ParseDecimalFormat();
+  private static Pattern fDecimalInputPattern = fDecimalParser.getDecimalFormatPattern(fDecimalSeparator);// the default, as usual
+  
+  private static String fBigDecimalDisplayFormat = "#,##0.00";
+  private static String fBooleanTrueDisplayFormat = "<![CDATA[  <input type='checkbox' name='true' value='true' checked readonly notab> ]]>";
+  private static String fBooleanFalseDisplayFormat = "<![CDATA[ <input type='checkbox' name='false' value='false' checked readonly notab>]]>";
+  private static String fEmptyOrNullDisplayFormat = "-";
+  private static String fIntegerDisplayFormat = "#,###";
+  private static String fIgnorableParamValue = "";
+  
+  //database items
+  private static DbConfigParser fIsSQLPrecompilationAttempted = new DbConfigParser("TRUE");
+  private static DbConfigParser fMaxRows = new DbConfigParser("300");
+  private static DbConfigParser fFetchSize = new DbConfigParser("25");
+  private static DbConfigParser fHasAutoGeneratedKeys = new DbConfigParser("FALSE");
+  private static DbConfigParser fErrorCodeForDuplicateKey =  new DbConfigParser("1");
+  private static DbConfigParser fErrorCodeForForeignKey = new DbConfigParser("2291");
+  private static DbConfigParser fSqlFetcherDefaultTxIsolationLevel = new DbConfigParser("DATABASE_DEFAULT");
+  private static DbConfigParser fSqlEditorDefaultTxIsolationLevel = new DbConfigParser("DATABASE_DEFAULT");
+  private static DbConfigParser fDateTimeFormatForPassingParamsToDb = new DbConfigParser("YYYY-MM-DD^hh:mm:ss^YYYY-MM-DD hh:mm:ss");
+
+  private static Boolean fIsTesting = Boolean.FALSE;
+  
+  /* Simple conversion methods. */
+  
+  private static Long asLong(String aValue){
+    return Long.valueOf(aValue);
+  }
+  
+  private static Integer asInteger(String aValue){
+    return Integer.valueOf(aValue);
+  }
+
+  private static TimeZone asTimeZone(String aValue){
+    TimeZone result = null;
+    try{
+      result = Util.buildTimeZone(aValue);
+    }
+    catch(Throwable ex){
+      fErrors.add(ex.getMessage());
+    }
+    return result;
+  }
+
+  private static Locale asLocale(String aValue){
+    return Util.buildLocale(aValue);
+  }
+  
+  /** 
+   Separated by a comma.
+   Special value 'NONE' denotes an empty list. 
+  */
+  private static List<String> asStringListWithNone(String aValue){
+    List<String> result = new ArrayList<String>();
+    if (! "NONE".equalsIgnoreCase(aValue)){
+      result.addAll(asStringList(aValue));
+    }
+    return result;
+  }
+  
+  /**  Separated by a comma. */
+  private static List<String> asStringList(String aValue){
+    List<String> result = new ArrayList<String>();
+    StringTokenizer parser = new StringTokenizer(aValue, ",");
+    while (parser.hasMoreElements()){
+      String item = (String)parser.nextElement();
+      result.add(item);
+    }
+    return result;
+  }
+  
+  
+  /** Separated by a comma. */
+  private static List<Integer> asIntegerList(String aValue){
+    List<Integer> result = new ArrayList<Integer>(); 
+    String DELIMITER = ",";
+    StringTokenizer parser = new StringTokenizer(aValue, DELIMITER);
+    while ( parser.hasMoreTokens() ) {
+      String errorCode = parser.nextToken();
+      result.add(new Integer(errorCode.trim()));
+    }
+    return result;
+  }
+  
+  private static Boolean asBoolean(String aValue){
+    return Util.parseBoolean(aValue);
+  }
+
+  private static String asDateTimeFormat(String aDbSetting, int aPart){
+    String[] formats = aDbSetting.split("\\^");
+    if(formats.length != 3) {
+      fErrors.add(
+        "DateTimeFormatForPassingParamsToDb setting in web.xml does not have a valid value: " + Util.quote(aDbSetting) + 
+        ". Does not have 3 entries, separated by a '^' character."
+      );
+    }
+    return formats[aPart];
+  }
+  
+  private static void checkTooLow(Long aValue, Long aMin, String aName) {
+    if (aValue < aMin){
+      fErrors.add(
+        "Configured value of " + aValue + " in web.xml for " + aName + 
+        " is less than " + aMin  + ". Please see web.xml for more information." 
+      );
+    }
+  }
+}