New Upstream Snapshot - libowasp-esapi-java

Ready changes

Summary

Merged new upstream version: 2.4.0.0+git20221127.1.565ba3c (was: 2.4.0.0).

Resulting package

Built on 2023-01-08T19:13 (took 9m22s)

The resulting binary packages can be installed (if you have the apt repository enabled) by running one of:

apt install -t fresh-snapshots libowasp-esapi-java

Lintian Result

Diff

diff --git a/.gitattributes b/.gitattributes
deleted file mode 100644
index 74f99db..0000000
--- a/.gitattributes
+++ /dev/null
@@ -1,77 +0,0 @@
-# Autodetect text files
-#
-# In addition:
-#   Windows developers should set:
-#       git config --global core.autocrlf true
-#   UNIX / MacOS develoers should set:
-#       git config --global core.autocrlf input
-* text=auto
-
-#
-# And configure default EOL terminators for various text types
-#
-
-# Explicitly declare text files you want to always be normalized and converted
-# to native line endings on checkout.
-*.java text
-*.properties text
-*.xml text
-*.xsd text
-*.dtd text
-*.MF text
-*.md text
-*.html text
-*.tld text
-*.json text
-
-# Declare files that will always have CRLF line endings on checkout.
-*.cmd text eol=crlf
-*.bat text eol=crlf
-# Because *nix editors / paginators can handle either way, but braindead
-# Windoze notepad which is used by default to handle text files in Windows,
-# not so much, we also make the concession here to use CRLF for EOL.
-*.txt text eol=crlf
-# Ditto for Eclipse related preferences
-*.prefs text eol=crlf
-
-# Declare files that will always have LF line endings on checkout
-*.sh text eol=lf
-*.bsh text eol=lf
-*.ksh text eol=lf
-
-# Eclipse stuff
-.settings/* text eol=crlf
-.classpath text eol=crlf
-.project text eol=crlf
-
-# Miscellaneous text
-.gitattributes text eol=lf
-.gitignore text eol=lf
-*.MF text eol=crlf
-LICENSE text eol=crlf
-LICENSE-CONTENT text eol=crlf
-LICENSE-README text eol=crlf
-
-
-# Denote all files that are truly binary and should not be modified,
-# or simply replaced in whole if committed.
-*.jpg binary
-*.JPG binary
-*.png binary
-*.jks binary
-*.ser binary
-*.doc binary
-*.docx binary
-*.xls binary
-*.xlsx binary
-*.pptx binary
-*.odt binary
-*.pdf binary
-*.zip binary
-*.jar binary
-*.war binary
-*.ear binary
-*.7z binary
-*.rar binary
-*.tgz binary
-*.tar binary
diff --git a/.github/workflows/maven.yml b/.github/workflows/maven.yml
deleted file mode 100644
index a81c847..0000000
--- a/.github/workflows/maven.yml
+++ /dev/null
@@ -1,24 +0,0 @@
-# This workflow will build a Java project with Maven
-# For more information see: https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-maven
-
-name: Java CI with Maven
-
-on:
-  push:
-    branches: [ develop ]
-  pull_request:
-    branches: [ develop ]
-
-jobs:
-  build:
-
-    runs-on: ubuntu-latest
-
-    steps:
-    - uses: actions/checkout@v2
-    - name: Set up JDK 1.8
-      uses: actions/setup-java@v1
-      with:
-        java-version: 1.8
-    - name: Build with Maven
-      run: mvn -B package --file pom.xml
diff --git a/.github/workflows/superlinter.yml b/.github/workflows/superlinter.yml
deleted file mode 100644
index b263fdd..0000000
--- a/.github/workflows/superlinter.yml
+++ /dev/null
@@ -1,26 +0,0 @@
-name: Super-Linter
-
-# Run this workflow every time a new commit pushed to your repository
-on: push
-
-jobs:
-  # Set the job key. The key is displayed as the job name
-  # when a job name is not provided
-  super-lint:
-    # Name the Job
-    name: Lint code base
-    # Set the type of machine to run on
-    runs-on: ubuntu-latest
-
-    steps:
-      # Checks out a copy of your repository on the ubuntu-latest machine
-      - name: Checkout code
-        uses: actions/checkout@v2
-
-      # Runs the Super-Linter action and ignore errors
-      - name: Run Super-Linter
-        uses: github/super-linter@v4
-        env:
-          DEFAULT_BRANCH: develop
-          DISABLE_ERRORS: true
-          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
diff --git a/.gitignore b/.gitignore
deleted file mode 100644
index 0a3094a..0000000
--- a/.gitignore
+++ /dev/null
@@ -1,18 +0,0 @@
-# Eclipse / IntelliJ / Maven / backup editor files
-/target
-/.settings/**
-.classpath
-.project
-*.swp
-*~
-*.iml
-.idea/
-*.iws
-*.eml
-out/
-bin/
-
-# Leftover test files
-ciphertext-portable.ser
-ReferenceEncryptedProperties.test.txt
-test.out
diff --git a/CONTRIBUTING-TO-ESAPI.txt b/CONTRIBUTING-TO-ESAPI.txt
index df79adc..2baee17 100644
--- a/CONTRIBUTING-TO-ESAPI.txt
+++ b/CONTRIBUTING-TO-ESAPI.txt
@@ -3,12 +3,12 @@
 Getting Started:
     If you have not already done so, go back and read the section
     "Contributing to ESAPI legacy" in ESAPI's README.md file. It
-    make contain updates and advice not contained herein.
+    may contain updates and advice not contained herein.
 
 A Special Note on GitHub Authentication:
-    GitHub has announced that they are deprecating authentiation based on
-    username / password and beginning 2021-08-13, you will no longer be able
-    to your password to authenticate to 'git' operations on GitHub.com.
+    GitHub has announced that they are deprecating password based authentication
+    using username / password and beginning 2021-08-13, you will no longer be
+    able to your password to authenticate to 'git' operations on GitHub.com.
     Please see https://github.blog/2020-12-15-token-authentication-requirements-for-git-operations/
     for details and plan accordingly.
 
@@ -21,22 +21,23 @@ Finding Something Interesting to Work on:
     or "help wanted", those are good places to start for someone not yet
     familiar with the ESAPI code base.
 
-    You will need a account on GitHub though. Once you create one, let me know
+    You will need a account on GitHub though. Once you create one, let us know
     what it is. Then if you want to work on a particular issue, we can assign
     it to you so someone else won't take it.
 
-    If you have questions, email Kevin Wall (Kevin.W.Wall@gmail.com) or Matt Seil (xeno6696@gmail.com).
+    If you have questions, email Kevin Wall (Kevin.W.Wall@gmail.com) or Matt
+    Seil (xeno6696@gmail.com).
 
 Overview:
     We are following the branching model described in
         https://nvie.com/posts/a-successful-git-branching-model
-    If you are unfamiliar with it, you would be advised to give it a
-    quick perusal. The major point is that the 'main' (formerly 'master') branch
-    is reserved for official releases (which will be tagged), the 'develop' branch is
-    used for ongoing development work and is the default branch, and we generally work
-    off 'issue' branches named 'issue-#' where # is the GitHub issue number.
-    (The last is not an absolute requirement, but rather a suggested
-    approach.)
+    If you are unfamiliar with it, you would be advised to give it a quick
+    perusal. The major point is that the 'main' (formerly 'master') branch is
+    reserved for official releases (which will be tagged), the 'develop' branch
+    is used for ongoing development work and is the default branch, and we
+    generally work off 'issue' branches named 'issue-#' where # is the GitHub
+    issue number. (The last is not an absolute requirement, but rather a
+    suggested approach.)
 
     Finally, we recommend setting the git property 'core.autocrlf' to 'input'
     in your $HOME/.gitconfig file; e.g., that file should contain something
@@ -47,10 +48,10 @@ Overview:
 
 Required Software:
     We use Maven for building. Maven 3.3.9 or later is required. You also need
-    JDK 8 or later.
-    [Note: If you use JDK 9 or later, there will be multiple
+    JDK 8 or later. [Note: If you use JDK 9 or later, there will be multiple
     failures when you try to run 'mvn test' as well as some general warnings.
-    See ESAPI GitHub issue #496 for details.]
+    See ESAPI GitHub issue #496 for details. We welcome volunteers to address
+    this.]
 
 Building ESAPI:
     https://www.owasp.org/index.php/ESAPI-Building briefly discusses how to
@@ -80,7 +81,10 @@ Steps to work with ESAPI:
        'issue-#' where '#' is the GitHub issue # is will be working on, but
        you can call it whatever. E.g.,
             git checkout -b issue-#
-    4. Work on the GitHub issue on this newly created issue-# branch.
+    4. Work on the GitHub issue on this newly created issue-# branch. Be sure
+       that you also create new JUnit tests as required that confirm that the
+       issue is corrected, or if you are introducing new functionality, ensure
+       that functionality is sufficiently covered.
     5. Make sure everything builds correctly and all the JUnit tests pass
        ('mvn test'). [Note: There are some known issues with test failures if
        your are running under Windows and your local ESAPI Git repo located
@@ -103,11 +107,16 @@ Steps to work with ESAPI:
             $ git remote -v | grep origin       # Confirm 'origin' refers to YOUR PERSONAL GitHub repo
             $ git push origin issue-444         # Push the committed changes on the 'issue-444' branch
     9. Go to your personal, forked ESAPI GitHub repo (web interface) and create a
-       'Pull Request' from your 'issue-#' branch.
+       'Pull Request' (PR) from your 'issue-#' branch.
    10. Back on your local personal laptop / desktop, merge your issue branch with
-       your local 'develop' branch. I.e.
+       your local 'develop' branch. I.e.,
             $ git checkout develop
             $ git merge issue-444
+   11. Do not remove your branch on your forked repository until your PR from your
+       branch has been merged into the ESAPI/esapi-java/legacy 'develop' branch.
+       Note at least one the 3 main contributors on will review your commits before
+       merging them and they may do a formal code review and request further changes.
+       Once they are satisfied, they will merge your PR.
 
 In theory, you can do all this 'git' magic from Eclipse and presumably other
 IDEs like Oracle NetBeans or IntelliJ IDEA). From Eclipse, it is right-click
diff --git a/README.md b/README.md
index 700ad6c..f49c827 100644
--- a/README.md
+++ b/README.md
@@ -6,7 +6,7 @@ Enterprise Security API for Java (Legacy)
 [![Coverity Status](https://scan.coverity.com/projects/8517/badge.svg)](https://scan.coverity.com/projects/bkimminich-esapi-java-legacy)
 [![OpenSSF Best Practices](https://bestpractices.coreinfrastructure.org/projects/137/badge)](https://bestpractices.coreinfrastructure.org/projects/137)
 
-<table border=0>
+<table border=10>
 <tr>
 <td>
 OWASP® ESAPI (The OWASP Enterprise Security API) is a free, open source, web application security control library that makes it easier for programmers to write lower-risk applications. The ESAPI for Java library is designed to make it easier for programmers to retrofit security into existing applications. ESAPI for Java also serves as a solid foundation for new development.
@@ -14,96 +14,190 @@ OWASP® ESAPI (The OWASP Enterprise Security API) is a free, open source, web ap
 </tr>
 </table>
 
-# A word about ESAPI and Log4J vulnerabilities
-This is way too detailed to litter the README file with, but several of you have
-been asking about this, so I wrote up something on it and posted it to the ESAPI
-Users Google group. You can find it at [A word about Log4J vulnerabilities in ESAPI - the TL;DR version](https://groups.google.com/a/owasp.org/g/esapi-project-users/c/_CR8d-dpvMU).
+# A word about ESAPI vulnerabilities
+A summary of all the vulnerabilities that we have written about in either the
+ESAPI Security Bulletins or in the GitHub Security Advisories may be found
+in this [Vulnerability Summary](https://github.com/ESAPI/esapi-java-legacy/blob/develop/Vulnerability-Summary.md).
+It is too lengthy, and if you are using the latest available ESAPI version--generally not relevant--to
+place in this **README** file.
 
-# Where is the OWASP ESAPI wiki page?
-You can find the OWASP ESAPI wiki pages at [https://owasp.org/www-project-enterprise-security-api/](https://owasp.org/www-project-enterprise-security-api/). The ESAPI legacy GitHub repo also has a few useful wiki pages.
+# Where are the OWASP ESAPI wiki pages?
+You can find the official OWASP ESAPI Project wiki pages at
+[https://owasp.org/www-project-enterprise-security-api/](https://owasp.org/www-project-enterprise-security-api/).
+The ESAPI legacy GitHub repo also has several useful [wiki pages](https://github.com/ESAPI/esapi-java-legacy/wiki).
 
 # What does Legacy mean?
-<p>This is the legacy branch of ESAPI which means it is an actively maintained branch of the project, however significan *new* feature development for this branch will *not* be done. Features that have already been scheduled for the 2.x branch will move forward.
-You will find that GitHub repository at [https://github.com/ESAPI/esapi-java-legacy](https://github.com/ESAPI/esapi-java-legacy).
+This is the legacy branch of ESAPI which means it is an actively maintained branch of the project, however significant *new* **feature development** for this branch will *not* be done. Features that have already been scheduled for the 2.x branch will move forward.
+Development for the "next generation" of ESAPI (starting with ESAPI 3.0), will be done at the
+GitHub repository at [https://github.com/ESAPI/esapi-java](https://github.com/ESAPI/esapi-java).
 
-<b>IMPORTANT NOTES:</b>
-The default branch for ESAPI legacy is now the 'develop' branch (rather than the 'main' (formerly 'master') branch), where future development, bug fixes, etc. will now be done. The 'main' branch is now marked as "protected"; it reflects the latest stable ESAPI release (2.1.0.1 as of this date). Note that this change of making the 'develop' branch the default may affect any pull requests that you were intending to make.
-
-Also, the <i>minimal</i> baseline Java version to use ESAPI is Java 8. (This was changed from Java 7 during the 2.4.0.0 release.)
+**IMPORTANT NOTES:**
+* The default branch for ESAPI legacy is the 'develop' branch (rather than the 'main' (formerly 'master') branch), where future development, bug fixes, etc. are now being done. The 'main' branch is now marked as "protected"; it reflects the latest stable ESAPI release (2.5.1.0 as of this date). Note that this change of making the 'develop' branch the default may affect any pull requests that you were intending to make.
+* Also, the *minimal* baseline Java version to use ESAPI is now Java 8. (This was changed from Java 7 during the 2.4.0.0 release.)
+* Support was dropped for Log4J 1 during ESAPI 2.5.0.0 release. If you need it, configure it via SLF4J. See  the
+  [2.5.0.0 release notes](https://github.com/ESAPI/esapi-java-legacy/blob/develop/documentation/esapi4java-core-2.5.0.0-release-notes.txt)
+for details.
 
 # Where can I find ESAPI 3.x?
-[https://github.com/ESAPI/esapi-java](https://github.com/ESAPI/esapi-java)
+As mentioned above, you can find it at [https://github.com/ESAPI/esapi-java](https://github.com/ESAPI/esapi-java).
 
-Note however that work on ESAPI 3 has not yet become in earnest and is only in its earliest planning stages. Even the code that is presently there will likely change.
+Note however that work on ESAPI 3 has not yet begun in earnest and is only
+in its earliest planning stages. Even the code that is presently there
+will likely change.
 
-# ESAPI release notes
+# ESAPI Release Notes
 The ESAPI release notes may be found in ESAPI's "documentation" directory. They are generally named "esapi4java-core-*2.#.#.#*-release-notes.txt", where "*2.#.#.#*" refers to the ESAPI release number (which uses semantic versioning).
-## IMPORTANT
-Starting with ESAPI 2.2.3.0, ESAPI is using a version of AntiSamy that by default includes 'slf4j-simple' and does XML schema validation on the AntiSamy policy files. Please **READ** the [release notes for the 2.2.3.0 release](https://github.com/ESAPI/esapi-java-legacy/blob/develop/documentation/esapi4java-core-2.2.3.0-release-notes.txt) (at least the beginning portion) for some important notes that likely will affect your use of ESAPI! You have been warned!!!
+
+See the GitHub [Releases](https://github.com/ESAPI/esapi-java-legacy/releases) information for a list of releases which generally
+link to the specific release notes.
+
+### Really IMPORTANT information in release notes
+* Starting with ESAPI 2.2.1.0, important details changed reading the ESAPI
+  Logger. If you have are getting things like ClassNotFoundException, you
+  probably have not read it. Please be sure to read this specific section
+  of the
+  [2.2.1.0 release notes](https://github.com/ESAPI/esapi-java-legacy/blob/develop/documentation/esapi4java-core-2.2.1.0-release-notes.txt#L128-L155)
+* Starting with ESAPI 2.2.3.0, ESAPI is using a version of AntiSamy that by default includes 'slf4j-simple' and
+  does XML schema validation on the AntiSamy policy files. Please **READ** this
+  section from the
+  [2.2.3.0 release notes](https://github.com/ESAPI/esapi-java-legacy/blob/1312102e79d4ed98d1396f5c56e12f437534d62b/documentation/esapi4java-core-2.2.3.0-release-notes.txt#L22-L34)
+  (at least the beginning portion) for some important notes that likely will affect your use of ESAPI! You have been warned!!!
+* ESAPI 2.3.0.0 is the last release to support Java 7 as the minimal JDK.
+  Starting with release 2.4.0.0, Java 8 or later is required.
 
 # Locating ESAPI Jar files
-The [latest ESAPI release](https://github.com/ESAPI/esapi-java-legacy/releases/latest) is 2.2.3.1. The default configuration jar and its GPG signature can be found at [esapi-2.2.3.1-configuration.jar](https://github.com/ESAPI/esapi-java-legacy/releases/download/esapi-2.2.3.1/esapi-2.2.3.1-configuration.jar) and [esapi-2.2.3.1-configuration.jar.asc](https://github.com/ESAPI/esapi-java-legacy/releases/download/esapi-2.2.3.1/esapi-2.2.3.1-configuration.jar.asc) respectively.
+The [latest ESAPI release](https://github.com/ESAPI/esapi-java-legacy/releases/latest) is 2.5.1.0.
+All the *regular* ESAPI jars, with the exception of the ESAPI configuration
+jar (i.e., esapi-2.#.#.#-configuration.jar) and its associated detached
+GPG signature, are available from Maven Central. The ESAPI configuration
+jars are linked under the 'Assets' section to each of the specific
+ESAPI releases under the
+GitHub [Releases page](https://github.com/ESAPI/esapi-java-legacy/releases).
 
-The latest *regular* ESAPI jars can are available from Maven Central.
 
-However, before you start a *new* project using ESAPI, but sure to read "[Should I use ESAPI?](https://owasp.org/www-project-enterprise-security-api/#div-shouldiuseesapi)".
+However, **before** you start a *new* project using ESAPI, but sure to read "[Should I use ESAPI?](https://owasp.org/www-project-enterprise-security-api/#div-shouldiuseesapi)".
 
 # ESAPI Deprecation Policy
-Unless we unintentionally screw-up, our intent is to keep classes, methods, and/or fields whihc have been annotated as "@deprecated" for a minimum of two (2) years or until the next major release number (e.g., 3.x as of now), which ever comes first, before we remove them.
-Note that this policy does not apply to classes under the **org.owasp.esapi.reference** package. You are not expected to be using such classes directly in your code.
+Unless we unintentionally screw-up, our intent is to keep classes, methods,
+and/or fields which have been annotated as "@deprecated" for a
+minimum of two (2) years or until the next major release number (e.g.,
+3.x as of now), which ever comes first, before we remove them. Note
+that this policy does not apply to classes under
+the **org.owasp.esapi.reference** package. You generally are not expected
+to be using such classes directly in your code. At the ESAPI team's discretion,
+it will also not apply for any known exploitable vulnerabilities for which
+no available workaround exists.
+
+**IMPORTANT NOTES:** As of ESAPI 2.5.0.0, all the Log4J 1.x related code
+has been removed from the ESAPI code base (with the exception of some
+references in documentation). If you must, you still should be able to
+use Log4J 1.x logging via ESAPI SLF4J support. See the ESAPI 2.5.0.0 release
+notes for further details.
 
 # Contributing to ESAPI legacy
-## How can I contribute or help with fix bugs?
-Fork and submit a pull request! Simple as pi! We generally only accept bug fixes, not new features because as a legacy project, we don't intend on adding new features, although we may make exceptions. If you wish to propose a new feature, the best place to discuss it is via the ESAPI-DEV mailing list mentioned below. Note that we vet all pull requests, including coding style of any contributions; use the same coding style found in the files you are already editing.
+### How can I contribute or help with fix bugs?
+Fork and submit a pull request! Easy as pi! (How's that for an irrational
+statement, you math nerds? :) We generally only accept bug fixes, not
+new features because as a legacy project, we don't intend on adding new
+features that we will have to maintain long term (although we may make
+exceptions; see the 'New Features' section in this **README**). If
+you are interesting in doing bug fixes though, the best place to start is the
+[CONTRIBUTING-TO-ESAPI.txt](https://github.com/ESAPI/esapi-java-legacy/blob/develop/CONTRIBUTING-TO-ESAPI.txt)
 
 If you are new to ESAPI, a good place to start is to look for GitHub issues labled as 'good first issue'. (E.g., to find all open issues with that label, use [https://github.com/ESAPI/esapi-java-legacy/issues?q=is%3Aissue+is%3Aopen+label%3A%22good+first+issue%22](https://github.com/ESAPI/esapi-java-legacy/issues?q=is%3Aissue+is%3Aopen+label%3A%22good+first+issue%22).)
 
-You can find additional details in the file '[CONTRIBUTING-TO-ESAPI.txt](https://raw.githubusercontent.com/ESAPI/esapi-java-legacy/develop/CONTRIBUTING-TO-ESAPI.txt)'.
-
+Again, please find additional important details in the file
+'[CONTRIBUTING-TO-ESAPI.txt](https://github.com/ESAPI/esapi-java-legacy/blob/develop/CONTRIBUTING-TO-ESAPI.txt)',
+which will also describe the tool requirements.
+
+#### Want to report an issue?
+If you have found a bug, then create an issue on the esapi-legacy-java repo at [https://github.com/ESAPI/esapi-java-legacy/issues](https://github.com/ESAPI/esapi-java-legacy/issues)
+As of May 11, 2022, we switched back to using (GitHub) issue templates. (We previously used issue templates when our source code repository was still on Google Code.) You can read more about our issue templates in this brief
+[announcement](https://github.com/ESAPI/esapi-java-legacy/discussions/700).
+
+NOTE: Please do **NOT** use GitHub issues to ask questions about ESAPI.
+If you wish to ask questions, instead, post to either of the 2 mailing
+lists (now on Google Groups) found the References section at the bottom
+of this page. If we find questions posted as GitHub issues, we simply will
+close them and direct you to do this anyhow. Alternately you may use the new
+[Q&A](https://github.com/ESAPI/esapi-java-legacy/discussions/categories/q-a) section of our GitHub
+[Discussions](https://github.com/ESAPI/esapi-java-legacy/discussions) page to ask questions.
+
+When reporting an issue or just asking a question, please be clear and try
+to ensure that the ESAPI development team has sufficient information to be
+able to reproduce your results or to understand your question. If you have
+not already done so, this might be a good time to read Eric S. Raymond's classic
+"[How to Ask Questions the Smart Way](http://www.catb.org/esr/faqs/smart-questions.html)"
+before posting your issue.
+
+#### Find a Vulnerability?
+If believe you have found a vulnerability in ESAPI legacy, for the sake of the
+ESAPI community, please practice Responsible Disclosure. (Note: We will be sure
+you get credit and will work with you to create a GitHub Security Advisory, and
+if you so choose, to pursue filing a CVE via the GitHub CNA.)
+
+You are of course encouraged to first search our GitHub issues list (see above)
+to see if it has already been reported. If it has not, then please contact
+both Kevin W. Wall (kevin.w.wall at gmail.com) and
+Matt Seil (matt.seil at owasp.org) directly. Please do not report
+vulnerabilities via GitHub issues or via the ESAPI mailing lists as
+we wish to keep our users secure while a patch is implemented and
+deployed. If you wish to be acknowledged for finding the vulnerability,
+then please follow this process. Also, when you post the email describing
+the vulnerability, please do so from an email address that you usually
+monitor.
+
+More detail is available in the file
+'[SECURITY.md](https://github.com/ESAPI/esapi-java-legacy/blob/develop/SECURITY.md)'.
+https://raw.githubusercontent.com/ESAPI/esapi-java-legacy/blob/develop/SECURITY.md)'.
+
+### New Features
+If you wish to propose a new feature, the best place to discuss it is via
+new 'Discussions' board, probably under
+'[Ideas](https://github.com/ESAPI/esapi-java-legacy/discussions/categories/ideas)',
+or on the ESAPI-DEV mailing list mentioned below under the References section.
+As mentioned previously, we generally are not considering new features
+for ESAPI 2.x. This is because:
+- ESAPI is already too monolithic and has too many dependencies for its size.
+- We are trying to wind down support of ESAPI 2.x and get ESAPI 3.0 going so any
+  resources we throw at ESAPI 2.x will slow down that goal.
+
+That said, if you believe you have an idea for an additional simple feature that
+does not pull in any additional 3rd party libraries, toss it out there for
+discussion or even show us how it works with a PR. (Note that we vet all pull
+requests, including coding style of any contributions, so please use the same
+coding style found in the files you are already editing.)
+
+# Ancient History
 ### What happened to Google code?
-In mid-2014 ESAPI Migrated all code to GitHub. This migration was completed in November 2014.
+In mid-2014 ESAPI migrated all code and issues from Google Code to GitHub. This migration was completed in November 2014.
 
 ### What about the issues still located on Google Code?
-All issues from Google Code have been migrated to GitHub issues. We have a JIRA/Confluence instance allocated to us, but it has not be configured to synchronize with the GitHub issues, and thus is should not be used. JIRA is fine, but if we can't have it synchronized with GitHub issues (which is where the majority of our users report issues), it is not usuable. As developers, we do not want to spent time having to close issues from multiple bug-tracking sites. Therefore, until this synchronization happens (see GitHub issue #371), please ONLY use GitHub for reporting bugs.
-
-When reporting an issue, please be clear and try to ensure that the ESAPI development team has sufficient information to be able to reproduce your results. If you have not already done so, this might be a good time to read Eric S. Raymond's classic "How to Ask Questions the Smart Way", at [http://www.catb.org/esr/faqs/smart-questions.html](http://www.catb.org/esr/faqs/smart-questions.html) before posting your issue.
-
-### Find an Issue?
-If you have found a bug, then create an issue on the esapi-legacy-java repo: [https://github.com/ESAPI/esapi-java-legacy/issues](https://github.com/ESAPI/esapi-java-legacy/issues)
-
-NOTE: Please do NOT use GitHub issues to ask questions about ESAPI. If you wish to do this, post to either of the 2 mailing lists (now on Google Groups) found at the bottom of this page. If we find questions as GitHub issues, we simply will close them and direct you to do this anyhow.
-
-### Find a Vulnerability?
-If you have found a vulnerability in ESAPI legacy, first search the issues list (see above) to see if it has already been reported. If it has not, then please contact both Kevin W. Wall (kevin.w.wall at gmail.com) and Matt Seil (matt.seil at owasp.org) directly. Please do not report vulnerabilities via GitHub issues or via the ESAPI mailing lists as we wish to keep our users secure while a patch is implemented and deployed. If you wish to be acknowledged for finding the vulnerability, then please follow this process. (Eventually, we would like to have BugCrowd handle this, but that's still a ways off.) Also, when you post the email describing the vulnerability, please do so from an email address that you usually monitor.
-
-More detail is available in the file '[SECURITY.md](https://raw.githubusercontent.com/ESAPI/esapi-java-legacy/develop/SECURITY.md)'.
-
-## Where to Find More Information on ESAPI
-
-*Wiki:* https://owasp.org/www-project-enterprise-security-api/
-
-*Nightly Build:* Travis CI - https://travis-ci.org/bkimminich/esapi-java-legacy
-
-~~JIRA: https://owasp-esapi.atlassian.net/browse/ESAPILEG~~<br />Issues: Until further notice, use the GitHub issues for reporting bugs and enhancement requests.
-
-
-*Documentation:* https://owasp-esapi.atlassian.net/wiki/display/ESAPILEG/ESAPI+Legacy (Coming Soon), for now find general documentation under the 'documentation/' directory, and the latest Javadoc under https://www.javadoc.io/doc/org.owasp.esapi/esapi/
+All issues from Google Code have been migrated to GitHub issues. We now
+use GitHut Issues for reporting everything *except* security vulnerabilities.
+Other bug tracking sites are undoubtedly more advanced, but as developers,
+we do not want to spent time having to close issues from multiple bug-tracking
+systems. Therefore, until the synchronization happens with the Atlassian Jira
+instance that we have (but are not using; see GitHub issue #371), please
+ONLY use GitHub Issues for reporting bugs.
 
-*Realtime Support available on our IRC Channel (but if you want to do so, and want the ESAPI dev team to participate, email us a heads up first as to the date/time):*<br/>
-Server: irc.freenode.net<br/>
-Channel: #esapi<br/>
-Webchat: [https://webchat.freenode.net/](https://webchat.freenode.net/)
+# References: Where to Find More Information on ESAPI
+**OWASP Wiki:** https://owasp.org/www-project-enterprise-security-api/
 
-*Mailing lists:*
-As of 2019-03-25, ESAPI's 2 mailing lists were officially moved OFF of their Mailman mailing lists to a new home on Google Groups.
+**GitHub ESAPI Wiki:** https://github.com/ESAPI/esapi-java-legacy/wiki
 
-The names of the 2 Google Groups are "[esapi-project-users](mailto:esapi-project-users@owasp.org)" and "[esapi-project-dev](mailto:esapi-project-dev@owasp.org)", which you may POST to *after* you subscribe to them via "[Subscribe to ESAPI Users list](https://groups.google.com/a/owasp.org/forum/#!forum/esapi-project-users/join)" and "[Subscribe to ESAPI Developers list](https://groups.google.com/a/owasp.org/forum/#!forum/esapi-project-dev/join)" respectively.
+**General Documentation:** Under the '[documentation](https://github.com/ESAPI/esapi-java-legacy/tree/develop/documentation)' folder.
 
-Old archives for the old Mailman mailing lists for ESAPI-Users and ESAPI-Dev are still available at https://lists.owasp.org/pipermail/esapi-users/ and https://lists.owasp.org/pipermail/esapi-dev/ respectively.
+**OWASP Slack Channel:** [#owasp-esapi](https://owasp.slack.com/archives/CQ2ET27AN)
 
-For a general overview of Google Groups and its web interface, see [https://groups.google.com/forum/#!overview](https://groups.google.com/forum/#!overview)
+**GitHub Discussions:** [Discussions](https://github.com/ESAPI/esapi-java-legacy/discussions) - Not a lot there yet, but we only started this on May 11, 2022.
 
-For assistance subscribing and unsubscribing to Google Groups, see [https://webapps.stackexchange.com/questions/13508/how-can-i-subscribe-to-a-google-mailing-list-with-a-non-google-e-mail-address/15593#15593](https://webapps.stackexchange.com/questions/13508/how-can-i-subscribe-to-a-google-mailing-list-with-a-non-google-e-mail-address/15593#15593).
+**Mailing lists:**
+* As of 2019-03-25, ESAPI's 2 mailing lists were officially moved OFF of their Mailman mailing lists to a new home on Google Groups.
+* The names of the 2 Google Groups are "[esapi-project-users](mailto:esapi-project-users@owasp.org)" and "[esapi-project-dev](mailto:esapi-project-dev@owasp.org)", which you may POST to *after* you subscribe to them via "[Subscribe to ESAPI Users list](https://groups.google.com/a/owasp.org/forum/#!forum/esapi-project-users/join)" and "[Subscribe to ESAPI Developers list](https://groups.google.com/a/owasp.org/forum/#!forum/esapi-project-dev/join)" respectively.
+* Old archives for the old Mailman mailing lists for ESAPI-Users and ESAPI-Dev are still available at https://lists.owasp.org/pipermail/esapi-users/ and https://lists.owasp.org/pipermail/esapi-dev/ respectively.
+* For a general overview of Google Groups and its web interface, see [https://groups.google.com/forum/#!overview](https://groups.google.com/forum/#!overview)
+* For assistance subscribing and unsubscribing to Google Groups, see [https://webapps.stackexchange.com/questions/13508/how-can-i-subscribe-to-a-google-mailing-list-with-a-non-google-e-mail-address/15593#15593](https://webapps.stackexchange.com/questions/13508/how-can-i-subscribe-to-a-google-mailing-list-with-a-non-google-e-mail-address/15593#15593).
 
 ----------
 OWASP is a registered trademark of the OWASP Foundation, Inc.
diff --git a/SECURITY.md b/SECURITY.md
index afed854..890ee2d 100644
--- a/SECURITY.md
+++ b/SECURITY.md
@@ -4,8 +4,8 @@
 
 | Version | Supported          |
 | ------- | ------------------ |
-| 2.2.3.1 (latest) | :white_check_mark: |
-| 2.1.0.1-2.2.3.0  | :x:, upgrade to latest release |
+| 2.5.0.0 (latest) | :white_check_mark: |
+| 2.1.0.1-2.4.0.0  | :x:, upgrade to latest release |
 | <= 1.4.x  | :x:, no longer supported AT ALL |
 
 ## Reporting a Vulnerability
@@ -41,11 +41,9 @@ are not in a position to pay out bug bounties for vulnerabilities.
 
 Eventually, we would like to have BugCrowd handle this, but that's still a ways off.
 
-## Security Bulletins
+## ESAPI Security Bulletins and GitHub Security Advisories
 
 There are some ESAPI security bulletins published in the "documentation" directory on GitHub.
-For details see:
+GitHub also has published some Security Advisories for ESAPI.
+For details, see [Vulnerability Summary](https://github.com/ESAPI/esapi-java-legacy/blob/develop/Vulnerability-Summary.md).
 
-* [Security Bulletin #1 - MAC Bypass in ESAPI Symmetric Encryption](documentation/ESAPI-security-bulletin1.pdf), which covers CVE-2013-5679 and CVE-2013-5960
-* [Security Bulletin #2 - How Does CVE-2019-17571 Impact ESAPI?](documentation/ESAPI-security-bulletin2.pdf), which covers the Log4J 1 deserialization CVE.
-* [Security Bulletin #3 - How Does the Apache Xerces Vulnerability(SNYK-JAVA-XERCES-608891) Impact ESAPI?](documentation/ESAPI-security-bulletin3.pdf), which decribes a unpatched Apache Xerces vulnerability similar to [CVE-2020-14621](https://nvd.nist.gov/vuln/detail/CVE-2020-14621)
diff --git a/Vulnerability-Summary.md b/Vulnerability-Summary.md
new file mode 100644
index 0000000..98ccf75
--- /dev/null
+++ b/Vulnerability-Summary.md
@@ -0,0 +1,27 @@
+# Summary of ESAPI Security Bulletins and GitHub Security Advisories</h1>
+This page attempts to summarize all the ESAPI Security Bulletins and GitHub Security Advisories in a table format. This started out as a lengthy email to the ESAPI User's Google group which you can find at
+"[A word about Log4J vulnerabilities in ESAPI - the TL;DR version](https://groups.google.com/a/owasp.org/g/esapi-project-users/c/_CR8d-dpvMU)",
+but then morphed into this current format as more and more Log4J 1.x vulnerabilities were discovered as well as one in ESAPI itself that we felt compelled to detail.
+
+Note that not all CVEs for ESAPI are reflected here as we only wrote ESAPI
+Security Bulletins for CVEs that we believed were either not exploitable via
+standard ESAPI configurations or that required special explanation above and beyond
+was provided in the description of the CVE.
+
+---
+
+
+|||||||
+|--- |--- |--- |--- |--- |--- |
+|**Relevant ESAPI Security Bulletin / GitHub Security Advisory**|**Summary**|**Relevant CWEs**|**Relevant Vuln ID**|**Notes regarding potential impact**|**ESAPI versions where default configuration is impacted**|
+|[1](https://github.com/ESAPI/esapi-java-legacy/blob/develop/documentation/ESAPI-security-bulletin1.pdf)|MAC bypass in ESAPI symmetric encryption|[CWE-310](https://cwe.mitre.org/data/definitions/310.html)|[CVE-2013-5679](https://nvd.nist.gov/vuln/detail/CVE-2013-5679)|MAC check may be bypassed thus not assuring the authenticity of the received ciphertext.|ESAPI 2.x versions before 2.1.0|
+|[2](https://github.com/ESAPI/esapi-java-legacy/blob/develop/documentation/ESAPI-security-bulletin2.pdf)|Java deserialization vulnerability in Log4J 1 (via SocketServer) for ESAPI logging may lead to code injection|[CWE-502](https://cwe.mitre.org/data/definitions/502.html)|[CVE-2019-17571](https://nvd.nist.gov/vuln/detail/CVE-2019-17571)|SocketServer is a class presumably intended for aggregating Log4J log events. It is a server-side class. ESAPI does not use it, nor any Log4J 1 classes that use it.|None.ESAPI 2.x versions 2.2.1.0 and later default to use JUL (java.util.logging)|
+|[3](https://github.com/ESAPI/esapi-java-legacy/blob/develop/documentation/ESAPI-security-bulletin3.pdf)|This flaw allows a specially-crafted XML file to manipulate the validation process in processed by Xerces’ XMLSchemaValidation class in certain cases.|[CWE-20](https://cwe.mitre.org/data/definitions/20.html)|[SNYK-JAVA-XERCES-608891](https://security.snyk.io/vuln/SNYK-JAVA-XERCES-608891) (related to [CVE-2020-14621](https://nvd.nist.gov/vuln/detail/CVE-2020-14621))|An analysis of the ESAPI and Xerces code shows that ESAPI does not use the vulnerable Xerces class either directly or indirectly.|None, but fixed even with respect to SCA tools for ESAPI 2.2.3.0 and later which AntiSamy 1.6.2, which uses Xerces 2.12.1, where this vulnerability is fixed.|
+|[4](https://github.com/ESAPI/esapi-java-legacy/blob/develop/documentation/ESAPI-security-bulletin4.pdf)|SMTPS (SMTP over SSL/TLS) can allow MITM attack if SMTPAppender is used with Log4J 1 ESAPI logging.|[CWE-295](https://cwe.mitre.org/data/definitions/295.html)|[CVE-2020-9488](https://nvd.nist.gov/vuln/detail/CVE-2020-9488)|If you are using Log4J 1’s SMTPAppender in your code, you already have a direct dependency that makes it exploitable. ESAPI does nothing to cause or prevent that.|None. ESAPI uses ConsoleAppender as the default appender even if ESAPI logging is configured to use Log4J 1.|
+|[5](https://github.com/ESAPI/esapi-java-legacy/blob/develop/documentation/ESAPI-security-bulletin5.pdf)|Invoking the method Commons IO method, FileNameUtils.normalize() with an improper input string could allow a limited path traversal.|[CWE-22](https://cwe.mitre.org/data/definitions/22.html)|[CVE-2021-29425](https://nvd.nist.gov/vuln/detail/CVE-2021-29425)|Commons IO is being pulled in via AntiSamy, which pulls in Apache Batik-CSS.  Batik-CSS is part of a larger Apache Xmlgraphics Batik family.Nothing in the Batik family of libraries uses org.apache.commons.io.FileNameUtils and neither ESAPI nor AntiSamy use Commons IO directly. Thus ESAPI is not affected by this CVE.|None. However may still show up in SCA output as AntiSamy using latest Apache Commons IO library version (2.6) that still support Java 7. AntiSamy 1.7 and later will require Java 8 as will ESAPI versions after 2.3.|
+|[6](https://github.com/ESAPI/esapi-java-legacy/blob/develop/documentation/ESAPI-security-bulletin6.pdf)|Flaw in Log4J 1’s JSMAppender could cause insecure deserialization potentially leading to remote code execution.|[CWE-502](https://cwe.mitre.org/data/definitions/502.html)|[CVE-2021-4104](https://nvd.nist.gov/vuln/detail/CVE-2021-4104)|All versions of ESAPI are vulnerable and impacted if your application is doing all 3 of the following:1) Using the deprecated ESAPI Log4J logging.2) You have changed your default log4j.xml (or log4j.properties) file to use JMSAppender.3) An attacker is able to overwrite the contents of your Log4J 1 configuration file.|None. ESAPI uses ConsoleAppender as the default appender even if ESAPI logging is configured to use Log4J 1.|
+|[7](https://github.com/ESAPI/esapi-java-legacy/blob/develop/documentation/ESAPI-security-bulletin7.pdf)|Improper validation (or, specifically, not using parameterized SQL queries) of a SQL statement makes Apache Log4j JDBCAppender vulnerable to SQL Injection. This potentially could allow attackers to execute unintended SQL statements by entering data that is logged via Log4J 1.|[CWE-89](https://cwe.mitre.org/data/definitions/89.html)|[CVE-2022-23305](https://nvd.nist.gov/vuln/detail/CVE-2022-23305)|All versions of ESAPI are vulnerable and impacted if your application is doing both of the following:1) Using the deprecated ESAPI Log4J logging.2) You have changed your default log4j.xml (or log4j.properties) file to use JDBCAppender.|None. ESAPI uses ConsoleAppender as the default appender even if ESAPI logging is configured to use Log4J 1.|
+|[8](https://github.com/ESAPI/esapi-java-legacy/blob/develop/documentation/ESAPI-security-bulletin8.pdf)<br/>[GHSA-q77q-vx4q-xx6q](https://github.com/ESAPI/esapi-java-legacy/security/advisories/GHSA-q77q-vx4q-xx6q)|Improper sanitization of user-controlled input permitted by an incorrect regular expression in an ESAPI configuration file can result in that input being unintentionally executing javascript: URLs, resulting in Cross-Site Scripting (XSS).|[CWE-79](https://cwe.mitre.org/data/definitions/79.html)|[CVE-2022-24891](https://nvd.nist.gov/vuln/detail/CVE-2022-24891)|A malformed regular expression in ESAPI’s default AntiSamy policy file, “antisamy-esapi.xml”, accidentally allowed the “:” character to match as a part of the “onsiteURL” regular expression. This allowed 'javascript:' pseudo-URIs to slip past ESAPI which could result in XSS vulnerabilities. Note that this vulnerability dates back at least to the ESAPI 1.4 release.|ESAPI 1.4 and all ESAPI 2.x versions before 2.3.0.0.|
+|[9](https://github.com/ESAPI/esapi-java-legacy/blob/develop/documentation/ESAPI-security-bulletin9.pdf)|Apache Log4j 1’s JMSSink is vulnerable to insecure deserialization of untrusted logged data when the attacker has write access to the Log4j configuration or if the configuration references an LDAP service that the attacker has access to. This may resulting in remote code execution.|[CWE-502](https://cwe.mitre.org/data/definitions/502.html)|[CVE-2022-23302](https://nvd.nist.gov/vuln/detail/CVE-2022-23302)|Remote Code Execution is possible.|None. ESAPI uses ConsoleAppender as the default appender even if ESAPI logging is configured to use Log4J 1.|
+|[10](https://github.com/ESAPI/esapi-java-legacy/blob/develop/documentation/ESAPI-security-bulletin10.pdf)|There is an RCE flaw caused by an insecure deserialization vulnerability in Apache Chainsaw, a Java-based GUI log viewer.            CVE-2020-9493 identified a deserialization issue that was present in Apache Chainsaw 2.x prior to 2.1.0. However, prior to Chainsaw V2.0, Chainsaw was a component of Apache Log4j 1.2.x where the same issue exists and remains unfixed.|[CWE-502](https://cwe.mitre.org/data/definitions/502.html)|[CVE-2022-23307](https://nvd.nist.gov/vuln/detail/CVE-2022-23307)|Remote Code Execution is possible if you are running Apache Chainsaw 1.x from the Apache Log4J 1.2.x jar..|None. ESAPI uses ConsoleAppender as the default appender even if ESAPI logging is configured to use Log4J 1.|
+|[GHSA-8m5h-hrqm-pxm2](https://github.com/ESAPI/esapi-java-legacy/security/advisories/GHSA-8m5h-hrqm-pxm2)|The default implementation of `Validator.getValidDirectoryPath(String, String, File, boolean)` may incorrectly treat the tested input string as a child of the specified parent directory. This potentially could allow control-flow bypass checks to be defeated if an attack can specify the entire string representing the 'input' path.|[CWE-22](https://cwe.mitre.org/data/definitions/22.html)|[CVE-2022-23457](https://nvd.nist.gov/vuln/detail/CVE-2022-23457)|Control-flow bypass may be possible.|ESAPI 2.x, prior to the ESAPI 2.3.0.0 release. Version 2.3.0.0 and later are patched.|
diff --git a/ant-javadoc.xml b/ant-javadoc.xml
deleted file mode 100644
index 2995a75..0000000
--- a/ant-javadoc.xml
+++ /dev/null
@@ -1,8 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<project default="javadoc">
-    <target name="javadoc">
-        <javadoc access="private" additionalparam="-J-Xmx768m " author="true" classpath="C:\Users\kww\.m2\repository\org\beanshell\bsh-core\2.0b4\bsh-core-2.0b4.jar;C:\Users\kww\.m2\repository\xalan\xalan\2.7.0\xalan-2.7.0.jar;C:\Users\kww\.m2\repository\logkit\logkit\1.0.1\logkit-1.0.1.jar;C:\Users\kww\.m2\repository\commons-io\commons-io\1.3\commons-io-1.3.jar;C:\Users\kww\.m2\repository\commons-collections\commons-collections\3.2\commons-collections-3.2.jar;C:\Users\kww\.m2\repository\commons-fileupload\commons-fileupload\1.2\commons-fileupload-1.2.jar;C:\Users\kww\.m2\repository\xml-apis\xml-apis\1.3.03\xml-apis-1.3.03.jar;C:\Users\kww\.m2\repository\org\apache\xmlgraphics\batik-util\1.7\batik-util-1.7.jar;C:\Users\kww\.m2\repository\commons-logging\commons-logging\1.1\commons-logging-1.1.jar;C:\Users\kww\.m2\repository\xom\xom\1.2.5\xom-1.2.5.jar;C:\Users\kww\.m2\repository\junit\junit\4.4\junit-4.4.jar;C:\Users\kww\.m2\repository\commons-beanutils\commons-beanutils\1.7.0\commons-beanutils-1.7.0.jar;C:\Users\kww\.m2\repository\xerces\xercesImpl\2.8.0\xercesImpl-2.8.0.jar;C:\Users\kww\.m2\repository\commons-codec\commons-codec\1.2\commons-codec-1.2.jar;C:\Users\kww\.m2\repository\commons-beanutils\commons-beanutils-core\1.7.0\commons-beanutils-core-1.7.0.jar;C:\Users\kww\.m2\repository\net\sourceforge\nekohtml\nekohtml\1.9.12\nekohtml-1.9.12.jar;C:\Users\kww\.m2\repository\org\apache\xmlgraphics\batik-css\1.7\batik-css-1.7.jar;C:\Users\kww\.m2\repository\xml-apis\xml-apis-ext\1.3.04\xml-apis-ext-1.3.04.jar;C:\Users\kww\.m2\repository\org\owasp\antisamy\antisamy\1.4.3\antisamy-1.4.3.jar;C:\Users\kww\.m2\repository\commons-httpclient\commons-httpclient\3.1\commons-httpclient-3.1.jar;C:\Users\kww\.m2\repository\javax\servlet\servlet-api\2.4\servlet-api-2.4.jar;C:\Users\kww\.m2\repository\commons-lang\commons-lang\2.3\commons-lang-2.3.jar;C:\Users\kww\.m2\repository\log4j\log4j\1.2.16\log4j-1.2.16.jar;C:\Users\kww\.m2\repository\commons-digester\commons-digester\1.8\commons-digester-1.8.jar;C:\Users\kww\.m2\repository\avalon-framework\avalon-framework\4.1.3\avalon-framework-4.1.3.jar;C:\Users\kww\.m2\repository\commons-configuration\commons-configuration\1.5\commons-configuration-1.5.jar;C:\Users\kww\.m2\repository\org\apache\xmlgraphics\batik-ext\1.7\batik-ext-1.7.jar;C:\Users\kww\.m2\repository\javax\servlet\jsp-api\2.0\jsp-api-2.0.jar;target/test-classes" destdir="doc" doctitle="OWASP ESAPI 2.1.0 API" nodeprecated="false" nodeprecatedlist="false" noindex="false" nonavbar="false" notree="false" packagenames="org.owasp.esapi.waf.rules,org.owasp.esapi.waf.actions,org.owasp.esapi.tags,org.owasp.esapi.waf.configuration" source="1.5" sourcefiles="src/main/java/org/owasp/esapi/errors/ConfigurationException.java,src/main/java/org/owasp/esapi/AccessController.java,src/main/java/org/owasp/esapi/reference/accesscontrol/DelegatingACR.java,src/main/java/org/owasp/esapi/Encryptor.java,src/main/java/org/owasp/esapi/Authenticator.java,src/main/java/org/owasp/esapi/errors/AccessControlException.java,src/main/java/org/owasp/esapi/util/DefaultMessageUtil.java,src/main/java/org/owasp/esapi/errors/EncodingException.java,src/main/java/org/owasp/esapi/reference/crypto/DefaultEncryptedProperties.java,src/main/java/org/owasp/esapi/reference/accesscontrol/policyloader/DynaBeanACRParameterLoader.java,src/main/java/org/owasp/esapi/AccessReferenceMap.java,src/main/java/org/owasp/esapi/reference/validation/HTMLValidationRule.java,src/main/java/org/owasp/esapi/errors/AuthenticationAccountsException.java,src/main/java/org/owasp/esapi/Randomizer.java,src/main/java/org/owasp/esapi/reference/accesscontrol/policyloader/PolicyParameters.java,src/main/java/org/owasp/esapi/errors/ValidationUploadException.java,src/main/java/org/owasp/esapi/crypto/KeyDerivationFunction.java,src/main/java/org/owasp/esapi/reference/DefaultIntrusionDetector.java,src/main/java/org/owasp/esapi/Logger.java,src/main/java/org/owasp/esapi/reference/DefaultSecurityConfiguration.java,src/main/java/org/owasp/esapi/IntrusionDetector.java,src/main/java/org/owasp/esapi/filters/SecurityWrapper.java,src/main/java/org/owasp/esapi/EncoderConstants.java,src/main/java/org/owasp/esapi/Encoder.java,src/main/java/org/owasp/esapi/reference/accesscontrol/policyloader/ACRParameterLoader.java,src/main/java/org/owasp/esapi/reference/accesscontrol/BaseACR.java,src/main/java/org/owasp/esapi/errors/AuthenticationException.java,src/main/java/org/owasp/esapi/reference/DefaultRandomizer.java,src/main/java/org/owasp/esapi/reference/validation/NumberValidationRule.java,src/main/java/org/owasp/esapi/reference/JavaLogFactory.java,src/main/java/org/owasp/esapi/codecs/JavaScriptCodec.java,src/main/java/org/owasp/esapi/errors/AuthenticationCredentialsException.java,src/main/java/org/owasp/esapi/reference/accesscontrol/DynaBeanACRParameter.java,src/main/java/org/owasp/esapi/errors/ExecutorException.java,src/main/java/org/owasp/esapi/filters/SecurityWrapperResponse.java,src/main/java/org/owasp/esapi/codecs/UnixCodec.java,src/main/java/org/owasp/esapi/codecs/WindowsCodec.java,src/main/java/org/owasp/esapi/waf/ConfigurationException.java,src/main/java/org/owasp/esapi/reference/Log4JLogFactory.java,src/main/java/org/owasp/esapi/Validator.java,src/main/java/org/owasp/esapi/crypto/CryptoDiscoverer.java,src/main/java/org/owasp/esapi/crypto/CipherTextSerializer.java,src/main/java/org/owasp/esapi/reference/validation/CreditCardValidationRule.java,src/main/java/org/owasp/esapi/AccessControlRule.java,src/main/java/org/owasp/esapi/reference/RandomAccessReferenceMap.java,src/main/java/org/owasp/esapi/errors/EncryptionRuntimeException.java,src/main/java/org/owasp/esapi/ValidationErrorList.java,src/main/java/org/owasp/esapi/ValidationRule.java,src/main/java/org/owasp/esapi/codecs/MySQLCodec.java,src/main/java/org/owasp/esapi/EncryptedProperties.java,src/main/java/org/owasp/esapi/reference/validation/DateValidationRule.java,src/main/java/org/owasp/esapi/codecs/HTMLEntityCodec.java,src/main/java/org/owasp/esapi/util/NullSafe.java,src/main/java/org/owasp/esapi/codecs/VBScriptCodec.java,src/main/java/org/owasp/esapi/reference/DefaultHTTPUtilities.java,src/main/java/org/owasp/esapi/PreparedString.java,src/main/java/org/owasp/esapi/errors/IntrusionException.java,src/main/java/org/owasp/esapi/crypto/CryptoHelper.java,src/main/java/org/owasp/esapi/crypto/CipherText.java,src/main/java/org/owasp/esapi/reference/accesscontrol/EchoRuntimeParameterACR.java,src/main/java/org/owasp/esapi/reference/accesscontrol/AlwaysTrueACR.java,src/main/java/org/owasp/esapi/codecs/Codec.java,src/main/java/org/owasp/esapi/errors/EnterpriseSecurityException.java,src/main/java/org/owasp/esapi/SecurityConfiguration.java,src/main/java/org/owasp/esapi/errors/AvailabilityException.java,src/main/java/org/owasp/esapi/reference/AbstractAuthenticator.java,src/main/java/org/owasp/esapi/waf/internal/InterceptingServletOutputStream.java,src/main/java/org/owasp/esapi/codecs/Hex.java,src/main/java/org/owasp/esapi/codecs/PercentCodec.java,src/main/java/org/owasp/esapi/codecs/Trie.java,src/main/java/org/owasp/esapi/codecs/HashTrie.java,src/main/java/org/owasp/esapi/reference/IntegerAccessReferenceMap.java,src/main/java/org/owasp/esapi/ESAPI.java,src/main/java/org/owasp/esapi/reference/Log4JLogger.java,src/main/java/org/owasp/esapi/crypto/PlainText.java,src/main/java/org/owasp/esapi/SafeFile.java,src/main/java/org/owasp/esapi/waf/internal/InterceptingHTTPServletResponse.java,src/main/java/org/owasp/esapi/errors/ValidationAvailabilityException.java,src/main/java/org/owasp/esapi/reference/AbstractAccessReferenceMap.java,src/main/java/org/owasp/esapi/crypto/CipherSpec.java,src/main/java/org/owasp/esapi/StringUtilities.java,src/main/java/org/owasp/esapi/codecs/OracleCodec.java,src/main/java/org/owasp/esapi/codecs/CSSCodec.java,src/main/java/org/owasp/esapi/waf/internal/Parameter.java,src/main/java/org/owasp/esapi/util/CollectionsUtil.java,src/main/java/org/owasp/esapi/crypto/CryptoToken.java,src/main/java/org/owasp/esapi/reference/crypto/ReferenceEncryptedProperties.java,src/main/java/org/owasp/esapi/errors/EnterpriseSecurityRuntimeException.java,src/main/java/org/owasp/esapi/HTTPUtilities.java,src/main/java/org/owasp/esapi/codecs/PushbackString.java,src/main/java/org/owasp/esapi/filters/ESAPIFilter.java,src/main/java/org/owasp/esapi/waf/internal/InterceptingHTTPServletRequest.java,src/main/java/org/owasp/esapi/reference/Log4JLoggerFactory.java,src/main/java/org/owasp/esapi/reference/validation/StringValidationRule.java,src/main/java/org/owasp/esapi/waf/ESAPIWebApplicationFirewallFilter.java,src/main/java/org/owasp/esapi/reference/accesscontrol/AlwaysFalseACR.java,src/main/java/org/owasp/esapi/errors/EncryptionException.java,src/main/java/org/owasp/esapi/codecs/Base64.java,src/main/java/org/owasp/esapi/errors/AuthenticationLoginException.java,src/main/java/org/owasp/esapi/reference/accesscontrol/policyloader/EchoDynaBeanPolicyParameterACR.java,src/main/java/org/owasp/esapi/reference/DefaultExecutor.java,src/main/java/org/owasp/esapi/errors/IntegrityException.java,src/main/java/org/owasp/esapi/codecs/XMLEntityCodec.java,src/main/java/org/owasp/esapi/User.java,src/main/java/org/owasp/esapi/filters/SecurityWrapperRequest.java,src/main/java/org/owasp/esapi/reference/DefaultEncoder.java,src/main/java/org/owasp/esapi/reference/crypto/JavaEncryptor.java,src/main/java/org/owasp/esapi/errors/AuthenticationHostException.java,src/main/java/org/owasp/esapi/util/ObjFactory.java,src/main/java/org/owasp/esapi/reference/crypto/EncryptedPropertiesUtils.java,src/main/java/org/owasp/esapi/crypto/SecurityProviderLoader.java,src/main/java/org/owasp/esapi/waf/internal/InterceptingPrintWriter.java,src/main/java/org/owasp/esapi/reference/DefaultUser.java,src/main/java/org/owasp/esapi/reference/accesscontrol/policyloader/ACRParameterLoaderHelper.java,src/main/java/org/owasp/esapi/filters/ClickjackFilter.java,src/main/java/org/owasp/esapi/reference/accesscontrol/policyloader/PolicyDTO.java,src/main/java/org/owasp/esapi/reference/DefaultValidator.java,src/main/java/org/owasp/esapi/reference/DefaultAccessController.java,src/main/java/org/owasp/esapi/codecs/DB2Codec.java,src/main/java/org/owasp/esapi/reference/accesscontrol/ExperimentalAccessController.java,src/main/java/org/owasp/esapi/errors/ValidationException.java,src/main/java/org/owasp/esapi/Executor.java,src/main/java/org/owasp/esapi/reference/validation/IntegerValidationRule.java,src/main/java/org/owasp/esapi/reference/accesscontrol/FileBasedACRs.java,src/main/java/org/owasp/esapi/filters/RequestRateThrottleFilter.java,src/main/java/org/owasp/esapi/util/ByteConversionUtil.java,src/main/java/org/owasp/esapi/reference/validation/BaseValidationRule.java,src/main/java/org/owasp/esapi/LogFactory.java,src/main/java/org/owasp/esapi/reference/accesscontrol/policyloader/ACRPolicyFileLoader.java,src/main/java/org/owasp/esapi/reference/FileBasedAuthenticator.java,src/main/java/org/owasp/esapi/errors/CertificateException.java,src/main/java/org/owasp/esapi/ExecuteResult.java" sourcepath="src/test/resources;src/test/java;src/main/java" splitindex="true" use="true" version="true">
-            <link href="http://java.sun.com/javase/7/docs/api/"/>
-        </javadoc>
-    </target>
-</project>
diff --git a/configuration/esapi/ESAPI.properties b/configuration/esapi/ESAPI.properties
index bbb7531..19c34b7 100644
--- a/configuration/esapi/ESAPI.properties
+++ b/configuration/esapi/ESAPI.properties
@@ -66,9 +66,6 @@ ESAPI.Encryptor=org.owasp.esapi.reference.crypto.JavaEncryptor
 ESAPI.Executor=org.owasp.esapi.reference.DefaultExecutor
 ESAPI.HTTPUtilities=org.owasp.esapi.reference.DefaultHTTPUtilities
 ESAPI.IntrusionDetector=org.owasp.esapi.reference.DefaultIntrusionDetector
-# Log4JFactory Requires log4j.xml or log4j.properties in classpath - http://www.laliluna.de/log4j-tutorial.html
-# Note that this is now considered deprecated!
-#ESAPI.Logger=org.owasp.esapi.logging.log4j.Log4JLogFactory
 ESAPI.Logger=org.owasp.esapi.logging.java.JavaLogFactory
 # To use the new SLF4J logger in ESAPI (see GitHub issue #129), set
 #    ESAPI.Logger=org.owasp.esapi.logging.slf4j.Slf4JLogFactory
diff --git a/configuration/log4j.dtd b/configuration/log4j.dtd
deleted file mode 100644
index 1aabd96..0000000
--- a/configuration/log4j.dtd
+++ /dev/null
@@ -1,227 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<!--
- Licensed to the Apache Software Foundation (ASF) under one or more
- contributor license agreements.  See the NOTICE file distributed with
- this work for additional information regarding copyright ownership.
- The ASF licenses this file to You under the Apache License, Version 2.0
- (the "License"); you may not use this file except in compliance with
- the License.  You may obtain a copy of the License at
-
-      http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-
-<!-- Authors: Chris Taylor, Ceki Gulcu. -->
-
-<!-- Version: 1.2 -->
-
-<!-- A configuration element consists of optional renderer
-elements,appender elements, categories and an optional root
-element. -->
-
-<!ELEMENT log4j:configuration (renderer*, appender*,plugin*, (category|logger)*,root?,
-                               (categoryFactory|loggerFactory)?)>
-
-<!-- The "threshold" attribute takes a level value below which -->
-<!-- all logging statements are disabled. -->
-
-<!-- Setting the "debug" enable the printing of internal log4j logging   -->
-<!-- statements.                                                         -->
-
-<!-- By default, debug attribute is "null", meaning that we not do touch -->
-<!-- internal log4j logging settings. The "null" value for the threshold -->
-<!-- attribute can be misleading. The threshold field of a repository	 -->
-<!-- cannot be set to null. The "null" value for the threshold attribute -->
-<!-- simply means don't touch the threshold field, the threshold field   --> 
-<!-- keeps its old value.                                                -->
-     
-<!ATTLIST log4j:configuration
-  xmlns:log4j              CDATA #FIXED "http://jakarta.apache.org/log4j/" 
-  threshold                (all|trace|debug|info|warn|error|fatal|off|null) "null"
-  debug                    (true|false|null)  "null"
-  reset                    (true|false) "false"
->
-
-<!-- renderer elements allow the user to customize the conversion of  -->
-<!-- message objects to String.                                       -->
-
-<!ELEMENT renderer EMPTY>
-<!ATTLIST renderer
-  renderedClass  CDATA #REQUIRED
-  renderingClass CDATA #REQUIRED
->
-
-<!-- Appenders must have a name and a class. -->
-<!-- Appenders may contain an error handler, a layout, optional parameters -->
-<!-- and filters. They may also reference (or include) other appenders. -->
-<!ELEMENT appender (errorHandler?, param*,
-      rollingPolicy?, triggeringPolicy?, connectionSource?,
-      layout?, filter*, appender-ref*)>
-<!ATTLIST appender
-  name 		CDATA 	#REQUIRED
-  class 	CDATA	#REQUIRED
->
-
-<!ELEMENT layout (param*)>
-<!ATTLIST layout
-  class		CDATA	#REQUIRED
->
-
-<!ELEMENT filter (param*)>
-<!ATTLIST filter
-  class		CDATA	#REQUIRED
->
-
-<!-- ErrorHandlers can be of any class. They can admit any number of -->
-<!-- parameters. -->
-
-<!ELEMENT errorHandler (param*, root-ref?, logger-ref*,  appender-ref?)> 
-<!ATTLIST errorHandler
-   class        CDATA   #REQUIRED 
->
-
-<!ELEMENT root-ref EMPTY>
-
-<!ELEMENT logger-ref EMPTY>
-<!ATTLIST logger-ref
-  ref CDATA #REQUIRED
->
-
-<!ELEMENT param EMPTY>
-<!ATTLIST param
-  name		CDATA   #REQUIRED
-  value		CDATA	#REQUIRED
->
-
-
-<!-- The priority class is org.apache.log4j.Level by default -->
-<!ELEMENT priority (param*)>
-<!ATTLIST priority
-  class   CDATA	#IMPLIED
-  value	  CDATA #REQUIRED
->
-
-<!-- The level class is org.apache.log4j.Level by default -->
-<!ELEMENT level (param*)>
-<!ATTLIST level
-  class   CDATA	#IMPLIED
-  value	  CDATA #REQUIRED
->
-
-
-<!-- If no level element is specified, then the configurator MUST not -->
-<!-- touch the level of the named category. -->
-<!ELEMENT category (param*,(priority|level)?,appender-ref*)>
-<!ATTLIST category
-  class         CDATA   #IMPLIED
-  name		CDATA	#REQUIRED
-  additivity	(true|false) "true"  
->
-
-<!-- If no level element is specified, then the configurator MUST not -->
-<!-- touch the level of the named logger. -->
-<!ELEMENT logger (level?,appender-ref*)>
-<!ATTLIST logger
-  name		CDATA	#REQUIRED
-  additivity	(true|false) "true"  
->
-
-
-<!ELEMENT categoryFactory (param*)>
-<!ATTLIST categoryFactory 
-   class        CDATA #REQUIRED>
-
-<!ELEMENT loggerFactory (param*)>
-<!ATTLIST loggerFactory
-   class        CDATA #REQUIRED>
-
-<!ELEMENT appender-ref EMPTY>
-<!ATTLIST appender-ref
-  ref CDATA #REQUIRED
->
-
-<!-- plugins must have a name and class and can have optional parameters -->
-<!ELEMENT plugin (param*, connectionSource?)>
-<!ATTLIST plugin
-  name 		CDATA 	   #REQUIRED
-  class 	CDATA  #REQUIRED
->
-
-<!ELEMENT connectionSource (dataSource?, param*)>
-<!ATTLIST connectionSource
-  class        CDATA  #REQUIRED
->
-
-<!ELEMENT dataSource (param*)>
-<!ATTLIST dataSource
-  class        CDATA  #REQUIRED
->
-
-<!ELEMENT triggeringPolicy ((param|filter)*)>
-<!ATTLIST triggeringPolicy
-  name 		CDATA  #IMPLIED
-  class 	CDATA  #REQUIRED
->
-
-<!ELEMENT rollingPolicy (param*)>
-<!ATTLIST rollingPolicy
-  name 		CDATA  #IMPLIED
-  class 	CDATA  #REQUIRED
->
-
-
-<!-- If no priority element is specified, then the configurator MUST not -->
-<!-- touch the priority of root. -->
-<!-- The root category always exists and cannot be subclassed. -->
-<!ELEMENT root (param*, (priority|level)?, appender-ref*)>
-
-
-<!-- ==================================================================== -->
-<!--                       A logging event                                -->
-<!-- ==================================================================== -->
-<!ELEMENT log4j:eventSet (log4j:event*)>
-<!ATTLIST log4j:eventSet
-  xmlns:log4j             CDATA #FIXED "http://jakarta.apache.org/log4j/" 
-  version                (1.1|1.2) "1.2" 
-  includesLocationInfo   (true|false) "true"
->
-
-
-
-<!ELEMENT log4j:event (log4j:message, log4j:NDC?, log4j:throwable?, 
-                       log4j:locationInfo?, log4j:properties?) >
-
-<!-- The timestamp format is application dependent. -->
-<!ATTLIST log4j:event
-    logger     CDATA #REQUIRED
-    level      CDATA #REQUIRED
-    thread     CDATA #REQUIRED
-    timestamp  CDATA #REQUIRED
-    time       CDATA #IMPLIED
->
-
-<!ELEMENT log4j:message (#PCDATA)>
-<!ELEMENT log4j:NDC (#PCDATA)>
-
-<!ELEMENT log4j:throwable (#PCDATA)>
-
-<!ELEMENT log4j:locationInfo EMPTY>
-<!ATTLIST log4j:locationInfo
-  class  CDATA	#REQUIRED
-  method CDATA	#REQUIRED
-  file   CDATA	#REQUIRED
-  line   CDATA	#REQUIRED
->
-
-<!ELEMENT log4j:properties (log4j:data*)>
-
-<!ELEMENT log4j:data EMPTY>
-<!ATTLIST log4j:data
-  name   CDATA	#REQUIRED
-  value  CDATA	#REQUIRED
->
diff --git a/configuration/log4j.xml b/configuration/log4j.xml
deleted file mode 100644
index 47c0640..0000000
--- a/configuration/log4j.xml
+++ /dev/null
@@ -1,62 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
-<!--
-        #     #    #    ######  #     #   ###   #     #  #####
-        #  #  #   # #   #     # ##    #    #    ##    # #     #
-        #  #  #  #   #  #     # # #   #    #    # #   # #
-        #  #  # #     # ######  #  #  #    #    #  #  # #  ####
-        #  #  # ####### #   #   #   # #    #    #   # # #     #
-        #  #  # #     # #    #  #    ##    #    #    ## #     #
-         ## ##  #     # #     # #     #   ###   #     #  #####
-
-        WARNING:    Log4j 1.x has been deprecated in ESAPI since 2020-07-23 in
-                    release 2.2.1.0.  It will be removed in a future release.
-                    The new default for ESAPI logging is JUL.  Either switch
-                    to JUL or SLF4J (which can support log4j 2). See the latest
-                    release notes for further details.
-  -->
-<!-- main resources -->
-<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">
-  <appender name="console" class="org.apache.log4j.ConsoleAppender"> 
-    <param name="Target" value="System.out"/> 
-    <layout class="org.apache.log4j.PatternLayout"> 
-      <param name="ConversionPattern" value="%-5p %m%n"/> 
-    </layout> 
-  </appender> 
-
-  <logger name="org.owasp.esapi.reference.TestTrace">
-    <level value="trace"/>
-  </logger>
-
-  <logger name="org.owasp.esapi.reference.TestDebug">
-    <level value="debug"/>
-  </logger>
-
-  <logger name="org.owasp.esapi.reference.TestInfo">
-    <level value="info"/>
- </logger>
-
-  <logger name="org.owasp.esapi.reference.TestWarning">
-    <level value="warn"/>
-  </logger>
-
-  <logger name="org.owasp.esapi.reference.TestError">
-    <level value="error"/>
-  </logger>
-
-  <logger name="org.owasp.esapi.reference.TestFatal">
-    <level value="fatal"/>
-  </logger>
-
-  <logger name="org.owasp.esapi.reference">
-    <level value="info"/>
-  </logger>
-
-  <root> 
-    <priority value ="debug" /> 
-    <appender-ref ref="console" /> 
-  </root>
-
-  <loggerFactory class="org.owasp.esapi.logging.log4j.Log4JLogFactory"/>
-  
-</log4j:configuration>
diff --git a/debian/changelog b/debian/changelog
index 7f04655..faab8ae 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,9 @@
+libowasp-esapi-java (2.4.0.0+git20221127.1.565ba3c-1) UNRELEASED; urgency=low
+
+  * New upstream snapshot.
+
+ -- Debian Janitor <janitor@jelmer.uk>  Sun, 08 Jan 2023 19:08:33 -0000
+
 libowasp-esapi-java (2.4.0.0-2) unstable; urgency=medium
 
   * Team upload.
diff --git a/documentation/ESAPI-configuration-user-guide.md b/documentation/ESAPI-configuration-user-guide.md
index 72694bb..420a4fb 100644
--- a/documentation/ESAPI-configuration-user-guide.md
+++ b/documentation/ESAPI-configuration-user-guide.md
@@ -41,7 +41,7 @@ until these deprecated methods are removed, but it will be a minumum of 2 years
 or 1 major release [e.g., 3.x], whichever comes first. Also, we may not
 necessarily remove all of them at once, depending on community feedback.)
 
-DefaultSecurityConfiguration implements the new contract. New contract methods implementations work as described in 
+DefaultSecurityConfiguration implements the new contract. New contract methods implementations work as described in
 'Multiple configuration files support' paragraph.
 
 ## Multiple configuration files support
@@ -49,7 +49,7 @@ DefaultSecurityConfiguration implements the new contract. New contract methods i
 EsapiPropertyManager is the new implementation for getting properties, which uses prioritized property loaders (each one associated with a specific configuration file). This allows to have multiple configuration files existing with priority connected to each one. At this moment, there
 are two configuration files possible to use, the path to them is set through following Java
 system properties:
- 
+
 * org.owasp.esapi.opsteam = <full_path_to_file> (higher priority config)
 * org.owasp.esapi.devteam = <full_path_to_file> (lower priority config)
 
@@ -86,9 +86,9 @@ ESAPI.securityConfiguration().getBooleanProp("propertyXXX");
 where "propertyXXX" is some property name relevant to ESAPI (and
 in this case, one that would hold a boolean value). See ESAPI.properties
 for a list of current property names known to ESAPI.
- 
+
 In above example, following happens:
-  
+
 1. org.owasp.esapi.opsteam configuration is used to get propertyXXX and return it as boolean.
 2. If (1) fails to find property, org.owasp.esapi.devteam is used to get propertyXXX and return it as boolean.
 3. If (2) fails to find property, ESAPI.properties is used to get propertyXXX and return it as boolean.
diff --git a/documentation/ESAPI-release-steps.odt b/documentation/ESAPI-release-steps.odt
index ea02433..c54ff25 100644
Binary files a/documentation/ESAPI-release-steps.odt and b/documentation/ESAPI-release-steps.odt differ
diff --git a/documentation/ESAPI-release-steps.pdf b/documentation/ESAPI-release-steps.pdf
index 405dc1d..62fe3fe 100644
Binary files a/documentation/ESAPI-release-steps.pdf and b/documentation/ESAPI-release-steps.pdf differ
diff --git a/documentation/ESAPI-security-bulletin10.odt b/documentation/ESAPI-security-bulletin10.odt
new file mode 100644
index 0000000..87db70d
Binary files /dev/null and b/documentation/ESAPI-security-bulletin10.odt differ
diff --git a/documentation/ESAPI-security-bulletin10.pdf b/documentation/ESAPI-security-bulletin10.pdf
new file mode 100644
index 0000000..90b84b4
Binary files /dev/null and b/documentation/ESAPI-security-bulletin10.pdf differ
diff --git a/documentation/ESAPI-security-bulletin8.odt b/documentation/ESAPI-security-bulletin8.odt
index 81a1d98..2b73a5e 100644
Binary files a/documentation/ESAPI-security-bulletin8.odt and b/documentation/ESAPI-security-bulletin8.odt differ
diff --git a/documentation/ESAPI-security-bulletin8.pdf b/documentation/ESAPI-security-bulletin8.pdf
index 04f8767..646050e 100644
Binary files a/documentation/ESAPI-security-bulletin8.pdf and b/documentation/ESAPI-security-bulletin8.pdf differ
diff --git a/documentation/ESAPI-security-bulletin9.odt b/documentation/ESAPI-security-bulletin9.odt
new file mode 100644
index 0000000..68b1ba7
Binary files /dev/null and b/documentation/ESAPI-security-bulletin9.odt differ
diff --git a/documentation/ESAPI-security-bulletin9.pdf b/documentation/ESAPI-security-bulletin9.pdf
new file mode 100644
index 0000000..ed46ea8
Binary files /dev/null and b/documentation/ESAPI-security-bulletin9.pdf differ
diff --git a/documentation/LoggerDesignAndTesting.md b/documentation/LoggerDesignAndTesting.md
index 259488a..d3542a4 100644
--- a/documentation/LoggerDesignAndTesting.md
+++ b/documentation/LoggerDesignAndTesting.md
@@ -22,6 +22,6 @@ The general workflow is:
 
     Logger.info/warn/etc(message) -> forwards to LogBridgelog(logger, esapiLevel, type, message) -> forwards to LogHandler.log(...) -> forwards to slf4j Logger implementation with appropriate level and composed message.
 
-So each of the tests for each of the classes verifies data in -> data out based on the Logging API.  The structure for JUL, Log4J, and SLF4J are almost identical.  There are a few differences in the interaction with the underlying Logger interactions and expectations.  As a result, the tests are also almost full duplications (again accounting for differences in the underlying logging API).
+So each of the tests for each of the classes verifies data in -> data out based on the Logging API.  The structure for JUL and SLF4J are almost identical.  There are a few differences in the interaction with the underlying Logger interactions and expectations.  As a result, the tests are also almost full duplications (again accounting for differences in the underlying logging API).
 
 -J
diff --git a/documentation/esapi4java-2.0-readme.txt b/documentation/esapi4java-2.0-readme.txt
index 7f568fb..7fd25e0 100644
--- a/documentation/esapi4java-2.0-readme.txt
+++ b/documentation/esapi4java-2.0-readme.txt
@@ -7,7 +7,7 @@ Here are the most significant directories and files included the zip file for th
 
 File / Directory                                                        Description
 =========================================================================================
-<root>/	
+<root>/
 |
 +---configuration/                                                      Directory of ESAPI configuration files
 |     |
diff --git a/documentation/esapi4java-2.0rc6-override-log4jloggingfactory.txt b/documentation/esapi4java-2.0rc6-override-log4jloggingfactory.txt
index 49accdb..35290f5 100644
--- a/documentation/esapi4java-2.0rc6-override-log4jloggingfactory.txt
+++ b/documentation/esapi4java-2.0rc6-override-log4jloggingfactory.txt
@@ -1,4 +1,4 @@
-This release includes critical changes to the ESAPI Log4JLogger that will now allow you to over-ride the user specific 
+This release includes critical changes to the ESAPI Log4JLogger that will now allow you to over-ride the user specific
 message using your own User or java.security.Principal implementation.
 
 There are a three critical steps that need to be taken to over-ride the ESAPI Log4JLogger:
@@ -23,8 +23,8 @@ ESAPI.Logger=com.yourcompany.logging.ExtendedLog4JFactory
 
 And you should be all set!
 
-PS: The original ESAPI Log4JLogging class used a secure random number as a replacement to logging the session ID. This allowed 
-us to tie log messages from the same session together, without exposing the actual session id in the log file. The code looks 
+PS: The original ESAPI Log4JLogging class used a secure random number as a replacement to logging the session ID. This allowed
+us to tie log messages from the same session together, without exposing the actual session id in the log file. The code looks
 like this, and you may wish to use it in your over-ridden version of getUserInfo.
 
 HttpServletRequest request = ESAPI.httpUtilities().getCurrentRequest();
@@ -40,7 +40,7 @@ if ( request != null ) {
     }
 }
 
-In fact, here is the entire original getUserInfo() implementation (that was tied to the ESAPI request and user object) – 
+In fact, here is the entire original getUserInfo() implementation (that was tied to the ESAPI request and user object) –
 you may wish to emulate some of this.
 
 public String getUserInfo() {
@@ -58,14 +58,14 @@ public String getUserInfo() {
             }
         }
     }
-    
+
     // log user information - username:session@ipaddr
-    User user = ESAPI.authenticator().getCurrentUser();            
+    User user = ESAPI.authenticator().getCurrentUser();
     String userInfo = "";
     //TODO - make type logging configurable
     if ( user != null) {
         userInfo += user.getAccountName()+ ":" + sid + "@"+ user.getLastHostAddress();
     }
-    
+
     return userInfo;
 }
diff --git a/documentation/esapi4java-core-2.0-readme-crypto-changes.html b/documentation/esapi4java-core-2.0-readme-crypto-changes.html
index 8687f5c..db403b9 100644
--- a/documentation/esapi4java-core-2.0-readme-crypto-changes.html
+++ b/documentation/esapi4java-core-2.0-readme-crypto-changes.html
@@ -63,7 +63,7 @@ encrypted with the same key, those identical blocks of ciphertext
 always encrypt to the same ciphertext block, thus revealing patterns
 in the plaintext input. For example, these images from Wikipedia's
 <A HREF="http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation">Block
-cipher modes of operation</A> illustrate this point well: 
+cipher modes of operation</A> illustrate this point well:
 </P>
 <TABLE BORDER=0 CELLPADDING=4 CELLSPACING=0>
 	<TR>
@@ -92,7 +92,7 @@ cipher modes of operation</A> illustrate this point well:
 <P>Ciphertext encrypted with ECB cipher mode are also subject to
 &quot;block replay attacks&quot;. See Bruce Schneier's <A HREF="http://www.google.com/url?sa=t&amp;source=web&amp;ct=res&amp;cd=2&amp;url=http%3A%2F%2Fbooks.google.com%2Fbooks%3Fid%3DA6ZO2D6ayNwC%26pg%3DPT216%26lpg%3DPT216%26dq%3Decb%2B%2522block%2Breplay%2522%26source%3Dbl%26ots%3DiEbAWQpu0e%26sig%3D8xiUva4XKaAOfPJEPsULPAJPk88%26hl%3Den%26ei%3Da6yISoLQPJOuMI-Z_OkE%26sa%3DX%26oi%3Dbook_result%26ct%3Dresult%26resnum%3D2&amp;ei=a6yISoLQPJOuMI-Z_OkE&amp;rct=j&amp;q=ecb+%22block+replay%22&amp;usg=AFQjCNF-IjrE4dL7M2LELh48hYPP6A_bpQ"><I>Applied
 Cryptography: protocols, algorithms, and source code</I> </A>for
-details. 
+details.
 </P>
 <P>In both ESAPI 2.0-rc1 and 2.0-rc2, one can choose other block
 ciphers (e.g. Blowfish) or other key sizes (e.g., 512-bit AES), but
@@ -123,7 +123,7 @@ are many. Here are some of the main issues:</P>
 </OL>
 <H2>The Encryption Changes in ESAPI 2.0-rc3 and Later</H2>
 <P>Briefly speaking, the changes being implemented for ESAPI Java 2.0
-are: 
+are:
 </P>
 <OL>
 	<LI><P STYLE="margin-bottom: 0in">Starting in ESAPI Java 2.0-rc3,
@@ -156,7 +156,7 @@ are:
 	response was deafening. There literally was but a single response
 	and that was to kill off <CODE>LegacyJavaEncryptor</CODE><CODE><FONT FACE="Thorndale AMT, serif">.</FONT></CODE>
 	(By this time, the two symmetric encryption interfaces in <CODE>Encryptor</CODE>
-	had already been deprecated.) 
+	had already been deprecated.)
 	</P>
 	<LI><P>The byte-encoding has been changed from native byte encoding
 	to UTF-8 byte-encoding throughout ESAPI 2.0 and not just for
@@ -167,7 +167,7 @@ are:
 	guaranteed.</P>
 </OL>
 <H2>The Good, the Bad, and the Ugly</H2>
-<P>Or put another way, there are always trade-offs to be made... 
+<P>Or put another way, there are always trade-offs to be made...
 </P>
 <H3>The Good</H3>
 <P>We get improved security by encouraging the use of stronger cipher
@@ -205,9 +205,9 @@ file.)</P>
 both to encrypt and decrypt. While it is not required that the IV be
 kept secret from adversaries, there are some attacks that are
 possible if the adversary is permitted to alter the IV at will and
-observe the results of the ensuing decryption attempt. 
+observe the results of the ensuing decryption attempt.
 </P>
-<P>So that leaves two choices for the IV: 
+<P>So that leaves two choices for the IV:
 </P>
 <UL>
 	<LI><P STYLE="margin-bottom: 0in">Using a <I><B>fixed IV</B></I>:
@@ -223,7 +223,7 @@ observe the results of the ensuing decryption attempt.
 	persisted (e.g., to a database) or transmitted to the recipient this
 	random IV must be stored / made known. Therefore, the raw ciphertext
 	can no longer suffice; whatever random IV that was chosen must be
-	communicated. 
+	communicated.
 	</P>
 </UL>
 <P>Likewise, the use of padding is going to add some overhead to the
@@ -360,7 +360,7 @@ between 1 to the cipher block size (in bits) / 8 bytes. For AES, the
 cipher block size is 128-bits, but more typically, a cipher's block
 size is 64-bits so the padding would be between 1 to 16 bytes for AES
 and 1 to 8 bytes for a 64-bit block size cipher and the IV would be
-IV would be 16 bytes for AES and 8 bytes for most other ciphers. 
+IV would be 16 bytes for AES and 8 bytes for most other ciphers.
 </P>
 <H3>The Ugly</H3>
 <P>Well, so far, this &quot;bad&quot; news may be bad for you but
@@ -370,7 +370,7 @@ recoding of your database table sizes.</P>
 <P>But wait Skippy, don't go running off just quite yet. As Robert
 Heinlein wrote in his 1966 novel <I>The Moon is a Harsh Mistress</I>
 &quot;There ain't no such thing as a free lunch&quot;. (Some of us
-more hardened cynics know it more commonly as <I>TANSTAAFL</I>.) 
+more hardened cynics know it more commonly as <I>TANSTAAFL</I>.)
 </P>
 <P>As mentioned earlier, backward compatibility with ESAPI 1.4
 (originally planned via <CODE>LegacyJavaEncryptor</CODE>) has been
@@ -395,11 +395,11 @@ and ciphertext (<CODE>CipherText)</CODE> class to coalesce all this
 complexity of handling the ciphertext result from encryption
 operations. And then there are new encryption and decryption methods
 for the <CODE>Encryptor</CODE> interface. Specifically, the encrypt
-and decrypt methods have been generalized as: 
+and decrypt methods have been generalized as:
 </P>
 <PRE STYLE="margin-left: 0.49in"><FONT COLOR="#000000"><FONT FACE="Monospace">CipherText encrypt(SecretKey key, PlainText plaintext)</FONT></FONT>
 <FONT COLOR="#000000">        <FONT FACE="Monospace">throws EncryptionException;</FONT></FONT></PRE><P STYLE="margin-bottom: 0in">
-and 
+and
 </P>
 <PRE STYLE="margin-left: 0.49in"><FONT COLOR="#000000"><FONT FACE="Monospace">PlainText decrypt(SecretKey key, CipherText ciphertext)</FONT></FONT>
 <FONT COLOR="#000000">        <FONT FACE="Monospace">throws EncryptionException</FONT></FONT></PRE><P>
@@ -409,7 +409,7 @@ argument and instead use the <FONT FACE="DejaVu Sans Mono, sans-serif">SecretKey
 based on <FONT FACE="DejaVu Sans Mono, sans-serif">Encryptor.MasterKey</FONT>.)</P>
 <P>The two existing interfaces from ESAPI 1.4 and earlier:</P>
 <PRE STYLE="margin-left: 0.49in; margin-bottom: 0.2in">String encrypt(String plaintext) throws EncryptionException</PRE><P STYLE="margin-bottom: 0in">
-and 
+and
 </P>
 <PRE STYLE="margin-left: 0.49in; margin-bottom: 0.2in">String decrypt(String ciphertext) throws EncryptionException</PRE><P>
 are still supported but have been <I>deprecated</I>, mainly because
diff --git a/documentation/esapi4java-core-2.0-symmetric-crypto-user-guide.html b/documentation/esapi4java-core-2.0-symmetric-crypto-user-guide.html
index d0ecfb2..19298d4 100644
--- a/documentation/esapi4java-core-2.0-symmetric-crypto-user-guide.html
+++ b/documentation/esapi4java-core-2.0-symmetric-crypto-user-guide.html
@@ -353,7 +353,7 @@ are ones that you would replace.</P>
 <H2>How the Old (Deprecated) Methods Were Used</H2>
 <P>To encrypt / decrypt using the String-based, deprecated methods
 carried over from ESAPI 1.4, code similar to the following would be
-used. 
+used.
 </P>
 <PRE>    String myplaintext = &quot;My plaintext&quot;;
     try {
@@ -411,10 +411,10 @@ resulting in (possibly complete) leakage of the corresponding plaintext.
 <P>Using the new encryption / decryption methods is somewhat more
 complicated, but this is in part because they are more flexible and
 that flexibility means that more information needs to be communicated
-as to the details of the encryption. 
+as to the details of the encryption.
 </P>
 <P>A code snippet using the new methods that use the master
-encryption key would look something like this: 
+encryption key would look something like this:
 </P>
 <PRE>    String myplaintext = &quot;My plaintext&quot;;
     try {
@@ -432,7 +432,7 @@ methods may not, and 2) it provides for <I>authenticity</I> <I><B>and</B></I>
 mode is chosen.</P>
 <P>Also, these new methods allow a general byte array to be
 encrypted, not just a Java String. If one needed to encrypt a byte
-array with the old deprecated method, one would first have to use 
+array with the old deprecated method, one would first have to use
 </P>
 <PRE>    byte[] plaintextByteArray = { /* byte array to be encrypted */ };
     String plaintext = new String(plaintextByteArray, &quot;UTF-8&quot;);</PRE><P>
@@ -541,7 +541,7 @@ to encrypt both bank account numbers and credit card numbers. The
 encrypted bank account numbers are to be sent to one recipient and
 the encrypted credit card numbers are to be sent to a different
 recipient. Obviously in such cases, you do not want to share the same
-key for both recipients. 
+key for both recipients.
 </P>
 <P>In ESAPI 1.4 there was not much you can do, but in ESAPI 2.0 and
 later, there are new encryption / decryption methods that allow you
@@ -553,14 +553,14 @@ will assume that secret keys are first generated, and then
 distributed to the recipients out-of-band. On you could distribute
 them dynamically via asymmetric encryption assuming that you've
 previously exchanged public keys with the recipients.)</P>
-<P>The following illustrates how these new methods might be used. 
+<P>The following illustrates how these new methods might be used.
 </P>
 <P>First, we would generate some appropriate secret keys and
 distribute them securely (e.g., perhaps over SSL/TLS) or exchange
 them earlier out-of-band to the intended recipients. (E.g., one could
 put them on two separate thumb drives and use a trusted courier to
 distribute them to the recipients or one could use PGP-mail or S/MIME
-to securely email them, etc.) 
+to securely email them, etc.)
 </P>
 <PRE>    // Generate two random, 128-bit AES keys to be distributed out-of-band.
     import javax.crypto.SecretKey;
@@ -587,10 +587,10 @@ to securely email them, etc.)
 Second, these keys would be printed out and stored somewhere secure
 by our application, perhaps using something like ESAPI's
 <CODE>EncryptedProperties</CODE> class, where they could later be
-retrieved and used. 
+retrieved and used.
 </P>
 <P>In the following code, we assume that the <CODE>SecretKey</CODE>
-values have already been initialized elsewhere. 
+values have already been initialized elsewhere.
 </P>
 <PRE>    SecretKey bankAcctKey = ...;        // These might be read from EncryptedProperties
     SecretKey credCardKey = ...;        // or from a restricted database, etc.
diff --git a/documentation/esapi4java-core-2.1-release-notes.txt b/documentation/esapi4java-core-2.1-release-notes.txt
index d84097d..e97e56c 100644
--- a/documentation/esapi4java-core-2.1-release-notes.txt
+++ b/documentation/esapi4java-core-2.1-release-notes.txt
@@ -8,7 +8,7 @@ ESAPI for Java - 2.1.0 Release Notes
    deprecated more than 2 years ago and they are known to be insecure
    (they are vulnerable to padding oracle attacks), the ESAPI team has
    decided to remove them in accordance to their support policy.
-   
+
    See comments for issue #306 for further details, as well as additional
    safety precautions that you may wish to take in the unlikely, but possible
    event that this vulnerability resulted in an actual security breach.
@@ -64,5 +64,5 @@ NOTE: A follow-up patch release is scheduled within the next few months to
       based on findings in Google Issue # 306. I will periodically try
       to keep the ESAPI mailing lists updated with the progress so watch
       there for emerging details and anticipated schedule.
-      
+
 -Kevin W. Wall <kevin.w.wall@gmail.com>, 2013-08-30
diff --git a/documentation/esapi4java-core-2.2.0.0-release-notes.txt b/documentation/esapi4java-core-2.2.0.0-release-notes.txt
index 8deafbb..b43efc7 100644
--- a/documentation/esapi4java-core-2.2.0.0-release-notes.txt
+++ b/documentation/esapi4java-core-2.2.0.0-release-notes.txt
@@ -46,7 +46,7 @@ Issue #			GitHub Issue Title
 37		RandomAccessReferenceMap.update() can randomly corrupt the map
 71		java.lang.ExceptionInInitializerError in 2.0 version
 129		Add Logging support for SLF4J
-157		minimum-config deployment fails 
+157		minimum-config deployment fails
 188		SecurityWrapperRequest seems to mishandle/swallow allowNull argument
 209		Build an encoding function specific to HTTP/Response Splitting (tactical remediation)
 213		Provide a taglib descriptor (.tld file)
@@ -116,7 +116,7 @@ Issue #			GitHub Issue Title
 386		Avoid using System.err in EsapiPropertyManager
 387		&#39;mvn site&#39; fails for FindBugs report, causing &#39;site&#39; goal to fail
 389		Provide an option for the encodeForLDAP method to not encode wildcard characters
-394		Refactor Validator.getCanonicalizedUri into Encoder.  
+394		Refactor Validator.getCanonicalizedUri into Encoder.
 395		Issues when I am passing htttp://localhost:8080/user=admin&amp;prodversion=no
 396		Trust Boundary Violation - while triggering veracode
 397		Update Resource path search to maintain legacy behavior in DefaultSecurityConfiguration.java
@@ -128,7 +128,7 @@ Issue #			GitHub Issue Title
 417		Add additional protection against CVE-2016-1000031
 422		Inconsistent dependency structure and vulnerable xml (xerces, xalan, xml-apis ...) dependencies
 424		issue with Filename encoding for executeSystemCommand
-425		Project build error: Non-resolvable parent POM for org.owasp.esapi:esapi:2.1.0.2-SNAPSHOT: Could not transfer artifact 
+425		Project build error: Non-resolvable parent POM for org.owasp.esapi:esapi:2.1.0.2-SNAPSHOT: Could not transfer artifact
 427		HTTP cookie validation rules too restrictive?
 429		Miscellaneous updates to pom.xml
 432		ESAPI.properties not found.
@@ -140,7 +140,7 @@ Issue #			GitHub Issue Title
 442		Remove deprecated fields in Encoder interface
 444		Delete deprecated method Base64.decodeToObject() and related methods
 445		A bunch of dependencies are out of date , I will list them below with the associated vulnerability
-447		can&#39;t generate MasterKey / MasterSalt 
+447		can&#39;t generate MasterKey / MasterSalt
 448		Clean up pom.xml
 454		about code eclipse formatter template question
 455		New release for mitigation of CVEs
@@ -194,7 +194,7 @@ Issue #			GitHub Issue Title
 
     Issue 483     More miscellaneous prep work for ESAPI 2.2.0.0 release
         Specifically, CipherText.getSerialVersionUID() and DefaultSecurityConfiguration.MAX_FILE_NAME_LENGTH have actually been deleted from the ESAPI code base. For the former, use CipherText.cipherTextVersion() instead. For the latter, there is no replacement. (This wasn't being used, but it was set to 1000 in case you're wondering.)
-        
+
 * Various properties in ESAPI.properties were changed in a way that might affect your application:
     Issue 439		Tighten ESAPI defaults to disallow dubious file suffixes
 
@@ -220,10 +220,10 @@ Issue #			GitHub Issue Title
                                                     Validator.HTTPQueryString=^([a-zA-Z0-9_\\-]{1,32}=[\\p{L}\\p{N}.\\-/+=_ !$*?@%]*&?)*$
                                                 (Left as an exercise for the reader to figure out what exactly this means. ;-)
             Validator.HTTPURI:              Changed to be much more restrictive; i.e., changed from:
-                                                    Validator.HTTPURI=^[a-zA-Z0-9()\\-=\\*\\.\\?;,+\\/:&_ ]*$ 
+                                                    Validator.HTTPURI=^[a-zA-Z0-9()\\-=\\*\\.\\?;,+\\/:&_ ]*$
                                                 to:
                                                     Validator.HTTPURI=^/([a-zA-Z0-9.\\-_]*/?)*$
-            
+
 * Other changes:
     Issue 500		Suppress noise from ESAPI searching for properties and stop ignoring important IOExceptions
 
@@ -241,7 +241,7 @@ Issue #			GitHub Issue Title
 
         Other changes in this release, some of which not tracked via GitHub issues
 
-* Updated minimal version of Maven from 3.0 to 3.1 required to build ESAPI. 
+* Updated minimal version of Maven from 3.0 to 3.1 required to build ESAPI.
 * Miscellaneous minor javadoc fixes and updates.
 * Added the Maven plug-in for OWASP Dependency Check so 3rd party dependencies can be kept up-to-date.
 * Updated .gitignore file with additional files to be ignored.
diff --git a/documentation/esapi4java-core-2.2.1.0-release-notes.txt b/documentation/esapi4java-core-2.2.1.0-release-notes.txt
index 6119a5c..e32e0ad 100644
--- a/documentation/esapi4java-core-2.2.1.0-release-notes.txt
+++ b/documentation/esapi4java-core-2.2.1.0-release-notes.txt
@@ -80,7 +80,7 @@ Issue #         GitHub Issue Title
 The new default ESAPI logger is JUL (java.util.logging packages) and we have deprecated the use of Log4J 1.x because we now support SLF4J and Log4J 1.x is way past its end-of-life. We did not want to make SLF4J the default logger (at least not yet) as we did not want to have the default ESAPI use require additional dependencies. However, SLF4J is likely to be the future choice, at least once we start on ESAPI 3.0. A special shout-out to Jeremiah Stacey for making this possible by re-factoring much of the ESAPI logger code. Note, the straw that broke the proverbial camel's back was the announcement of CVE-2019-17571 (rated Critical), for which there is no fix available and likely will never be.
 
 Related to that CVE and how it affects ESAPI, be sure to read
-   https://github.com/ESAPI/esapi-java-legacy/blob/develop/documentation/ESAPI-security-bulletin2.pdf 
+   https://github.com/ESAPI/esapi-java-legacy/blob/develop/documentation/ESAPI-security-bulletin2.pdf
 which describes CVE-2019-17571, a deserialization vulnerability in Log4J 1.2.17. ESAPI is not affected by this (even if you chose to use Log4J 1 as you default ESAPI logger). This security bulletin describes why this CVE is not exploitable as used by ESAPI.
 
 Notable dependency updates (excludes those only used with JUnit tests):
@@ -204,21 +204,21 @@ PR#    GitHub ID                Description
 506 -- kwwall           -- Closes Issue 245
 508 -- Michael-Ziluck   -- Resolves #226 - Corrected docs for the bounded, numeric, random methods
 510 -- Michael-Ziluck   -- Resolve #509 - Properly throw exception when HTML fails
-513 -- kwwall           -- Close issue #512 by updating to 1.9.4 of Commons Beans Util. 
-514 -- xeno6696         -- Fixed issues #503 by writing a new addReferer method, also temporarily… 
-516 -- jeremiahjstacey  -- Issue 515 
-518 -- jeremiahjstacey  -- Issue #511 Copying Docs from DefaultValidator 
-519 -- jeremiahjstacey  -- Issue 494 CSSCodec RGB Triplets 
-520 -- jeremiahjstacey  -- OS Name DefaultExecutorTests #143 
-533 -- jeremiahjstacey  -- #532 JUL and Log4J match SLF4J class structure and Workflow 
-535 -- kwwall           -- Issue 521 
-537 -- jeremiahjstacey  -- Issue 536 
-539 -- wiiitek          -- upgrade for convergence 
-540 -- wiiitek          -- Issue 382: Build Fails on path with space 
-541 -- HJW8472          -- Fixed issue #310 
-543 -- sempf            -- Release notes for 2.2.1.0 
-551 -- kwwall           -- Misc cleanup 
-553 -- kwwall           -- Fix for GitHub Issue 552 
+513 -- kwwall           -- Close issue #512 by updating to 1.9.4 of Commons Beans Util.
+514 -- xeno6696         -- Fixed issues #503 by writing a new addReferer method, also temporarily…
+516 -- jeremiahjstacey  -- Issue 515
+518 -- jeremiahjstacey  -- Issue #511 Copying Docs from DefaultValidator
+519 -- jeremiahjstacey  -- Issue 494 CSSCodec RGB Triplets
+520 -- jeremiahjstacey  -- OS Name DefaultExecutorTests #143
+533 -- jeremiahjstacey  -- #532 JUL and Log4J match SLF4J class structure and Workflow
+535 -- kwwall           -- Issue 521
+537 -- jeremiahjstacey  -- Issue 536
+539 -- wiiitek          -- upgrade for convergence
+540 -- wiiitek          -- Issue 382: Build Fails on path with space
+541 -- HJW8472          -- Fixed issue #310
+543 -- sempf            -- Release notes for 2.2.1.0
+551 -- kwwall           -- Misc cleanup
+553 -- kwwall           -- Fix for GitHub Issue 552
 557 -- kwwall           -- Final prep for 2.2.1.0 release
 
 
@@ -234,11 +234,11 @@ Direct and Transitive Runtime and Test Dependencies:
 
         $ mvn dependency:tree
         [INFO] Scanning for projects...
-        [INFO] 
+        [INFO]
         [INFO] -----------------------< org.owasp.esapi:esapi >------------------------
         [INFO] Building ESAPI 2.2.1.0
         [INFO] --------------------------------[ jar ]---------------------------------
-        [INFO] 
+        [INFO]
         [INFO] --- maven-dependency-plugin:3.1.2:tree (default-cli) @ esapi ---
         [INFO] org.owasp.esapi:esapi:jar:2.2.1.0
         [INFO] +- javax.servlet:javax.servlet-api:jar:3.0.1:provided
@@ -271,9 +271,9 @@ Direct and Transitive Runtime and Test Dependencies:
         [INFO] |  \- xalan:serializer:jar:2.7.2:compile
         [INFO] +- xerces:xercesImpl:jar:2.12.0:compile
         [INFO] +- xml-apis:xml-apis:jar:1.4.01:compile
-        [INFO] +- com.github.spotbugs:spotbugs-annotations:jar:4.0.4:compile (optional) 
-        [INFO] |  \- com.google.code.findbugs:jsr305:jar:3.0.2:compile (optional) 
-        [INFO] +- net.jcip:jcip-annotations:jar:1.0:compile (optional) 
+        [INFO] +- com.github.spotbugs:spotbugs-annotations:jar:4.0.4:compile (optional)
+        [INFO] |  \- com.google.code.findbugs:jsr305:jar:3.0.2:compile (optional)
+        [INFO] +- net.jcip:jcip-annotations:jar:1.0:compile (optional)
         [INFO] +- junit:junit:jar:4.13:test
         [INFO] |  \- org.hamcrest:hamcrest-core:jar:1.3:test
         [INFO] +- org.bouncycastle:bcprov-jdk15on:jar:1.65.01:test
diff --git a/documentation/esapi4java-core-2.2.1.1-release-notes.txt b/documentation/esapi4java-core-2.2.1.1-release-notes.txt
index 7fa3ffc..4670706 100644
--- a/documentation/esapi4java-core-2.2.1.1-release-notes.txt
+++ b/documentation/esapi4java-core-2.2.1.1-release-notes.txt
@@ -79,7 +79,7 @@ See GitHub issue #560 for additional details.
 
 
 Related to that aforemented Log4J 1.x CVE and how it affects ESAPI, be sure to read
-   https://github.com/ESAPI/esapi-java-legacy/blob/develop/documentation/ESAPI-security-bulletin2.pdf 
+   https://github.com/ESAPI/esapi-java-legacy/blob/develop/documentation/ESAPI-security-bulletin2.pdf
 which describes CVE-2019-17571, a deserialization vulnerability in Log4J 1.2.17. ESAPI is *NOT* affected by this (even if you chose to use Log4J 1 as you default ESAPI logger). This security bulletin describes why this CVE is not exploitable as used by ESAPI.
 
 
@@ -150,7 +150,7 @@ kwwall          67             64               8
 PR#    GitHub ID                Description
 ----------------------------------------------------------------------
 559 -- synk-bot         -- Upgrade com.github.spotbugs:spotbugs-annotations from 4.0.4 to 4.0.5
-562 -- jeremiahjstacey  -- Issue #560 JUL fixes 
+562 -- jeremiahjstacey  -- Issue #560 JUL fixes
 
 CHANGELOG:      Create your own. May I suggest:
 
@@ -164,11 +164,11 @@ Direct and Transitive Runtime and Test Dependencies:
 
         $ mvn dependency:tree
         [INFO] Scanning for projects...
-        [INFO] 
+        [INFO]
         [INFO] -----------------------< org.owasp.esapi:esapi >------------------------
         [INFO] Building ESAPI 2.2.1.1
         [INFO] --------------------------------[ jar ]---------------------------------
-        [INFO] 
+        [INFO]
         [INFO] --- maven-dependency-plugin:3.1.2:tree (default-cli) @ esapi ---
         [INFO] org.owasp.esapi:esapi:jar:2.2.1.1
         [INFO] +- javax.servlet:javax.servlet-api:jar:3.0.1:provided
@@ -201,9 +201,9 @@ Direct and Transitive Runtime and Test Dependencies:
         [INFO] |  \- xalan:serializer:jar:2.7.2:compile
         [INFO] +- xerces:xercesImpl:jar:2.12.0:compile
         [INFO] +- xml-apis:xml-apis:jar:1.4.01:compile
-        [INFO] +- com.github.spotbugs:spotbugs-annotations:jar:4.0.5:compile (optional) 
-        [INFO] |  \- com.google.code.findbugs:jsr305:jar:3.0.2:compile (optional) 
-        [INFO] +- net.jcip:jcip-annotations:jar:1.0:compile (optional) 
+        [INFO] +- com.github.spotbugs:spotbugs-annotations:jar:4.0.5:compile (optional)
+        [INFO] |  \- com.google.code.findbugs:jsr305:jar:3.0.2:compile (optional)
+        [INFO] +- net.jcip:jcip-annotations:jar:1.0:compile (optional)
         [INFO] +- junit:junit:jar:4.13:test
         [INFO] |  \- org.hamcrest:hamcrest-core:jar:1.3:test
         [INFO] +- org.bouncycastle:bcprov-jdk15on:jar:1.65.01:test
diff --git a/documentation/esapi4java-core-2.2.2.0-release-notes.txt b/documentation/esapi4java-core-2.2.2.0-release-notes.txt
index 4920a29..833d1b9 100644
--- a/documentation/esapi4java-core-2.2.2.0-release-notes.txt
+++ b/documentation/esapi4java-core-2.2.2.0-release-notes.txt
@@ -13,7 +13,7 @@ Executive Summary: Important Things to Note for this Release
 This is a patch release with the primary intent of updating some dependencies with known vulnerabilities.  The main vulnerability that was remediated was CVE-2020-13956, which was a vulnerability introduced through the ESAPI transitive dependency org.apache.httpcomponents:httpclient:4.5.12, potentially exposed through org.owasp.antisamy:antisamy:1.5.10. Updating to AntiSamy 1.5.11 remediated that issue.  In addition, that update to AntiSamy 1.5.11 also addressed AntiSamy issue #48 (https://github.com/nahsra/antisamy/issues/48), which was a low risk security issue that potentially could be exposed via phishing.
 
 For those of you using a Software Configuration Analysis (SCA) services such as Snyk, BlackDuck, Veracode SourceClear, OWASP Dependency Check, etc., you might notice that there is vulnerability in xerces:xercesImpl:2.12.0 that ESAPI uses (also a transitive dependency) that is similar to CVE-2020-14621. Unfortunately there is no official patch for this in the regular Maven Central repository. Further details are described in Security Bulletin #3, which is viewable here
-   https://github.com/ESAPI/esapi-java-legacy/blob/develop/documentation/ESAPI-security-bulletin3.pdf 
+   https://github.com/ESAPI/esapi-java-legacy/blob/develop/documentation/ESAPI-security-bulletin3.pdf
 and associated with this release on GitHub. Manual workarounds possible. See the security bulletin for further details.
 
 
@@ -91,7 +91,7 @@ See GitHub issue #560 for additional details.
 
 
 Related to that aforemented Log4J 1.x CVE and how it affects ESAPI, be sure to read
-   https://github.com/ESAPI/esapi-java-legacy/blob/develop/documentation/ESAPI-security-bulletin2.pdf 
+   https://github.com/ESAPI/esapi-java-legacy/blob/develop/documentation/ESAPI-security-bulletin2.pdf
 which describes CVE-2019-17571, a deserialization vulnerability in Log4J 1.2.17. ESAPI is *NOT* affected by this (even if you chose to use Log4J 1 as you default ESAPI logger). This security bulletin describes why this CVE is not exploitable as used by ESAPI.
 
 
@@ -132,9 +132,9 @@ We do not know the reason for these failures, but only that we have observed the
 
 
 Lastly, some SCA services may continue to flag vulnerabilties in ESAPI 2.2.2.0 related to log4j 1.2.17 and xerces 2.12.0.  We do not believe the way that ESAPI uses either of these in a manner that leads to any exploitable behavior.  See the security bulletins
-   https://github.com/ESAPI/esapi-java-legacy/blob/develop/documentation/ESAPI-security-bulletin2.pdf 
+   https://github.com/ESAPI/esapi-java-legacy/blob/develop/documentation/ESAPI-security-bulletin2.pdf
 and
-   https://github.com/ESAPI/esapi-java-legacy/blob/develop/documentation/ESAPI-security-bulletin3.pdf 
+   https://github.com/ESAPI/esapi-java-legacy/blob/develop/documentation/ESAPI-security-bulletin3.pdf
 respectively, for additional details.
 
 -----------------------------------------------------------------------------
@@ -175,11 +175,11 @@ Direct and Transitive Runtime and Test Dependencies:
 
         $ mvn dependency:tree
         [INFO] Scanning for projects...
-        [INFO] 
+        [INFO]
         [INFO] -----------------------< org.owasp.esapi:esapi >------------------------
         [INFO] Building ESAPI 2.2.2.0
         [INFO] --------------------------------[ jar ]---------------------------------
-        [INFO] 
+        [INFO]
         [INFO] --- maven-dependency-plugin:3.1.2:tree (default-cli) @ esapi ---
         [INFO] org.owasp.esapi:esapi:jar:2.2.2.0-SNAPSHOT
         [INFO] +- javax.servlet:javax.servlet-api:jar:3.0.1:provided
@@ -212,9 +212,9 @@ Direct and Transitive Runtime and Test Dependencies:
         [INFO] |  \- xalan:serializer:jar:2.7.2:compile
         [INFO] +- xerces:xercesImpl:jar:2.12.0:compile
         [INFO] +- xml-apis:xml-apis:jar:1.4.01:compile
-        [INFO] +- com.github.spotbugs:spotbugs-annotations:jar:4.1.4:compile (optional) 
-        [INFO] |  \- com.google.code.findbugs:jsr305:jar:3.0.2:compile (optional) 
-        [INFO] +- net.jcip:jcip-annotations:jar:1.0:compile (optional) 
+        [INFO] +- com.github.spotbugs:spotbugs-annotations:jar:4.1.4:compile (optional)
+        [INFO] |  \- com.google.code.findbugs:jsr305:jar:3.0.2:compile (optional)
+        [INFO] +- net.jcip:jcip-annotations:jar:1.0:compile (optional)
         [INFO] +- junit:junit:jar:4.13.1:test
         [INFO] |  \- org.hamcrest:hamcrest-core:jar:1.3:test
         [INFO] +- org.bouncycastle:bcprov-jdk15on:jar:1.65.01:test
diff --git a/documentation/esapi4java-core-2.2.3.0-release-notes.txt b/documentation/esapi4java-core-2.2.3.0-release-notes.txt
index df95a77..1b96a66 100644
--- a/documentation/esapi4java-core-2.2.3.0-release-notes.txt
+++ b/documentation/esapi4java-core-2.2.3.0-release-notes.txt
@@ -16,7 +16,7 @@ This is a patch release with the primary intent of updating some dependencies, s
         -- AntiSamy, from 1.5.11 to 1.6.2.
         -- As a result of the AntiSamy upgrade, the transitive dependency xercesImpl was updated from 2.12.0 to 2.12.1 which should address CVE-2020-14338.
         -- Apache batik-css, updated from 1.13 to 1.14.
-        
+
 Details follow.
 
     * IMPORTANT: Effects of updating to AntiSamy 1.6.2
@@ -30,7 +30,7 @@ Details follow.
                         </exclusion>
                   in your dependency for ESAPI in your application's pom.xml. (You Gradle, Ivy, etc. other build tool users will have to figure out how to do this yourself.)
                   This is especially important if you are using SLF4J logging in ESAPI with some other SLF4J logger such as slf4j-log4j2, etc. If you don't do that, your logging may not come out as expected. See <https://github.com/nahsra/antisamy#note-schema-validation-behavior-change-starting-with-antisamy-160>, under its section discussing Logging for more details.
-        
+
                 o Previously, ESAPI shipped with a default AntiSamy policy file called 'antisamy-esapi.xml'. For 10 plus years, unbeknownst to anyone, that file contained an unused '<html-entities>' node that not only did ESAPI not directly used, but was also completely ignored by AntiSamy! However, starting with AntiSamy 1.6.0, AntiSamy does XML schema validation by default, so that causes any non-compliant AntiSamy policy file to be rejected. This may result in some rather obtuse error messages and you may want to set the AntiSamy system property 'owasp.validator.validateschema' to "false" temporarily until you have time to correct your AntiSamy policy file(s).
 
     Old News
@@ -72,7 +72,7 @@ Issue #         GitHub Issue Title
 602             Update failing ValidatorTest in 'Java CI with Maven' GitHub workflow
 606             Vulnerability in transitive dependency of esapi
 609             Change log4j dependency scope to provided Build-Maven Component-Docs Component-Logger Configuration
-614             Potentlial XXE Injection vulnerability in loading XML version of ESAPI properties file 
+614             Potentlial XXE Injection vulnerability in loading XML version of ESAPI properties file
 
 -----------------------------------------------------------------------------
 
@@ -125,7 +125,7 @@ See GitHub issue #560 for additional details.
 
 
 Related to that aforemented Log4J 1.x CVE and how it affects ESAPI, be sure to read
-   https://github.com/ESAPI/esapi-java-legacy/blob/develop/documentation/ESAPI-security-bulletin2.pdf 
+   https://github.com/ESAPI/esapi-java-legacy/blob/develop/documentation/ESAPI-security-bulletin2.pdf
 which describes CVE-2019-17571, a deserialization vulnerability in Log4J 1.2.17. ESAPI is *NOT* affected by this (even if you chose to use Log4J 1 as you default ESAPI logger). This security bulletin describes why this CVE is not exploitable as used by ESAPI.
 
 
@@ -211,11 +211,11 @@ Direct and Transitive Runtime and Test Dependencies:
 
         $ mvn -B dependency:tree
         [INFO] Scanning for projects...
-        [INFO] 
+        [INFO]
         [INFO] -----------------------< org.owasp.esapi:esapi >------------------------
         [INFO] Building ESAPI 2.2.3.0-SNAPSHOT
         [INFO] --------------------------------[ jar ]---------------------------------
-        [INFO] 
+        [INFO]
         [INFO] --- maven-dependency-plugin:3.1.2:tree (default-cli) @ esapi ---
         [INFO] org.owasp.esapi:esapi:jar:2.2.3.0-SNAPSHOT
         [INFO] +- javax.servlet:javax.servlet-api:jar:3.0.1:provided
@@ -249,9 +249,9 @@ Direct and Transitive Runtime and Test Dependencies:
         [INFO] +- xalan:xalan:jar:2.7.2:compile
         [INFO] |  \- xalan:serializer:jar:2.7.2:compile
         [INFO] +- xml-apis:xml-apis:jar:1.4.01:compile
-        [INFO] +- com.github.spotbugs:spotbugs-annotations:jar:4.2.0:compile (optional) 
-        [INFO] |  \- com.google.code.findbugs:jsr305:jar:3.0.2:compile (optional) 
-        [INFO] +- net.jcip:jcip-annotations:jar:1.0:compile (optional) 
+        [INFO] +- com.github.spotbugs:spotbugs-annotations:jar:4.2.0:compile (optional)
+        [INFO] |  \- com.google.code.findbugs:jsr305:jar:3.0.2:compile (optional)
+        [INFO] +- net.jcip:jcip-annotations:jar:1.0:compile (optional)
         [INFO] +- junit:junit:jar:4.13.1:test
         [INFO] |  \- org.hamcrest:hamcrest-core:jar:1.3:test
         [INFO] +- org.bouncycastle:bcprov-jdk15on:jar:1.68:test
diff --git a/documentation/esapi4java-core-2.2.3.1-release-notes.txt b/documentation/esapi4java-core-2.2.3.1-release-notes.txt
index b76e9c6..f53aa83 100644
--- a/documentation/esapi4java-core-2.2.3.1-release-notes.txt
+++ b/documentation/esapi4java-core-2.2.3.1-release-notes.txt
@@ -43,7 +43,7 @@ Issue #         GitHub Issue Title
         Changes Requiring Special Attention
 
 -----------------------------------------------------------------------------
-See this section from the previous release notes at: 
+See this section from the previous release notes at:
     https://github.com/ESAPI/esapi-java-legacy/blob/develop/documentation/esapi4java-core-2.2.3.0-release-notes.txt
 
 -----------------------------------------------------------------------------
@@ -51,12 +51,12 @@ See this section from the previous release notes at:
         Remaining Known Issues / Problems
 
 -----------------------------------------------------------------------------
-See this section from the previous release notes at: 
+See this section from the previous release notes at:
     https://github.com/ESAPI/esapi-java-legacy/blob/develop/documentation/esapi4java-core-2.2.3.0-release-notes.txt
 
 NEW since last release (ESAPI 2.2.3.0) - CVE-2021-29425
     https://nvd.nist.gov/vuln/detail/CVE-2021-29425
-    
+
 
 -----------------------------------------------------------------------------
 
@@ -93,11 +93,11 @@ Direct and Transitive Runtime and Test Dependencies:
 
         $ mvn dependency:tree
         [INFO] Scanning for projects...
-        [INFO] 
+        [INFO]
         [INFO] -----------------------< org.owasp.esapi:esapi >------------------------
         [INFO] Building ESAPI 2.2.3.1-SNAPSHOT
         [INFO] --------------------------------[ jar ]---------------------------------
-        [INFO] 
+        [INFO]
         [INFO] --- maven-dependency-plugin:3.1.2:tree (default-cli) @ esapi ---
         [INFO] org.owasp.esapi:esapi:jar:2.2.3.1-SNAPSHOT
         [INFO] +- javax.servlet:javax.servlet-api:jar:3.0.1:provided
@@ -128,8 +128,8 @@ Direct and Transitive Runtime and Test Dependencies:
         [INFO] +- org.slf4j:slf4j-api:jar:1.7.30:compile
         [INFO] +- xml-apis:xml-apis:jar:1.4.01:compile
         [INFO] +- commons-io:commons-io:jar:2.6:compile
-        [INFO] +- com.github.spotbugs:spotbugs-annotations:jar:4.2.2:compile (optional) 
-        [INFO] |  \- com.google.code.findbugs:jsr305:jar:3.0.2:compile (optional) 
+        [INFO] +- com.github.spotbugs:spotbugs-annotations:jar:4.2.2:compile (optional)
+        [INFO] |  \- com.google.code.findbugs:jsr305:jar:3.0.2:compile (optional)
         [INFO] +- commons-codec:commons-codec:jar:1.15:test
         [INFO] +- junit:junit:jar:4.13.2:test
         [INFO] +- org.bouncycastle:bcprov-jdk15on:jar:1.68:test
diff --git a/documentation/esapi4java-core-2.3.0.0-release-notes.txt b/documentation/esapi4java-core-2.3.0.0-release-notes.txt
index 5d2a5b4..e4cdefb 100644
--- a/documentation/esapi4java-core-2.3.0.0-release-notes.txt
+++ b/documentation/esapi4java-core-2.3.0.0-release-notes.txt
@@ -39,7 +39,7 @@ ESAPI 2.3.0.0 release (current / new release):
 
 Issue #         GitHub Issue Title
 ----------------------------------------------------------------------------------------------
-163             Limit max size of entire cookies Component-Validator enhancement good first issue help wanted imported Priority-High 
+163             Limit max size of entire cookies Component-Validator enhancement good first issue help wanted imported Priority-High
 198             Uninitialized esapi logging assumes logging to System.out/System.err - Make configurable/extensible bug imported wontfix
 324             ClassCastException during web application redeploy due to the grift logging classes enhancement imported
 564             Create release notes for 2.2.1.1 patch release Component-Docs
@@ -70,20 +70,21 @@ Issue #         GitHub Issue Title
 
 -----------------------------------------------------------------------------
 
-1) This likely will be the LAST ESAPI release supporting Java 7. There are just some vulnerabilities (notably a DoS one in Neko HtmlUnit that does not yet have an assigned CVE) that because they are transitive dependencies, that we simply cannot remediate without at least moving on to Java 8 as the minimally supported JDK. Please plan accordingly.  
+1) This likely will be the LAST ESAPI release supporting Java 7. There are just some vulnerabilities (notably a DoS one in Neko HtmlUnit that was assigned CVE-2022-28366 after the ESAPI 2.3.0.0 release) that because they are transitive dependencies, that we simply cannot remediate without at least moving on to Java 8 as the minimally supported JDK. Please plan accordingly.
 
 2) If you are not upgrading to ESAPI release 2.3.0.0 from 2.2.3.1 (the previous release), then you NEED to read at least the release notes in 2.2.3.1 and ideally, all the ones in all the previous ESAPI release notes from where you are updating to 2.3.0.0. In particular, if you were using ESAPI 2.2.1.0 or earlier, you need to see those ESAPI release notes in regards to changes in the ESAPI.Logger property.
 
                                         !!!!! VULNERABILITY ALERTS !!!!!
 
-3) There is one VERY SERIOUS (as in easy to exploit) vulnerability in ESAPI's default antisamy-esapi.xml configuration file. This problem seems to date back to at least ESAPI release 1.4. If you do nothing else, you should update your antisamy-esapi.xml to the one provided in the esapi-2.3.0.0-configuration.jar that can be found on GitHub under "https://github.com/ESAPI/esapi-java-legacy/releases/tag/esapi-2.3.0.0". The ESAPI team will be submitting an official CVE for this, but the bottom line is that the default ESAPI antisamy-esapi.xml configuration file does not properly sanitize 'javascript:' URLs in most cases, but instead accepts the input as "safe". A few more details regarding the configuration is provided in the section "Important checks you take as a developer using ESAPI" given below.
+3) There is one VERY SERIOUS (as in easy to exploit) vulnerability in ESAPI's default antisamy-esapi.xml configuration file. This problem seems to date back to at least ESAPI release 1.4. If you do nothing else, you should update your antisamy-esapi.xml to the one provided in the esapi-2.3.0.0-configuration.jar that can be found on GitHub under "https://github.com/ESAPI/esapi-java-legacy/releases/tag/esapi-2.3.0.0". The ESAPI team will be submitting an official CVE for this, but the bottom line is that the default ESAPI antisamy-esapi.xml configuration file does not properly sanitize 'javascript:' URLs in most cases, but instead accepts the input as "safe". A few more details regarding the configuration is provided in the section "Important checks you take as a developer using ESAPI" given below. (Update: This vulnerability was assigned CVE ID CVE-2022-24891. See GitHub Security Adivisory https://github.com/ESAPI/esapi-java-legacy/security/advisories/GHSA-q77q-vx4q-xx6q and ESAPI Security Bulletin 8 at https://github.com/ESAPI/esapi-java-legacy/blob/develop/documentation/ESAPI-security-bulletin8.pdf for further details.)
 
 4) Several other vulnerabilities associated with AntiSamy have been patched via the AntiSamy 1.6.7 (or prior) release. See the AntiSamy release notes for 1.6.7, 1.6.6.1, 1.6.6, 1.6.5 and 1.6.4 at https://github.com/nahsra/antisamy/releases for further details on what has been remediated. Note that the default ESAPI.properties and ESAPI AntiSamy configuration did not really leave ESAPI vulnerable to CVE-2021-35043 which was fixed in AntiSamy 1.6.4, but that was a moot point because of #3, above.
 
-5) A vulnerability found by GitHub Security Lab that is an example of CWE-22 [Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal')], was discovered by GHSL security researcher Jaroslav Lobačevski. You can find details of it under "documentation/GHSL-2022-008_The_OWASP_Enterprise_Security_API.md" or "documentation/GHSL-2022-008_The_OWASP_Enterprise_Security_API.pdf" on ESAPI's GitHub repo or from the ESAPI source zip or tarball files associated with this (or later) release. This currently does not have a CVE associated with it. We likely will leave it to GHSL to determine if they want to file a CVE for it or not.
+5) A vulnerability found by GitHub Security Lab that is an example of CWE-22 [Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal')], was discovered by GHSL security researcher Jaroslav Lobačevski. You can find details of it under "documentation/GHSL-2022-008_The_OWASP_Enterprise_Security_API.md" or "documentation/GHSL-2022-008_The_OWASP_Enterprise_Security_API.pdf" on ESAPI's GitHub repo or from the ESAPI source zip or tarball files associated with this (or later) release. (Update: After this release, this vulnerability was assigned CVE ID CVE-2022-23457. See GitHub Security Adivisory https://github.com/ESAPI/esapi-java-legacy/security/advisories/GHSA-8m5h-hrqm-pxm2 for further details.)
 
-6) There remains one known unpatched, potentially exploitable vulnerability (a DoS vulnerability in the transitive dependency Neko HtmlUnit) in ESAPI 2.3.0.0. To our knowledge, that vulnerability has not yet been assigned a CVE, but it is fixed in certain versions of Neko HtmlUnit after release 2.24.0. However, release 2.24.0 is the last Neko HtmlUnit release that supports Java 7 and thus is the latest one that we can use. That vulnerability is patched only fixed in a version of Neko HtmlUnit that was compiled with Java 8. Since ESAPI (as of release 2.3.0.0) only supports Java 7, we are currently unable to patch to remediate this DoS vulnerability. (This is why we are currently committed for this 2.3.0.0 release to be last release at least to support Java 7). The ESAPI team plans to release a 2.4.0.0 release that will require Java 8 or later as the minimal JDK, and with that release, we will update to AntiSamy 1.7.0 (which requires Java 8) and which uses Neko HtmlUnit 2.60.0 (which also requires Java 8 or later) and that addresses the DoS vulnerability. For further information, see the JUnit test testNekoDOSWithAnHTMLComment in "src/test/java/org/owasp/esapi/reference/validation/HTMLValidationRuleCleanTest.java". (Note that currently, this JUnit test is annotated as '@Ignore' since it would not pass under Java 7 and using Neko HtmlUnit 2.24.0.)
+6) There remains one known unpatched, potentially exploitable vulnerability (a DoS vulnerability in the transitive dependency Neko HtmlUnit) in ESAPI 2.3.0.0. That vulnerability was later assigned CVE-20222-28366, but it is fixed in certain versions of Neko HtmlUnit after release 2.24.0. However, release 2.24.0 is the last Neko HtmlUnit release that supports Java 7 and thus is the latest one that we can use. That vulnerability is patched only fixed in a version of Neko HtmlUnit that was compiled with Java 8. Since ESAPI (as of release 2.3.0.0) only supports Java 7, we are currently unable to patch to remediate this DoS vulnerability. (This is why we are currently committed for this 2.3.0.0 release to be last release at least to support Java 7). The ESAPI team plans to release a 2.4.0.0 release that will require Java 8 or later as the minimal JDK, and with that release, we will update to AntiSamy 1.7.0 (which requires Java 8) and which uses Neko HtmlUnit 2.60.0 (which also requires Java 8 or later) and that addresses the DoS vulnerability. For further information, see the JUnit test testNekoDOSWithAnHTMLComment in "src/test/java/org/owasp/esapi/reference/validation/HTMLValidationRuleCleanTest.java". (Note that currently, this JUnit test is annotated as '@Ignore' since it would not pass under Java 7 and using Neko HtmlUnit 2.24.0.)
 
+7) *NEW* It later came to our attention that there was a unknown XSS vulnerability in AntiSamy [later identified as CVE-2022-29577] that was patched in AntiSamy 1.6.8, which was not available at the time of the ESAPI 2.3.0.0 release. (Someone on the AntiSamy team probably told me about this, but I just forgot. Sorry ESAPI folks!)
 
 NOTE: We plan on issuing an updated README.md and updated security bulletins on #3 and #4 soon, but we wanted to focus on getting the patches out rather than getting the documentation out. This probably will not be in a separate release, but we will announce in on the ESAPI Users and ESAPI Dev Google lists once we drop them on our GitHub repo under the "documentation" folder.
 
diff --git a/documentation/esapi4java-core-2.4.0.0-release-notes.txt b/documentation/esapi4java-core-2.4.0.0-release-notes.txt
index 44ae6a2..bfc5036 100644
--- a/documentation/esapi4java-core-2.4.0.0-release-notes.txt
+++ b/documentation/esapi4java-core-2.4.0.0-release-notes.txt
@@ -4,7 +4,7 @@ Release notes for ESAPI 2.4.0.0
         -Kevin W. Wall <kevin.w.wall@gmail.com>
         -Matt Seil <matt.seil@owasp.org>
 
-Previous release: ESAPI 2.3.0.0, 2022-04-18
+Previous release: ESAPI 2.3.0.0, 2022-04-17
 
 Important Announcement
 ----------------------
@@ -13,7 +13,7 @@ Do NOT:  Do NOT use GitHub Issues to ask questions about this of future releases
 
 Executive Summary: Important Things to Note for this Release
 ------------------------------------------------------------
-This is a very important ESAPI release as it is the first release to be FULLY INCOMPATIBLE WITH JAVA 1.7!  This was expedited in response to some dependencies to resolve prior CVEs (see release notes in 2.3.0.0) that could not be updated as those versions required a JDK > 1.7 which we were forced to.  The slightly premature update to java 1.8 is done to address CVE-2022-28366 that had to be fixed with a version of the transitive depenedency via AntiSamy of NekoHTML that was java 1.8+ only.  (Wrapped into issue #682)  It is important to note that the solution to fix CVE-2022-28366 does not exist in ESAPI 2.3.0.0 and there is no intention to fix it for Java 1.7.    
+This is a very important ESAPI release as it is the first release to be FULLY INCOMPATIBLE WITH JAVA 1.7!  This was expedited in response to some dependencies to resolve prior CVEs (see release notes in 2.3.0.0) that could not be updated as those versions required a JDK > 1.7 which we were forced to.  The slightly premature update to Java 1.8 is done to address CVE-2022-28366 that had to be fixed with a version of the transitive depenedency via AntiSamy of NekoHTML that was Java 1.8+ only.  (Wrapped into issue #682)  It is important to note that the solution to fix CVE-2022-28366 does not exist in ESAPI 2.3.0.0 and there is no intention to fix it for Java 1.7.
 
 =================================================================================================================
 
@@ -26,19 +26,17 @@ ESAPI 2.3.0.0 release (previous release):
 
 ESAPI 2.4.0.0 release (current / new release):
      212 Java source files
-    4325 JUnit tests in 136 Java source files (1 test ignored)
+    4326 JUnit tests in 136 Java source files
 
 3 GitHub Issues closed in this release, including those we've decided not to fix (marked 'wontfix' and 'falsepositive').
-[Reference: https://github.com/ESAPI/esapi-java-legacy/issues?q=is%3Aissue+state%3Aclosed+updated%3A%3E%3D2021-05-07]
+[Reference: https://github.com/ESAPI/esapi-java-legacy/issues?q=is%3Aissue+state%3Aclosed+updated%3A%3E%3D2022-04-17]
 
 Issue #         GitHub Issue Title
 ----------------------------------------------------------------------------------------------
-682             Update baseline to java 1.8 
-679             Completely remove support for fixed IVs and throw a ConfigurationException if encountered.
+644             Do not include a logging implementation as a dependency slf4j-simple
 672             (wontfix) HTMLEntityCodec Bug Decoding "Left Angular Bracket" Symbol
-644             Do not include a logging implementation as a dependency slf4j-simple 
-
-
+679             Completely remove support for fixed IVs and throw a ConfigurationException if encountered.
+682             Update baseline to Java 1.8
 
 -----------------------------------------------------------------------------
 
@@ -46,26 +44,28 @@ Issue #         GitHub Issue Title
 
 -----------------------------------------------------------------------------
 
-1) This is the first ESAPI release that does not support java 1.7.  This library will no longer work if youre application is that old.  
+1) This is the first ESAPI release that does not support Java 1.7.  This library will no longer work if your application is that old.
 
                                         !!!!! VULNERABILITY ALERTS !!!!!
 
-2) This release closes our implementation of fixes outlined in CVE-2022-28366 from AntiSamy.  This was a DoS vulnerability discovered in HtmlUnit-Neko affecting all versions up to 2.26.  Details from MITRE are here:  https://cve.mitre.org/cgi-bin/cvename.cgi?name=2022-28366  
+2) This release fixes the known vulnerability ESAPI 2.3.0.0 that had to wait until we supported Java 8 to be patched. The patch was in Neko-HtmlUntil and was fixed in version 2.27, which required Java 8 or later. It was a transitive dependency via AntiSamy and we picked it up by updating to AntiSamy 1.6.8.  This was a DoS vulnerability discovered in HtmlUnit-Neko affecting all versions up to 2.26.  Full details from MITRE are here:  https://cve.mitre.org/cgi-bin/cvename.cgi?name=2022-28366
+
+3) This release also patches the (known, but forgotten?) XSS vulnerability ESAPI 2.3.0.0 in AntiSamy 1.6.7 but was fixed in 1.6.8.  (The 2.3.0.0 release notes have been updated to mention this.) Full details from MITRE are here:  https://cve.mitre.org/cgi-bin/cvename.cgi?name=2022-29577
 
 -----------------------------------------------------------------------------
 
 Developer Activity Report (Changes between release 2.3.0.0 and 2.4.0.0, i.e., between 2022-04-17 and 2022-04-24)
 
-Special thanks to Dave Wichers and Sebastian Pessaro from AntiSamy for their work to close CVE-2022-28366. 
-Special thanks to Jeremiah J. Stacey for his work to update and prep the library to support java 1.8.  (He literally created the PR the day after 2.3.0.0's release.)  
-Special thanks to Kevin Wall for support in pushing out this release.  
+Special thanks to Dave Wichers and Sebastian Pessaro from AntiSamy for their work to provide version 1.6.8 which patched 2 CVEs.
+Special thanks to Jeremiah J. Stacey for his work to update and prep the library to support java 1.8.  (He literally created the PR the day after 2.3.0.0's release.)
+Special thanks to Kevin Wall for support in pushing out this release.
 
 
 -----------------------------------------------------------------------------
 
 CHANGELOG:      Create your own. May we suggest:
 
-        git log --stat --since=2021-05-07 --reverse --pretty=medium
+        git log --stat --since=2022-04-17 --reverse --pretty=medium
 
     or clone the ESAPI/esapi-java-legacy repo and then run
 
@@ -138,11 +138,10 @@ Direct and Transitive Runtime and Test Dependencies:
 -----------------------------------------------------------------------------
 
 Acknowledgments:
-    * A special shout out to Jaroslav Lobačevski, a security researcher at GitHub Security Labs, who notified the ESAPI team via responsible disclosure and allowed us sufficient time to address GHSL-2022-008.
-    * A huge hat-tip to Dave Wichers and Sebastian Passaro for promptly addressing vulnerabilities in AntiSamy, many of which were caused by poorly maintained dependencies of AntiSamy.
-    * A special thanks to Matt Seil, Jeremiah Stacey, and all the ESAPI contributors whom I've undoubtedly forgotten.
+    * A huge hat-tip to Dave Wichers and Sebastian Passaro for promptly releasing AntiSamy 1.6.8 which simplified this releaese
+    * A special thanks to Jeremiah Stacey to wrote the PR #683, that addressed the updates for Java 8.
     * Finally, to all the ESAPI users who make our efforts worthwhile. This is for you.
 
 A special thanks to the ESAPI community from the ESAPI project co-leaders:
     Kevin W. Wall (kwwall) <== The irresponsible party for these release notes!
-    Matt Seil (xeno6696)
+    Matt Seil (xeno6696)   <== (Him too, this time! :)
diff --git a/documentation/esapi4java-core-2.5.0.0-release-notes.txt b/documentation/esapi4java-core-2.5.0.0-release-notes.txt
new file mode 100644
index 0000000..b47b084
--- /dev/null
+++ b/documentation/esapi4java-core-2.5.0.0-release-notes.txt
@@ -0,0 +1,254 @@
+Release notes for ESAPI 2.5.0.0
+    Release date: 2022-07-20
+    Project leaders:
+        -Kevin W. Wall <kevin.w.wall@gmail.com>
+        -Matt Seil <matt.seil@owasp.org>
+
+Previous release: ESAPI 2.4.0.0, 2022-04-24
+
+
+Executive Summary: Important Things to Note for this Release
+------------------------------------------------------------
+
+In addition to this summary, please also be sure to thoroughly read the section "Changes Requiring Special Attention", below.
+
+Major changes:
+    Logging:
+        The major change in ESAPI 2.5.0.0 is the removal of the Log4J 1 dependency (specifically, log4j-1.2.17). It has been removed because in accordance with the ESAPI deprecation policy (see the README.md file), the Log4J supported logger has been deprecated for 2 years.
+
+        For those of you using a Software Configuration Analysis (SCA) services such as Snyk, BlackDuck, Veracode SourceClear, OWASP Dependency Check, etc., you will notice that the 4 Log4J 1.x related CVEs are no longer flagged. This is because of removal of the Log4J 1.2.17 dependency.
+
+        Any remaining flagged vulnerabilities (e.g., CVE-2020-7791 for transitive dependency batik-i18n-1.14) are believed to be false positives.
+
+        You are encouraged to review the vulnerability analysis written up in https://github.com/ESAPI/esapi-java-legacy/blob/develop/Vulnerability-Summary.md and email us or contact us in our GitHub Discussions page if you have questions.
+
+    AntiSamy 1.7.0 and potentially breaking changes
+        We have updated to AntiSamy 1.7.0. If you have a custom version of antisamy-esapi.xml,then be sure to read the section "Changes Requiring Special Attention", below.
+
+Minor changes:
+    Miscellaneous bug fixes, Javadoc enhancements, and minor dependency updates.
+
+=================================================================================================================
+
+Basic ESAPI facts
+-----------------
+
+ESAPI 2.4.0.0 release:
+     212 Java source files
+    4325 JUnit tests in 136 Java source files (1 test skipped)
+
+ESAPI 2.5.0.0 release:
+     206 Java source files
+    4274 JUnit tests in 131 Java source files (0 tests skipped)
+
+19 GitHub Issues closed in this release, including those we've decided not to fix (marked 'wontfix' and 'falsepositive').
+(Reference: https://github.com/ESAPI/esapi-java-legacy/issues?q=is%3Aissue+state%3Aclosed+updated%3A%3E%3D2022-04-24)
+
+Issue #         GitHub Issue Title
+----------------------------------------------------------------------------------------------
+717             Update to AntiSamy 1.7.0 once it is officially released
+715             ESAPI - Not working with Eclipse bug
+713             Should '/' be encoded for LDAP searches? bug
+705             Add more details to DefaultValidator class-level javadoc on ESAPI canonicalization properties Component-Docs Component-Validator javadoc
+702             ValidatorTest#testIsValidDirectoryPathGHSL_POC fails on Mac
+695             Esapi 2.3.0.0 does not supported in opensaml 2.6.6 bug
+692             Multiple (2x) encoding detected in from PercentCodec question
+690             Plugin/Dependency Version Updates
+689             Clean-up ESAPI Javadoc Component-Docs javadoc
+686             ESAPI canonicalization in DefaultEncoder ignoring Encoder.DefaultCodecList property bug Component-Encoder
+684             Hello world
+682             Update baseline to java 1.8
+674             Add the missing Javadoc for the Validator interface Component-Docs Component-Validator good first issue
+656             DefaultHTTPUtility uses hard coded Header name/value lengths (Note: Actually fixed in ESAPI 2.3.0.0, but just closed this release. - kww)
+644             Do not include a logging implementation as a dependency slf4j-simple
+620             Move the default property names and values out of a reference implementation class Component-SecurityConfiguration
+587             Drop Xerces dependency from pom.xml Build-Maven Vulnerable Dependencies
+534             Delete Deprecated Log4J implementation and Dependencies wait4future
+507             LDAP encoding of slash character
+
+-----------------------------------------------------------------------------
+
+        Changes Requiring Special Attention
+
+-----------------------------------------------------------------------------
+
+Important ESAPI Logging Changes
+
+* Since ESAPI 2.5.0.0, support for logging directly via Log4J 1 has been removed. (This was two years after it having first been deprecated.) Thus, your only choice for ESAPI logging are:
+    - java.util.logging (JUL), which as been the default since ESAPI 2.2.1.0.
+        * Set ESAPI.Logger=org.owasp.esapi.logging.java.JavaLogFactory in your ESAPI.properties file.
+    - SLF4J (which your choice of supported SLF4J logging implementation)
+        * Set ESAPI.Logger=org.owasp.esapi.logging.slf4j.Slf4JLogFactory in your ESAPI.properties file.
+        * Create your own custom logger.
+* Logger configuration notes - If you are migrating from prior to ESAPI 2.2.1.1, you will need to update your ESAPI.properties file as logging-related configuration as per the ESAPI 2.2.1.1 release notes, which may be found at:
+    https://github.com/ESAPI/esapi-java-legacy/blob/develop/documentation/esapi4java-core-2.2.1.1-release-notes.txt#L39-L78
+
+If you use ESAPI 2.5.0.0 or later, you will get an ClassNotFoundException as the root cause if you still have your ESAPI.Logger property set to use Log4J because the org.owasp.esapi.logger.log4j.Log4JFactory class has been completely removed from the ESAPI jar.  If you are dead set on continuing to use Log4J 1, you ought to be able to do so via SLF4J. The set up for Log4J 1 (which has not be tested), should be similar to configure ESAPI to use SLF4J with Log4J 2 as described here:
+    https://github.com/ESAPI/esapi-java-legacy/wiki/Using-ESAPI-with-SLF4J#slf4j-using-log4j-2x
+
+Potentially Breaking Changes in AntiSamy 1.7.0
+
+* This version of ESAPI has upgraded to the latest version of AntiSamy (1.7.0 at the time of our release). AntiSamy 1.7.0 has some breaking changes to its SDK and the way that it processes AntiSamy policy files, of which the antisamy-esapi.xml file, included in our esapi-2.5.0.0-configuration.jar found at https://github.com/ESAPI/esapi-java-legacy/releases/download/esapi-2.5.0.0/esapi-2.4.0.0-configuration.jar, is the one we include.
+
+* None of the AntiSamy SDK changes affected how ESAPI, in its default configuration, uses it, but you may be affected if you have customized your AntiSamy policy file. If your regression tests fail when you upgrade to ESAPI 2.5.0.0 sand they seem to be related to AntiSamy, then please review https://github.com/nahsra/antisamy/blob/main/README.md#important---api-breaking-changes-in-170. Also, as a temporary workaround, you could do something like this (in Maven, but similar exclusion can be done with Gradle) to allow you time to correct your customized AntiSamy policy file:
+
+        <dependency>
+            <groupId>org.owasp.esapi</groupId>
+            <artifactId>esapi</artifactId>
+            <version>2.5.0.0</version>
+            <exclusions>
+                <!-- Exclude breaking version of AntiSamy 1.7.0 to allow time to fix our AntiSamy policy file, antisamy-esapi.xml -->
+                <exclusion>
+                    <groupId>org.owasp.antisamy</groupId>
+                    <artifactId>antisamy</artifactId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+        <dependency>
+            <groupId>org.owasp.antisamy</groupId>
+            <artifactId>antisamy</artifactId>
+            <version>1.6.8</version>
+        </dependency>
+
+Indeed the only change that we had to make is to alter a JUnit test that was intended to ensure that invalid AntiSamy policy files could be disabled by setting
+    Policy.setSchemaValidation(false);
+before processing any AntiSamy policy file not conforming to its schema. This specific (previously deprecated) method was removed in AntiSamy 1.7.0 so the schema validation checks can no longer be ignored. (And hence the reason for the workaround noted above.)
+
+Instead, we simply changed the JUnit test to check that the expected AntiSamy org.owasp.validator.html.PolicyException class is thrown when the invalid policy file is loaded.
+
+-----------------------------------------------------------------------------
+
+        Remaining Known Issues / Problems
+
+-----------------------------------------------------------------------------
+* 'mvn site' fails to build these two reports:
+    "Tag reference" report           --- maven-taglib-plugin:2.4:tagreference
+    "Taglibdoc documentation" report --- maven-taglib-plugin:2.4:taglibdoc
+
+  Thus no tag library documentation will be generated. :-(
+
+  We are attempting to find a solution, but on the surface, it seems like the maven-taglib-plugin does not play nicely with versions of Java after Java 6. (So, this probably has been happening for a while and we just noticed it.)
+
+* We have had to suppress CVE-2017-10355, related to the transitive dependency xercesImpl-2.12.2.jar via antisamy-1.7.0.jar. It is the same jar that has been used for the past 2 years but the CVE just started popping up now, apparently because of changes to Sonatype's OSS Index. More details are available in the OWASP Dependency Check suppression rules contained in the 'suppressions.xml' file. Note that other SCA tools such as Snyk or GitHub Dependabot are not presently reporting it, but it bears watching.
+
+* Trying to run 'mvn test' with Java 11 or later results in multiple errors in maven-surefire-plugin, so for now, that should be avoided. We think we may have a solution, but at this point, it is too late to test for this release.
+
+* No others problems are known, other than the remaining open issues on GitHub.
+
+-----------------------------------------------------------------------------
+
+        Other changes in this release, some of which not tracked via GitHub issues
+
+-----------------------------------------------------------------------------
+
+* Minor updates to README.md file with respect to version information.
+
+-----------------------------------------------------------------------------
+
+Developer Activity Report (Changes between release 2.4.0.0 and 2.5.0.0, i.e., between 2022-04-24 and 2022-07-20)
+Generated manually (this time) -- all errors are the fault of kwwall and his inability to do simple arithmetic.
+
+#
+# 34 PRs merged since ESAPI 2.4.0.0 release
+#   Apparent disparement in the figures below may be explained by serveral things:
+#       * My failure to do proper counting and basic arithmetic after 4 hours of tweak release notes.
+#       * Different basis for calculations:
+#           - Figures here may not agree with generated Change Log Report, which is date-based, as some commits included in this release were prior to ESAPI 2.4.0.0 and thus not included in the Change Log Report.
+#           - Some commits are done without PRs. Generally, we don't require PRs when we don't require code reviews. That generally is restricted to documenation files, making simple config file changes, and correcting obvious typos. Commits without PRs are resricted to the 3 ESAPI core team members.
+#           - Sometimes in a PR, multiple commits touch a file multiple times so we count those files once for each commit.
+#
+Developer       Total       Total Number        # Merged
+(GitHub ID)     commits   of Files Changed        PRs
+========================================================
+jeremiahjstacey 265            180               24
+kwwall           39             69                5
+xeno6696          1            267                1
+noloader          5              2                1
+stevebosman-oc    4              3                2
+VinodAnandan      1              1                1
+========================================================
+                                     Total PRs:  34
+
+-----------------------------------------------------------------------------
+
+CHANGELOG:      Create your own. May I suggest:
+
+        git log --stat --since=2022-04-24 --reverse --pretty=medium
+
+    which will show all the commits since just after the previous (2.4.0.0) release.
+
+    Alternately, you can download the most recent ESAPI source and run
+
+        mvn site
+
+    which will create a CHANGELOG file named 'target/site/changelog.html'
+
+
+-----------------------------------------------------------------------------
+
+Direct and Transitive Runtime and Test Dependencies:
+
+        $ mvn -B dependency:tree
+        ...
+        [INFO] --- maven-dependency-plugin:3.3.0:tree (default-cli) @ esapi ---
+        [INFO] org.owasp.esapi:esapi:jar:2.5.0.0
+        [INFO] +- javax.servlet:javax.servlet-api:jar:3.1.0:provided
+        [INFO] +- javax.servlet.jsp:javax.servlet.jsp-api:jar:2.3.3:provided
+        [INFO] +- xom:xom:jar:1.3.7:compile
+        [INFO] +- commons-beanutils:commons-beanutils:jar:1.9.4:compile
+        [INFO] |  +- commons-logging:commons-logging:jar:1.2:compile
+        [INFO] |  \- commons-collections:commons-collections:jar:3.2.2:compile
+        [INFO] +- commons-configuration:commons-configuration:jar:1.10:compile
+        [INFO] +- commons-lang:commons-lang:jar:2.6:compile
+        [INFO] +- commons-fileupload:commons-fileupload:jar:1.4:compile
+        [INFO] +- org.apache.commons:commons-collections4:jar:4.4:compile
+        [INFO] +- org.apache-extras.beanshell:bsh:jar:2.0b6:compile
+        [INFO] +- org.owasp.antisamy:antisamy:jar:1.7.0:compile
+        [INFO] |  +- net.sourceforge.htmlunit:neko-htmlunit:jar:2.63.0:compile
+        [INFO] |  +- org.apache.httpcomponents.client5:httpclient5:jar:5.1.3:compile
+        [INFO] |  |  \- org.apache.httpcomponents.core5:httpcore5-h2:jar:5.1.3:compile
+        [INFO] |  +- org.apache.httpcomponents.core5:httpcore5:jar:5.1.4:compile
+        [INFO] |  +- org.apache.xmlgraphics:batik-css:jar:1.14:compile
+        [INFO] |  |  +- org.apache.xmlgraphics:batik-shared-resources:jar:1.14:compile
+        [INFO] |  |  +- org.apache.xmlgraphics:batik-util:jar:1.14:compile
+        [INFO] |  |  |  +- org.apache.xmlgraphics:batik-constants:jar:1.14:compile
+        [INFO] |  |  |  \- org.apache.xmlgraphics:batik-i18n:jar:1.14:compile
+        [INFO] |  |  \- org.apache.xmlgraphics:xmlgraphics-commons:jar:2.6:compile
+        [INFO] |  +- xerces:xercesImpl:jar:2.12.2:compile
+        [INFO] |  \- xml-apis:xml-apis-ext:jar:1.3.04:compile
+        [INFO] +- org.slf4j:slf4j-api:jar:1.7.36:compile
+        [INFO] +- xml-apis:xml-apis:jar:1.4.01:compile
+        [INFO] +- commons-io:commons-io:jar:2.11.0:compile
+        [INFO] +- com.github.spotbugs:spotbugs-annotations:jar:4.7.1:compile
+        [INFO] |  \- com.google.code.findbugs:jsr305:jar:3.0.2:compile
+        [INFO] +- commons-codec:commons-codec:jar:1.15:test
+        [INFO] +- junit:junit:jar:4.13.2:test
+        [INFO] +- org.bouncycastle:bcprov-jdk15on:jar:1.70:test
+        [INFO] +- org.hamcrest:hamcrest-core:jar:2.2:test
+        [INFO] |  \- org.hamcrest:hamcrest:jar:2.2:test
+        [INFO] +- org.powermock:powermock-api-mockito2:jar:2.0.9:test
+        [INFO] |  \- org.powermock:powermock-api-support:jar:2.0.9:test
+        [INFO] +- org.mockito:mockito-core:jar:3.12.4:test
+        [INFO] |  +- net.bytebuddy:byte-buddy:jar:1.11.13:test
+        [INFO] |  +- net.bytebuddy:byte-buddy-agent:jar:1.11.13:test
+        [INFO] |  \- org.objenesis:objenesis:jar:3.2:test
+        [INFO] +- org.powermock:powermock-core:jar:2.0.9:test
+        [INFO] |  \- org.javassist:javassist:jar:3.27.0-GA:test
+        [INFO] +- org.powermock:powermock-module-junit4:jar:2.0.9:test
+        [INFO] |  \- org.powermock:powermock-module-junit4-common:jar:2.0.9:test
+        [INFO] +- org.powermock:powermock-reflect:jar:2.0.9:test
+        [INFO] \- org.openjdk.jmh:jmh-core:jar:1.35:test
+        [INFO]    +- net.sf.jopt-simple:jopt-simple:jar:5.0.4:test
+        [INFO]    \- org.apache.commons:commons-math3:jar:3.2:test
+        ...
+
+
+-----------------------------------------------------------------------------
+
+Acknowledgments:
+    A special shout-out our new contributors noloader, stevebosman-oc, and VinodAnandan.
+    Another hat tip to Dave Wichers, Sebastián Passaro, and the rest of the AntiSamy crew for promptly releasing AntiSamy 1.7.0.  And thanks to Matt Seil, Jeremiah Stacey, and all the ESAPI users who make this worthwhile. This is for you.
+
+A special thanks to the ESAPI community from the ESAPI project co-leaders:
+    Kevin W. Wall (kwwall) <== The irresponsible party for these release notes!
+    Matt Seil (xeno6696)
diff --git a/documentation/esapi4java-core-2.5.1.0-release-notes.txt b/documentation/esapi4java-core-2.5.1.0-release-notes.txt
new file mode 100644
index 0000000..b8bfb22
--- /dev/null
+++ b/documentation/esapi4java-core-2.5.1.0-release-notes.txt
@@ -0,0 +1,203 @@
+Release notes for ESAPI 2.5.1.0
+    Release date: 2022-11-27
+    Project leaders:
+        -Kevin W. Wall <kevin.w.wall@gmail.com>
+        -Matt Seil <matt.seil@owasp.org>
+
+Previous release: ESAPI 2.5.0.0, 2022-07-20
+
+
+Executive Summary: Important Things to Note for this Release
+------------------------------------------------------------
+This is a patch release with the primary intent of updating some dependencies, some which addressed known vulnerabilities in these dependencies, but which we do not believe were exploitable via ESAPI. The major updates are:
+    * Updates to latest versions of direct dependencies, including:
+        - An update to AntiSamy:        1.7.0  --> 1.7.2
+        - An update to SLFJ4 API:       1.7.36 --> 2.0.4    (Note: 2.0.5 is available and likely would would result in "convergence" issues with the version AntiSamy 1.7.2 pulls in)
+    * A new codec (org.owasp.esapi.codecs.JSONCodec) is provided that provides JSON output encoding as per section 7 of RFC 8259. It is made available via Encoder.encodeForJSON(). (Note unlike other encoders, there is no corresponding decoder (i.e., decodeForJSON()) made available. Since that would normally be done by your JavaScript code, it wasn't deemed essential.
+    * Executing 'mvn site' now creates Javadoc for the ESAPI tag library (GitHub issue #733).
+
+For those of you using a Software Configuration Analysis (SCA) services such as Snyk, BlackDuck, Veracode SourceClear, OWASP Dependency Check, etc., you will notice that the 4 Log4J 1.x related CVEs are no longer flagged. This is because we have finally removed the Log4J 1.2.17 dependency in ESAPI 2.5.0.0.
+
+Any remaining flagged vulnerabilities (e.g., CVE-2017-10355 for transitive dependency apache:xerces2_java:2.12.2) are believed to be false postives.
+
+You are encouraged to review the vulnerability analysis written up in https://github.com/ESAPI/esapi-java-legacy/blob/develop/Vulnerability-Summary.md and email us or contact us in our GitHub Discussions page if you have questions.
+
+
+=================================================================================================================
+
+Basic ESAPI facts
+-----------------
+
+ESAPI 2.5.0.0 release:
+     206 Java source files
+    4274 JUnit tests in 131 Java source files (0 tests skipped)
+
+ESAPI 2.5.1.0 release:
+    207 Java source files
+    4292 JUnit tests in 131 Java source files (0 tests skipped)
+
+15 GitHub Issues closed in this release, including those we've decided not to fix (marked 'wontfix' and 'falsepositive').
+(Reference: https://github.com/ESAPI/esapi-java-legacy/issues?q=is%3Aissue+state%3Aclosed+updated%3A%3E%3D2022-07-20)
+
+Issue #         GitHub Issue Title
+----------------------------------------------------------------------------------------------
+757             again .. [falsepositive]
+755             Upgrade batik-css-1.14 because of vulnerability
+754             JSON encoder
+749             Error in initializing org.owasp.esapi.logging.java.JavaLogFactory. [Converted to discussion #750.]
+747             Encoder class (org.owasp.esapi.reference.DefaultEncoder) CTOR threw exception [Converted to discussion #751]
+743             Indirect dependency to vulnerable Xerces, CVE-2017-10355 [falsepositive, wontfix]
+740             Update SLF4J log bridge to allow NULL EventTypes
+735             Improve ConfigurationException message thrown from EsapiPropertyLoaderFactory.createPropertyLoader()
+734             Change skin for mvn site report to use fluido Build-Maven
+733             Executing 'mvn site' does not produce tag documentation
+727             ESAPI - Not working with Eclipse [falsepositive, wontfix]
+710             JavaLogFactory configuration should not override custom java LogManager configuration
+610             Add Deprecation Logging content for Log4JLogFactory Usage
+527             Configuration flag for disabling Logger User and App Information [falsepositive]
+433             Class Cast Exception when trying to run JUnit Tests [question, wontfix]
+
+-----------------------------------------------------------------------------
+
+        Changes Requiring Special Attention
+
+-----------------------------------------------------------------------------
+
+Important JDK Support Announcement
+* ESAPI 2.3.0.0 was the last Java release to support Java 7. ESAPI 2.4.0 requires using Java 8 or later. See the ESAPI 2.4.0.0 release notes (https://github.com/ESAPI/esapi-java-legacy/blob/develop/documentation/esapi4java-core-2.4.0.0-release-notes.txt) for details as to the reason.
+    - This means if your project requires Java 7, you must use ESAPI 2.3.0.0 or earlier.
+
+Important ESAPI Logging Changes
+
+* Since ESAPI 2.5.0.0, support for logging directly via Log4J 1 has been removed. (This was two years after it haveing first been deprecated.) Thus, you only choice of ESAPI logging are
+    - java.util.logging (JUL), which as been the default since ESAPI 2.2.1.0.
+        * Set ESAPI.Logger=org.owasp.esapi.logging.java.JavaLogFactory in your ESAPI.properties file.
+    - SLF4J (which your choice of supported SLF4J logging implemmentation)
+        * Set ESAPI.Logger=org.owasp.esapi.logging.slf4j.Slf4JLogFactory in your ESAPI.properties file.
+* Logger configuration notes - If you are migrating from prior to ESAPI 2.2.1.1, you will need to update your ESAPI.properties file as logging-related configuration as per the ESAPI 2.2.1.1 release notes, which may be found at:
+    https://github.com/ESAPI/esapi-java-legacy/blob/develop/documentation/esapi4java-core-2.2.1.1-release-notes.txt#L39-L78
+
+If you use ESAPI 2.5.0.0 or later, you will get an ClassNotFoundException as the root cause if you still have your ESAPI.Logger property set to use Log4J because the org.owasp.esapi.logger.log4j.Log4JFactory class has been completely removed from the ESAPI jar.  If you are dead set on continuing to use Log4J 1, you ought to be able to do so via SLF4J. The set up for Log4J 1 (which has not be tested), should be similar to configure ESAPI to use SLF4J with Log4J 2 as described here:
+    https://github.com/ESAPI/esapi-java-legacy/wiki/Using-ESAPI-with-SLF4J#slf4j-using-log4j-2x
+
+-----------------------------------------------------------------------------
+
+        Remaining Known Issues / Problems
+
+-----------------------------------------------------------------------------
+None known, other than the remaining open issues on GitHub.
+
+-----------------------------------------------------------------------------
+
+        Other changes in this release, some of which not tracked via GitHub issues
+
+-----------------------------------------------------------------------------
+
+* Minor updates to README.md file with respect to version information.
+
+-----------------------------------------------------------------------------
+
+Developer Activity Report (Changes between release 2.5.0.0 and 2.5.1.0, i.e., between 2022-07-20 and 2022-11-27)
+Generated manually (this time) -- all errors are the fault of kwwall and his inability to do simple arithmetic.
+
+Developer       Total       Total Number        # Merged
+(GitHub ID)     commits   of Files Changed        PRs
+========================================================
+jeremiahjstacey  10             10              3
+noloader          4            316              4
+Jeff-Walker       2              3              1
+HenriquePinto333  2              1              1
+davewichers       2              3              1
+xeno6696         31              6              1
+kwwall           17              9              0
+========================================================
+                             Total Merged PRs: 11
+
+    (Note: Total # commits as reflected in CHANGELOG [see below] are less since commits from PRs are generally "squashed" when the are merged.)
+-----------------------------------------------------------------------------
+
+CHANGELOG:      Create your own. May I suggest:
+
+        git log --stat --since=2022-07-20 --reverse --pretty=medium
+
+    which will show all the commits since just after the previous (2.5.0.0) release.
+
+    Alternately, you can download the most recent ESAPI source and run
+
+        mvn site
+
+    which will create a CHANGELOG file named 'target/site/changelog.html'
+
+
+-----------------------------------------------------------------------------
+
+Direct and Transitive Runtime and Test Dependencies:
+
+        $ mvn -B dependency:tree
+        ...
+        [INFO] --- maven-dependency-plugin:3.3.0:tree (default-cli) @ esapi ---
+        [INFO] org.owasp.esapi:esapi:jar:2.5.1.0-SNAPSHOT
+        [INFO] +- javax.servlet:javax.servlet-api:jar:3.1.0:provided
+        [INFO] +- javax.servlet.jsp:javax.servlet.jsp-api:jar:2.3.3:provided
+        [INFO] +- xom:xom:jar:1.3.8:compile
+        [INFO] +- commons-beanutils:commons-beanutils:jar:1.9.4:compile
+        [INFO] |  +- commons-logging:commons-logging:jar:1.2:compile
+        [INFO] |  \- commons-collections:commons-collections:jar:3.2.2:compile
+        [INFO] +- commons-configuration:commons-configuration:jar:1.10:compile
+        [INFO] +- commons-lang:commons-lang:jar:2.6:compile
+        [INFO] +- commons-fileupload:commons-fileupload:jar:1.4:compile
+        [INFO] +- org.apache.commons:commons-collections4:jar:4.4:compile
+        [INFO] +- org.apache-extras.beanshell:bsh:jar:2.0b6:compile
+        [INFO] +- org.owasp.antisamy:antisamy:jar:1.7.2:compile
+        [INFO] |  +- net.sourceforge.htmlunit:neko-htmlunit:jar:2.66.0:compile
+        [INFO] |  +- org.apache.httpcomponents.client5:httpclient5:jar:5.2:compile
+        [INFO] |  |  \- org.apache.httpcomponents.core5:httpcore5-h2:jar:5.2:compile
+        [INFO] |  +- org.apache.httpcomponents.core5:httpcore5:jar:5.2:compile
+        [INFO] |  +- org.apache.xmlgraphics:batik-css:jar:1.16:compile
+        [INFO] |  |  +- org.apache.xmlgraphics:batik-shared-resources:jar:1.16:compile
+        [INFO] |  |  +- org.apache.xmlgraphics:batik-util:jar:1.16:compile
+        [INFO] |  |  |  +- org.apache.xmlgraphics:batik-constants:jar:1.16:compile
+        [INFO] |  |  |  \- org.apache.xmlgraphics:batik-i18n:jar:1.16:compile
+        [INFO] |  |  \- org.apache.xmlgraphics:xmlgraphics-commons:jar:2.7:compile
+        [INFO] |  +- xerces:xercesImpl:jar:2.12.2:compile
+        [INFO] |  \- xml-apis:xml-apis-ext:jar:1.3.04:compile
+        [INFO] +- org.slf4j:slf4j-api:jar:2.0.4:compile
+        [INFO] +- xml-apis:xml-apis:jar:1.4.01:compile
+        [INFO] +- commons-io:commons-io:jar:2.11.0:compile
+        [INFO] +- com.github.spotbugs:spotbugs-annotations:jar:4.7.3:compile
+        [INFO] |  \- com.google.code.findbugs:jsr305:jar:3.0.2:compile
+        [INFO] +- commons-codec:commons-codec:jar:1.15:test
+        [INFO] +- junit:junit:jar:4.13.2:test
+        [INFO] +- org.bouncycastle:bcprov-jdk15on:jar:1.70:test
+        [INFO] +- org.hamcrest:hamcrest-core:jar:2.2:test
+        [INFO] |  \- org.hamcrest:hamcrest:jar:2.2:test
+        [INFO] +- org.powermock:powermock-api-mockito2:jar:2.0.9:test
+        [INFO] |  \- org.powermock:powermock-api-support:jar:2.0.9:test
+        [INFO] +- org.mockito:mockito-core:jar:3.12.4:test
+        [INFO] |  +- net.bytebuddy:byte-buddy:jar:1.11.13:test
+        [INFO] |  +- net.bytebuddy:byte-buddy-agent:jar:1.11.13:test
+        [INFO] |  \- org.objenesis:objenesis:jar:3.2:test
+        [INFO] +- org.powermock:powermock-core:jar:2.0.9:test
+        [INFO] |  \- org.javassist:javassist:jar:3.27.0-GA:test
+        [INFO] +- org.powermock:powermock-module-junit4:jar:2.0.9:test
+        [INFO] |  \- org.powermock:powermock-module-junit4-common:jar:2.0.9:test
+        [INFO] +- org.powermock:powermock-reflect:jar:2.0.9:test
+        [INFO] \- org.openjdk.jmh:jmh-core:jar:1.36:test
+        [INFO]    +- net.sf.jopt-simple:jopt-simple:jar:5.0.4:test
+        [INFO]    \- org.apache.commons:commons-math3:jar:3.2:test
+        [INFO] ------------------------------------------------------------------------
+        [INFO] BUILD SUCCESS
+        [INFO] ------------------------------------------------------------------------
+
+-----------------------------------------------------------------------------
+
+Acknowledgments:
+    Special thanks to
+        noloader, Jeff-Walker, HenriquePinto333, & davewichers
+    for submitting PRs to ESAPI.
+
+    Another hat tip to the AntiSamy crew for promptly releasing AntiSamy 1.7.2.  And thanks to Matt Seil, Jeremiah Stacey, and all the ESAPI users who make this worthwhile. This is for you.
+
+A special thanks to the ESAPI community from the ESAPI project co-leaders:
+    Kevin W. Wall (kwwall) <== The irresponsible party for these release notes!
+    Matt Seil (xeno6696)
diff --git a/pom.xml b/pom.xml
index 4ae5b5a..8e4b926 100644
--- a/pom.xml
+++ b/pom.xml
@@ -1,9 +1,9 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/maven-v4_0_0.xsd">
     <modelVersion>4.0.0</modelVersion>
     <groupId>org.owasp.esapi</groupId>
     <artifactId>esapi</artifactId>
-    <version>2.4.0.0-SNAPSHOT</version>
+    <version>2.5.2.0-SNAPSHOT</version>
     <packaging>jar</packaging>
 
     <distributionManagement>
@@ -26,12 +26,12 @@
     <licenses>
         <license>
             <name>BSD</name>
-            <url>http://www.opensource.org/licenses/bsd-license.php</url>
+            <url>https://www.opensource.org/licenses/bsd-license.php</url>
             <comments>Code License - New BSD License</comments>
         </license>
         <license>
             <name>Creative Commons 3.0 BY-SA</name>
-            <url>http://creativecommons.org/licenses/by-sa/3.0/</url>
+            <url>https://creativecommons.org/licenses/by-sa/3.0/</url>
             <comments>Content License - Create Commons 3.0 BY-SA</comments>
         </license>
     </licenses>
@@ -136,17 +136,17 @@
 
     <properties>
         <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
-	    <version.jmh>1.35</version.jmh>
+	    <version.jmh>1.36</version.jmh>
         <version.powermock>2.0.9</version.powermock>
-        <version.spotbugs>4.6.0</version.spotbugs>
+        <version.spotbugs>4.7.3</version.spotbugs>
         <version.findsecbugs>1.12.0</version.findsecbugs>
-        <version.spotbugs.maven>4.6.0.0</version.spotbugs.maven>
-        <version.surefire>3.0.0-M6</version.surefire>
+        <version.spotbugs.maven>4.7.3.0</version.spotbugs.maven>
+        <version.surefire>3.0.0-M7</version.surefire>
         <project.java.target>1.8</project.java.target>
             <!-- TODO: Be sure to update. Should be date of previous official release -->
             <!-- Exact date in the form 'yyyy-dd-yy 00:00:00' should be used. You can find the previous release date -->
             <!-- n the previous release notes file under the 'documentation/' directory. -->
-        <date.prev_release>2021-05-07 00:00:00</date.prev_release>
+        <date.prev_release>2022-07-20 00:00:00</date.prev_release>
     </properties>
 
     <dependencies>
@@ -169,9 +169,9 @@
             </exclusions>
         </dependency>
         <dependency>
-            <groupId>com.io7m.xom</groupId>
+            <groupId>xom</groupId>
             <artifactId>xom</artifactId>
-            <version>1.2.10</version>
+            <version>1.3.8</version>
             <exclusions>
                 <!-- excluded because we directly import newer versions. -->
                 <exclusion>
@@ -235,11 +235,6 @@
                 </exclusion>
             </exclusions>
         </dependency>
-        <dependency>
-            <groupId>log4j</groupId>
-            <artifactId>log4j</artifactId>
-            <version>1.2.17</version>
-        </dependency>
         <dependency>
             <groupId>org.apache.commons</groupId>
             <artifactId>commons-collections4</artifactId>
@@ -253,12 +248,12 @@
         <dependency>
             <groupId>org.owasp.antisamy</groupId>
             <artifactId>antisamy</artifactId>
-            <version>1.6.8</version>
+            <version>1.7.2</version>
         </dependency>
         <dependency>
             <groupId>org.slf4j</groupId>
             <artifactId>slf4j-api</artifactId>
-            <version>1.7.36</version>
+            <version>2.0.4</version>
         </dependency>
         <dependency>
             <groupId>xml-apis</groupId>
@@ -411,7 +406,7 @@
                 <plugin>
                     <groupId>org.apache.maven.plugins</groupId>
                     <artifactId>maven-assembly-plugin</artifactId>
-                    <version>3.3.0</version>
+                    <version>3.4.2</version>
                 </plugin>
                 <plugin>
                     <groupId>org.apache.maven.plugins</groupId>
@@ -421,12 +416,12 @@
                 <plugin>
                     <groupId>org.apache.maven.plugins</groupId>
                     <artifactId>maven-release-plugin</artifactId>
-                    <version>3.0.0-M5</version>
+                    <version>3.0.0-M7</version>
                 </plugin>
                 <plugin>
                      <groupId>org.codehaus.mojo</groupId>
                      <artifactId>versions-maven-plugin</artifactId>
-                     <version>2.10.0</version>
+                     <version>2.13.0</version>
                      <configuration>
                          <rulesUri>file:${project.basedir}/versionRuleset.xml</rulesUri>
                      </configuration>
@@ -439,7 +434,7 @@
             <plugin>
                 <groupId>org.cyclonedx</groupId>
                 <artifactId>cyclonedx-maven-plugin</artifactId>
-                <version>2.5.3</version>
+                <version>2.7.3</version>
                 <executions>
                   <execution>
                     <phase>package</phase>
@@ -467,13 +462,11 @@
                 <artifactId>findsecbugs-plugin</artifactId>
                 <version>${version.findsecbugs}</version>
             </plugin>
-
             <plugin>
-                <groupId>net.sourceforge.maven-taglib</groupId>
-                <artifactId>maven-taglib-plugin</artifactId>
-                <version>2.4</version>
+                <groupId>io.github.weblegacy</groupId>
+                <artifactId>taglib-maven-plugin</artifactId>
+                <version>2.6</version>
             </plugin>
-
             <plugin>
                 <groupId>org.apache.maven.plugins</groupId>
                 <artifactId>maven-changelog-plugin</artifactId>
@@ -523,7 +516,7 @@
             <plugin>
                 <groupId>org.apache.maven.plugins</groupId>
                 <artifactId>maven-deploy-plugin</artifactId>
-                <version>3.0.0-M2</version>
+                <version>3.0.0</version>
             </plugin>
 
             <plugin>
@@ -538,12 +531,12 @@
             <plugin>
                 <groupId>org.apache.maven.plugins</groupId>
                 <artifactId>maven-enforcer-plugin</artifactId>
-                <version>3.0.0</version>
+                <version>3.1.0</version>
                 <dependencies>
                   <dependency>
                     <groupId>org.codehaus.mojo</groupId>
                     <artifactId>extra-enforcer-rules</artifactId>
-                    <version>1.5.1</version>
+                    <version>1.6.0</version>
                   </dependency>
                   <dependency>
                     <groupId>org.codehaus.mojo</groupId>
@@ -627,13 +620,13 @@
             <plugin>
                 <groupId>org.apache.maven.plugins</groupId>
                 <artifactId>maven-install-plugin</artifactId>
-                <version>3.0.0-M1</version>
+                <version>3.1.0</version>
             </plugin>
 
             <plugin>
                 <groupId>org.apache.maven.plugins</groupId>
                 <artifactId>maven-jar-plugin</artifactId>
-                <version>3.2.2</version>
+                <version>3.3.0</version>
                 <configuration>
                     <archive>
                         <manifest>
@@ -647,7 +640,7 @@
             <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-javadoc-plugin</artifactId>
-               <version>3.4.0</version>
+               <version>3.4.1</version>
                <configuration>
                  <source>8</source>
                  <doclint>none</doclint>
@@ -665,31 +658,38 @@
             <plugin>
               <groupId>org.apache.maven.plugins</groupId>
               <artifactId>maven-jxr-plugin</artifactId>
-              <version>3.2.0</version>
+              <version>3.3.0</version>
             </plugin>
 
             <plugin>
                 <groupId>org.apache.maven.plugins</groupId>
                 <artifactId>maven-pmd-plugin</artifactId>
-                <version>3.16.0</version>
+                <version>3.19.0</version>
             </plugin>
 
             <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-project-info-reports-plugin</artifactId>
-               <version>3.2.2</version>
+               <version>3.4.1</version>
             </plugin>
 
             <plugin>
                 <groupId>org.apache.maven.plugins</groupId>
                 <artifactId>maven-resources-plugin</artifactId>
-                <version>3.2.0</version>
+                <version>3.3.0</version>
             </plugin>
 
             <plugin>
+                <!-- Note: This uses the maven-fluido-skin version specified next. The skin is referenced in src/site/site.xml. -->
                 <groupId>org.apache.maven.plugins</groupId>
                 <artifactId>maven-site-plugin</artifactId>
-                <version>3.12.0</version>
+                <version>4.0.0-M3</version>
+            </plugin>
+
+            <plugin>
+                <groupId>org.apache.maven.skins</groupId>
+                <artifactId>maven-fluid-skin</artifactId>
+                <version>1.11.1</version>
             </plugin>
 
             <plugin>
@@ -743,7 +743,7 @@
             <plugin>
                 <groupId>org.owasp</groupId>
                 <artifactId>dependency-check-maven</artifactId>
-                <version>7.1.0</version>
+                <version>7.3.2</version>
                 <configuration>
                     <failBuildOnCVSS>1.0</failBuildOnCVSS>
                     <suppressionFiles>./suppressions.xml</suppressionFiles>
@@ -762,9 +762,9 @@
 
     <reporting>
         <plugins>
-            <plugin>
-                <groupId>net.sourceforge.maven-taglib</groupId>
-                <artifactId>maven-taglib-plugin</artifactId>
+	     <plugin>
+	            <groupId>io.github.weblegacy</groupId>
+                <artifactId>taglib-maven-plugin</artifactId>
             </plugin>
             <plugin>
                 <groupId>org.apache.maven.plugins</groupId>
@@ -787,6 +787,8 @@
                 <configuration>
                     <doclint>none</doclint>
                     <source>8</source>
+                    <failOnError>true</failOnError>
+                    <failOnWarnings>true</failOnWarnings>
                 </configuration>
             </plugin>
             <plugin>
diff --git a/scripts/README.txt b/scripts/README.txt
index 61df78f..4c76a5f 100644
--- a/scripts/README.txt
+++ b/scripts/README.txt
@@ -9,7 +9,6 @@ mvnQuietTest.sh     -- Run 'mvn test' from bash with logSpecial output suppresse
 createVarsFile.sh   -- Bash script to create a vars.2.x.y.z file that is 'sourced' by the 'newReleaseNotes.sh' script.
 esapi4java-core-TEMPLATE-release-notes.txt - Basic template used to create the new release notes file.
 newReleaseNotes.sh  -- Bash script to create the release notes boillerplate from the provided release argument and the TEMPLATE file.
-vars.2.2.3.0        -- File that is 'sourced' (as in "source ./filename") and used with newReleaseNotes.sh
-vars.2.2.3.1        -- File that is 'sourced' (as in "source ./filename") and used with newReleaseNotes.sh
-vars.2.3.0.0        -- File that is 'sourced' (as in "source ./filename") and used with newReleaseNotes.sh
+vars.2.?.?.?        -- File that is 'sourced' (as in "source ./filename") and used with newReleaseNotes.sh
+                       and is associated with the release number associated with the file name.
 vars.template       -- Template to construct the release specific vars files
diff --git a/scripts/esapi-release.sh b/scripts/esapi-release.sh
index 88c78e2..14253ff 100755
--- a/scripts/esapi-release.sh
+++ b/scripts/esapi-release.sh
@@ -64,8 +64,8 @@ USAGE="Usage: $PROG esapi_svn_dir"
 tmpdir="/tmp/$PROG.$RANDOM-$$"
 esapi_release_dir="$tmpdir/esapi_release_dir"
 
-    # This is the directory under esapi_svn_dir where the log4j and ESAPI
-    # properties files are located as well as the $esapiConfig/* config files.
+    # This is the directory under esapi_svn_dir where ESAPI configuration files
+    # such as ESAPI.properties are located as well as the $esapiConfig/* config files.
     # Note that formerly used to be under src/main/resources, but it since
     # has been moved because where it was previously was causing problems with
     # Sonatype's Nexus. That particular problem may have been resolved, but it
@@ -141,7 +141,7 @@ mkdir $jartmpdir
 cd $jartmpdir || exit
 jar xf "$jarfile"
 rm -fr ${esapiConfig:?}
-rm -f properties/* log4j.*
+rm -f properties/*
 rm -f settings.xml owasp-esapi-dev.jks
 # TODO: This part would need some work if we sign or seal the ESAPI jar as
 #       that creates a special MANIFEST.MF file and other special files and
diff --git a/scripts/esapi4java-core-TEMPLATE-release-notes.txt b/scripts/esapi4java-core-TEMPLATE-release-notes.txt
index 5caad5c..0decbe0 100644
--- a/scripts/esapi4java-core-TEMPLATE-release-notes.txt
+++ b/scripts/esapi4java-core-TEMPLATE-release-notes.txt
@@ -1,6 +1,7 @@
 @@@@ IMPORTANT: Be sure to 1) save in DOS text format, and 2) Delete this line and others starting with @@@@
 @@@@             Edit this file in vim with       :set tw=0
 @@@@            Meant to be used with   scripts/newReleaseNotes.sh and the 'vars.*' scripts there.
+@@@@    There are specific references to ESAPI 2.5.0.0 and other old releases in this file. Do NOT change the version #s. They are there for a reason.
 Release notes for ESAPI ${VERSION}
     Release date: ${YYYY_MM_DD_RELEASE_DATE}
     Project leaders:
@@ -13,11 +14,14 @@ Previous release: ESAPI ${PREV_VERSION}, ${PREV_RELEASE_DATE}
 Executive Summary: Important Things to Note for this Release
 ------------------------------------------------------------
 @@@@ View previous release notes to see examples of what to put here. This is typical. YMMV.
+@@@@ Obviously, you should summarize any major changes / new features here.
 This is a patch release with the primary intent of updating some dependencies, some with known vulnerabilities. Details follow.
 
-For those of you using a Software Configuration Analysis (SCA) services such as Snyk, BlackDuck, Veracode SourceClear, OWASP Dependency Check, etc., you might notice that there is vulnerability in xerces:xercesImpl:2.12.0 that ESAPI uses (also a transitive dependency) that is similar to CVE-2020-14621. Unfortunately there is no official patch for this in the regular Maven Central repository. Further details are described in Security Bulletin #3, which is viewable here
-   https://github.com/ESAPI/esapi-java-legacy/blob/develop/documentation/ESAPI-security-bulletin3.pdf 
-and associated with this release on GitHub. Manual workarounds possible. See the security bulletin for further details.
+For those of you using a Software Configuration Analysis (SCA) services such as Snyk, BlackDuck, Veracode SourceClear, OWASP Dependency Check, etc., you will notice that the 4 Log4J 1.x related CVEs are no longer flagged. This is because we have finally removed the Log4J 1.2.17 dependency in ESAPI 2.5.0.0.
+
+Any remaining flagged vulnerabilities (e.g., CVE-2020-7791 for transitive dependency batik-i18n-1.14) are believed to be false postives.
+
+You are encouraged to review the vulnerability analysis written up in https://github.com/ESAPI/esapi-java-legacy/blob/develop/Vulnerability-Summary.md and email us or contact us in our GitHub Discussions page if you have questions.
 
 
 =================================================================================================================
@@ -49,89 +53,30 @@ Issue #         GitHub Issue Title
 
 -----------------------------------------------------------------------------
 @@@@ NOTE any special notes here. Probably leave this one, but I would suggest noting additions BEFORE this.
-[If you have already successfully been using ESAPI 2.2.1.0 or later, you probably can skip this section.]
-
-Since ESAPI 2.2.1.0, the new default ESAPI logger is JUL (java.util.logging packages) and we have deprecated the use of Log4J 1.x because we now support SLF4J and Log4J 1.x is way past its end-of-life. We did not want to make SLF4J the default logger (at least not yet) as we did not want to have the default ESAPI use require additional dependencies. However, SLF4J is likely to be the future choice, at least once we start on ESAPI 3.0. A special shout-out to Jeremiah Stacey for making this possible by re-factoring much of the ESAPI logger code. Note, the straw that broke the proverbial camel's back was the announcement of CVE-2019-17571 (rated Critical), for which there is no fix available and likely will never be.
-
-However, if you try to juse the new ESAPI 2.2.1.0 or later logging you will notice that you need to change ESAPI.Logger and also possibly provide some other properties as well to get the logging behavior that you desire.
-
-To use ESAPI logging in ESAPI 2.2.1.0 (and later), you will need to set the ESAPI.Logger property to
-
-    org.owasp.esapi.logging.java.JavaLogFactory     - To use the new default, java.util.logging (JUL)
-    org.owasp.esapi.logging.log4j.Log4JLogFactory   - To use the end-of-life Log4J 1.x logger
-    org.owasp.esapi.logging.slf4j.Slf4JLogFactory   - To use the new (to release 2.2.0.0) SLF4J logger
 
-In addition, if you wish to use JUL for logging, you *MUST* supply an "esapi-java-logging.properties" file in your classpath. This file is included in the 'esapi-2.2.2.0-configuration.jar' file provided under the 'Assets' section of the GitHub Release at
-    https://github.com/ESAPI/esapi-java-legacy/releases/esapi-2.2.2.0
+Important JDK Support Announcement
+* ESAPI 2.3.0.0 was the last Java release to support Java 7. ESAPI 2.4.0 requires using Java 8 or later. See the ESAPI 2.4.0.0 release notes (https://github.com/ESAPI/esapi-java-legacy/blob/develop/documentation/esapi4java-core-2.4.0.0-release-notes.txt) for details as to the reason.
+    - This means if your project requires Java 7, you must use ESAPI 2.3.0.0 or earlier.
 
-Unfortunately, there was a logic error in the static initializer of JavaLogFactory (now fixed in this release) that caused a NullPointerException to be thrown so that the message about the missing "esapi-java-logging.properties" file was never seen.
+Important ESAPI Logging Changes
 
-If you are using JavaLogFactory, you will also want to ensure that you have the following ESAPI logging properties set:
-    # Set the application name if these logs are combined with other applications
-    Logger.ApplicationName=ExampleApplication
-    # If you use an HTML log viewer that does not properly HTML escape log data, you can set LogEncodingRequired to true
-    Logger.LogEncodingRequired=false
-    # Determines whether ESAPI should log the application name. This might be clutter in some single-server/single-app environments.
-    Logger.LogApplicationName=true
-    # Determines whether ESAPI should log the server IP and port. This might be clutter in some single-server environments.
-    Logger.LogServerIP=true
-    # LogFileName, the name of the logging file. Provide a full directory path (e.g., C:\\ESAPI\\ESAPI_logging_file) if you
-    # want to place it in a specific directory.
-    Logger.LogFileName=ESAPI_logging_file
-    # MaxLogFileSize, the max size (in bytes) of a single log file before it cuts over to a new one (default is 10,000,000)
-    Logger.MaxLogFileSize=10000000
-    # Determines whether ESAPI should log the user info.
-    Logger.UserInfo=true
-    # Determines whether ESAPI should log the session id and client IP.
-    Logger.ClientInfo=true
+* Since ESAPI 2.5.0.0, support for logging directly via Log4J 1 has been removed. (This was two years after it haveing first been deprecated.) Thus, you only choice of ESAPI logging are
+    - java.util.logging (JUL), which as been the default since ESAPI 2.2.1.0.
+        * Set ESAPI.Logger=org.owasp.esapi.logging.java.JavaLogFactory in your ESAPI.properties file.
+    - SLF4J (which your choice of supported SLF4J logging implemmentation)
+        * Set ESAPI.Logger=org.owasp.esapi.logging.slf4j.Slf4JLogFactory in your ESAPI.properties file.
+* Logger configuration notes - If you are migrating from prior to ESAPI 2.2.1.1, you will need to update your ESAPI.properties file as logging-related configuration as per the ESAPI 2.2.1.1 release notes, which may be found at:
+    https://github.com/ESAPI/esapi-java-legacy/blob/develop/documentation/esapi4java-core-2.2.1.1-release-notes.txt#L39-L78
 
-See GitHub issue #560 for additional details.
-
-
-Related to that aforemented Log4J 1.x CVE and how it affects ESAPI, be sure to read
-   https://github.com/ESAPI/esapi-java-legacy/blob/develop/documentation/ESAPI-security-bulletin2.pdf 
-which describes CVE-2019-17571, a deserialization vulnerability in Log4J 1.2.17. ESAPI is *NOT* affected by this (even if you chose to use Log4J 1 as you default ESAPI logger). This security bulletin describes why this CVE is not exploitable as used by ESAPI.
-
-
-Finally, while ESAPI still supports JDK 7 (even though that too is way past end-of-life), the next ESAPI release will move to JDK 8 as the minimal baseline. (We already use Java 8 for development but still to Java 7 source and runtime compatibility.) We need to do this out of necessity because some of our dependencies are no longer doing updates that support Java 7.
+If you use ESAPI 2.5.0.0 or later, you will get an ClassNotFoundException as the root cause if you still have your ESAPI.Logger property set to use Log4J because the org.owasp.esapi.logger.log4j.Log4JFactory class has been completely removed from the ESAPI jar.  If you are dead set on continuing to use Log4J 1, you ought to be able to do so via SLF4J. The set up for Log4J 1 (which has not be tested), should be similar to configure ESAPI to use SLF4J with Log4J 2 as described here:
+    https://github.com/ESAPI/esapi-java-legacy/wiki/Using-ESAPI-with-SLF4J#slf4j-using-log4j-2x
 
 -----------------------------------------------------------------------------
 
         Remaining Known Issues / Problems
 
 -----------------------------------------------------------------------------
-If you use Java 7 (the minimal Java baseline supported by ESAPI) and try to run 'mvn test' there is one test that fails. This test passes with Java 8. The failing test is:
-
-        [ERROR] Tests run: 5, Failures: 1, Errors: 0, Skipped: 0, Time elapsed: 0.203 s
-        <<< FAILURE! - in org.owasp.esapi.crypto.SecurityProviderLoaderTest
-        [ERROR] org.owasp.esapi.crypto.SecurityProviderLoaderTest.testWithBouncyCastle
-        Time elapsed: 0.116 s <<< FAILURE!
-        java.lang.AssertionError: Encryption w/ Bouncy Castle failed with
-        EncryptionException for preferred cipher transformation; exception was:
-        org.owasp.esapi.errors.EncryptionException: Encryption failure (unavailable
-        cipher requested)
-        at
-        org.owasp.esapi.crypto.SecurityProviderLoaderTest.testWithBouncyCastle(Security
-        ProviderLoaderTest.java:133)
-
-I will spare you all the details and tell you that this has to do with Java 7 not being able to correctly parse the signed Bouncy Castle JCE provider jar. More details are available at:
-    https://www.bouncycastle.org/latest_releases.html
-and
-    https://github.com/bcgit/bc-java/issues/477
-I am sure that there are ways of making Bouncy Castle work with Java 7, but since ESAPI does not rely on Bouncy Castle (it can use any compliant JCE provider), this should not be a problem. (It works fine with the default SunJCE provider.) If it is important to get the BC provider working with the ESAPI Encryptor and Java 7, then open a GitHub issue and we will take a deeper look at it and see if we can suggest something.
-
-
-
-Another problem is if you run 'mvn test' from the 'cmd' prompt (and possibly PowerShell as well), you will get intermittent failures (generally between 10-25% of the time) at arbitrary spots. If you run it again without any changes it will work fine without any failures. We have discovered that it doesn't seem to fail if you run the tests from an IDE like Eclipse or if you redirect both stdout and stderr to a file; e.g.,
-
-    C:\code\esapi-java-legacy> mvn test >testoutput.txt 2>&1
-
-We believe these failures is because the maven-surefire-plugin is by default not forking a new JVM process for each test class. We are looking into this. For now, we have only have observed this behavior on Windows 10. If you see this error, please do NOT report it as a GitHub issue unless you know a fix for it. (And yes, we are aware of '<reuseForks>false</reuseForks>' in the pom for the maven-surefire-plugin, but that causes other tests to fail that we haven't had time to fix.)
-
-
-Lastly, some SCA services may continue to flag vulnerabilties in ESAPI ${VERSION} related to log4j 1.2.17 (e.g., CVE-2020-9488). We do not believe the way that ESAPI uses log4j in a manner that leads to any exploitable behavior.  See the security bulletins
-   https://github.com/ESAPI/esapi-java-legacy/blob/develop/documentation/ESAPI-security-bulletin2.pdf 
-for additional details.
+None known, other than the remaining open issues on GitHub.
 
 -----------------------------------------------------------------------------
 
@@ -139,13 +84,16 @@ for additional details.
 
 -----------------------------------------------------------------------------
 
-* Minor updates to README.md file
+* Minor updates to README.md file with respect to version information.
 
 -----------------------------------------------------------------------------
 
 Developer Activity Report (Changes between release ${PREV_VERSION} and ${VERSION}, i.e., between ${PREV_RELEASE_DATE} and ${YYYY_MM_DD_RELEASE_DATE})
 Generated manually (this time) -- all errors are the fault of kwwall and his inability to do simple arithmetic.
 
+@@@@
+@@@@ This section needs to be manually updated.
+@@@@
 Developer       Total       Total Number        # Merged
 (GitHub ID)     commits   of Files Changed        PRs
 ========================================================
@@ -155,8 +103,6 @@ kwwall           7              8               0
 ========================================================
                                     Total PRs:  2
 
-There were also several snyk-bot PRs that were rejected for various reasons, mostly because 1) I was already making the proposed changes and preferred to do them in single commit or 2) there were other reasons for rejecting them (such as the dependency requiring Java 8). The proposed changes that were not outright rejected were included as part of commit a8a79bc5196653500ce664b7b063284e60bddaa0.
-
 -----------------------------------------------------------------------------
 
 CHANGELOG:      Create your own. May I suggest:
@@ -165,6 +111,13 @@ CHANGELOG:      Create your own. May I suggest:
 
     which will show all the commits since just after the previous (${PREV_VERSION}) release.
 
+    Alternately, you can download the most recent ESAPI source and run
+
+        mvn site
+
+    which will create a CHANGELOG file named 'target/site/changelog.html'
+
+
 -----------------------------------------------------------------------------
 
 Direct and Transitive Runtime and Test Dependencies:
@@ -174,8 +127,9 @@ Direct and Transitive Runtime and Test Dependencies:
 
 -----------------------------------------------------------------------------
 
+@@@@ Review these notes, especially the reference to the AntiSamy version information.
 Acknowledgments:
-    Another hat tip to Dave Wichers for promptly releasing AntiSamy 1.6.1.  And thanks to Matt Seil, Jeremiah Stacey, and all the ESAPI users who make this worthwhile. This is for you.
+    Another hat tip to Dave Wichers and the AntiSamy crew for promptly releasing AntiSamy 1.7.0.  And thanks to Matt Seil, Jeremiah Stacey, and all the ESAPI users who make this worthwhile. This is for you.
 
 A special thanks to the ESAPI community from the ESAPI project co-leaders:
     Kevin W. Wall (kwwall) <== The irresponsible party for these release notes!
diff --git a/scripts/vars.2.4.0.0 b/scripts/vars.2.4.0.0
new file mode 100644
index 0000000..9e2f84d
--- /dev/null
+++ b/scripts/vars.2.4.0.0
@@ -0,0 +1,14 @@
+# Do NOT edit this file directly. It will be created by the new createVarsFile.sh script,
+# which should be run prior to the newReleaseNotes.sh script.
+
+# ESAPI (new / current) version
+VERSION=2.4.0.0
+
+# Previous ESAPI version
+PREV_VERSION=2.3.0.0
+
+# Release date of current version in yyyy-mm-dd format
+YYYY_MM_DD_RELEASE_DATE=2022-04-24
+
+# Previous ESAPI release date in same format
+PREV_RELEASE_DATE=2022-04-16
diff --git a/scripts/vars.2.5.0.0 b/scripts/vars.2.5.0.0
new file mode 100644
index 0000000..4d33532
--- /dev/null
+++ b/scripts/vars.2.5.0.0
@@ -0,0 +1,14 @@
+# Do NOT edit this file directly. It will be created by the new createVarsFile.sh script,
+# which should be run prior to the newReleaseNotes.sh script.
+
+# ESAPI (new / current) version
+VERSION=2.5.0.0
+
+# Previous ESAPI version
+PREV_VERSION=2.4.0.0
+
+# Release date of current version in yyyy-mm-dd format
+YYYY_MM_DD_RELEASE_DATE=2022-07-20
+
+# Previous ESAPI release date in same format
+PREV_RELEASE_DATE=2022-04-24
diff --git a/scripts/vars.2.5.1.0 b/scripts/vars.2.5.1.0
new file mode 100644
index 0000000..ab72bcf
--- /dev/null
+++ b/scripts/vars.2.5.1.0
@@ -0,0 +1,14 @@
+# Do NOT edit this file directly. It will be created by the new createVarsFile.sh script,
+# which should be run prior to the newReleaseNotes.sh script.
+
+# ESAPI (new / current) version
+VERSION=2.5.1.0
+
+# Previous ESAPI version
+PREV_VERSION=2.5.0.0
+
+# Release date of current version in yyyy-mm-dd format
+YYYY_MM_DD_RELEASE_DATE=2022-11-27
+
+# Previous ESAPI release date in same format
+PREV_RELEASE_DATE=2022-07-20
diff --git a/src/examples/java/DisplayEncryptedProperties.java b/src/examples/java/DisplayEncryptedProperties.java
index d71ac7d..ba0ce15 100644
--- a/src/examples/java/DisplayEncryptedProperties.java
+++ b/src/examples/java/DisplayEncryptedProperties.java
@@ -8,7 +8,7 @@ import org.owasp.esapi.reference.crypto.DefaultEncryptedProperties;
 //          that were encrypted using ESAPI's EncryptedProperties class.
 //
 // Usage: java -classpath <cp> DisplayEncryptedProperties encryptedPropFileName
-//        where <cp> is proper classpath, which minimally include esapi.jar & log4j.jar
+//        where <cp> is proper classpath, which minimally includes the esapi.jar.
 public class DisplayEncryptedProperties {
 
     public DisplayEncryptedProperties() {
diff --git a/src/examples/java/ESAPILogging.java b/src/examples/java/ESAPILogging.java
index 338e77e..e2b1fc8 100644
--- a/src/examples/java/ESAPILogging.java
+++ b/src/examples/java/ESAPILogging.java
@@ -4,14 +4,14 @@ import org.owasp.esapi.Logger;
 // Purpose: Short code snippet to show how ESAPI logging works.
 //
 // Usage: java -classpath <cp> ESAPILogging
-//        where <cp> is proper classpath, which minimally include esapi.jar & log4j.jar
+//        where <cp> is proper classpath, which minimally includes the esapi.jar.
 public class ESAPILogging {
 
     public static void main(String[] args) {
 
         try {
             Logger logger = ESAPI.getLogger("ESAPILogging");
-            
+
             logger.warning(Logger.SECURITY_FAILURE, "This is a warning.");
             logger.always(Logger.SECURITY_AUDIT, "This is an audit log. It always logs.");
         } catch(Throwable t) {
diff --git a/src/examples/java/PersistedEncryptedData.java b/src/examples/java/PersistedEncryptedData.java
index a034d0a..1cabc04 100644
--- a/src/examples/java/PersistedEncryptedData.java
+++ b/src/examples/java/PersistedEncryptedData.java
@@ -4,7 +4,6 @@ import org.owasp.esapi.crypto.*;
 import org.owasp.esapi.errors.*;
 import org.owasp.esapi.codecs.*;
 import javax.servlet.ServletRequest;
-import org.apache.log4j.Logger;
 
 /** A slightly more complex example showing encoding encrypted data and writing
  *  it out to a file. This is very similar to the example in the ESAPI User
@@ -72,7 +71,7 @@ public class PersistedEncryptedData
         fos.close();
         return serializedBytes.length;
     }
- 
+
     /** Read the specified file name containing encoded encrypted data,
      *  and then decode it and decrypt it to retrieve the original plaintext.
      *
diff --git a/src/examples/scripts/encryptProperties.sh b/src/examples/scripts/encryptProperties.sh
index bc60683..4ee001d 100755
--- a/src/examples/scripts/encryptProperties.sh
+++ b/src/examples/scripts/encryptProperties.sh
@@ -49,8 +49,7 @@ cd ../java
 if [[ "$action" == "-display" ]]
 then
     set -x
-    java -Dlog4j.configuration="file:$log4j_properties" \
-         -Dorg.owasp.esapi.resources="$esapi_resources_test" \
+    java -Dorg.owasp.esapi.resources="$esapi_resources_test" \
          -classpath "$esapi_classpath" \
          DisplayEncryptedProperties "$filename"
 else
@@ -65,8 +64,7 @@ else
     echo
     echo "Hit <Enter> to continue..."; read GO
     set -x
-    java -Dlog4j.configuration="file:$log4j_properties" \
-         -Dorg.owasp.esapi.resources="$esapi_resources_test" \
+    java -Dorg.owasp.esapi.resources="$esapi_resources_test" \
          -classpath "$esapi_classpath" \
       org.owasp.esapi.reference.crypto.DefaultEncryptedProperties "$filename" &&
       echo "Output of encrypted properties in file: $filename"
diff --git a/src/examples/scripts/persistEncryptedData.sh b/src/examples/scripts/persistEncryptedData.sh
index e7dbbe4..fc4a5ed 100755
--- a/src/examples/scripts/persistEncryptedData.sh
+++ b/src/examples/scripts/persistEncryptedData.sh
@@ -23,7 +23,6 @@ set -x
 # Since this is just an illustration, we will use the test ESAPI.properties in
 # $esapi_resources_test. That way, it won't matter if the user has neglected
 # to run the 'setMasterKey.sh' example before running this one.
-java -Dlog4j.configuration="file:$log4j_properties" \
-    -Dorg.owasp.esapi.resources="$esapi_resources_test" \
-    -ea -classpath "$esapi_classpath" \
-    PersistedEncryptedData "$@"
+java -Dorg.owasp.esapi.resources="$esapi_resources_test" \
+     -ea -classpath "$esapi_classpath" \
+     PersistedEncryptedData "$@"
diff --git a/src/examples/scripts/runClass.sh b/src/examples/scripts/runClass.sh
index 1c79082..2b28a4a 100755
--- a/src/examples/scripts/runClass.sh
+++ b/src/examples/scripts/runClass.sh
@@ -19,10 +19,8 @@ then echo >2&1 "Can't find class file: ${className}.class"
      exit 1
 fi
 echo "Your ESAPI.properties file: ${esapi_resources_test:?}/ESAPI.properties"
-echo "Your log4j properties file: ${log4j_properties:?}"
 echo
 set -x
-java -Dlog4j.configuration="file:$log4j_properties" \
-     -Dorg.owasp.esapi.resources="$esapi_resources_test" \
+java -Dorg.owasp.esapi.resources="$esapi_resources_test" \
      -classpath "$esapi_classpath" \
      ${className} "$@"
diff --git a/src/examples/scripts/setMasterKey.sh b/src/examples/scripts/setMasterKey.sh
index 7075532..ecd0937 100755
--- a/src/examples/scripts/setMasterKey.sh
+++ b/src/examples/scripts/setMasterKey.sh
@@ -16,7 +16,6 @@ echo
 # set -x
 # This should use the real ESAPI.properties in $esapi_resources that does
 # not yet have Encryptor.MasterKey and Encryptor.MasterSalt yet set.
-java -Dlog4j.configuration="file:$log4j_properties" \
-     -Dorg.owasp.esapi.resources="$esapi_resources" \
+java -Dorg.owasp.esapi.resources="$esapi_resources" \
      -classpath "$esapi_classpath" \
      org.owasp.esapi.reference.crypto.JavaEncryptor "$@"
diff --git a/src/examples/scripts/setenv-svn.sh b/src/examples/scripts/setenv-svn.sh
index db4846e..d8ab6d7 100755
--- a/src/examples/scripts/setenv-svn.sh
+++ b/src/examples/scripts/setenv-svn.sh
@@ -9,23 +9,17 @@
 #           where '$' represents the shell command line prompt.
 ###########################################################################
 
-# IMPORTANT NOTE:  Since you may have multiple (say) log4j jars under
-#                  your Maven2 repository under $HOME/.m2/respository, we
-#                  look for the specific versions that ESAPI was using as of
-#                  ESAPI 2.0_RC10 release on 2010/10/18. If these versions
-#                  changed, they will have to be reflected here.
-#
+# IMPORTANT NOTE:  These dependency versions may need updated. Should match
+#                  what is in ESAPI's pom.xml.
 esapi_classpath=".:\
 ../../../target/classes:\
 $(ls ../../../target/esapi-*.jar 2>&- || echo .):\
-$(./findjar.sh log4j-1.2.17.jar):\
-$(./findjar.sh commons-fileupload-1.3.1.jar):\
-$(./findjar.sh servlet-api-2.5.jar)"
+$(./findjar.sh commons-fileupload-1.4.jar):\
+$(./findjar.sh servlet-api-3.1.0.jar)"
 
 esapi_resources="$(\cd ../../../configuration/esapi >&- 2>&- && pwd)"
 esapi_resources_test="$(\cd ../../../src/test/resources/esapi >&- 2>&- && pwd)"
 
-log4j_properties="../../../src/test/resources/log4j.xml"
 
 if [[ ! -r "$esapi_resources"/ESAPI.properties ]]
 then echo 2>&1 "setenv-svn.sh: Can't read ESAPI.properties in $esapi_resources"
@@ -37,16 +31,10 @@ then echo 2>&1 "setenv-svn.sh: Can't read ESAPI.properties in $esapi_resources_t
      return 1   # Don't use 'exit' here or it will kill their current shell.
 fi
 
-if [[ ! -r "$log4j_properties" ]]
-then echo 2>&1 "setenv-svn.sh: Can't read log4j.xml: $log4j_properties"
-     return 1   # Don't use 'exit' here or it will kill their current shell.
-fi
-
 echo ############################################################
 echo "esapi_resources=$esapi_resources"
 echo "esapi_resources_test=$esapi_resources_test"
-echo "log4j_properties=$log4j_properties"
 echo "esapi_classpath=$esapi_classpath"
 echo ############################################################
 
-export esapi_classpath esapi_resources esapi_resources_test log4j_properties
+export esapi_classpath esapi_resources esapi_resources_test
diff --git a/src/examples/scripts/setenv-zip.sh b/src/examples/scripts/setenv-zip.sh
index 310864a..199d9c0 100755
--- a/src/examples/scripts/setenv-zip.sh
+++ b/src/examples/scripts/setenv-zip.sh
@@ -12,18 +12,15 @@
 # Here we don't look for the specific versions of the dependent libraries
 # since the specific version of the library is delivered as part of the
 # ESAPI zip file. In this manner, we do not have to update this if these
-# versions change. For the record, at the time of this writing, these were
-# log4j-1.2.17.jar, commons-fileupload-1.3.1.jar, and servlet-api-2.5.jar.
+# versions change.
 esapi_classpath=".:\
 $(ls ../../../esapi*.jar):\
-$(./findjar.sh -start ../../../libs log4j-*.jar):\
 $(./findjar.sh -start ../../../libs commons-fileupload-*.jar):\
 $(./findjar.sh -start ../../../libs servlet-api-*.jar)"
 
 esapi_resources="$(\cd ../../../configuration/esapi >&- 2>&- && pwd)"
 esapi_resources_test="$(\cd ../../../src/test/resources/esapi >&- 2>&- && pwd)"
 
-log4j_properties="../../../src/test/resources/log4j.xml"
 
 if [[ ! -r "$esapi_resources"/ESAPI.properties ]]
 then echo 2>&1 "setenv-svn.sh: Can't read ESAPI.properties in $esapi_resources"
@@ -35,16 +32,11 @@ then echo 2>&1 "setenv-svn.sh: Can't read ESAPI.properties in $esapi_resources_t
      return 1   # Don't use 'exit' here or it will kill their current shell.
 fi
 
-if [[ ! -r "$log4j_properties" ]]
-then echo 2>&1 "setenv-svn.sh: Can't read log4j.xml: $log4j_properties"
-     return 1   # Don't use 'exit' here or it will kill their current shell.
-fi
 
 echo ############################################################
 echo "esapi_resources=$esapi_resources"
 echo "esapi_resources_test=$esapi_resources_test"
-echo "log4j_properties=$log4j_properties"
 echo "esapi_classpath=$esapi_classpath"
 echo ############################################################
 
-export esapi_classpath esapi_resources esapi_resources_test log4j_properties
+export esapi_classpath esapi_resources esapi_resources_test
diff --git a/src/main/assembly/dist.xml b/src/main/assembly/dist.xml
index 3b2ee8e..676039c 100644
--- a/src/main/assembly/dist.xml
+++ b/src/main/assembly/dist.xml
@@ -38,8 +38,6 @@
             <outputDirectory>configuration</outputDirectory>
             <includes>
                 <include>esapi/**/*</include>
-                <include>log4j.dtd</include>
-                <include>log4j.xml</include>
                 <include>properties/**/*</include>
             </includes>
         </fileSet>
diff --git a/src/main/java/org/owasp/esapi/AccessControlRule.java b/src/main/java/org/owasp/esapi/AccessControlRule.java
index b89af4e..51458ff 100644
--- a/src/main/java/org/owasp/esapi/AccessControlRule.java
+++ b/src/main/java/org/owasp/esapi/AccessControlRule.java
@@ -2,7 +2,7 @@ package org.owasp.esapi;
 
 
 public interface AccessControlRule<P, R> {
-	void setPolicyParameters(P policyParameter);
-	P getPolicyParameters();
-	boolean isAuthorized(R runtimeParameter) throws Exception;
+    void setPolicyParameters(P policyParameter);
+    P getPolicyParameters();
+    boolean isAuthorized(R runtimeParameter) throws Exception;
 }
diff --git a/src/main/java/org/owasp/esapi/AccessController.java b/src/main/java/org/owasp/esapi/AccessController.java
index 15dfb5d..ad23d14 100644
--- a/src/main/java/org/owasp/esapi/AccessController.java
+++ b/src/main/java/org/owasp/esapi/AccessController.java
@@ -1,15 +1,15 @@
 /**
  * OWASP Enterprise Security API (ESAPI)
- * 
+ *
  * This file is part of the Open Web Application Security Project (OWASP)
  * Enterprise Security API (ESAPI) project. For details, please see
  * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
  *
  * Copyright (c) 2007-2019 - The OWASP Foundation
- * 
+ *
  * The ESAPI is published by OWASP under the BSD license. You should read and accept the
  * LICENSE before you use, modify, and/or redistribute this software.
- * 
+ *
  * @author Jeff Williams <a href="http://www.aspectsecurity.com">Aspect Security</a>
  * @created 2007
  */
@@ -26,18 +26,18 @@ import org.owasp.esapi.errors.AccessControlException;
  * The implementation of this interface will need to access the current User object (from Authenticator.getCurrentUser())
  * to determine roles or permissions. In addition, the implementation
  * will also need information about the resources that are being accessed. Using the user information and the resource
- * information, the implementation should return an access control decision. 
+ * information, the implementation should return an access control decision.
  * <P>
- * Implementers are encouraged to implement the ESAPI access control rules, like assertAuthorizedForFunction() using 
- * existing access control mechanisms, such as methods like isUserInRole() or hasPrivilege(). While powerful, 
- * methods like isUserInRole() can be confusing for developers, as users may be in multiple roles or possess multiple 
- * overlapping privileges. Direct use of these finer grained access control methods encourages the use of complex boolean 
+ * Implementers are encouraged to implement the ESAPI access control rules, like assertAuthorizedForFunction() using
+ * existing access control mechanisms, such as methods like isUserInRole() or hasPrivilege(). While powerful,
+ * methods like isUserInRole() can be confusing for developers, as users may be in multiple roles or possess multiple
+ * overlapping privileges. Direct use of these finer grained access control methods encourages the use of complex boolean
  * tests throughout the code, which can easily lead to developer mistakes.
  * <P>
- * The point of the ESAPI access control interface is to centralize access control logic behind easy to use calls like 
- * assertAuthorized() so that access control is easy to use and easy to verify. Here is an example of a very 
- * straightforward to implement, understand, and verify ESAPI access control check: 
- * 
+ * The point of the ESAPI access control interface is to centralize access control logic behind easy to use calls like
+ * assertAuthorized() so that access control is easy to use and easy to verify. Here is an example of a very
+ * straightforward to implement, understand, and verify ESAPI access control check:
+ *
  * <pre>
  * try {
  *     ESAPI.accessController().assertAuthorized("businessFunction", runtimeData);
@@ -46,13 +46,13 @@ import org.owasp.esapi.errors.AccessControlException;
  * ... attack in progress
  * }
  * </pre>
- * 
+ *
  * Note that in the user interface layer, access control checks can be used to control whether particular controls are
  * rendered or not. These checks are supposed to fail when an unauthorized user is logged in, and do not represent
  * attacks. Remember that regardless of how the user interface appears, an attacker can attempt to invoke any business
  * function or access any data in your application. Therefore, access control checks in the user interface should be
  * repeated in both the business logic and data layers.
- * 
+ *
  * <pre>
  * &lt;% if ( ESAPI.accessController().isAuthorized( "businessFunction", runtimeData ) ) { %&gt;
  * &lt;a href=&quot;/doAdminFunction&quot;&gt;ADMIN&lt;/a&gt;
@@ -60,140 +60,140 @@ import org.owasp.esapi.errors.AccessControlException;
  * &lt;a href=&quot;/doNormalFunction&quot;&gt;NORMAL&lt;/a&gt;
  * &lt;% } %&gt;
  * </pre>
- * 
+ *
  * @author Mike H. Fauzy (mike.fauzy@aspectsecurity.com) ESAPI v1.6-
  * @author Jeff Williams (jeff.williams@aspectsecurity.com) ESAPI v0-1.5
  */
 public interface AccessController {
 
-	/**
-	 * <code>isAuthorized</code> executes the <code>AccessControlRule</code> 
-	 * that is identified by <code>key</code> and listed in the 
-	 * <code>resources/ESAPI-AccessControlPolicy.xml</code> file. It returns 
-	 * true if the <code>AccessControlRule</code> decides that the operation 
-	 * should be allowed. Otherwise, it returns false. Any exception thrown by 
-	 * the <code>AccessControlRule</code> must result in false. If 
-	 * <code>key</code> does not map to an <code>AccessControlRule</code>, then 
-	 * false is returned. 
-	 *  
-	 * Developers should call isAuthorized to control execution flow. For 
-	 * example, if you want to decide whether to display a UI widget in the 
-	 * browser using the same logic that you will use to enforce permissions
-	 * on the server, then isAuthorized is the method that you want to use.
-	 * 
-	 * Typically, assertAuthorized should be used to enforce permissions on the 
-	 * server.
-	 *  
-	 * @param key <code>key</code> maps to 
-	 * <code>&lt;AccessControlPolicy&gt;&lt;AccessControlRules&gt;
-	 *     &lt;AccessControlRule name="key"</code>
-	 * @param runtimeParameter runtimeParameter can contain anything that 
-	 *        the AccessControlRule needs from the runtime system. 
-	 * @return Returns <code>true</code> if and only if the AccessControlRule specified 
-	 *        by <code>key</code> exists and returned <code>true</code>. 
-	 *        Otherwise returns <code>false</code> 
-	 */
-	boolean isAuthorized(Object key, Object runtimeParameter);
-	
-	/**
-	 * <code>assertAuthorized</code> executes the <code>AccessControlRule</code> 
-	 * that is identified by <code>key</code> and listed in the 
-	 * <code>resources/ESAPI-AccessControlPolicy.xml</code> file. It does 
-	 * nothing if the <code>AccessControlRule</code> decides that the operation 
-	 * should be allowed. Otherwise, it throws an 
-	 * <code>org.owasp.esapi.errors.AccessControlException</code>. Any exception
-	 * thrown by the <code>AccessControlRule</code> will also result in an 
-	 * <code>AccesControlException</code>. If <code>key</code> does not map to 
-	 * an <code>AccessControlRule</code>, then an <code>AccessControlException
-	 * </code> is thrown.  
-	 *  
-	 * Developers should call {@code assertAuthorized} to enforce privileged access to 
-	 * the system. It should be used to answer the question: "Should execution 
-	 * continue." Ideally, the call to <code>assertAuthorized</code> should
-	 * be integrated into the application framework so that it is called 
-	 * automatically. 
-	 *  
-	 * @param key <code>key</code> maps to 
-	 * &lt;AccessControlPolicy&gt;&lt;AccessControlRules&gt;
-	 *     &lt;AccessControlRule name="key"
-	 * @param runtimeParameter runtimeParameter can contain anything that 
-	 *        the AccessControlRule needs from the runtime system.
-	 */
-	void assertAuthorized(Object key, Object runtimeParameter)
-		throws AccessControlException;
+    /**
+     * <code>isAuthorized</code> executes the <code>AccessControlRule</code>
+     * that is identified by <code>key</code> and listed in the
+     * <code>resources/ESAPI-AccessControlPolicy.xml</code> file. It returns
+     * true if the <code>AccessControlRule</code> decides that the operation
+     * should be allowed. Otherwise, it returns false. Any exception thrown by
+     * the <code>AccessControlRule</code> must result in false. If
+     * <code>key</code> does not map to an <code>AccessControlRule</code>, then
+     * false is returned.
+     *
+     * Developers should call isAuthorized to control execution flow. For
+     * example, if you want to decide whether to display a UI widget in the
+     * browser using the same logic that you will use to enforce permissions
+     * on the server, then isAuthorized is the method that you want to use.
+     *
+     * Typically, assertAuthorized should be used to enforce permissions on the
+     * server.
+     *
+     * @param key <code>key</code> maps to
+     * <code>&lt;AccessControlPolicy&gt;&lt;AccessControlRules&gt;
+     *     &lt;AccessControlRule name="key"</code>
+     * @param runtimeParameter runtimeParameter can contain anything that
+     *        the AccessControlRule needs from the runtime system.
+     * @return Returns <code>true</code> if and only if the AccessControlRule specified
+     *        by <code>key</code> exists and returned <code>true</code>.
+     *        Otherwise returns <code>false</code>
+     */
+    boolean isAuthorized(Object key, Object runtimeParameter);
+
+    /**
+     * <code>assertAuthorized</code> executes the <code>AccessControlRule</code>
+     * that is identified by <code>key</code> and listed in the
+     * <code>resources/ESAPI-AccessControlPolicy.xml</code> file. It does
+     * nothing if the <code>AccessControlRule</code> decides that the operation
+     * should be allowed. Otherwise, it throws an
+     * <code>org.owasp.esapi.errors.AccessControlException</code>. Any exception
+     * thrown by the <code>AccessControlRule</code> will also result in an
+     * <code>AccesControlException</code>. If <code>key</code> does not map to
+     * an <code>AccessControlRule</code>, then an <code>AccessControlException
+     * </code> is thrown.
+     *
+     * Developers should call {@code assertAuthorized} to enforce privileged access to
+     * the system. It should be used to answer the question: "Should execution
+     * continue." Ideally, the call to <code>assertAuthorized</code> should
+     * be integrated into the application framework so that it is called
+     * automatically.
+     *
+     * @param key <code>key</code> maps to
+     * &lt;AccessControlPolicy&gt;&lt;AccessControlRules&gt;
+     *     &lt;AccessControlRule name="key"
+     * @param runtimeParameter runtimeParameter can contain anything that
+     *        the AccessControlRule needs from the runtime system.
+     */
+    void assertAuthorized(Object key, Object runtimeParameter)
+        throws AccessControlException;
+
+
+
+
+    /*** Below this line has been deprecated as of ESAPI 1.6 ***/
+
+
 
-		
 
-	
-	/*** Below this line has been deprecated as of ESAPI 1.6 ***/ 
-	
-	
-	
-	
     /**
      * Checks if the current user is authorized to access the referenced URL. Generally, this method should be invoked in the
      * application's controller or a filter as follows:
      * <PRE>ESAPI.accessController().isAuthorizedForURL(request.getRequestURI().toString());</PRE>
-     * 
-     * The implementation of this method should call assertAuthorizedForURL(String url), and if an AccessControlException is 
-     * not thrown, this method should return true. This way, if the user is not authorized, false would be returned, and the 
+     *
+     * The implementation of this method should call assertAuthorizedForURL(String url), and if an AccessControlException is
+     * not thrown, this method should return true. This way, if the user is not authorized, false would be returned, and the
      * exception would be logged.
-     * 
-     * @param url 
-     * 		the URL as returned by request.getRequestURI().toString()
-     * 
-     * @return 
-     * 		true, if is authorized for URL
+     *
+     * @param url
+     *         the URL as returned by request.getRequestURI().toString()
+     *
+     * @return
+     *         true, if is authorized for URL
      */
     @Deprecated
     boolean isAuthorizedForURL(String url);
 
     /**
-     * Checks if the current user is authorized to access the referenced function. 
-     * 
-     * The implementation of this method should call assertAuthorizedForFunction(String functionName), and if an 
+     * Checks if the current user is authorized to access the referenced function.
+     *
+     * The implementation of this method should call assertAuthorizedForFunction(String functionName), and if an
      * AccessControlException is not thrown, this method should return true.
-     * 
-     * @param functionName 
-     * 		the name of the function
-     * 
-     * @return 
-     * 		true, if is authorized for function
+     *
+     * @param functionName
+     *         the name of the function
+     *
+     * @return
+     *         true, if is authorized for function
      */
     @Deprecated
     boolean isAuthorizedForFunction(String functionName);
 
 
     /**
-     * Checks if the current user is authorized to access the referenced data, represented as an Object. 
-     * 
-     * The implementation of this method should call assertAuthorizedForData(String action, Object data), and if an 
+     * Checks if the current user is authorized to access the referenced data, represented as an Object.
+     *
+     * The implementation of this method should call assertAuthorizedForData(String action, Object data), and if an
      * AccessControlException is not thrown, this method should return true.
-     * 
+     *
      * @param action
-     *      The action to verify for an access control decision, such as a role, or an action being performed on the object 
+     *      The action to verify for an access control decision, such as a role, or an action being performed on the object
      *      (e.g., Read, Write, etc.), or the name of the function the data is being passed to.
-     * 
+     *
      * @param data
-     * 		The actual object or object identifier being accessed or a reference to the object being accessed.
-     * 
-     * @return 
-     * 		true, if is authorized for the data
+     *         The actual object or object identifier being accessed or a reference to the object being accessed.
+     *
+     * @return
+     *         true, if is authorized for the data
      */
     @Deprecated
     boolean isAuthorizedForData(String action, Object data);
-    
+
     /**
-     * Checks if the current user is authorized to access the referenced file. 
-     * 
-     * The implementation of this method should call assertAuthorizedForFile(String filepath), and if an AccessControlException 
+     * Checks if the current user is authorized to access the referenced file.
+     *
+     * The implementation of this method should call assertAuthorizedForFile(String filepath), and if an AccessControlException
      * is not thrown, this method should return true.
-     *   
-     * @param filepath 
-     * 		the path of the file to be checked, including filename
-     * 
-     * @return 
-     * 		true, if is authorized for the file
+     *
+     * @param filepath
+     *         the path of the file to be checked, including filename
+     *
+     * @return
+     *         true, if is authorized for the file
      */
     @Deprecated
     boolean isAuthorizedForFile(String filepath);
@@ -201,15 +201,15 @@ public interface AccessController {
     /**
      * Checks if the current user is authorized to access the referenced service. This can be used in applications that
      * provide access to a variety of back end services.
-     * 
-     * The implementation of this method should call assertAuthorizedForService(String serviceName), and if an 
+     *
+     * The implementation of this method should call assertAuthorizedForService(String serviceName), and if an
      * AccessControlException is not thrown, this method should return true.
-     * 
-     * @param serviceName 
-     * 		the service name
-     * 
-     * @return 
-     * 		true, if is authorized for the service
+     *
+     * @param serviceName
+     *         the service name
+     *
+     * @return
+     *         true, if is authorized for the service
      */
     @Deprecated
     boolean isAuthorizedForService(String serviceName);
@@ -218,8 +218,8 @@ public interface AccessController {
      * Checks if the current user is authorized to access the referenced URL. The implementation should allow
      * access to be granted to any part of the URL. Generally, this method should be invoked in the
      * application's controller or a filter as follows:
-     * <PRE>ESAPI.accessController().assertAuthorizedForURL(request.getRequestURI().toString());</PRE> 
-     * 
+     * <PRE>ESAPI.accessController().assertAuthorizedForURL(request.getRequestURI().toString());</PRE>
+     *
      * This method throws an AccessControlException if access is not authorized, or if the referenced URL does not exist.
      * If the User is authorized, this method simply returns.
      * <P>
@@ -229,20 +229,20 @@ public interface AccessController {
      * <li>Use available information to make an access control decision</li>
      *      <ol type="a">
      *      <li>Ideally, this policy would be data driven</li>
-     * 		<li>You can use the current User, roles, data type, data name, time of day, etc.</li>
-     *  	<li>Access control decisions must deny by default</li>
+     *         <li>You can use the current User, roles, data type, data name, time of day, etc.</li>
+     *      <li>Access control decisions must deny by default</li>
      *      </ol>
      * <li>If access is not permitted, throw an AccessControlException with details</li>
-     * </ol> 
-     * @param url 
-     * 		the URL as returned by request.getRequestURI().toString()
-     * 
-     * @throws AccessControlException 
-     * 		if access is not permitted
+     * </ol>
+     * @param url
+     *         the URL as returned by request.getRequestURI().toString()
+     *
+     * @throws AccessControlException
+     *         if access is not permitted
      */
     @Deprecated
     void assertAuthorizedForURL(String url) throws AccessControlException;
-    
+
     /**
      * Checks if the current user is authorized to access the referenced function. The implementation should define the
      * function "namespace" to be enforced. Choosing something simple like the class name of action classes or menu item
@@ -257,24 +257,24 @@ public interface AccessController {
      * <li>Use available information to make an access control decision</li>
      *      <ol type="a">
      *      <li>Ideally, this policy would be data driven</li>
-     * 		<li>You can use the current User, roles, data type, data name, time of day, etc.</li>
-     *  	<li>Access control decisions must deny by default</li>
+     *         <li>You can use the current User, roles, data type, data name, time of day, etc.</li>
+     *      <li>Access control decisions must deny by default</li>
      *      </ol>
      * <li>If access is not permitted, throw an AccessControlException with details</li>
-     * </ol> 
-     * 
-     * @param functionName 
-     * 		the function name
-     * 
-     * @throws AccessControlException 
-     * 		if access is not permitted
+     * </ol>
+     *
+     * @param functionName
+     *         the function name
+     *
+     * @throws AccessControlException
+     *         if access is not permitted
      */
     @Deprecated
     void assertAuthorizedForFunction(String functionName) throws AccessControlException;
-    
+
 
     /**
-     * Checks if the current user is authorized to access the referenced data.  This method simply returns if access is authorized.  
+     * Checks if the current user is authorized to access the referenced data.  This method simply returns if access is authorized.
      * It throws an AccessControlException if access is not authorized, or if the referenced data does not exist.
      * <P>
      * Specification:  The implementation should do the following:
@@ -283,27 +283,27 @@ public interface AccessController {
      * <li>Use available information to make an access control decision</li>
      *      <ol type="a">
      *      <li>Ideally, this policy would be data driven</li>
-     * 		<li>You can use the current User, roles, data type, data name, time of day, etc.</li>
-     *  	<li>Access control decisions must deny by default</li>
+     *         <li>You can use the current User, roles, data type, data name, time of day, etc.</li>
+     *      <li>Access control decisions must deny by default</li>
      *      </ol>
      * <li>If access is not permitted, throw an AccessControlException with details</li>
-     * </ol> 
-     * 
+     * </ol>
+     *
      * @param action
-     *      The action to verify for an access control decision, such as a role, or an action being performed on the object 
+     *      The action to verify for an access control decision, such as a role, or an action being performed on the object
      *      (e.g., Read, Write, etc.), or the name of the function the data is being passed to.
-     * 
+     *
      * @param data
-     * 		The actual object or object identifier being accessed or a reference to the object being accessed.
-     * 
-     * @throws AccessControlException 
-     * 		if access is not permitted
+     *         The actual object or object identifier being accessed or a reference to the object being accessed.
+     *
+     * @throws AccessControlException
+     *         if access is not permitted
      */
     @Deprecated
     void assertAuthorizedForData(String action, Object data) throws AccessControlException;
-   
+
     /**
-     * Checks if the current user is authorized to access the referenced file. The implementation should validate and canonicalize the 
+     * Checks if the current user is authorized to access the referenced file. The implementation should validate and canonicalize the
      * input to be sure the filepath is not malicious.
      * <P>
      * This method throws an AccessControlException if access is not authorized, or if the referenced File does not exist.
@@ -315,19 +315,19 @@ public interface AccessController {
      * <li>Use available information to make an access control decision</li>
      *      <ol type="a">
      *      <li>Ideally, this policy would be data driven</li>
-     * 		<li>You can use the current User, roles, data type, data name, time of day, etc.</li>
-     *  	<li>Access control decisions must deny by default</li>
+     *         <li>You can use the current User, roles, data type, data name, time of day, etc.</li>
+     *      <li>Access control decisions must deny by default</li>
      *      </ol>
      * <li>If access is not permitted, throw an AccessControlException with details</li>
-     * </ol> 
-     * 
+     * </ol>
+     *
      * @param filepath
-     * 			Path to the file to be checked
+     *             Path to the file to be checked
      * @throws AccessControlException if access is denied
      */
     @Deprecated
     void assertAuthorizedForFile(String filepath) throws AccessControlException;
-    
+
     /**
      * Checks if the current user is authorized to access the referenced service. This can be used in applications that
      * provide access to a variety of backend services.
@@ -341,19 +341,19 @@ public interface AccessController {
      * <li>Use available information to make an access control decision</li>
      *      <ol type="a">
      *      <li>Ideally, this policy would be data driven</li>
-     * 		<li>You can use the current User, roles, data type, data name, time of day, etc.</li>
-     *  	<li>Access control decisions must deny by default</li>
+     *         <li>You can use the current User, roles, data type, data name, time of day, etc.</li>
+     *      <li>Access control decisions must deny by default</li>
      *      </ol>
      * <li>If access is not permitted, throw an AccessControlException with details</li>
-     * </ol> 
-     * 
-     * @param serviceName 
-     * 		the service name
-     * 
+     * </ol>
+     *
+     * @param serviceName
+     *         the service name
+     *
      * @throws AccessControlException
-     * 		if access is not permitted
-     */				
+     *         if access is not permitted
+     */
     @Deprecated
     void assertAuthorizedForService(String serviceName) throws AccessControlException;
-    
+
 }
diff --git a/src/main/java/org/owasp/esapi/AccessReferenceMap.java b/src/main/java/org/owasp/esapi/AccessReferenceMap.java
index 4fd74e0..5f7e4e7 100644
--- a/src/main/java/org/owasp/esapi/AccessReferenceMap.java
+++ b/src/main/java/org/owasp/esapi/AccessReferenceMap.java
@@ -1,15 +1,15 @@
 /**
  * OWASP Enterprise Security API (ESAPI)
- * 
+ *
  * This file is part of the Open Web Application Security Project (OWASP)
  * Enterprise Security API (ESAPI) project. For details, please see
  * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
  *
  * Copyright (c) 2007 - The OWASP Foundation
- * 
+ *
  * The ESAPI is published by OWASP under the BSD license. You should read and accept the
  * LICENSE before you use, modify, and/or redistribute this software.
- * 
+ *
  * @author Jeff Williams <a href="http://www.aspectsecurity.com">Aspect Security</a>
  * @created 2007
  */
@@ -40,7 +40,7 @@ import java.util.Set;
  * references, as opposed to simple integers makes it impossible for an attacker to
  * guess valid identifiers. So if per-user AccessReferenceMaps are used, then request
  * forgery (CSRF) attacks will also be prevented.
- * 
+ *
  * <pre>
  * Set fileSet = new HashSet();
  * fileSet.addAll(...); // add direct references (e.g. File objects)
@@ -55,42 +55,42 @@ import java.util.Set;
  * String indref = request.getParameter( &quot;file&quot; );
  * File file = (File)map.getDirectReference( indref );
  * </pre>
- * 
+ *
  * <P>
- * 
+ *
  * @author Jeff Williams (jeff.williams@aspectsecurity.com)
  * @author Chris Schmidt (chrisisbeef@gmail.com)
  */
 public interface AccessReferenceMap<K> extends Serializable {
 
-	/**
-	 * Get an iterator through the direct object references. No guarantee is made as 
-	 * to the order of items returned.
-	 * 
-	 * @return the iterator
-	 */
-	Iterator iterator();
+    /**
+     * Get an iterator through the direct object references. No guarantee is made as
+     * to the order of items returned.
+     *
+     * @return the iterator
+     */
+    Iterator iterator();
 
-	/**
-	 * Get a safe indirect reference to use in place of a potentially sensitive
-	 * direct object reference. Developers should use this call when building
-	 * URL's, form fields, hidden fields, etc... to help protect their private
-	 * implementation information.
-	 * 
-	 * @param directReference
-	 * 		the direct reference
-	 * 
-	 * @return 
-	 * 		the indirect reference
-	 */
-	<T> K getIndirectReference(T directReference);
+    /**
+     * Get a safe indirect reference to use in place of a potentially sensitive
+     * direct object reference. Developers should use this call when building
+     * URL's, form fields, hidden fields, etc... to help protect their private
+     * implementation information.
+     *
+     * @param directReference
+     *         the direct reference
+     *
+     * @return
+     *         the indirect reference
+     */
+    <T> K getIndirectReference(T directReference);
 
-	/**
-	 * Get the original direct object reference from an indirect reference.
-	 * Developers should use this when they get an indirect reference from a
-	 * request to translate it back into the real direct reference. If an
-	 * invalid indirect reference is requested, then an AccessControlException is
-	 * thrown.
+    /**
+     * Get the original direct object reference from an indirect reference.
+     * Developers should use this when they get an indirect reference from a
+     * request to translate it back into the real direct reference. If an
+     * invalid indirect reference is requested, then an AccessControlException is
+     * thrown.
     *
     * If a type is implied the requested object will be cast to that type, if the
     * object is not of the requested type, a AccessControlException will be thrown to
@@ -122,55 +122,55 @@ public interface AccessReferenceMap<K> extends Serializable {
     *     // ...
     * }
     * </pre>
-	 * 
-	 * @param indirectReference
-	 * 		the indirect reference
-	 * 
-	 * @return 
-	 * 		the direct reference
-	 * 
-	 * @throws AccessControlException 
-	 * 		if no direct reference exists for the specified indirect reference
+     *
+     * @param indirectReference
+     *         the indirect reference
+     *
+     * @return
+     *         the direct reference
+     *
+     * @throws AccessControlException
+     *         if no direct reference exists for the specified indirect reference
     * @throws ClassCastException
     *       if the implied type is not the same as the referenced object type
-	 */
-	<T> T getDirectReference(K indirectReference) throws AccessControlException;
+     */
+    <T> T getDirectReference(K indirectReference) throws AccessControlException;
+
+    /**
+     * Adds a direct reference to the AccessReferenceMap, then generates and returns
+     * an associated indirect reference.
+     *
+     * @param direct
+     *         the direct reference
+     *
+     * @return
+     *         the corresponding indirect reference
+     */
+    <T> K addDirectReference(T direct);
 
-	/**
-	 * Adds a direct reference to the AccessReferenceMap, then generates and returns 
-	 * an associated indirect reference.
-	 *  
-	 * @param direct 
-	 * 		the direct reference
-	 * 
-	 * @return 
-	 * 		the corresponding indirect reference
-	 */
-	<T> K addDirectReference(T direct);
-	
-	/**
-	 * Removes a direct reference and its associated indirect reference from the AccessReferenceMap.
-	 * 
-	 * @param direct 
-	 * 		the direct reference to remove
-	 * 
-	 * @return 
-	 * 		the corresponding indirect reference
-	 * 
-	 * @throws AccessControlException
+    /**
+     * Removes a direct reference and its associated indirect reference from the AccessReferenceMap.
+     *
+     * @param direct
+     *         the direct reference to remove
+     *
+     * @return
+     *         the corresponding indirect reference
+     *
+     * @throws AccessControlException
     *          if the reference does not exist.
-	 */
-	<T> K removeDirectReference(T direct) throws AccessControlException;
+     */
+    <T> K removeDirectReference(T direct) throws AccessControlException;
 
-	/**
-	 * Updates the access reference map with a new set of direct references, maintaining
-	 * any existing indirect references associated with items that are in the new list.
-	 * New indirect references could be generated every time, but that
-	 * might mess up anything that previously used an indirect reference, such
-	 * as a URL parameter. 
-	 * 
-	 * @param directReferences
-	 * 		a Set of direct references to add
-	 */
-	void update(Set directReferences);
+    /**
+     * Updates the access reference map with a new set of direct references, maintaining
+     * any existing indirect references associated with items that are in the new list.
+     * New indirect references could be generated every time, but that
+     * might mess up anything that previously used an indirect reference, such
+     * as a URL parameter.
+     *
+     * @param directReferences
+     *         a Set of direct references to add
+     */
+    void update(Set directReferences);
 }
diff --git a/src/main/java/org/owasp/esapi/Authenticator.java b/src/main/java/org/owasp/esapi/Authenticator.java
index 57c090a..e113b0b 100644
--- a/src/main/java/org/owasp/esapi/Authenticator.java
+++ b/src/main/java/org/owasp/esapi/Authenticator.java
@@ -1,15 +1,15 @@
 /**
  * OWASP Enterprise Security API (ESAPI)
- * 
+ *
  * This file is part of the Open Web Application Security Project (OWASP)
  * Enterprise Security API (ESAPI) project. For details, please see
  * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
  *
  * Copyright (c) 2007 - The OWASP Foundation
- * 
+ *
  * The ESAPI is published by OWASP under the BSD license. You should read and accept the
  * LICENSE before you use, modify, and/or redistribute this software.
- * 
+ *
  * @author Jeff Williams <a href="http://www.aspectsecurity.com">Aspect Security</a>
  * @created 2007
  */
@@ -42,7 +42,7 @@ import java.util.Set;
  * current request and the name of the parameters containing the username and
  * password. The implementation should verify the password if necessary, create
  * a session if necessary, and set the user as the current user.
- * 
+ *
  * <pre>
  * public void doPost(ServletRequest request, ServletResponse response) {
  * try {
@@ -52,99 +52,99 @@ import java.util.Set;
  * // handle failed authentication (it's already been logged)
  * }
  * </pre>
- * 
+ *
  * @author Jeff Williams (jeff.williams .at. aspectsecurity.com) <a
  *         href="http://www.aspectsecurity.com">Aspect Security</a>
  * @since June 1, 2007
  */
 public interface Authenticator {
 
-	/**
-	 * Clears the current User. This allows the thread to be reused safely.
-     * 
+    /**
+     * Clears the current User. This allows the thread to be reused safely.
+     *
      * This clears all threadlocal variables from the thread. This should ONLY be called after
      * all possible ESAPI operations have concluded. If you clear too early, many calls will
-     * fail, including logging, which requires the user identity.  
-	 */
-	void clearCurrent();
+     * fail, including logging, which requires the user identity.
+     */
+    void clearCurrent();
 
-	/**
-	 * Calls login with the *current* request and response.
-	 * @return Authenticated {@code User} if login is successful.
-	 * @see HTTPUtilities#setCurrentHTTP(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
-	 */
-	User login() throws AuthenticationException;
-	
-	/**
-	 * This method should be called for every HTTP request, to login the current user either from the session of HTTP
-     * request. This method will set the current user so that getCurrentUser() will work properly. 
-	 * 
-	 * Authenticates the user's credentials from the HttpServletRequest if
-	 * necessary, creates a session if necessary, and sets the user as the
-	 * current user.
-	 * 
-	 * Specification:  The implementation should do the following:
-     * 	1) Check if the User is already stored in the session
-     * 		a. If so, check that session absolute and inactivity timeout have not expired
-     * 		b. Step 2 may not be required if 1a has been satisfied
-     * 	2) Verify User credentials
-     * 		a. It is recommended that you use 
-     * 			loginWithUsernameAndPassword(HttpServletRequest, HttpServletResponse) to verify credentials
-     * 	3) Set the last host of the User (ex.  user.setLastHostAddress(address) )
-     * 	4) Verify that the request is secure (ex. over SSL)
-     * 	5) Verify the User account is allowed to be logged in
-     * 		a. Verify the User is not disabled, expired or locked
-     * 	6) Assign User to session variable      	
-	 * 
-	 * @param request
-	 *            the current HTTP request
-	 * @param response
-	 *            the HTTP response
-	 * 
-	 * @return 
-	 * 		the User
-	 * 
-	 * @throws AuthenticationException
-	 *             if the credentials are not verified, or if the account is disabled, locked, expired, or timed out
-	 */
-	User login(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException;
+    /**
+     * Calls login with the *current* request and response.
+     * @return Authenticated {@code User} if login is successful.
+     * @see HTTPUtilities#setCurrentHTTP(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
+     */
+    User login() throws AuthenticationException;
+
+    /**
+     * This method should be called for every HTTP request, to login the current user either from the session of HTTP
+     * request. This method will set the current user so that getCurrentUser() will work properly.
+     *
+     * Authenticates the user's credentials from the HttpServletRequest if
+     * necessary, creates a session if necessary, and sets the user as the
+     * current user.
+     *
+     * Specification:  The implementation should do the following:
+     *     1) Check if the User is already stored in the session
+     *         a. If so, check that session absolute and inactivity timeout have not expired
+     *         b. Step 2 may not be required if 1a has been satisfied
+     *     2) Verify User credentials
+     *         a. It is recommended that you use
+     *             loginWithUsernameAndPassword(HttpServletRequest, HttpServletResponse) to verify credentials
+     *     3) Set the last host of the User (ex.  user.setLastHostAddress(address) )
+     *     4) Verify that the request is secure (ex. over SSL)
+     *     5) Verify the User account is allowed to be logged in
+     *         a. Verify the User is not disabled, expired or locked
+     *     6) Assign User to session variable
+     *
+     * @param request
+     *            the current HTTP request
+     * @param response
+     *            the HTTP response
+     *
+     * @return
+     *         the User
+     *
+     * @throws AuthenticationException
+     *             if the credentials are not verified, or if the account is disabled, locked, expired, or timed out
+     */
+    User login(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException;
 
-	/**
-	 * Verify that the supplied password matches the password for this user. Password should
-	 * be stored as a hash. By default, this method verifies password hashes created via the
+    /**
+     * Verify that the supplied password matches the password for this user. Password should
+     * be stored as a hash. By default, this method verifies password hashes created via the
      * {@code hashPassword(password, accountName)} method in this class, however see WARNING
      * the {@code hashPassword} method.
      * <p>
-	 * This method is typically used for "reauthentication" for the most sensitive functions, such
-	 * as transactions, changing email address, and changing other account information.
-	 * 
-	 * @param user 
-	 * 		the user who requires verification
-	 * @param password 
-	 * 		the hashed user-supplied password
-	 * 
-	 * @return 
-	 * 		true, if the password is correct for the specified user
+     * This method is typically used for "reauthentication" for the most sensitive functions, such
+     * as transactions, changing email address, and changing other account information.
+     *
+     * @param user
+     *         the user who requires verification
+     * @param password
+     *         the hashed user-supplied password
+     *
+     * @return
+     *         true, if the password is correct for the specified user
      *
      * @see #hashPassword(String password, String accountName)
-	 */
-	boolean verifyPassword(User user, String password);
-	
-	/**
-	 * Logs out the current user.
-	 * 
-	 * This is usually done by calling User.logout on the current User. 
-	 */
+     */
+    boolean verifyPassword(User user, String password);
+
+    /**
+     * Logs out the current user.
+     *
+     * This is usually done by calling User.logout on the current User.
+     */
     void logout();
 
-	/**
-	 * Creates a new User with the information provided. Implementations should check
-	 * accountName and password for proper format and strength against brute force 
-	 * attacks ( verifyAccountNameStrength(String), verifyPasswordStrength(String, String)  ).
-	 * 
-	 * Two copies of the new password are required to encourage user interface designers to
-	 * include a "re-type password" field in their forms. Implementations should verify that 
-	 * both are the same. 
+    /**
+     * Creates a new User with the information provided. Implementations should check
+     * accountName and password for proper format and strength against brute force
+     * attacks ( verifyAccountNameStrength(String), verifyPasswordStrength(String, String)  ).
+     *
+     * Two copies of the new password are required to encourage user interface designers to
+     * include a "re-type password" field in their forms. Implementations should verify that
+     * both are the same.
      * <p>
      * <b>WARNING:</b> The implementation of this method as defined in the
      * default reference implementation class, {@code FileBasedAuthenticator},
@@ -152,122 +152,122 @@ public interface Authenticator {
      * to replace the default reference implementation class with your own custom
      * implementation that uses a stronger password hashing algorithm.
      * See class comments in * {@code FileBasedAuthenticator} for further details.
-	 * 
-	 * @param accountName 
-	 * 		the account name of the new user
-	 * @param password1 
-	 * 		the password of the new user
-	 * @param password2 
-	 * 		the password of the new user.  This field is to encourage user interface designers to include two password fields in their forms.
-	 * 
-	 * @return 
-	 * 		the User that has been created 
-	 * 
-	 * @throws AuthenticationException 
-	 * 		if user creation fails due to any of the qualifications listed in this method's description
-	 */
-	User createUser(String accountName, String password1, String password2) throws AuthenticationException;
+     *
+     * @param accountName
+     *         the account name of the new user
+     * @param password1
+     *         the password of the new user
+     * @param password2
+     *         the password of the new user.  This field is to encourage user interface designers to include two password fields in their forms.
+     *
+     * @return
+     *         the User that has been created
+     *
+     * @throws AuthenticationException
+     *         if user creation fails due to any of the qualifications listed in this method's description
+     */
+    User createUser(String accountName, String password1, String password2) throws AuthenticationException;
+
+    /**
+     * Generate a strong password. Implementations should use a large character set that does not
+     * include confusing characters, such as i I 1 l 0 o and O.  There are many algorithms to
+     * generate strong memorable passwords that have been studied in the past.
+     *
+     * @return
+     *         a password with strong password strength
+     */
+    String generateStrongPassword();
 
-	/**
-	 * Generate a strong password. Implementations should use a large character set that does not
-	 * include confusing characters, such as i I 1 l 0 o and O.  There are many algorithms to
-	 * generate strong memorable passwords that have been studied in the past.
-	 * 
-	 * @return 
-	 * 		a password with strong password strength
-	 */
-	String generateStrongPassword();
+    /**
+     * Generate strong password that takes into account the user's information and old password. Implementations
+     * should verify that the new password does not include information such as the username, fragments of the
+     * old password, and other information that could be used to weaken the strength of the password.
+     *
+     * @param user
+     *         the user whose information to use when generating password
+     * @param oldPassword
+     *         the old password to use when verifying strength of new password.  The new password may be checked for fragments of oldPassword.
+     *
+     * @return
+     *         a password with strong password strength
+     */
+    String generateStrongPassword(User user, String oldPassword);
 
-	/**
-	 * Generate strong password that takes into account the user's information and old password. Implementations
-	 * should verify that the new password does not include information such as the username, fragments of the
-	 * old password, and other information that could be used to weaken the strength of the password.
-	 * 
-	 * @param user 
-	 * 		the user whose information to use when generating password
-	 * @param oldPassword 
-	 * 		the old password to use when verifying strength of new password.  The new password may be checked for fragments of oldPassword.
-	 * 
-	 * @return 
-	 * 		a password with strong password strength
-	 */
-	String generateStrongPassword(User user, String oldPassword);
+    /**
+     * Changes the password for the specified user. This requires the current password, as well as
+     * the password to replace it with. The new password should be checked against old hashes to be sure the new password does not closely resemble or equal any recent passwords for that User.
+     * Password strength should also be verified.  This new password must be repeated to ensure that the user has typed it in correctly.
+     *
+     * @param user
+     *         the user to change the password for
+     * @param currentPassword
+     *         the current password for the specified user
+     * @param newPassword
+     *         the new password to use
+     * @param newPassword2
+     *         a verification copy of the new password
+     *
+     * @throws AuthenticationException
+     *         if any errors occur
+     */
+    void changePassword(User user, String currentPassword, String newPassword, String newPassword2) throws AuthenticationException;
 
-	/**
-	 * Changes the password for the specified user. This requires the current password, as well as 
-	 * the password to replace it with. The new password should be checked against old hashes to be sure the new password does not closely resemble or equal any recent passwords for that User.
-	 * Password strength should also be verified.  This new password must be repeated to ensure that the user has typed it in correctly.
-	 * 
-	 * @param user 
-	 * 		the user to change the password for
-	 * @param currentPassword 
-	 * 		the current password for the specified user
-	 * @param newPassword 
-	 * 		the new password to use
-	 * @param newPassword2 
-	 * 		a verification copy of the new password
-	 * 
-	 * @throws AuthenticationException 
-	 * 		if any errors occur
-	 */
-	void changePassword(User user, String currentPassword, String newPassword, String newPassword2) throws AuthenticationException;
-	
-	/**
-	 * Returns the User matching the provided accountId.  If the accoundId is not found, an Anonymous
-	 * User or null may be returned.
-	 * 
-	 * @param accountId
-	 *            the account id
-	 * 
-	 * @return 
-	 * 		the matching User object, or the Anonymous User if no match exists
-	 */
-	User getUser(long accountId);
-		
-	/**
-	 * Returns the User matching the provided accountName.  If the accoundId is not found, an Anonymous
-	 * User or null may be returned.
-	 * 
-	 * @param accountName
-	 *            the account name
-	 * 
-	 * @return 
-	 * 		the matching User object, or the Anonymous User if no match exists
-	 */
-	User getUser(String accountName);
+    /**
+     * Returns the User matching the provided accountId.  If the accoundId is not found, an Anonymous
+     * User or null may be returned.
+     *
+     * @param accountId
+     *            the account id
+     *
+     * @return
+     *         the matching User object, or the Anonymous User if no match exists
+     */
+    User getUser(long accountId);
 
-	/**
-	 * Gets a collection containing all the existing user names.
-	 * 
-	 * @return 
-	 * 		a set of all user names
-	 */
-	Set getUserNames();
+    /**
+     * Returns the User matching the provided accountName.  If the accoundId is not found, an Anonymous
+     * User or null may be returned.
+     *
+     * @param accountName
+     *            the account name
+     *
+     * @return
+     *         the matching User object, or the Anonymous User if no match exists
+     */
+    User getUser(String accountName);
 
-	/**
-	 * Returns the currently logged in User.
-	 * 
-	 * @return 
-	 * 		the matching User object, or the Anonymous User if no match
-	 *         exists
-	 */
-	User getCurrentUser();
+    /**
+     * Gets a collection containing all the existing user names.
+     *
+     * @return
+     *         a set of all user names
+     */
+    Set getUserNames();
+
+    /**
+     * Returns the currently logged in User.
+     *
+     * @return
+     *         the matching User object, or the Anonymous User if no match
+     *         exists
+     */
+    User getCurrentUser();
 
-	/**
-	 * Sets the currently logged in User.
-	 * 
-	 * @param user
-	 *          the user to set as the current user
-	 */
-	void setCurrentUser(User user);
+    /**
+     * Sets the currently logged in User.
+     *
+     * @param user
+     *          the user to set as the current user
+     */
+    void setCurrentUser(User user);
 
-	/**
-	 * Returns a string representation of the hashed password, using the
-	 * accountName as the salt. The salt helps to prevent against "rainbow"
-	 * table attacks where the attacker pre-calculates hashes for known strings.
-	 * This method specifies the use of the user's account name as the "salt"
-	 * value. The Encryptor.hash method can be used if a different salt is
-	 * required.
+    /**
+     * Returns a string representation of the hashed password, using the
+     * accountName as the salt. The salt helps to prevent against "rainbow"
+     * table attacks where the attacker pre-calculates hashes for known strings.
+     * This method specifies the use of the user's account name as the "salt"
+     * value. The Encryptor.hash method can be used if a different salt is
+     * required.
      * <p>
      * <b>WARNING:</b> The implementation of this method as defined in the
      * default reference implementation class, {@code FileBasedAuthenticator},
@@ -275,71 +275,71 @@ public interface Authenticator {
      * meant to be an example implementation and generally should be avoided
      * and replaced with your own implementation. See class comments in
      * {@code FileBasedAuthenticator} for further details.
-	 * 
-	 * @param password
-	 *            the password to hash
-	 * @param accountName
-	 *            the account name to use as the salt
-	 * 
-	 * @return 
-     * 		the hashed password
+     *
+     * @param password
+     *            the password to hash
+     * @param accountName
+     *            the account name to use as the salt
+     *
+     * @return
+     *         the hashed password
      * @throws EncryptionException
      *
      * @see org.owasp.esapi.reference.FileBasedAuthenticator FileBasedAuthenticator,
      *                          the default reference implementation of this interface.
-	 */
-	String hashPassword(String password, String accountName) throws EncryptionException;
+     */
+    String hashPassword(String password, String accountName) throws EncryptionException;
 
-	/**
-	 * Removes the account of the specified accountName.
-	 * 
-	 * @param accountName
-	 *            the account name to remove
-	 * 
-	 * @throws AuthenticationException
-	 *             the authentication exception if user does not exist
-	 */
-	void removeUser(String accountName) throws AuthenticationException;
+    /**
+     * Removes the account of the specified accountName.
+     *
+     * @param accountName
+     *            the account name to remove
+     *
+     * @throws AuthenticationException
+     *             the authentication exception if user does not exist
+     */
+    void removeUser(String accountName) throws AuthenticationException;
 
-	/**
-	 * Ensures that the account name passes site-specific complexity requirements, like minimum length.
-	 * 
-	 * @param accountName
-	 *            the account name
-	 * 
-	 * @throws AuthenticationException
-	 *             if account name does not meet complexity requirements
-	 */
-	void verifyAccountNameStrength(String accountName) throws AuthenticationException;
+    /**
+     * Ensures that the account name passes site-specific complexity requirements, like minimum length.
+     *
+     * @param accountName
+     *            the account name
+     *
+     * @throws AuthenticationException
+     *             if account name does not meet complexity requirements
+     */
+    void verifyAccountNameStrength(String accountName) throws AuthenticationException;
 
-	/**
-	 * Ensures that the password meets site-specific complexity requirements, like length or number 
-	 * of character sets. This method takes the old password so that the algorithm can analyze the 
-	 * new password to see if it is too similar to the old password. Note that this has to be
-	 * invoked when the user has entered the old password, as the list of old
-	 * credentials stored by ESAPI is all hashed.
-	 * Additionally, the user object is taken in order to verify the password and account name differ.
-	 * 
-	 * @param oldPassword
-	 *            the old password
-	 * @param newPassword
-	 *            the new password
-	 * @param user
-	 * 			  the user
-	 * 
-	 * @throws AuthenticationException
-	 *				if newPassword is too similar to oldPassword or if newPassword does not meet complexity requirements
-	 */
-	void verifyPasswordStrength(String oldPassword, String newPassword, User user) throws AuthenticationException;
+    /**
+     * Ensures that the password meets site-specific complexity requirements, like length or number
+     * of character sets. This method takes the old password so that the algorithm can analyze the
+     * new password to see if it is too similar to the old password. Note that this has to be
+     * invoked when the user has entered the old password, as the list of old
+     * credentials stored by ESAPI is all hashed.
+     * Additionally, the user object is taken in order to verify the password and account name differ.
+     *
+     * @param oldPassword
+     *            the old password
+     * @param newPassword
+     *            the new password
+     * @param user
+     *               the user
+     *
+     * @throws AuthenticationException
+     *                if newPassword is too similar to oldPassword or if newPassword does not meet complexity requirements
+     */
+    void verifyPasswordStrength(String oldPassword, String newPassword, User user) throws AuthenticationException;
 
-	/**
-	 * Determine if the account exists.
-	 * 
-	 * @param accountName
-	 *            the account name
-	 * 
-	 * @return true, if the account exists
-	 */
-	boolean exists(String accountName);
+    /**
+     * Determine if the account exists.
+     *
+     * @param accountName
+     *            the account name
+     *
+     * @return true, if the account exists
+     */
+    boolean exists(String accountName);
 
 }
diff --git a/src/main/java/org/owasp/esapi/ESAPI.java b/src/main/java/org/owasp/esapi/ESAPI.java
index e11239c..ef389d0 100644
--- a/src/main/java/org/owasp/esapi/ESAPI.java
+++ b/src/main/java/org/owasp/esapi/ESAPI.java
@@ -1,15 +1,15 @@
 /**
  * OWASP Enterprise Security API (ESAPI)
- * 
+ *
  * This file is part of the Open Web Application Security Project (OWASP)
  * Enterprise Security API (ESAPI) project. For details, please see
  * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
  *
  * Copyright (c) 2008 - The OWASP Foundation
- * 
+ *
  * The ESAPI is published by OWASP under the BSD license. You should read and accept the
  * LICENSE before you use, modify, and/or redistribute this software.
- * 
+ *
  * @author Mike Fauzy <a href="http://www.aspectsecurity.com">Aspect Security</a>
  * @author Rogan Dawes <a href="http://www.aspectsecurity.com">Aspect Security</a>
  * @created 2008
@@ -26,171 +26,171 @@ import org.owasp.esapi.util.ObjFactory;
  * Use the set methods to override the reference implementations with instances of any custom ESAPI implementations.
  */
 public final class ESAPI {
-	private static String securityConfigurationImplName = System.getProperty("org.owasp.esapi.SecurityConfiguration", "org.owasp.esapi.reference.DefaultSecurityConfiguration");
-
-	/**
-	 * prevent instantiation of this class
-	 */
-	private ESAPI() {
-	}
-	
-    /**
-	 * Clears the current User, HttpRequest, and HttpResponse associated with the current thread. This method
-	 * MUST be called as some containers do not properly clear threadlocal variables when the execution of
-	 * a thread is complete. The suggested approach is to put this call in a finally block inside a filter.
-	 * <pre>
-		public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException {
-			try {
-				HttpServletRequest request = (HttpServletRequest) req;
-				HttpServletResponse response = (HttpServletResponse) resp;
-				ESAPI.httpUtilities().setCurrentHTTP(request, response);
-				ESAPI.authenticator().login();
-				chain.doFilter(request, response);
-			} catch (Exception e) {
-				logger.error( Logger.SECURITY_FAILURE, "Error in ESAPI security filter: " + e.getMessage(), e );
-			} finally {
-				// VERY IMPORTANT
-				// clear out ThreadLocal variables
-				ESAPI.clearCurrent();
-			}
-		}
-	 * </pre>
-	 * The advantages of having identity everywhere are worth the risk here.
-	 */
-	public static void clearCurrent() {
-		authenticator().clearCurrent();
-		httpUtilities().clearCurrent();
-	}
-
-	/**
-	 * Get the current HTTP Servlet Request being processed.
-	 * @return the current HTTP Servlet Request.
-	 */
-	public static HttpServletRequest currentRequest() {
-		return httpUtilities().getCurrentRequest();
-	}
-	
-	/**
-	 * Get the current HTTP Servlet Response being generated.
-	 * @return the current HTTP Servlet Response.
-	 */
-	public static HttpServletResponse currentResponse() {
-		return httpUtilities().getCurrentResponse();
-	}
-	
-	/**
-	 * @return the current ESAPI AccessController object being used to maintain the access control rules for this application. 
-	 */
-	public static AccessController accessController() {
+    private static String securityConfigurationImplName = System.getProperty("org.owasp.esapi.SecurityConfiguration", "org.owasp.esapi.reference.DefaultSecurityConfiguration");
+
+    /**
+     * prevent instantiation of this class
+     */
+    private ESAPI() {
+    }
+
+    /**
+     * Clears the current User, HttpRequest, and HttpResponse associated with the current thread. This method
+     * MUST be called as some containers do not properly clear threadlocal variables when the execution of
+     * a thread is complete. The suggested approach is to put this call in a finally block inside a filter.
+     * <pre>
+        public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException {
+            try {
+                HttpServletRequest request = (HttpServletRequest) req;
+                HttpServletResponse response = (HttpServletResponse) resp;
+                ESAPI.httpUtilities().setCurrentHTTP(request, response);
+                ESAPI.authenticator().login();
+                chain.doFilter(request, response);
+            } catch (Exception e) {
+                logger.error( Logger.SECURITY_FAILURE, "Error in ESAPI security filter: " + e.getMessage(), e );
+            } finally {
+                // VERY IMPORTANT
+                // clear out ThreadLocal variables
+                ESAPI.clearCurrent();
+            }
+        }
+     * </pre>
+     * The advantages of having identity everywhere are worth the risk here.
+     */
+    public static void clearCurrent() {
+        authenticator().clearCurrent();
+        httpUtilities().clearCurrent();
+    }
+
+    /**
+     * Get the current HTTP Servlet Request being processed.
+     * @return the current HTTP Servlet Request.
+     */
+    public static HttpServletRequest currentRequest() {
+        return httpUtilities().getCurrentRequest();
+    }
+
+    /**
+     * Get the current HTTP Servlet Response being generated.
+     * @return the current HTTP Servlet Response.
+     */
+    public static HttpServletResponse currentResponse() {
+        return httpUtilities().getCurrentResponse();
+    }
+
+    /**
+     * @return the current ESAPI AccessController object being used to maintain the access control rules for this application.
+     */
+    public static AccessController accessController() {
         return ObjFactory.make( securityConfiguration().getAccessControlImplementation(), "AccessController" );
-	}
+    }
 
-	/**
-	 * @return the current ESAPI Authenticator object being used to authenticate users for this application. 
-	 */
-	public static Authenticator authenticator() {
+    /**
+     * @return the current ESAPI Authenticator object being used to authenticate users for this application.
+     */
+    public static Authenticator authenticator() {
         return ObjFactory.make( securityConfiguration().getAuthenticationImplementation(), "Authenticator" );
-	}
+    }
 
-	/**
+    /**
      * The ESAPI Encoder is primarilly used to provide <i>output</i> encoding to
      * prevent Cross-Site Scripting (XSS).
-	 * @return the current ESAPI Encoder object being used to encode and decode data for this application. 
-	 */
-	public static Encoder encoder() {
+     * @return the current ESAPI Encoder object being used to encode and decode data for this application.
+     */
+    public static Encoder encoder() {
         return ObjFactory.make( securityConfiguration().getEncoderImplementation(), "Encoder" );
-	}
+    }
 
-	/**
-	 * @return the current ESAPI Encryptor object being used to encrypt and decrypt data for this application. 
-	 */
-	public static Encryptor encryptor() {
+    /**
+     * @return the current ESAPI Encryptor object being used to encrypt and decrypt data for this application.
+     */
+    public static Encryptor encryptor() {
         return ObjFactory.make( securityConfiguration().getEncryptionImplementation(), "Encryptor" );
-	}
+    }
 
-	/**
-	 * @return the current ESAPI Executor object being used to safely execute OS commands for this application. 
-	 */
-	public static Executor executor() {
+    /**
+     * @return the current ESAPI Executor object being used to safely execute OS commands for this application.
+     */
+    public static Executor executor() {
         return ObjFactory.make( securityConfiguration().getExecutorImplementation(), "Executor" );
-	}
+    }
 
-	/**
-	 * @return the current ESAPI HTTPUtilities object being used to safely access HTTP requests and responses 
-	 * for this application. 
-	 */
-	public static HTTPUtilities httpUtilities() {
+    /**
+     * @return the current ESAPI HTTPUtilities object being used to safely access HTTP requests and responses
+     * for this application.
+     */
+    public static HTTPUtilities httpUtilities() {
         return ObjFactory.make( securityConfiguration().getHTTPUtilitiesImplementation(), "HTTPUtilities" );
-	}
+    }
 
-	/**
-	 * @return the current ESAPI IntrusionDetector being used to monitor for intrusions in this application. 
-	 */
-	public static IntrusionDetector intrusionDetector() {
+    /**
+     * @return the current ESAPI IntrusionDetector being used to monitor for intrusions in this application.
+     */
+    public static IntrusionDetector intrusionDetector() {
         return ObjFactory.make( securityConfiguration().getIntrusionDetectionImplementation(), "IntrusionDetector" );
-	}
-
-	/**
-	 * Get the current LogFactory being used by ESAPI. If there isn't one yet, it will create one, and then 
-	 * return this same LogFactory from then on.
-	 * @return The current LogFactory being used by ESAPI.
-	 */
-	private static LogFactory logFactory() {
+    }
+
+    /**
+     * Get the current LogFactory being used by ESAPI. If there isn't one yet, it will create one, and then
+     * return this same LogFactory from then on.
+     * @return The current LogFactory being used by ESAPI.
+     */
+    private static LogFactory logFactory() {
         return ObjFactory.make( securityConfiguration().getLogImplementation(), "LogFactory" );
-	}
-	
-	/**
-	 * @param clazz The class to associate the logger with.
-	 * @return The current Logger associated with the specified class.
-	 */
-	public static Logger getLogger(Class clazz) {
-		return logFactory().getLogger(clazz);
-	}
-	
-	/**
-	 * @param moduleName The module to associate the logger with.
-	 * @return The current Logger associated with the specified module.
-	 */
-	public static Logger getLogger(String moduleName) {
-		return logFactory().getLogger(moduleName);
-	}
-	
-	/**
-	 * @return The default Logger.
-	 */
-	public static Logger log() {
+    }
+
+    /**
+     * @param clazz The class to associate the logger with.
+     * @return The current Logger associated with the specified class.
+     */
+    public static Logger getLogger(Class clazz) {
+        return logFactory().getLogger(clazz);
+    }
+
+    /**
+     * @param moduleName The module to associate the logger with.
+     * @return The current Logger associated with the specified module.
+     */
+    public static Logger getLogger(String moduleName) {
+        return logFactory().getLogger(moduleName);
+    }
+
+    /**
+     * @return The default Logger.
+     */
+    public static Logger log() {
         return logFactory().getLogger("DefaultLogger");
     }
-	
-	/**
-	 * @return the current ESAPI Randomizer being used to generate random numbers in this application. 
-	 */
-	public static Randomizer randomizer() {
+
+    /**
+     * @return the current ESAPI Randomizer being used to generate random numbers in this application.
+     */
+    public static Randomizer randomizer() {
         return ObjFactory.make( securityConfiguration().getRandomizerImplementation(), "Randomizer" );
-	}
+    }
 
     private static volatile SecurityConfiguration overrideConfig = null;
 
-	/**
-	 * @return the current ESAPI SecurityConfiguration being used to manage the security configuration for 
-	 * ESAPI for this application. 
-	 */
-	public static SecurityConfiguration securityConfiguration() {
-		// copy the volatile into a non-volatile to prevent TOCTTOU race condition
-		SecurityConfiguration override = overrideConfig;
-		if ( override != null ) {
-			return override;
+    /**
+     * @return the current ESAPI SecurityConfiguration being used to manage the security configuration for
+     * ESAPI for this application.
+     */
+    public static SecurityConfiguration securityConfiguration() {
+        // copy the volatile into a non-volatile to prevent TOCTTOU race condition
+        SecurityConfiguration override = overrideConfig;
+        if ( override != null ) {
+            return override;
         }
 
         return ObjFactory.make( securityConfigurationImplName, "SecurityConfiguration" );
-	}
+    }
 
-	/**
-	 * @return the current ESAPI Validator being used to validate data in this application. 
-	 */
-	public static Validator validator() {
+    /**
+     * @return the current ESAPI Validator being used to validate data in this application.
+     */
+    public static Validator validator() {
         return ObjFactory.make( securityConfiguration().getValidationImplementation(), "Validator" );
-	}
+    }
 
     // TODO: This should probably use the SecurityManager or some value within the current
     // securityConfiguration to determine if this method is allowed to be called. This could
diff --git a/src/main/java/org/owasp/esapi/Encoder.java b/src/main/java/org/owasp/esapi/Encoder.java
index 4c831d2..4cae3f2 100644
--- a/src/main/java/org/owasp/esapi/Encoder.java
+++ b/src/main/java/org/owasp/esapi/Encoder.java
@@ -1,15 +1,15 @@
 /**
  * OWASP Enterprise Security API (ESAPI)
- * 
+ *
  * This file is part of the Open Web Application Security Project (OWASP)
  * Enterprise Security API (ESAPI) project. For details, please see
  * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
  *
  * Copyright (c) 2007-2019 - The OWASP Foundation
- * 
+ *
  * The ESAPI is published by OWASP under the BSD license. You should read and accept the
  * LICENSE before you use, modify, and/or redistribute this software.
- * 
+ *
  * @author Jeff Williams <a href="http://www.aspectsecurity.com">Aspect Security</a>
  * @created 2007
  */
@@ -45,6 +45,7 @@ import org.owasp.esapi.errors.EncodingException;
  * <li>JavaScript Escaping</li>
  * <li>MySQL Database Escaping</li>
  * <li>Oracle Database Escaping</li>
+ * <li>JSON Escaping</li>
  * <li>Percent Encoding (aka URL Encoding)</li>
  * <li>Unix Shell Escaping</li>
  * <li>VBScript Escaping</li>
@@ -148,7 +149,7 @@ import org.owasp.esapi.errors.EncodingException;
  * <a href="https://beefproject.com/" target="_blank" rel="noopener noreferrer">BeEF - The Browser Exploitation Framework Project</a>.
  * </li>
  * </ul>
- * 
+ *
  * @see <a href="https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html">OWASP Cross-Site Scripting Prevention Cheat Sheet</a>
  * @see <a href="https://owasp.org/www-project-proactive-controls/v3/en/c4-encode-escape-data">OWASP Proactive Controls: C4: Encode and Escape Data</a>
  * @see <a href="https://www.onwebsecurity.com/security/properly-encoding-and-escaping-for-the-web.html" target="_blank" rel="noopener noreferrer">Properly encoding and escaping for the web</a>
@@ -156,35 +157,44 @@ import org.owasp.esapi.errors.EncodingException;
  * @since June 1, 2007
  */
 public interface Encoder {
-    
+
     /**
      * This method is equivalent to calling {@code Encoder.canonicalize(input, restrictMultiple, restrictMixed);}.
      *
-     * The default values for restrictMultiple and restrictMixed come from {@code ESAPI.properties}
+     * The <i>default</i> values for {@code restrictMultiple} and {@code restrictMixed} come from {@code ESAPI.properties}.
      * <pre>
      * Encoder.AllowMultipleEncoding=false
      * Encoder.AllowMixedEncoding=false
      * </pre>
+     * and the default codecs that are used for canonicalization are the list
+     * of codecs that comes from:
+     * <pre>
+     * Encoder.DefaultCodecList=HTMLEntityCodec,PercentCodec,JavaScriptCodec
+     * </pre>
+     * (If the {@code Encoder.DefaultCodecList} property is null or not set,
+     * these same codecs are listed in the same order. Note that you may supply
+     * your own codec by using a fully cqualified class name of a class that
+     * implements {@code org.owasp.esapi.codecs.Codec<T>}.
      *
      * @see #canonicalize(String, boolean, boolean)
      * @see <a href="http://www.w3.org/TR/html4/interact/forms.html#h-17.13.4">W3C specifications</a>
-     * 
+     *
      * @param input the text to canonicalize
      * @return a String containing the canonicalized text
      */
     String canonicalize(String input);
-    
+
     /**
      * This method is the equivalent to calling {@code Encoder.canonicalize(input, strict, strict);}.
      *
      * @see #canonicalize(String, boolean, boolean)
      * @see <a href="http://www.w3.org/TR/html4/interact/forms.html#h-17.13.4">W3C specifications</a>
-     *  
-     * @param input 
+     *
+     * @param input
      *      the text to canonicalize
-     * @param strict 
+     * @param strict
      *      true if checking for multiple and mixed encoding is desired, false otherwise
-     * 
+     *
      * @return a String containing the canonicalized text
      */
     String canonicalize(String input, boolean strict);
@@ -224,7 +234,25 @@ public interface Encoder {
      *     Encoder encoder = new DefaultEncoder( list );
      *     String clean = encoder.canonicalize( request.getParameter( "input" ));
      * </pre>
-     * In ESAPI, the Validator uses the canonicalize method before it does validation.  So all you need to
+     * or alternately, you can just customize {@code Encoder.DefaultCodecList} property
+     * in the {@code ESAPI.properties} file with your preferred codecs; for
+     * example:
+     * <pre>
+     * Encoder.DefaultCodecList=WindowsCodec,MySQLCodec,PercentCodec
+     * </pre>
+     * and then use:
+     * <pre>
+     *     Encoder encoder = ESAPI.encoder();
+     *     String clean = encoder.canonicalize( request.getParameter( "input" ));
+     * </pre>
+     * as you normally would. However, the downside to using the
+     * {@code ESAPI.properties} file approach does not allow you to vary your
+     * list of codecs that are used each time. The downside to using the
+     * {@code DefaultEncoder} constructor is that your code is now timed to
+     * specific reference implementations rather than just interfaces and those
+     * reference implementations are what is most likely to change in ESAPI 3.x.
+     * </p><p>
+     * In ESAPI, the {@code Validator} uses the {@code canonicalize} method before it does validation.  So all you need to
      * do is to validate as normal and you'll be protected against a host of encoded attacks.
      * <pre>
      *     String input = request.getParameter( "name" );
@@ -253,14 +281,22 @@ public interface Encoder {
      *     // disabling strict mode to allow mixed encoding
      *     String url = ESAPI.encoder().canonicalize( request.getParameter("url"), false, false);
      * </pre>
-     * <b>WARNING!!!</b> Please note that this method is incompatible with URLs and if there exist any HTML Entities
-     * that correspond with parameter values in a URL such as "&amp;para;" in a URL like 
+     * <b>WARNING #1!!!</b> Please note that this method is incompatible with URLs and if there exist any HTML Entities
+     * that correspond with parameter values in a URL such as "&amp;para;" in a URL like
      * "https://foo.com/?bar=foo&amp;parameter=wrong" you will get a mixed encoding validation exception.
      * <p>
      * If you wish to canonicalize a URL/URI use the method {@code Encoder.getCanonicalizedURI(URI dirtyUri);}
+     * </p><p>
+     * <b>WARNING #2!!!</b> Even if you use {@code WindowsCodec} or {@code UnixCodec}
+     * as appropriate, file path names in the {@code input} parameter will <b><i>NOT</i></b>
+     * be canonicalized. It the failure of such file path name canonicalization
+     * presents a potential security issue, consider using one of the
+     * {@code Validator.getValidDirectoryPath()} methods instead of or in addition to this method.
      *
      * @see <a href="http://www.w3.org/TR/html4/interact/forms.html#h-17.13.4">W3C specifications</a>
+     * @see #canonicalize(String)
      * @see #getCanonicalizedURI(URI dirtyUri)
+     * @see org.owasp.esapi.Validator#getValidDirectoryPath(java.lang.String, java.lang.String, java.io.File, boolean)
      *
      * @param input
      *      the text to canonicalize
@@ -275,30 +311,30 @@ public interface Encoder {
 
     /**
      * Encode data for use in Cascading Style Sheets (CSS) content.
-     * 
+     *
      * @see <a href="http://www.w3.org/TR/CSS21/syndata.html#escaped-characters">CSS Syntax [w3.org]</a>
-     * 
-     * @param untrustedData 
+     *
+     * @param untrustedData
      *      the untrusted data to output encode for CSS
-     * 
+     *
      * @return the untrusted data safely output encoded for use in a CSS
      */
     String encodeForCSS(String untrustedData);
 
     /**
      * Encode data for use in HTML using HTML entity encoding
-     * <p> 
+     * <p>
      * Note that the following characters:
      * 00-08, 0B-0C, 0E-1F, and 7F-9F
-     * <p>cannot be used in HTML. 
-     * 
-     * @see <a href="http://en.wikipedia.org/wiki/Character_encodings_in_HTML">HTML Encodings [wikipedia.org]</a> 
+     * <p>cannot be used in HTML.
+     *
+     * @see <a href="http://en.wikipedia.org/wiki/Character_encodings_in_HTML">HTML Encodings [wikipedia.org]</a>
      * @see <a href="http://www.w3.org/TR/html4/sgml/sgmldecl.html">SGML Specification [w3.org]</a>
      * @see <a href="http://www.w3.org/TR/REC-xml/#charsets">XML Specification [w3.org]</a>
-     * 
-     * @param untrustedData 
+     *
+     * @param untrustedData
      *      the untrusted data to output encode for HTML
-     * 
+     *
      * @return the untrusted data safely output encoded for use in a HTML
      */
     String encodeForHTML(String untrustedData);
@@ -309,35 +345,35 @@ public interface Encoder {
      * @return the newly decoded <code>String</code>
      */
     String decodeForHTML(String input);
-        
+
     /**
      * Encode data for use in HTML attributes.
-     * 
-     * @param untrustedData 
+     *
+     * @param untrustedData
      *      the untrusted data to output encode for an HTML attribute
-     * 
+     *
      * @return the untrusted data safely output encoded for use in a use as an HTML attribute
      */
     String encodeForHTMLAttribute(String untrustedData);
 
 
     /**
-     * Encode data for insertion inside a data value or function argument in JavaScript. Including user data 
+     * Encode data for insertion inside a data value or function argument in JavaScript. Including user data
      * directly inside a script is quite dangerous. Great care must be taken to prevent including user data
      * directly into script code itself, as no amount of encoding will prevent attacks there.
-     * 
-     * Please note there are some JavaScript functions that can never safely receive untrusted data 
+     *
+     * Please note there are some JavaScript functions that can never safely receive untrusted data
      * as input – even if the user input is encoded.
-     * 
+     *
      * For example:
      * <pre>
      *  &lt;script&gt;
      *    &nbsp;&nbsp;window.setInterval('&lt;%= EVEN IF YOU ENCODE UNTRUSTED DATA YOU ARE XSSED HERE %&gt;');
      *  &lt;/script&gt;
      * </pre>
-     * @param untrustedData 
+     * @param untrustedData
      *          the untrusted data to output encode for JavaScript
-     * 
+     *
      * @return the untrusted data safely output encoded for use in a use in JavaScript
      */
     String encodeForJavaScript(String untrustedData);
@@ -346,119 +382,119 @@ public interface Encoder {
      * Encode data for insertion inside a data value in a Visual Basic script. Putting user data directly
      * inside a script is quite dangerous. Great care must be taken to prevent putting user data
      * directly into script code itself, as no amount of encoding will prevent attacks there.
-     * 
+     *
      * This method is not recommended as VBScript is only supported by Internet Explorer
-     * 
-     * @param untrustedData 
+     *
+     * @param untrustedData
      *      the untrusted data to output encode for VBScript
-     * 
+     *
      * @return the untrusted data safely output encoded for use in a use in VBScript
      */
     String encodeForVBScript(String untrustedData);
 
 
     /**
-     * Encode input for use in a SQL query, according to the selected codec 
+     * Encode input for use in a SQL query, according to the selected codec
      * (appropriate codecs include the MySQLCodec and OracleCodec).
-     * 
+     *
      * This method is not recommended. The use of the {@code PreparedStatement}
-     * interface is the preferred approach. However, if for some reason 
-     * this is impossible, then this method is provided as a weaker 
-     * alternative. 
-     * 
+     * interface is the preferred approach. However, if for some reason
+     * this is impossible, then this method is provided as a weaker
+     * alternative.
+     *
      * The best approach is to make sure any single-quotes are double-quoted.
      * Another possible approach is to use the {escape} syntax described in the
      * JDBC specification in section 1.5.6.
      *
      * However, this syntax does not work with all drivers, and requires
      * modification of all queries.
-     * 
+     *
      * @see <a href="https://download.oracle.com/otn-pub/jcp/jdbc-4_2-mrel2-spec/jdbc4.2-fr-spec.pdf">JDBC Specification</a>
      * @see <a href="https://docs.oracle.com/javase/8/docs/api/java/sql/PreparedStatement.html">java.sql.PreparedStatement</a>
-     *  
-     * @param codec 
+     *
+     * @param codec
      *      a Codec that declares which database 'input' is being encoded for (ie. MySQL, Oracle, etc.)
-     * @param input 
+     * @param input
      *      the text to encode for SQL
-     * 
+     *
      * @return input encoded for use in SQL
      */
     String encodeForSQL(Codec codec, String input);
 
     /**
-     * Encode for an operating system command shell according to the selected codec (appropriate codecs include the WindowsCodec and UnixCodec). 
+     * Encode for an operating system command shell according to the selected codec (appropriate codecs include the WindowsCodec and UnixCodec).
+     *
+     * Please note the following recommendations before choosing to use this method:
      *
-     * Please note the following recommendations before choosing to use this method: 
-     * 
      * 1)      It is strongly recommended that applications avoid making direct OS system calls if possible as such calls are not portable, and they are potentially unsafe. Please use language provided features if at all possible, rather than native OS calls to implement the desired feature.
      * 2)      If an OS call cannot be avoided, then it is recommended that the program to be invoked be invoked directly (e.g., System.exec("nameofcommand" + "parameterstocommand");) as this avoids the use of the command shell. The "parameterstocommand" should of course be validated before passing them to the OS command.
      * 3)      If you must use this method, then we recommend validating all user supplied input passed to the command shell as well, in addition to using this method in order to make the command shell invocation safe.
-     *  
+     *
      * An example use of this method would be: System.exec("dir " + ESAPI.encodeForOS(WindowsCodec, "parameter(s)tocommandwithuserinput");
-     * 
-     * @param codec 
+     *
+     * @param codec
      *      a Codec that declares which operating system 'input' is being encoded for (ie. Windows, Unix, etc.)
-     * @param input 
+     * @param input
      *      the text to encode for the command shell
-     * 
+     *
      * @return input encoded for use in command shell
      */
     String encodeForOS(Codec codec, String input);
 
     /**
      * Encode data for use in LDAP queries. Wildcard (*) characters will be encoded.
-     * 
-     * @param input 
+     *
+     * @param input
      *      the text to encode for LDAP
-     * 
+     *
      * @return input encoded for use in LDAP
      */
     String encodeForLDAP(String input);
 
     /**
      * Encode data for use in LDAP queries. You have the option whether or not to encode wildcard (*) characters.
-     * 
-     * @param input 
+     *
+     * @param input
      *      the text to encode for LDAP
-     * @param encodeWildcards 
+     * @param encodeWildcards
      *      whether or not wildcard (*) characters will be encoded.
      *
      * @return input encoded for use in LDAP
      */
     String encodeForLDAP(String input, boolean encodeWildcards);
-     
+
     /**
      * Encode data for use in an LDAP distinguished name.
-     * 
-     *  @param input 
+     *
+     *  @param input
      *          the text to encode for an LDAP distinguished name
-     * 
+     *
      *  @return input encoded for use in an LDAP distinguished name
      */
     String encodeForDN(String input);
 
     /**
      * Encode data for use in an XPath query.
-     * 
-     * NB: The reference implementation encodes almost everything and may over-encode. 
-     * 
+     *
+     * NB: The reference implementation encodes almost everything and may over-encode.
+     *
      * The difficulty with XPath encoding is that XPath has no built in mechanism for escaping
      * characters. It is possible to use XQuery in a parameterized way to
-     * prevent injection. 
-     * 
+     * prevent injection.
+     *
      * For more information, refer to <a
      * href="http://www.ibm.com/developerworks/xml/library/x-xpathinjection.html">this
      * article</a> which specifies the following list of characters as the most
      * dangerous: ^&"*';<>(). <a
      * href="http://www.packetstormsecurity.org/papers/bypass/Blind_XPath_Injection_20040518.pdf">This
      * paper</a> suggests disallowing ' and " in queries.
-     * 
+     *
      * @see <a href="http://www.ibm.com/developerworks/xml/library/x-xpathinjection.html">XPath Injection [ibm.com]</a>
      * @see <a href="http://www.packetstormsecurity.org/papers/bypass/Blind_XPath_Injection_20040518.pdf">Blind XPath Injection [packetstormsecurity.org]</a>
-     *  
+     *
      * @param input
      *      the text to encode for XPath
-     * @return 
+     * @return
      *      input encoded for use in XPath
      */
     String encodeForXPath(String input);
@@ -472,12 +508,12 @@ public interface Encoder {
      * hopefully rare case that you need to make sure that data is safe for
      * inclusion in an XML document and cannot use a parser, this method provides
      * a safe mechanism to do so.
-     * 
+     *
      * @see <a href="https://www.w3.org/TR/REC-xml/#charencoding">Character Encoding in Entities</a>
-     * 
+     *
      * @param input
      *          the text to encode for XML
-     * 
+     *
      * @return
      *          input encoded for use in XML
      */
@@ -492,13 +528,13 @@ public interface Encoder {
      * hopefully rare case that you need to make sure that data is safe for
      * inclusion in an XML document and cannot use a parse, this method provides
      * a safe mechanism to do so.
-     * 
+     *
      * @see <a href="https://www.w3.org/TR/REC-xml/#charencoding">Character Encoding in Entities</a>
-     * 
+     *
      * @param input
      *          the text to encode for use as an XML attribute
-     * 
-     * @return 
+     *
+     * @return
      *          input encoded for use in an XML attribute
      */
     String encodeForXMLAttribute(String input);
@@ -507,69 +543,100 @@ public interface Encoder {
      * Encode for use in a URL. This method performs <a
      * href="http://en.wikipedia.org/wiki/Percent-encoding">URL encoding</a>
      * on the entire string.
-     * 
+     *
      * @see <a href="http://en.wikipedia.org/wiki/Percent-encoding">URL encoding</a>
-     * 
-     * @param input 
+     *
+     * @param input
      *      the text to encode for use in a URL
-     * 
-     * @return input 
+     *
+     * @return input
      *      encoded for use in a URL
-     * 
-     * @throws EncodingException 
+     *
+     * @throws EncodingException
      *      if encoding fails
      */
     String encodeForURL(String input) throws EncodingException;
 
+    /**
+     * Encode data for use in JSON strings. This method performs <a
+     * href="https://datatracker.ietf.org/doc/html/rfc8259#section-7">String escaping</a>
+     * on the entire string according to RFC 8259, Section 7.
+     *
+     * @see <a href="https://datatracker.ietf.org/doc/html/rfc8259#section-7">RFC 8259,
+     * The JavaScript Object Notation (JSON) Data Interchange Format, Section 7</a>
+     *
+     * @param input
+     *      the text to escape for JSON string
+     *
+     * @return input
+     *      escaped for use in JSON string
+     */
+    String encodeForJSON(String input);
+
     /**
      * Decode from URL. Implementations should first canonicalize and
      * detect any double-encoding. If this check passes, then the data is decoded using URL
      * decoding.
-     * 
-     * @param input 
+     *
+     * @param input
      *      the text to decode from an encoded URL
-     * 
-     * @return 
+     *
+     * @return
      *      the decoded URL value
-     * 
-     * @throws EncodingException 
+     *
+     * @throws EncodingException
      *      if decoding fails
      */
     String decodeFromURL(String input) throws EncodingException;
 
     /**
      * Encode for Base64.
-     * 
-     * @param input 
+     *
+     * @param input
      *      the text to encode for Base64
      * @param wrap
      *      the encoder will wrap lines every 64 characters of output
-     * 
+     *
      * @return input encoded for Base64
      */
     String encodeForBase64(byte[] input, boolean wrap);
 
     /**
      * Decode data encoded with BASE-64 encoding.
-     * 
-     * @param input 
+     *
+     * @param input
      *      the Base64 text to decode
-     * 
+     *
      * @return input decoded from Base64
-     * 
+     *
      * @throws IOException
      */
     byte[] decodeFromBase64(String input) throws IOException;
 
     /**
-     * Get a version of the input URI that will be safe to run regex and other validations against.  
-     * It is not recommended to persist this value as it will transform user input.  This method 
+     * Get a version of the input URI that will be safe to run regex and other validations against.
+     * It is not recommended to persist this value as it will transform user input.  This method
      * will not test to see if the URI is RFC-3986 compliant.
-     * 
+     *
      * @param dirtyUri
      *      the tainted URI
      * @return The canonicalized URI
      */
     String getCanonicalizedURI(URI dirtyUri);
 
+    /**
+     * Decode data encoded for JSON strings. This method removes <a
+     * href="https://datatracker.ietf.org/doc/html/rfc8259#section-7">String escaping</a>
+     * on the entire string according to RFC 8259, Section 7.
+     *
+     * @see <a href="https://datatracker.ietf.org/doc/html/rfc8259#section-7">RFC 8259,
+     * The JavaScript Object Notation (JSON) Data Interchange Format, Section 7</a>
+     *
+     * @param input
+     *      the JSON string to decode
+     *
+     * @return input
+     *      decoded from JSON string
+     */
+    String decodeFromJSON(String input);
 }
diff --git a/src/main/java/org/owasp/esapi/EncoderConstants.java b/src/main/java/org/owasp/esapi/EncoderConstants.java
index 1498d5e..ec2cbfa 100644
--- a/src/main/java/org/owasp/esapi/EncoderConstants.java
+++ b/src/main/java/org/owasp/esapi/EncoderConstants.java
@@ -11,107 +11,107 @@ import org.owasp.esapi.util.CollectionsUtil;
  * @see User
  */
 public class EncoderConstants {
-	/**
-	 * !$*-.=?@_
-	 */
-	public final static char[] CHAR_PASSWORD_SPECIALS = { '!', '$', '*', '-', '.', '=', '?', '@', '_' };
-	public final static Set<Character> PASSWORD_SPECIALS;
-	static {
-		PASSWORD_SPECIALS = CollectionsUtil.arrayToSet(CHAR_PASSWORD_SPECIALS);
-	}
-	
-	/**
-	 * a-b
-	 */
-	public final static char[] CHAR_LOWERS = { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z' };
-	public final static Set<Character> LOWERS;
-	static {
-		LOWERS = CollectionsUtil.arrayToSet(CHAR_PASSWORD_SPECIALS);
-	}
-	
-	/**
-	 * A-Z
-	 */
-	public final static char[] CHAR_UPPERS = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z' };
-	public final static Set<Character> UPPERS;
-	static {
-		UPPERS = CollectionsUtil.arrayToSet(CHAR_UPPERS);
-	}
-	/**
-	 * 0-9
-	 */
-	public final static char[] CHAR_DIGITS = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' };
-	public final static Set<Character> DIGITS;
-	static {
-		DIGITS = CollectionsUtil.arrayToSet(CHAR_DIGITS);
-	}
-	
-	/**
-	 * !$*+-.=?@^_|~
-	 */
-	public final static char[] CHAR_SPECIALS = { '!', '$', '*', '+', '-', '.', '=', '?', '@', '^', '_', '|', '~' };
-	public final static Set<Character> SPECIALS;
-	static {
-		SPECIALS = CollectionsUtil.arrayToSet(CHAR_SPECIALS);
-	}
-	
-	/**
-	 * CHAR_LOWERS union CHAR_UPPERS
-	 */
-	public final static char[] CHAR_LETTERS = StringUtilities.union(CHAR_LOWERS, CHAR_UPPERS);
-	public final static Set<Character> LETTERS;
-	static {
-		LETTERS = CollectionsUtil.arrayToSet(CHAR_LETTERS);
-	}
-	
-	/**
-	 * CHAR_LETTERS union CHAR_DIGITS
-	 */
-	public final static char[] CHAR_ALPHANUMERICS = StringUtilities.union(CHAR_LETTERS, CHAR_DIGITS);
-	public final static Set<Character> ALPHANUMERICS;
-	static {
-		ALPHANUMERICS = CollectionsUtil.arrayToSet(CHAR_ALPHANUMERICS);
-	}
-	
-	/**
-	 * Password character set, is alphanumerics (without l, i, I, o, O, and 0)
-	 * selected specials like + (bad for URL encoding, | is like i and 1,
-	 * etc...)
-	 */
-	public final static char[] CHAR_PASSWORD_LOWERS = { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'j', 'k', 'm', 'n', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z' };
-	public final static Set<Character> PASSWORD_LOWERS;
-	static {
-		PASSWORD_LOWERS = CollectionsUtil.arrayToSet(CHAR_ALPHANUMERICS);
-	}
-	
-	/**
-	 * 
-	 */
-	public final static char[] CHAR_PASSWORD_UPPERS = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'J', 'K', 'L', 'M', 'N', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z' };
-	public final static Set<Character> PASSWORD_UPPERS;
-	static {
-		PASSWORD_UPPERS = CollectionsUtil.arrayToSet(CHAR_PASSWORD_UPPERS);
-	}
-	
-	/**
-	 * 2-9
-	 */
-	public final static char[] CHAR_PASSWORD_DIGITS = { '2', '3', '4', '5', '6', '7', '8', '9' };
-	public final static Set<Character> PASSWORD_DIGITS;
-	static {
-		PASSWORD_DIGITS = CollectionsUtil.arrayToSet(CHAR_PASSWORD_DIGITS);
-	}
-	
-	/**
-	 * CHAR_PASSWORD_LOWERS union CHAR_PASSWORD_UPPERS
-	 */
-	public final static char[] CHAR_PASSWORD_LETTERS = StringUtilities.union( CHAR_PASSWORD_LOWERS, CHAR_PASSWORD_UPPERS );
-	public final static Set<Character> PASSWORD_LETTERS;
-	static {
-		PASSWORD_LETTERS = CollectionsUtil.arrayToSet(CHAR_PASSWORD_LETTERS);
-	}
+    /**
+     * !$*-.=?@_
+     */
+    public final static char[] CHAR_PASSWORD_SPECIALS = { '!', '$', '*', '-', '.', '=', '?', '@', '_' };
+    public final static Set<Character> PASSWORD_SPECIALS;
+    static {
+        PASSWORD_SPECIALS = CollectionsUtil.arrayToSet(CHAR_PASSWORD_SPECIALS);
+    }
 
-	private EncoderConstants() {
-		// prevent instantiation
-	}
+    /**
+     * a-b
+     */
+    public final static char[] CHAR_LOWERS = { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z' };
+    public final static Set<Character> LOWERS;
+    static {
+        LOWERS = CollectionsUtil.arrayToSet(CHAR_PASSWORD_SPECIALS);
+    }
+
+    /**
+     * A-Z
+     */
+    public final static char[] CHAR_UPPERS = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z' };
+    public final static Set<Character> UPPERS;
+    static {
+        UPPERS = CollectionsUtil.arrayToSet(CHAR_UPPERS);
+    }
+    /**
+     * 0-9
+     */
+    public final static char[] CHAR_DIGITS = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' };
+    public final static Set<Character> DIGITS;
+    static {
+        DIGITS = CollectionsUtil.arrayToSet(CHAR_DIGITS);
+    }
+
+    /**
+     * !$*+-.=?@^_|~
+     */
+    public final static char[] CHAR_SPECIALS = { '!', '$', '*', '+', '-', '.', '=', '?', '@', '^', '_', '|', '~' };
+    public final static Set<Character> SPECIALS;
+    static {
+        SPECIALS = CollectionsUtil.arrayToSet(CHAR_SPECIALS);
+    }
+
+    /**
+     * CHAR_LOWERS union CHAR_UPPERS
+     */
+    public final static char[] CHAR_LETTERS = StringUtilities.union(CHAR_LOWERS, CHAR_UPPERS);
+    public final static Set<Character> LETTERS;
+    static {
+        LETTERS = CollectionsUtil.arrayToSet(CHAR_LETTERS);
+    }
+
+    /**
+     * CHAR_LETTERS union CHAR_DIGITS
+     */
+    public final static char[] CHAR_ALPHANUMERICS = StringUtilities.union(CHAR_LETTERS, CHAR_DIGITS);
+    public final static Set<Character> ALPHANUMERICS;
+    static {
+        ALPHANUMERICS = CollectionsUtil.arrayToSet(CHAR_ALPHANUMERICS);
+    }
+
+    /**
+     * Password character set, is alphanumerics (without l, i, I, o, O, and 0)
+     * selected specials like + (bad for URL encoding, | is like i and 1,
+     * etc...)
+     */
+    public final static char[] CHAR_PASSWORD_LOWERS = { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'j', 'k', 'm', 'n', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z' };
+    public final static Set<Character> PASSWORD_LOWERS;
+    static {
+        PASSWORD_LOWERS = CollectionsUtil.arrayToSet(CHAR_ALPHANUMERICS);
+    }
+
+    /**
+     *
+     */
+    public final static char[] CHAR_PASSWORD_UPPERS = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'J', 'K', 'L', 'M', 'N', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z' };
+    public final static Set<Character> PASSWORD_UPPERS;
+    static {
+        PASSWORD_UPPERS = CollectionsUtil.arrayToSet(CHAR_PASSWORD_UPPERS);
+    }
+
+    /**
+     * 2-9
+     */
+    public final static char[] CHAR_PASSWORD_DIGITS = { '2', '3', '4', '5', '6', '7', '8', '9' };
+    public final static Set<Character> PASSWORD_DIGITS;
+    static {
+        PASSWORD_DIGITS = CollectionsUtil.arrayToSet(CHAR_PASSWORD_DIGITS);
+    }
+
+    /**
+     * CHAR_PASSWORD_LOWERS union CHAR_PASSWORD_UPPERS
+     */
+    public final static char[] CHAR_PASSWORD_LETTERS = StringUtilities.union( CHAR_PASSWORD_LOWERS, CHAR_PASSWORD_UPPERS );
+    public final static Set<Character> PASSWORD_LETTERS;
+    static {
+        PASSWORD_LETTERS = CollectionsUtil.arrayToSet(CHAR_PASSWORD_LETTERS);
+    }
+
+    private EncoderConstants() {
+        // prevent instantiation
+    }
 }
diff --git a/src/main/java/org/owasp/esapi/EncryptedProperties.java b/src/main/java/org/owasp/esapi/EncryptedProperties.java
index 9e1a857..b1db531 100644
--- a/src/main/java/org/owasp/esapi/EncryptedProperties.java
+++ b/src/main/java/org/owasp/esapi/EncryptedProperties.java
@@ -1,15 +1,15 @@
 /**
  * OWASP Enterprise Security API (ESAPI)
- * 
+ *
  * This file is part of the Open Web Application Security Project (OWASP)
  * Enterprise Security API (ESAPI) project. For details, please see
  * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
  *
  * Copyright (c) 2007-2019 - The OWASP Foundation
- * 
+ *
  * The ESAPI is published by OWASP under the BSD license. You should read and accept the
  * LICENSE before you use, modify, and/or redistribute this software.
- * 
+ *
  * @author Jeff Williams <a href="http://www.aspectsecurity.com">Aspect Security</a>
  * @created 2007
  */
@@ -38,75 +38,75 @@ import org.owasp.esapi.errors.EncryptionException;
  */
 public interface EncryptedProperties {
 
-	/**
-	 * Gets the property value from the encrypted store, decrypts it, and
-	 * returns the plaintext value to the caller.
-	 * 
-	 * @param key
-	 *      the name of the property to get 
-	 * 
-	 * @return 
-	 * 	The decrypted property value. null if the key is not set.
-	 * 
-	 * @throws EncryptionException
-	 *      if the property could not be decrypted
-	 */
-	String getProperty(String key) throws EncryptionException;
+    /**
+     * Gets the property value from the encrypted store, decrypts it, and
+     * returns the plaintext value to the caller.
+     *
+     * @param key
+     *      the name of the property to get
+     *
+     * @return
+     *     The decrypted property value. null if the key is not set.
+     *
+     * @throws EncryptionException
+     *      if the property could not be decrypted
+     */
+    String getProperty(String key) throws EncryptionException;
+
+    /**
+     * Encrypts the plaintext property value and stores the ciphertext value
+     * in the encrypted store.
+     *
+     * @param key
+     *      the name of the property to set
+     * @param value
+     *         the value of the property to set
+     *
+     * @return
+     *         the previously encrypted property value for the specified key, or
+     *      {@code null} if it did not have one.
+     *
+     * @throws EncryptionException
+     *      if the property could not be encrypted
+     */
+    String setProperty(String key, String value) throws EncryptionException;
+
+    /**
+     * Returns a {@code Set} view of properties. The {@code Set} is backed by a
+     * {@code java.util.Hashtable}, so changes to the {@code Hashtable} are
+     * reflected in the {@code Set}, and vice-versa. The {@code Set} supports element
+     * removal (which removes the corresponding entry from the {@code Hashtable},
+     * but not element addition.
+     *
+     * @return
+     *         a set view of the properties contained in this map.
+     */
+    Set<?> keySet();
+
+    /**
+     * Reads a property list (key and element pairs) from the input stream.
+     *
+     * @param in
+     *         the input stream that contains the properties file
+     *
+     * @throws IOException
+     *      Signals that an I/O exception has occurred.
+     */
+    void load(InputStream in) throws IOException;
+
+    /**
+     * Writes this property list (key and element pairs) in this Properties table to
+     * the output stream in a format suitable for loading into a Properties table using the load method.
+     *
+     * @param out
+     *         the output stream that contains the properties file
+     * @param comments
+     *            a description of the property list (ex. "Encrypted Properties File").
+     *
+     * @throws IOException
+     *             Signals that an I/O exception has occurred.
+     */
+    void store(OutputStream out, String comments) throws IOException;
+
 
-	/**
-	 * Encrypts the plaintext property value and stores the ciphertext value
-	 * in the encrypted store.
-	 * 
-	 * @param key
-	 *      the name of the property to set
-	 * @param value
-	 * 		the value of the property to set
-	 * 
-	 * @return 
-	 * 		the previously encrypted property value for the specified key, or
-	 *      {@code null} if it did not have one.
-	 * 
-	 * @throws EncryptionException
-	 *      if the property could not be encrypted
-	 */
-	String setProperty(String key, String value) throws EncryptionException;
-	
-	/**
-	 * Returns a {@code Set} view of properties. The {@code Set} is backed by a
-	 * {@code java.util.Hashtable}, so changes to the {@code Hashtable} are
-	 * reflected in the {@code Set}, and vice-versa. The {@code Set} supports element 
-	 * removal (which removes the corresponding entry from the {@code Hashtable},
-	 * but not element addition.
-	 * 
-	 * @return 
-	 * 		a set view of the properties contained in this map.
-	 */
-	Set<?> keySet();
-		
-	/**
-	 * Reads a property list (key and element pairs) from the input stream.
-	 * 
-	 * @param in
-	 * 		the input stream that contains the properties file
-	 * 
-	 * @throws IOException
-	 *      Signals that an I/O exception has occurred.
-	 */
-	void load(InputStream in) throws IOException;
-	
-	/**
-	 * Writes this property list (key and element pairs) in this Properties table to 
-	 * the output stream in a format suitable for loading into a Properties table using the load method. 
-	 * 
-	 * @param out
-	 * 		the output stream that contains the properties file
-	 * @param comments
-	 *            a description of the property list (ex. "Encrypted Properties File").
-	 * 
-	 * @throws IOException
-	 *             Signals that an I/O exception has occurred.
-	 */
-	void store(OutputStream out, String comments) throws IOException;	
-	
-	
 }
diff --git a/src/main/java/org/owasp/esapi/Encryptor.java b/src/main/java/org/owasp/esapi/Encryptor.java
index 6c83fef..28bb896 100644
--- a/src/main/java/org/owasp/esapi/Encryptor.java
+++ b/src/main/java/org/owasp/esapi/Encryptor.java
@@ -1,15 +1,15 @@
 /**
  * OWASP Enterprise Security API (ESAPI)
- * 
+ *
  * This file is part of the Open Web Application Security Project (OWASP)
  * Enterprise Security API (ESAPI) project. For details, please see
  * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
  *
  * Copyright &copy; 2007-2019 - The OWASP Foundation
- * 
+ *
  * The ESAPI is published by OWASP under the BSD license. You should read and accept the
  * LICENSE before you use, modify, and/or redistribute this software.
- * 
+ *
  * @author Jeff Williams <a href="http://www.aspectsecurity.com">Aspect Security</a>
  * @author kevin.w.wall@gmail.com
  * @created 2007
@@ -49,7 +49,7 @@ import org.owasp.esapi.errors.IntegrityException;
  * section 4 of
  * <a href="http://owasp-esapi-java.googlecode.com/svn/trunk/documentation/esapi4java-core-2.0-crypto-design-goals.doc">
  * Design Goals in OWASP ESAPI Cryptography</a>.
- * 
+ *
  * @author Jeff Williams (jeff.williams .at. aspectsecurity.com) <a
  *         href="http://www.aspectsecurity.com">Aspect Security</a>
  * @since June 1, 2007
@@ -57,177 +57,177 @@ import org.owasp.esapi.errors.IntegrityException;
  */
 public interface Encryptor {
 
-	/**
-	 * Returns a string representation of the hash of the provided plaintext and
-	 * salt. The salt helps to protect against a rainbow table attack by mixing
-	 * in some extra data with the plaintext. Some good choices for a salt might
-	 * be an account name or some other string that is known to the application
-	 * but not to an attacker.
-	 * See <a href="http://www.matasano.com/log/958/enough-with-the-rainbow-tables-what-you-need-to-know-about-secure-password-schemes/">
-	 * this article</a> for more information about hashing as it pertains to password schemes.
-	 * 
-	 * @param plaintext
-	 * 		the plaintext String to encrypt
-	 * @param salt
-	 *      the salt to add to the plaintext String before hashing
-	 * 
-	 * @return 
-	 * 		the encrypted hash of 'plaintext' stored as a String
-	 * 
-	 * @throws EncryptionException
-	 *      if the specified hash algorithm could not be found or another problem exists with 
-	 *      the hashing of 'plaintext'
-	 */
-	String hash(String plaintext, String salt) throws EncryptionException;
+    /**
+     * Returns a string representation of the hash of the provided plaintext and
+     * salt. The salt helps to protect against a rainbow table attack by mixing
+     * in some extra data with the plaintext. Some good choices for a salt might
+     * be an account name or some other string that is known to the application
+     * but not to an attacker.
+     * See <a href="http://www.matasano.com/log/958/enough-with-the-rainbow-tables-what-you-need-to-know-about-secure-password-schemes/">
+     * this article</a> for more information about hashing as it pertains to password schemes.
+     *
+     * @param plaintext
+     *         the plaintext String to encrypt
+     * @param salt
+     *      the salt to add to the plaintext String before hashing
+     *
+     * @return
+     *         the encrypted hash of 'plaintext' stored as a String
+     *
+     * @throws EncryptionException
+     *      if the specified hash algorithm could not be found or another problem exists with
+     *      the hashing of 'plaintext'
+     */
+    String hash(String plaintext, String salt) throws EncryptionException;
 
-	/**
-	 * Returns a string representation of the hash of the provided plaintext and
-	 * salt. The salt helps to protect against a rainbow table attack by mixing
-	 * in some extra data with the plaintext. Some good choices for a salt might
-	 * be an account name or some other string that is known to the application
-	 * but not to an attacker. 
-	 * See <a href="http://www.matasano.com/log/958/enough-with-the-rainbow-tables-what-you-need-to-know-about-secure-password-schemes/">
-	 * this article</a> for more information about hashing as it pertains to password schemes.
-	 * 
-	 * @param plaintext
-	 * 		the plaintext String to encrypt
-	 * @param salt
-	 *      the salt to add to the plaintext String before hashing
-	 * @param iterations
-	 *      the number of times to iterate the hash
-	 * 
-	 * @return 
-	 * 		the encrypted hash of 'plaintext' stored as a String
-	 * 
-	 * @throws EncryptionException
-	 *      if the specified hash algorithm could not be found or another problem exists with 
-	 *      the hashing of 'plaintext'
-	 */
-	String hash(String plaintext, String salt, int iterations) throws EncryptionException;
-	
-	/**
-	 * Encrypts the provided plaintext bytes using the cipher transformation
-	 * specified by the property <code>Encryptor.CipherTransformation</code>
-	 * and the <i>master encryption key</i> as specified by the property
-	 * {@code Encryptor.MasterKey} as defined in the <code>ESAPI.properties</code> file.
-	 * </p>
-	 * 
-	 * @param plaintext	The {@code PlainText} to be encrypted.
-	 * @return the {@code CipherText} object from which the raw ciphertext, the
-	 * 				IV, the cipher transformation, and many other aspects about
-	 * 				the encryption detail may be extracted.
-	 * @throws EncryptionException Thrown if something should go wrong such as
-	 * 				the JCE provider cannot be found, the cipher algorithm,
-	 * 				cipher mode, or padding scheme not being supported, specifying
-	 * 				an unsupported key size, specifying an IV of incorrect length,
-	 * 				etc.
-	 * @see #encrypt(SecretKey, PlainText)
-	 * @since 2.0
-	 */
-	 CipherText encrypt(PlainText plaintext) throws EncryptionException;
+    /**
+     * Returns a string representation of the hash of the provided plaintext and
+     * salt. The salt helps to protect against a rainbow table attack by mixing
+     * in some extra data with the plaintext. Some good choices for a salt might
+     * be an account name or some other string that is known to the application
+     * but not to an attacker.
+     * See <a href="http://www.matasano.com/log/958/enough-with-the-rainbow-tables-what-you-need-to-know-about-secure-password-schemes/">
+     * this article</a> for more information about hashing as it pertains to password schemes.
+     *
+     * @param plaintext
+     *         the plaintext String to encrypt
+     * @param salt
+     *      the salt to add to the plaintext String before hashing
+     * @param iterations
+     *      the number of times to iterate the hash
+     *
+     * @return
+     *         the encrypted hash of 'plaintext' stored as a String
+     *
+     * @throws EncryptionException
+     *      if the specified hash algorithm could not be found or another problem exists with
+     *      the hashing of 'plaintext'
+     */
+    String hash(String plaintext, String salt, int iterations) throws EncryptionException;
 
+    /**
+     * Encrypts the provided plaintext bytes using the cipher transformation
+     * specified by the property <code>Encryptor.CipherTransformation</code>
+     * and the <i>master encryption key</i> as specified by the property
+     * {@code Encryptor.MasterKey} as defined in the <code>ESAPI.properties</code> file.
+     * </p>
+     *
+     * @param plaintext    The {@code PlainText} to be encrypted.
+     * @return the {@code CipherText} object from which the raw ciphertext, the
+     *                 IV, the cipher transformation, and many other aspects about
+     *                 the encryption detail may be extracted.
+     * @throws EncryptionException Thrown if something should go wrong such as
+     *                 the JCE provider cannot be found, the cipher algorithm,
+     *                 cipher mode, or padding scheme not being supported, specifying
+     *                 an unsupported key size, specifying an IV of incorrect length,
+     *                 etc.
+     * @see #encrypt(SecretKey, PlainText)
+     * @since 2.0
+     */
+     CipherText encrypt(PlainText plaintext) throws EncryptionException;
 
-	 /**
-	  * Encrypts the provided plaintext bytes using the cipher transformation
-	  * specified by the property <code>Encryptor.CipherTransformation</code>
-	  * as defined in the <code>ESAPI.properties</code> file and the
-	  * <i>specified secret key</i>.
-	  * </p><p>
-	  * This method is similar to {@link #encrypt(PlainText)} except that it
-	  * permits a specific {@code SecretKey} to be used for encryption.
-	  *
-	  * @param key		The {@code SecretKey} to use for encrypting the plaintext.
-	  * @param plaintext	The byte stream to be encrypted. Note if a Java
-	  * 				{@code String} is to be encrypted, it should be converted
-	  * 				using {@code "some string".getBytes("UTF-8")}.
-	  * @return the {@code CipherText} object from which the raw ciphertext, the
-	  * 				IV, the cipher transformation, and many other aspects about
-	  * 				the encryption detail may be extracted.
-	  * @throws EncryptionException Thrown if something should go wrong such as
-	  * 				the JCE provider cannot be found, the cipher algorithm,
-	  * 				cipher mode, or padding scheme not being supported, specifying
-	  * 				an unsupported key size, specifying an IV of incorrect length,
-	  * 				etc.
-	  * @see #encrypt(PlainText)
-	  * @since 2.0
-	  */
-	 CipherText encrypt(SecretKey key, PlainText plaintext)
-	 		throws EncryptionException;
 
-	/**
-	 * Decrypts the provided {@link CipherText} using the information from it
-	 * and the <i>master encryption key</i> as specified by the property
-	 * {@code Encryptor.MasterKey} as defined in the {@code ESAPI.properties}
-	 * file.
-	 * </p>
-	 * @param ciphertext The {@code CipherText} object to be decrypted.
-	 * @return The {@code PlainText} object resulting from decrypting the specified
-	 * 		   ciphertext. Note that it it is desired to convert the returned
-	 * 		   plaintext byte array to a Java String is should be done using
-	 * 		   {@code new String(byte[], "UTF-8");} rather than simply using
-	 * 		   {@code new String(byte[]);} which uses native encoding and may
-	 * 		   not be portable across hardware and/or OS platforms.
-	 * @throws EncryptionException  Thrown if something should go wrong such as
-	 * 				the JCE provider cannot be found, the cipher algorithm,
-	 * 				cipher mode, or padding scheme not being supported, specifying
-	 * 				an unsupported key size, or incorrect encryption key was
-	 * 				specified or a {@code PaddingException} occurs.
-	 * @see #decrypt(SecretKey, CipherText)
-	 */
-	PlainText decrypt(CipherText ciphertext) throws EncryptionException;
-	
-	/**
-	 * Decrypts the provided {@link CipherText} using the information from it
-	 * and the <i>specified secret key</i>.
-	 * </p><p>
-	 * This decrypt method is similar to {@link #decrypt(CipherText)} except that
-	 * it allows decrypting with a secret key other than the <i>master secret key</i>.
-	 * </p>
-	 * @param key		The {@code SecretKey} to use for encrypting the plaintext.
-	 * @param ciphertext The {@code CipherText} object to be decrypted.
-	 * @return The {@code PlainText} object resulting from decrypting the specified
-	 * 		   ciphertext. Note that it it is desired to convert the returned
-	 * 		   plaintext byte array to a Java String is should be done using
-	 * 		   {@code new String(byte[], "UTF-8");} rather than simply using
-	 * 		   {@code new String(byte[]);} which uses native encoding and may
-	 * 		   not be portable across hardware and/or OS platforms.
-	 * @throws EncryptionException  Thrown if something should go wrong such as
-	 * 				the JCE provider cannot be found, the cipher algorithm,
-	 * 				cipher mode, or padding scheme not being supported, specifying
-	 * 				an unsupported key size, or incorrect encryption key was
-	 * 				specified or a {@code PaddingException} occurs.
-	 * @see #decrypt(CipherText)
-	 */
-	PlainText decrypt(SecretKey key, CipherText ciphertext) throws EncryptionException;
-	
-	/**
-	 * Create a digital signature for the provided data and return it in a
-	 * string.
-	 * <p>
-	 * <b>Limitations:</b> A new public/private key pair used for ESAPI 2.0 digital
-	 * signatures with this method and {@link #verifySignature(String, String)}
-	 * are dynamically created when the default reference implementation class,
-	 * {@link org.owasp.esapi.reference.crypto.JavaEncryptor} is first created.
-	 * Because this key pair is not persisted nor is the public key shared,
-	 * this method and the corresponding {@link #verifySignature(String, String)}
-	 * can not be used with expected results across JVM instances. This limitation
-	 * will be addressed in ESAPI 2.1.
-	 * </p>
-	 * 
-	 * @param data
-	 *      the data to sign
-	 * 
-	 * @return 
-	 * 		the digital signature stored as a String
-	 * 
-	 * @throws EncryptionException
-	 * 		if the specified signature algorithm cannot be found
-	 */
-	String sign(String data) throws EncryptionException;
+     /**
+      * Encrypts the provided plaintext bytes using the cipher transformation
+      * specified by the property <code>Encryptor.CipherTransformation</code>
+      * as defined in the <code>ESAPI.properties</code> file and the
+      * <i>specified secret key</i>.
+      * </p><p>
+      * This method is similar to {@link #encrypt(PlainText)} except that it
+      * permits a specific {@code SecretKey} to be used for encryption.
+      *
+      * @param key        The {@code SecretKey} to use for encrypting the plaintext.
+      * @param plaintext    The byte stream to be encrypted. Note if a Java
+      *                 {@code String} is to be encrypted, it should be converted
+      *                 using {@code "some string".getBytes("UTF-8")}.
+      * @return the {@code CipherText} object from which the raw ciphertext, the
+      *                 IV, the cipher transformation, and many other aspects about
+      *                 the encryption detail may be extracted.
+      * @throws EncryptionException Thrown if something should go wrong such as
+      *                 the JCE provider cannot be found, the cipher algorithm,
+      *                 cipher mode, or padding scheme not being supported, specifying
+      *                 an unsupported key size, specifying an IV of incorrect length,
+      *                 etc.
+      * @see #encrypt(PlainText)
+      * @since 2.0
+      */
+     CipherText encrypt(SecretKey key, PlainText plaintext)
+             throws EncryptionException;
 
-	/**
-	 * Verifies a digital signature (created with the sign method) and returns
-	 * the boolean result.
+    /**
+     * Decrypts the provided {@link CipherText} using the information from it
+     * and the <i>master encryption key</i> as specified by the property
+     * {@code Encryptor.MasterKey} as defined in the {@code ESAPI.properties}
+     * file.
+     * </p>
+     * @param ciphertext The {@code CipherText} object to be decrypted.
+     * @return The {@code PlainText} object resulting from decrypting the specified
+     *            ciphertext. Note that it it is desired to convert the returned
+     *            plaintext byte array to a Java String is should be done using
+     *            {@code new String(byte[], "UTF-8");} rather than simply using
+     *            {@code new String(byte[]);} which uses native encoding and may
+     *            not be portable across hardware and/or OS platforms.
+     * @throws EncryptionException  Thrown if something should go wrong such as
+     *                 the JCE provider cannot be found, the cipher algorithm,
+     *                 cipher mode, or padding scheme not being supported, specifying
+     *                 an unsupported key size, or incorrect encryption key was
+     *                 specified or a {@code PaddingException} occurs.
+     * @see #decrypt(SecretKey, CipherText)
+     */
+    PlainText decrypt(CipherText ciphertext) throws EncryptionException;
+
+    /**
+     * Decrypts the provided {@link CipherText} using the information from it
+     * and the <i>specified secret key</i>.
+     * </p><p>
+     * This decrypt method is similar to {@link #decrypt(CipherText)} except that
+     * it allows decrypting with a secret key other than the <i>master secret key</i>.
+     * </p>
+     * @param key        The {@code SecretKey} to use for encrypting the plaintext.
+     * @param ciphertext The {@code CipherText} object to be decrypted.
+     * @return The {@code PlainText} object resulting from decrypting the specified
+     *            ciphertext. Note that it it is desired to convert the returned
+     *            plaintext byte array to a Java String is should be done using
+     *            {@code new String(byte[], "UTF-8");} rather than simply using
+     *            {@code new String(byte[]);} which uses native encoding and may
+     *            not be portable across hardware and/or OS platforms.
+     * @throws EncryptionException  Thrown if something should go wrong such as
+     *                 the JCE provider cannot be found, the cipher algorithm,
+     *                 cipher mode, or padding scheme not being supported, specifying
+     *                 an unsupported key size, or incorrect encryption key was
+     *                 specified or a {@code PaddingException} occurs.
+     * @see #decrypt(CipherText)
+     */
+    PlainText decrypt(SecretKey key, CipherText ciphertext) throws EncryptionException;
+
+    /**
+     * Create a digital signature for the provided data and return it in a
+     * string.
+     * <p>
+     * <b>Limitations:</b> A new public/private key pair used for ESAPI 2.0 digital
+     * signatures with this method and {@link #verifySignature(String, String)}
+     * are dynamically created when the default reference implementation class,
+     * {@link org.owasp.esapi.reference.crypto.JavaEncryptor} is first created.
+     * Because this key pair is not persisted nor is the public key shared,
+     * this method and the corresponding {@link #verifySignature(String, String)}
+     * can not be used with expected results across JVM instances. This limitation
+     * will be addressed in ESAPI 2.1.
+     * </p>
+     *
+     * @param data
+     *      the data to sign
+     *
+     * @return
+     *         the digital signature stored as a String
+     *
+     * @throws EncryptionException
+     *         if the specified signature algorithm cannot be found
+     */
+    String sign(String data) throws EncryptionException;
+
+    /**
+     * Verifies a digital signature (created with the sign method) and returns
+     * the boolean result.
      * <p>
      * <b>Limitations:</b> A new public/private key pair used for ESAPI 2.0 digital
      * signatures with this method and {@link #sign(String)}
@@ -238,79 +238,79 @@ public interface Encryptor {
      * can not be used with expected results across JVM instances. This limitation
      * will be addressed in ESAPI 2.1.
      * </p>
-	 * @param signature
-	 *      the signature to verify against 'data'
-	 * @param data
-	 *      the data to verify against 'signature'
-	 * 
-	 * @return 
-	 * 		true, if the signature is verified, false otherwise
-	 */
-	boolean verifySignature(String signature, String data);
+     * @param signature
+     *      the signature to verify against 'data'
+     * @param data
+     *      the data to verify against 'signature'
+     *
+     * @return
+     *         true, if the signature is verified, false otherwise
+     */
+    boolean verifySignature(String signature, String data);
 
-	/**
-	 * Creates a seal that binds a set of data and includes an expiration timestamp.
-	 * 
-	 * @param data
-	 *      the data to seal
-	 * @param timestamp
-	 *      the absolute expiration date of the data, expressed as seconds since the epoch
-	 * 
-	 * @return 
-     * 		the seal
-	 * 
+    /**
+     * Creates a seal that binds a set of data and includes an expiration timestamp.
+     *
+     * @param data
+     *      the data to seal
+     * @param timestamp
+     *      the absolute expiration date of the data, expressed as seconds since the epoch
+     *
+     * @return
+     *         the seal
+     *
      * @throws IntegrityException
-	 */
-	String seal(String data, long timestamp) throws IntegrityException;
+     */
+    String seal(String data, long timestamp) throws IntegrityException;
+
+    /**
+     * Unseals data (created with the seal method) and throws an exception
+     * describing any of the various problems that could exist with a seal, such
+     * as an invalid seal format, expired timestamp, or decryption error.
+     *
+     * @param seal
+     *      the sealed data
+     *
+     * @return
+     *         the original (unsealed) data
+     *
+     * @throws EncryptionException
+     *         if the unsealed data cannot be retrieved for any reason
+     */
+    String unseal( String seal ) throws EncryptionException;
+
+    /**
+     * Verifies a seal (created with the seal method) and throws an exception
+     * describing any of the various problems that could exist with a seal, such
+     * as an invalid seal format, expired timestamp, or data mismatch.
+     *
+     * @param seal
+     *      the seal to verify
+     *
+     * @return
+     *         true, if the seal is valid.  False otherwise
+     */
+    boolean verifySeal(String seal);
+
+    /**
+     * Gets an absolute timestamp representing an offset from the current time to be used by
+     * other functions in the library.
+     *
+     * @param offset
+     *         the offset to add to the current time
+     *
+     * @return
+     *         the absolute timestamp
+     */
+    long getRelativeTimeStamp( long offset );
 
-	/**
-	 * Unseals data (created with the seal method) and throws an exception
-	 * describing any of the various problems that could exist with a seal, such
-	 * as an invalid seal format, expired timestamp, or decryption error.
-	 * 
-	 * @param seal
-	 *      the sealed data
-	 * 
-	 * @return 
-	 * 		the original (unsealed) data
-	 * 
-	 * @throws EncryptionException 
-	 * 		if the unsealed data cannot be retrieved for any reason
-	 */
-	String unseal( String seal ) throws EncryptionException;
-	
-	/**
-	 * Verifies a seal (created with the seal method) and throws an exception
-	 * describing any of the various problems that could exist with a seal, such
-	 * as an invalid seal format, expired timestamp, or data mismatch.
-	 * 
-	 * @param seal
-	 *      the seal to verify
-	 * 
-	 * @return 
-	 * 		true, if the seal is valid.  False otherwise
-	 */
-	boolean verifySeal(String seal);
-	
-	/**
-	 * Gets an absolute timestamp representing an offset from the current time to be used by
-	 * other functions in the library.
-	 * 
-	 * @param offset 
-	 * 		the offset to add to the current time
-	 * 
-	 * @return 
-	 * 		the absolute timestamp
-	 */
-	long getRelativeTimeStamp( long offset );
-	
-	/**
-	 * Gets a timestamp representing the current date and time to be used by
-	 * other functions in the library.
-	 * 
-	 * @return 
-	 * 		a timestamp representing the current time
-	 */
-	long getTimeStamp();
+    /**
+     * Gets a timestamp representing the current date and time to be used by
+     * other functions in the library.
+     *
+     * @return
+     *         a timestamp representing the current time
+     */
+    long getTimeStamp();
 
 }
\ No newline at end of file
diff --git a/src/main/java/org/owasp/esapi/ExecuteResult.java b/src/main/java/org/owasp/esapi/ExecuteResult.java
index e9835e3..6887b80 100644
--- a/src/main/java/org/owasp/esapi/ExecuteResult.java
+++ b/src/main/java/org/owasp/esapi/ExecuteResult.java
@@ -25,51 +25,51 @@ package org.owasp.esapi;
  * @since Aug 25, 2010
  */
 public class ExecuteResult {
-    
-	private final int exitValue;
-	private final String output;
-	private final String errors;
 
-	/**
-	 * Constructs an ExecuteResult from the given values.
-	 *
-	 * @param exitValue
-	 *            the code from java.lang.Process.exitValue()
-	 * @param output
-	 *            the contents read from java.lang.Process.getInputStream()
-	 * @param errors
-	 *            the contents read from java.lang.Process.getErrorStream()
-	 */
-	public ExecuteResult(int exitValue, String output, String errors) {
-		this.exitValue = exitValue;
-		this.output = output;
-		this.errors = errors;
-	}
+    private final int exitValue;
+    private final String output;
+    private final String errors;
 
-	/**
-	 * @return the code from java.lang.Process.exitValue()
-	 */
-	public int getExitValue() {
-		return exitValue;
-	}
+    /**
+     * Constructs an ExecuteResult from the given values.
+     *
+     * @param exitValue
+     *            the code from java.lang.Process.exitValue()
+     * @param output
+     *            the contents read from java.lang.Process.getInputStream()
+     * @param errors
+     *            the contents read from java.lang.Process.getErrorStream()
+     */
+    public ExecuteResult(int exitValue, String output, String errors) {
+        this.exitValue = exitValue;
+        this.output = output;
+        this.errors = errors;
+    }
 
-	/**
-	 * @return the contents read from java.lang.Process.getInputStream()
-	 */
-	public String getOutput() {
-		return output;
-	}
+    /**
+     * @return the code from java.lang.Process.exitValue()
+     */
+    public int getExitValue() {
+        return exitValue;
+    }
 
-	/**
-	 * @return the contents read from java.lang.Process.getErrorStream()
-	 */
-	public String getErrors() {
-		return errors;
-	}
-	
-	@Override
-	public String toString() {
-		return "ExecuteResult[exitValue="+exitValue+",output="+output+",errors="+errors+"]";
-	}
+    /**
+     * @return the contents read from java.lang.Process.getInputStream()
+     */
+    public String getOutput() {
+        return output;
+    }
+
+    /**
+     * @return the contents read from java.lang.Process.getErrorStream()
+     */
+    public String getErrors() {
+        return errors;
+    }
+
+    @Override
+    public String toString() {
+        return "ExecuteResult[exitValue="+exitValue+",output="+output+",errors="+errors+"]";
+    }
 
 }
diff --git a/src/main/java/org/owasp/esapi/Executor.java b/src/main/java/org/owasp/esapi/Executor.java
index b475da9..122dcdb 100644
--- a/src/main/java/org/owasp/esapi/Executor.java
+++ b/src/main/java/org/owasp/esapi/Executor.java
@@ -1,15 +1,15 @@
 /**
  * OWASP Enterprise Security API (ESAPI)
- * 
+ *
  * This file is part of the Open Web Application Security Project (OWASP)
  * Enterprise Security API (ESAPI) project. For details, please see
  * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
  *
  * Copyright (c) 2007 - The OWASP Foundation
- * 
+ *
  * The ESAPI is published by OWASP under the BSD license. You should read and accept the
  * LICENSE before you use, modify, and/or redistribute this software.
- * 
+ *
  * @author Jeff Williams <a href="http://www.aspectsecurity.com">Aspect Security</a>
  * @created 2007
  */
@@ -23,56 +23,56 @@ import org.owasp.esapi.errors.ExecutorException;
 
 /**
  * The Executor interface is used to run an OS command with reduced security risk.
- * 
+ *
  * <p>Implementations should do as much as possible to minimize the risk of
  * injection into either the command or parameters. In addition, implementations
  * should timeout after a specified time period in order to help prevent denial
- * of service attacks.</p> 
- * 
+ * of service attacks.</p>
+ *
  * <p>The class should perform logging and error handling as
  * well. Finally, implementation should handle errors and generate an
  * ExecutorException with all the necessary information.</p>
  *
  * <p>The reference implementation does all of the above.</p>
- * 
+ *
  * @author Jeff Williams (jeff.williams .at. aspectsecurity.com) <a
  *         href="http://www.aspectsecurity.com">Aspect Security</a>
  * @since June 1, 2007
  */
 public interface Executor {
 
-	/**
-	 * Invokes the specified executable with default workdir and codec and not logging parameters.
-	 * 
-	 * @param executable
-	 *            the command to execute
-	 * @param params
-	 *            the parameters of the command being executed
-	 */
-	ExecuteResult executeSystemCommand(File executable, List params) throws ExecutorException;
+    /**
+     * Invokes the specified executable with default workdir and codec and not logging parameters.
+     *
+     * @param executable
+     *            the command to execute
+     * @param params
+     *            the parameters of the command being executed
+     */
+    ExecuteResult executeSystemCommand(File executable, List params) throws ExecutorException;
 
-	/**
-	 * Executes a system command after checking that the executable exists and
-	 * escaping all the parameters to ensure that injection is impossible.
-	 * Implementations must change to the specified working
-	 * directory before invoking the command.
-	 *
-	 * @param executable
-	 *            the command to execute
-	 * @param params
-	 *            the parameters of the command being executed
-	 * @param workdir
-	 *            the working directory
-	 * @param codec
-	 *            the codec to use to encode for the particular OS in use
-	 * @param logParams
-	 *            use false if any parameters contains sensitive or confidential information
-	 *
-	 * @return the output of the command being run
-	 *
-	 * @throws ExecutorException
-	 *             the service exception
-	 */
-	ExecuteResult executeSystemCommand(File executable, List params, File workdir, Codec codec, boolean logParams, boolean redirectErrorStream) throws ExecutorException;
+    /**
+     * Executes a system command after checking that the executable exists and
+     * escaping all the parameters to ensure that injection is impossible.
+     * Implementations must change to the specified working
+     * directory before invoking the command.
+     *
+     * @param executable
+     *            the command to execute
+     * @param params
+     *            the parameters of the command being executed
+     * @param workdir
+     *            the working directory
+     * @param codec
+     *            the codec to use to encode for the particular OS in use
+     * @param logParams
+     *            use false if any parameters contains sensitive or confidential information
+     *
+     * @return the output of the command being run
+     *
+     * @throws ExecutorException
+     *             the service exception
+     */
+    ExecuteResult executeSystemCommand(File executable, List params, File workdir, Codec codec, boolean logParams, boolean redirectErrorStream) throws ExecutorException;
 
 }
diff --git a/src/main/java/org/owasp/esapi/HTTPUtilities.java b/src/main/java/org/owasp/esapi/HTTPUtilities.java
index c1b83f5..faa950d 100644
--- a/src/main/java/org/owasp/esapi/HTTPUtilities.java
+++ b/src/main/java/org/owasp/esapi/HTTPUtilities.java
@@ -36,27 +36,27 @@ import java.util.Map;
  */
 public interface HTTPUtilities
 {
-	// All implied static final as this is an interface
+    // All implied static final as this is an interface
     String REMEMBER_TOKEN_COOKIE_NAME = "rtoken";
     int MAX_COOKIE_LEN = 4096;            // From RFC 2109
-	int MAX_COOKIE_PAIRS = 20;			// From RFC 2109
-	String CSRF_TOKEN_NAME = "ctoken";
-	String ESAPI_STATE = "estate";
+    int MAX_COOKIE_PAIRS = 20;            // From RFC 2109
+    String CSRF_TOKEN_NAME = "ctoken";
+    String ESAPI_STATE = "estate";
 
-	int PARAMETER = 0;
-	int HEADER = 1;
-	int COOKIE = 2;
+    int PARAMETER = 0;
+    int HEADER = 1;
+    int COOKIE = 2;
 
-	/**
+    /**
      * Calls addCookie with the *current* request.
      *
      * @param cookie The cookie to add
-     * 
-	 * @see HTTPUtilities#setCurrentHTTP(HttpServletRequest, HttpServletResponse)
+     *
+     * @see HTTPUtilities#setCurrentHTTP(HttpServletRequest, HttpServletResponse)
      */
     void addCookie(Cookie cookie);
 
-	/**
+    /**
      * Add a cookie to the response after ensuring that there are no encoded or
      * illegal characters in the name and name and value. This method also sets
      * the secure and HttpOnly flags on the cookie.
@@ -66,7 +66,7 @@ public interface HTTPUtilities
      */
     void addCookie(HttpServletResponse response, Cookie cookie);
 
-	/**
+    /**
      * Adds the current user's CSRF token (see User.getCSRFToken()) to the URL for purposes of preventing CSRF attacks.
      * This method should be used on all URLs to be put into all links and forms the application generates.
      *
@@ -78,7 +78,7 @@ public interface HTTPUtilities
     /**
      * Calls addHeader with the *current* request.
      *
-	 * @see HTTPUtilities#setCurrentHTTP(HttpServletRequest, HttpServletResponse)
+     * @see HTTPUtilities#setCurrentHTTP(HttpServletRequest, HttpServletResponse)
      */
     void addHeader(String name, String value);
 
@@ -95,49 +95,49 @@ public interface HTTPUtilities
      */
     void addHeader(HttpServletResponse response, String name, String value);
 
-	/**
+    /**
      * Calls assertSecureRequest with the *current* request.
-	 * @see HTTPUtilities#assertSecureRequest(HttpServletRequest)
-	 * @see HTTPUtilities#setCurrentHTTP(HttpServletRequest, HttpServletResponse)
-	 */
-	void assertSecureRequest() throws AccessControlException;
+     * @see HTTPUtilities#assertSecureRequest(HttpServletRequest)
+     * @see HTTPUtilities#setCurrentHTTP(HttpServletRequest, HttpServletResponse)
+     */
+    void assertSecureRequest() throws AccessControlException;
 
-	/**
+    /**
      * Calls assertSecureChannel with the *current* request.
-	 * @see HTTPUtilities#assertSecureChannel(HttpServletRequest)
-	 * @see HTTPUtilities#setCurrentHTTP(HttpServletRequest, HttpServletResponse)
-	 */
-	void assertSecureChannel() throws AccessControlException;
+     * @see HTTPUtilities#assertSecureChannel(HttpServletRequest)
+     * @see HTTPUtilities#setCurrentHTTP(HttpServletRequest, HttpServletResponse)
+     */
+    void assertSecureChannel() throws AccessControlException;
 
-	/**
-	 * Ensures that the request uses both SSL and POST to protect any sensitive parameters
-	 * in the querystring from being sniffed, logged, bookmarked, included in referer header, etc...
-	 * This method should be called for any request that contains sensitive data from a web form.
+    /**
+     * Ensures that the request uses both SSL and POST to protect any sensitive parameters
+     * in the querystring from being sniffed, logged, bookmarked, included in referer header, etc...
+     * This method should be called for any request that contains sensitive data from a web form.
      *
      * @param request
      * @throws AccessControlException if security constraints are not met
-	 */
+     */
     void assertSecureRequest(HttpServletRequest request) throws AccessControlException;
 
-	/**
-	 * Ensures the use of SSL to protect any sensitive parameters in the request and
-	 * any sensitive data in the response. This method should be called for any request
-	 * that contains sensitive data from a web form or will result in sensitive data in the
-	 * response page.
+    /**
+     * Ensures the use of SSL to protect any sensitive parameters in the request and
+     * any sensitive data in the response. This method should be called for any request
+     * that contains sensitive data from a web form or will result in sensitive data in the
+     * response page.
      *
      * @param request
      * @throws AccessControlException if security constraints are not met
-	 */
+     */
     void assertSecureChannel(HttpServletRequest request) throws AccessControlException;
 
-	/**
+    /**
      * Calls changeSessionIdentifier with the *current* request.
      *
-	 * @see HTTPUtilities#setCurrentHTTP(HttpServletRequest, HttpServletResponse)
+     * @see HTTPUtilities#setCurrentHTTP(HttpServletRequest, HttpServletResponse)
      */
-	HttpSession changeSessionIdentifier() throws AuthenticationException;
+    HttpSession changeSessionIdentifier() throws AuthenticationException;
 
-	/**
+    /**
      * Invalidate the existing session after copying all of its contents to a newly created session with a new session id.
      * Note that this is different from logging out and creating a new session identifier that does not contain the
      * existing session contents. Care should be taken to use this only when the existing session does not contain
@@ -150,34 +150,34 @@ public interface HTTPUtilities
     HttpSession changeSessionIdentifier(HttpServletRequest request) throws AuthenticationException;
 
     /**
-	 * Clears the current HttpRequest and HttpResponse associated with the current thread.
+     * Clears the current HttpRequest and HttpResponse associated with the current thread.
      *
-	 * @see ESAPI#clearCurrent()
-	 */
+     * @see ESAPI#clearCurrent()
+     */
     void clearCurrent();
 
     /**
-	 * Decrypts an encrypted hidden field value and returns the cleartext. If the field does not decrypt properly,
-	 * an IntrusionException is thrown to indicate tampering.
+     * Decrypts an encrypted hidden field value and returns the cleartext. If the field does not decrypt properly,
+     * an IntrusionException is thrown to indicate tampering.
      *
-	 * @param encrypted hidden field value to decrypt
-	 * @return decrypted hidden field value stored as a String
-	 */
-	String decryptHiddenField(String encrypted);
+     * @param encrypted hidden field value to decrypt
+     * @return decrypted hidden field value stored as a String
+     */
+    String decryptHiddenField(String encrypted);
 
     /**
-	 * Takes an encrypted querystring and returns a Map containing the original parameters.
+     * Takes an encrypted querystring and returns a Map containing the original parameters.
      *
-	 * @param encrypted the encrypted querystring to decrypt
-	 * @return a Map object containing the decrypted querystring
-	 * @throws EncryptionException
-	 */
+     * @param encrypted the encrypted querystring to decrypt
+     * @return a Map object containing the decrypted querystring
+     * @throws EncryptionException
+     */
     Map<String, String> decryptQueryString(String encrypted) throws EncryptionException;
 
     /**
      * Calls decryptStateFromCookie with the *current* request.
      *
-	 * @see HTTPUtilities#setCurrentHTTP(HttpServletRequest, HttpServletResponse)
+     * @see HTTPUtilities#setCurrentHTTP(HttpServletRequest, HttpServletResponse)
      */
     Map<String, String> decryptStateFromCookie() throws EncryptionException;
 
@@ -186,7 +186,7 @@ public interface HTTPUtilities
      *
      * @param request
      * @return a map containing the decrypted cookie state value
-	 * @throws EncryptionException
+     * @throws EncryptionException
      */
     Map<String, String> decryptStateFromCookie(HttpServletRequest request) throws EncryptionException;
 
@@ -197,22 +197,22 @@ public interface HTTPUtilities
      * @return the encrypted value of the hidden field
      * @throws EncryptionException
      */
-	String encryptHiddenField(String value) throws EncryptionException;
+    String encryptHiddenField(String value) throws EncryptionException;
 
-	/**
-	 * Takes a querystring (everything after the question mark in the URL) and returns an encrypted string containing the parameters.
+    /**
+     * Takes a querystring (everything after the question mark in the URL) and returns an encrypted string containing the parameters.
      *
-	 * @param query the querystring to encrypt
-	 * @return encrypted querystring stored as a String
-	 * @throws EncryptionException
-	 */
-	String encryptQueryString(String query) throws EncryptionException;
+     * @param query the querystring to encrypt
+     * @return encrypted querystring stored as a String
+     * @throws EncryptionException
+     */
+    String encryptQueryString(String query) throws EncryptionException;
 
-	/**
-	 * Calls encryptStateInCookie with the *current* response.
+    /**
+     * Calls encryptStateInCookie with the *current* response.
      *
-	 * @see HTTPUtilities#setCurrentHTTP(HttpServletRequest, HttpServletResponse)
-	 */
+     * @see HTTPUtilities#setCurrentHTTP(HttpServletRequest, HttpServletResponse)
+     */
     void encryptStateInCookie(Map<String, String> cleartext) throws EncryptionException;
 
     /**
@@ -229,28 +229,28 @@ public interface HTTPUtilities
     void encryptStateInCookie(HttpServletResponse response, Map<String, String> cleartext) throws EncryptionException;
 
     /**
-	 * Calls getCookie with the *current* response.
-	 * 
-	 * @param name The cookie to get
+     * Calls getCookie with the *current* response.
+     *
+     * @param name The cookie to get
      * @return the requested cookie value
      * @throws ValidationException
      *
-	 * @see HTTPUtilities#setCurrentHTTP(HttpServletRequest, HttpServletResponse)
-	 */
-	String getCookie(String name) throws ValidationException;
+     * @see HTTPUtilities#setCurrentHTTP(HttpServletRequest, HttpServletResponse)
+     */
+    String getCookie(String name) throws ValidationException;
 
-	/**
+    /**
      * A safer replacement for getCookies() in HttpServletRequest that returns the canonicalized
      * value of the named cookie after "global" validation against the
      * general type defined in ESAPI.properties. This should not be considered a replacement for
      * more specific validation.
      *
      * @param request
-	 * @param name The cookie to get
+     * @param name The cookie to get
      * @return the requested cookie value
      * @throws ValidationException
      */
-	String getCookie(HttpServletRequest request, String name) throws ValidationException;
+    String getCookie(HttpServletRequest request, String name) throws ValidationException;
 
     /**
      * Returns the current user's CSRF token. If there is no current user then return null.
@@ -259,44 +259,44 @@ public interface HTTPUtilities
      */
     String getCSRFToken();
 
-	/**
+    /**
      * Retrieves the current HttpServletRequest
      *
      * @return the current request
      */
     HttpServletRequest getCurrentRequest();
 
-	/**
+    /**
      * Retrieves the current HttpServletResponse
      *
      * @return the current response
      */
     HttpServletResponse getCurrentResponse();
 
-	/**
-	 * Calls getFileUploads with the *current* request, default upload directory, and default allowed file extensions
+    /**
+     * Calls getFileUploads with the *current* request, default upload directory, and default allowed file extensions
      *
      * @return List of new File objects from upload
      * @throws ValidationException if the file fails validation
-     * 
-	 * @see HTTPUtilities#setCurrentHTTP(HttpServletRequest, HttpServletResponse)
-	 */
-	List getFileUploads() throws ValidationException;
+     *
+     * @see HTTPUtilities#setCurrentHTTP(HttpServletRequest, HttpServletResponse)
+     */
+    List getFileUploads() throws ValidationException;
 
     /**
-	 * Call getFileUploads with the specified request, default upload directory, and default allowed file extensions
+     * Call getFileUploads with the specified request, default upload directory, and default allowed file extensions
      *
      * @return List of new File objects from upload
      * @throws ValidationException if the file fails validation
-	 */
-	List getFileUploads(HttpServletRequest request) throws ValidationException;
+     */
+    List getFileUploads(HttpServletRequest request) throws ValidationException;
 
     /**
-	 * Call getFileUploads with the specified request, specified upload directory, and default allowed file extensions
+     * Call getFileUploads with the specified request, specified upload directory, and default allowed file extensions
      *
      * @return List of new File objects from upload
      * @throws ValidationException if the file fails validation
-	 */
+     */
     List getFileUploads(HttpServletRequest request, File finalDir) throws ValidationException;
 
 
@@ -306,7 +306,7 @@ public interface HTTPUtilities
      * possibly virus checking, and path and name checks. Refer to the file checking methods in Validator for more
      * information.
      * <p/>
-	 * This method uses {@link HTTPUtilities#getCurrentRequest()} to obtain the {@link HttpServletRequest} object
+     * This method uses {@link HTTPUtilities#getCurrentRequest()} to obtain the {@link HttpServletRequest} object
      *
      * @param request
      * @return List of new File objects from upload
@@ -315,12 +315,12 @@ public interface HTTPUtilities
     List getFileUploads(HttpServletRequest request, File destinationDir, List allowedExtensions) throws ValidationException;
 
 
-	/**
-	 * Calls getHeader with the *current* request.
+    /**
+     * Calls getHeader with the *current* request.
      *
-	 * @see HTTPUtilities#setCurrentHTTP(HttpServletRequest, HttpServletResponse)
-	 */
-	String getHeader(String name) throws ValidationException;
+     * @see HTTPUtilities#setCurrentHTTP(HttpServletRequest, HttpServletResponse)
+     */
+    String getHeader(String name) throws ValidationException;
 
     /**
      * A safer replacement for getHeader() in HttpServletRequest that returns the canonicalized
@@ -332,14 +332,14 @@ public interface HTTPUtilities
      * @param name
      * @return the requested header value
      */
-	String getHeader(HttpServletRequest request, String name) throws ValidationException;
+    String getHeader(HttpServletRequest request, String name) throws ValidationException;
 
-	/**
-	 * Calls getParameter with the *current* request.
+    /**
+     * Calls getParameter with the *current* request.
      *
-	 * @see HTTPUtilities#setCurrentHTTP(HttpServletRequest, HttpServletResponse)
-	 */
-	String getParameter(String name) throws ValidationException;
+     * @see HTTPUtilities#setCurrentHTTP(HttpServletRequest, HttpServletResponse)
+     */
+    String getParameter(String name) throws ValidationException;
 
     /**
      * A safer replacement for getParameter() in HttpServletRequest that returns the canonicalized
@@ -353,12 +353,12 @@ public interface HTTPUtilities
      */
     String getParameter(HttpServletRequest request, String name) throws ValidationException;
 
-	/**
-	 * Calls killAllCookies with the *current* request and response.
+    /**
+     * Calls killAllCookies with the *current* request and response.
      *
-	 * @see HTTPUtilities#setCurrentHTTP(HttpServletRequest, HttpServletResponse)
-	 */
-	void killAllCookies();
+     * @see HTTPUtilities#setCurrentHTTP(HttpServletRequest, HttpServletResponse)
+     */
+    void killAllCookies();
 
     /**
      * Kill all cookies received in the last request from the browser. Note that new cookies set by the application in
@@ -369,12 +369,12 @@ public interface HTTPUtilities
      */
     void killAllCookies(HttpServletRequest request, HttpServletResponse response);
 
-	/**
-	 * Calls killCookie with the *current* request and response.
+    /**
+     * Calls killCookie with the *current* request and response.
      *
-	 * @see HTTPUtilities#setCurrentHTTP(HttpServletRequest, HttpServletResponse)
-	 */
-	void killCookie(String name);
+     * @see HTTPUtilities#setCurrentHTTP(HttpServletRequest, HttpServletResponse)
+     */
+    void killCookie(String name);
 
     /**
      * Kills the specified cookie by setting a new cookie that expires immediately. Note that this
@@ -386,12 +386,12 @@ public interface HTTPUtilities
      */
     void killCookie(HttpServletRequest request, HttpServletResponse response, String name);
 
-	/**
-	 * Calls logHTTPRequest with the *current* request and logger.
+    /**
+     * Calls logHTTPRequest with the *current* request and logger.
      *
-	 * @see HTTPUtilities#setCurrentHTTP(HttpServletRequest, HttpServletResponse)
-	 */
-	void logHTTPRequest();
+     * @see HTTPUtilities#setCurrentHTTP(HttpServletRequest, HttpServletResponse)
+     */
+    void logHTTPRequest();
 
     /**
      * Format the Source IP address, URL, URL parameters, and all form
@@ -420,11 +420,11 @@ public interface HTTPUtilities
      */
     void logHTTPRequest(HttpServletRequest request, Logger logger, List parameterNamesToObfuscate);
 
-	/**
-	 * Calls sendForward with the *current* request and response.
+    /**
+     * Calls sendForward with the *current* request and response.
      *
-	 * @see HTTPUtilities#setCurrentHTTP(HttpServletRequest, HttpServletResponse)
-	 */
+     * @see HTTPUtilities#setCurrentHTTP(HttpServletRequest, HttpServletResponse)
+     */
     void sendForward(String location) throws AccessControlException, ServletException, IOException;
 
     /**
@@ -443,11 +443,11 @@ public interface HTTPUtilities
     void sendForward(HttpServletRequest request, HttpServletResponse response, String location) throws AccessControlException, ServletException, IOException;
 
 
-	/**
-	 * Calls sendRedirect with the *current* response.
+    /**
+     * Calls sendRedirect with the *current* response.
      *
-	 * @see HTTPUtilities#setCurrentHTTP(HttpServletRequest, HttpServletResponse)
-	 */
+     * @see HTTPUtilities#setCurrentHTTP(HttpServletRequest, HttpServletResponse)
+     */
     void sendRedirect(String location) throws AccessControlException, IOException;
 
 
@@ -464,25 +464,25 @@ public interface HTTPUtilities
      */
     void sendRedirect(HttpServletResponse response, String location) throws AccessControlException, IOException;
 
-	/**
-	 * Calls setContentType with the *current* request and response.
+    /**
+     * Calls setContentType with the *current* request and response.
      *
-	 * @see HTTPUtilities#setCurrentHTTP(HttpServletRequest, HttpServletResponse)
-	 */
+     * @see HTTPUtilities#setCurrentHTTP(HttpServletRequest, HttpServletResponse)
+     */
     void setContentType();
 
      /**
-	 * Set the content type character encoding header on every HttpServletResponse in order to limit
-	 * the ways in which the input data can be represented. This prevents
-	 * malicious users from using encoding and multi-byte escape sequences to
-	 * bypass input validation routines.
+     * Set the content type character encoding header on every HttpServletResponse in order to limit
+     * the ways in which the input data can be represented. This prevents
+     * malicious users from using encoding and multi-byte escape sequences to
+     * bypass input validation routines.
      * <p/>
-	 * Implementations of this method should set the content type header to a safe value for your environment.
+     * Implementations of this method should set the content type header to a safe value for your environment.
      * The default is text/html; charset=UTF-8 character encoding, which is the default in early
-	 * versions of HTML and HTTP. See RFC 2047 (http://ds.internic.net/rfc/rfc2045.txt) for more
-	 * information about character encoding and MIME.
+     * versions of HTML and HTTP. See RFC 2047 (http://ds.internic.net/rfc/rfc2045.txt) for more
+     * information about character encoding and MIME.
      * <p/>
-	 * The DefaultHTTPUtilities reference implementation sets the content type as specified.
+     * The DefaultHTTPUtilities reference implementation sets the content type as specified.
      *
      * @param response The servlet response to set the content type for.
      */
@@ -498,11 +498,11 @@ public interface HTTPUtilities
     void setCurrentHTTP(HttpServletRequest request, HttpServletResponse response);
 
 
-	/**
-	 * Calls setHeader with the *current* response.
+    /**
+     * Calls setHeader with the *current* response.
      *
-	 * @see HTTPUtilities#setCurrentHTTP(HttpServletRequest, HttpServletResponse)
-	 */
+     * @see HTTPUtilities#setCurrentHTTP(HttpServletRequest, HttpServletResponse)
+     */
     void setHeader(String name, String value);
 
     /**
@@ -518,11 +518,11 @@ public interface HTTPUtilities
     void setHeader(HttpServletResponse response, String name, String value);
 
 
-	/**
-	 * Calls setNoCacheHeaders with the *current* response.
+    /**
+     * Calls setNoCacheHeaders with the *current* response.
      *
-	 * @see HTTPUtilities#setCurrentHTTP(HttpServletRequest, HttpServletResponse)
-	 */
+     * @see HTTPUtilities#setCurrentHTTP(HttpServletRequest, HttpServletResponse)
+     */
     void setNoCacheHeaders();
 
 
@@ -556,67 +556,67 @@ public interface HTTPUtilities
      */
     void setNoCacheHeaders(HttpServletResponse response);
 
-	/**
-	 * Calls setNoCacheHeaders with the *current* response.
-	 * 
-	 * ~DEPRECATED~  Per Kevin Wall, storing passwords with reversible encryption is contrary to *many*
-	 * company's stated security policies.  
+    /**
+     * Calls setNoCacheHeaders with the *current* response.
+     *
+     * ~DEPRECATED~  Per Kevin Wall, storing passwords with reversible encryption is contrary to *many*
+     * company's stated security policies.
      *
-	 * @see HTTPUtilities#setCurrentHTTP(HttpServletRequest, HttpServletResponse)
-	 */
+     * @see HTTPUtilities#setCurrentHTTP(HttpServletRequest, HttpServletResponse)
+     */
     @Deprecated
     String setRememberToken(String password, int maxAge, String domain, String path);
 
     /**
-     * 
+     *
      */
     String setRememberToken(HttpServletRequest request, HttpServletResponse response, int maxAge, String domain, String path);
 
-    
+
     /**
-	 * Set a cookie containing the current User's remember me token for automatic authentication. The use of remember me tokens
-	 * is generally not recommended, but this method will help do it as safely as possible. The user interface should strongly warn
+     * Set a cookie containing the current User's remember me token for automatic authentication. The use of remember me tokens
+     * is generally not recommended, but this method will help do it as safely as possible. The user interface should strongly warn
      * the user that this should only be enabled on computers where no other users will have access.
      * <p/>
      * Implementations should save the user's remember me data in an encrypted cookie and send it to the user.
      * Any old remember me cookie should be destroyed first. Setting this cookie should keep the user
-	 * logged in until the maxAge passes, the password is changed, or the cookie is deleted.
-	 * If the cookie exists for the current user, it should automatically be used by ESAPI to
+     * logged in until the maxAge passes, the password is changed, or the cookie is deleted.
+     * If the cookie exists for the current user, it should automatically be used by ESAPI to
      * log the user in, if the data is valid and not expired.
      * <p/>
-	 * The ESAPI reference implementation, DefaultHTTPUtilities.setRememberToken() implements all these suggestions.
+     * The ESAPI reference implementation, DefaultHTTPUtilities.setRememberToken() implements all these suggestions.
      * <p/>
      * The username can be retrieved with: User username = ESAPI.authenticator().getCurrentUser();
      *
      *~DEPRECATED~  Per Kevin Wall, storing passwords with reversible encryption is contrary to *many*
-	 * company's stated security policies.  
+     * company's stated security policies.
      *
      * @param request
      * @param password the user's password
      * @param response
      * @param maxAge the length of time that the token should be valid for in relative seconds
-	 * @param domain the domain to restrict the token to or null
-	 * @param path the path to restrict the token to or null
-	 * @return encrypted "Remember Me" token stored as a String
-	 */
+     * @param domain the domain to restrict the token to or null
+     * @param path the path to restrict the token to or null
+     * @return encrypted "Remember Me" token stored as a String
+     */
     @Deprecated
     String setRememberToken(HttpServletRequest request, HttpServletResponse response, String password, int maxAge, String domain, String path);
 
 
-	/**
-	 * Calls verifyCSRFToken with the *current* request.
+    /**
+     * Calls verifyCSRFToken with the *current* request.
      *
-	 * @see HTTPUtilities#setCurrentHTTP(HttpServletRequest, HttpServletResponse)
-	 */
+     * @see HTTPUtilities#setCurrentHTTP(HttpServletRequest, HttpServletResponse)
+     */
     void verifyCSRFToken();
 
     /**
      * Checks the CSRF token in the URL (see User.getCSRFToken()) against the user's CSRF token and
-	 * throws an IntrusionException if it is missing.
+     * throws an IntrusionException if it is missing.
      *
      * @param request
      * @throws IntrusionException if CSRF token is missing or incorrect
-	 */
+     */
     void verifyCSRFToken(HttpServletRequest request) throws IntrusionException;
 
    /**
diff --git a/src/main/java/org/owasp/esapi/IntrusionDetector.java b/src/main/java/org/owasp/esapi/IntrusionDetector.java
index 6a14ec3..ccb2bc9 100644
--- a/src/main/java/org/owasp/esapi/IntrusionDetector.java
+++ b/src/main/java/org/owasp/esapi/IntrusionDetector.java
@@ -1,15 +1,15 @@
 /**
  * OWASP Enterprise Security API (ESAPI)
- * 
+ *
  * This file is part of the Open Web Application Security Project (OWASP)
  * Enterprise Security API (ESAPI) project. For details, please see
  * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
  *
  * Copyright (c) 2007 - The OWASP Foundation
- * 
+ *
  * The ESAPI is published by OWASP under the BSD license. You should read and accept the
  * LICENSE before you use, modify, and/or redistribute this software.
- * 
+ *
  * @author Jeff Williams <a href="http://www.aspectsecurity.com">Aspect Security</a>
  * @created 2007
  */
@@ -25,23 +25,23 @@ import org.owasp.esapi.errors.IntrusionException;
  * <P>
  * The interface is currently designed to accept exceptions as well as custom events. Implementations can use this
  * stream of information to detect both normal and abnormal behavior.
- * 
+ *
  * @author Jeff Williams (jeff.williams .at. aspectsecurity.com) <a href="http://www.aspectsecurity.com">Aspect Security</a>
  * @since June 1, 2007
  */
 public interface IntrusionDetector {
 
     /**
-     * Adds the exception to the IntrusionDetector.  This method should immediately log the exception so that developers throwing an 
+     * Adds the exception to the IntrusionDetector.  This method should immediately log the exception so that developers throwing an
      * IntrusionException do not have to remember to log every error.  The implementation should store the exception somewhere for the current user
      * in order to check if the User has reached the threshold for any Enterprise Security Exceptions.  The User object is the recommended location for storing
      * the current user's security exceptions.  If the User has reached any security thresholds, the appropriate security action can be taken and logged.
-     * 
-     * @param exception 
-     * 		the exception thrown
-     * 
-     * @throws IntrusionException 
-     * 		the intrusion exception
+     *
+     * @param exception
+     *         the exception thrown
+     *
+     * @throws IntrusionException
+     *         the intrusion exception
      */
     void addException(Exception exception) throws IntrusionException;
 
@@ -49,14 +49,14 @@ public interface IntrusionDetector {
      * Adds the event to the IntrusionDetector.  This method should immediately log the event.  The implementation should store the event somewhere for the current user
      * in order to check if the User has reached the threshold for any Enterprise Security Exceptions.  The User object is the recommended location for storing
      * the current user's security event.  If the User has reached any security thresholds, the appropriate security action can be taken and logged.
-     * 
-     * @param eventName 
-     * 		the event to add
-     * @param logMessage 
-     * 		the message to log with the event
-     * 
-     * @throws IntrusionException 
-     * 		the intrusion exception
+     *
+     * @param eventName
+     *         the event to add
+     * @param logMessage
+     *         the message to log with the event
+     *
+     * @throws IntrusionException
+     *         the intrusion exception
      */
     void addEvent(String eventName, String logMessage) throws IntrusionException;
 
diff --git a/src/main/java/org/owasp/esapi/LogFactory.java b/src/main/java/org/owasp/esapi/LogFactory.java
index e373698..7571ea4 100644
--- a/src/main/java/org/owasp/esapi/LogFactory.java
+++ b/src/main/java/org/owasp/esapi/LogFactory.java
@@ -1,15 +1,15 @@
 /**
  * OWASP Enterprise Security API (ESAPI)
- * 
+ *
  * This file is part of the Open Web Application Security Project (OWASP)
  * Enterprise Security API (ESAPI) project. For details, please see
  * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
  *
  * Copyright (c) 2007 - The OWASP Foundation
- * 
+ *
  * The ESAPI is published by OWASP under the BSD license. You should read and accept the
  * LICENSE before you use, modify, and/or redistribute this software.
- * 
+ *
  * @author Rogan Dawes<a href="http://www.aspectsecurity.com">Aspect Security</a>
  * @created 2008
  */
@@ -18,43 +18,43 @@ package org.owasp.esapi;
 /**
  * The LogFactory interface is intended to allow substitution of various logging packages, while providing
  * a common interface to access them.
- * 
- * In the reference implementation, JavaLogFactory.java implements this interface.  JavaLogFactory.java also contains an 
- * inner class called JavaLogger which implements Logger.java and uses the Java logging package to log events. 
- * 
+ *
+ * In the reference implementation, JavaLogFactory.java implements this interface.  JavaLogFactory.java also contains an
+ * inner class called JavaLogger which implements Logger.java and uses the Java logging package to log events.
+ *
  * @see org.owasp.esapi.ESAPI
- * 
+ *
  * @author rdawes
  *
  */
 public interface LogFactory {
-	
-	/**
-	 * Gets the logger associated with the specified module name. The module name is used by the logger to log which 
-	 * module is generating the log events. The implementation of this method should return any preexisting Logger 
-	 * associated with this module name, rather than creating a new Logger.
-	 * <br><br>
-	 * The JavaLogFactory reference implementation meets these requirements.
-	 * 
-	 * @param moduleName
-	 * 			The name of the module requesting the logger.
-	 * @return
-	 * 			The Logger associated with this module.
-	 */
-	Logger getLogger(String moduleName);
-	
-	/**
-	 * Gets the logger associated with the specified class. The class is used by the logger to log which 
-	 * class is generating the log events. The implementation of this method should return any preexisting Logger 
-	 * associated with this class name, rather than creating a new Logger.
-	 * <br><br>
-	 * The JavaLogFactory reference implementation meets these requirements.
-	 * 
-	 * @param clazz
-	 * 			The name of the class requesting the logger.
-	 * @return
-	 * 			The Logger associated with this class.
-	 */
-	Logger getLogger(Class clazz);
-	
+
+    /**
+     * Gets the logger associated with the specified module name. The module name is used by the logger to log which
+     * module is generating the log events. The implementation of this method should return any preexisting Logger
+     * associated with this module name, rather than creating a new Logger.
+     * <br><br>
+     * The JavaLogFactory reference implementation meets these requirements.
+     *
+     * @param moduleName
+     *             The name of the module requesting the logger.
+     * @return
+     *             The Logger associated with this module.
+     */
+    Logger getLogger(String moduleName);
+
+    /**
+     * Gets the logger associated with the specified class. The class is used by the logger to log which
+     * class is generating the log events. The implementation of this method should return any preexisting Logger
+     * associated with this class name, rather than creating a new Logger.
+     * <br><br>
+     * The JavaLogFactory reference implementation meets these requirements.
+     *
+     * @param clazz
+     *             The name of the class requesting the logger.
+     * @return
+     *             The Logger associated with this class.
+     */
+    Logger getLogger(Class clazz);
+
 }
diff --git a/src/main/java/org/owasp/esapi/Logger.java b/src/main/java/org/owasp/esapi/Logger.java
index 2e3ec33..288509b 100644
--- a/src/main/java/org/owasp/esapi/Logger.java
+++ b/src/main/java/org/owasp/esapi/Logger.java
@@ -1,27 +1,27 @@
 /**
  * OWASP Enterprise Security API (ESAPI)
- * 
+ *
  * This file is part of the Open Web Application Security Project (OWASP)
  * Enterprise Security API (ESAPI) project. For details, please see
  * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
  *
  * Copyright (c) 2007-2019 - The OWASP Foundation
- * 
+ *
  * The ESAPI is published by OWASP under the BSD license. You should read and accept the
  * LICENSE before you use, modify, and/or redistribute this software.
- * 
+ *
  * @author Jeff Williams <a href="http://www.aspectsecurity.com">Aspect Security</a>
  * @created 2007
  */
 package org.owasp.esapi;
 
 /**
- * The Logger interface defines a set of methods that can be used to log
+ * The {@code Logger} interface defines a set of methods that can be used to log
  * security events. It supports a hierarchy of logging levels which can be configured at runtime to determine
  * the severity of events that are logged, and those below the current threshold that are discarded.
  * Implementors should use a well established logging library
  * as it is quite difficult to create a high-performance logger.
- * <P>
+ * <p>
  * The logging levels defined by this interface (in descending order) are:
  * <ul>
  * <li>fatal (highest value)</li>
@@ -33,9 +33,9 @@ package org.owasp.esapi;
  * </ul>
  * There are also several variations of {@code always()} methods that will <i>always</i>
  * log a message regardless of the log level.
- * <p>
+ * </p><p>
  * ESAPI also allows for the definition of the type of log event that is being generated.
- * The Logger interface predefines 6 types of Log events:
+ * The {@code Logger} interface predefines 6 types of Log events:
  * <ul>
  * <li>SECURITY_SUCCESS</li>
  * <li>SECURITY_FAILURE</li>
@@ -44,385 +44,390 @@ package org.owasp.esapi;
  * <li>EVENT_FAILURE</li>
  * <li>EVENT_UNSPECIFIED</li>
  * </ul>
- * <p>
- * Your implementation can extend or change this list if desired. 
- * <p>
- * This Logger allows callers to determine which logging levels are enabled, and to submit events 
+ * </p><p>
+ * Your custom implementation can extend or change this list if desired.
+ * </p><p>
+ * This {@code Logger} allows callers to determine which logging levels are enabled, and to submit events
  * at different severity levels.<br>
  * <br>Implementors of this interface should:
- * 
+ *
  * <ol>
- * <li>provide a mechanism for setting the logging level threshold that is currently enabled. This usually works by logging all 
+ * <li>Provide a mechanism for setting the logging level threshold that is currently enabled. This usually works by logging all
  * events at and above that severity level, and discarding all events below that level.
  * This is usually done via configuration, but can also be made accessible programmatically.</li>
- * <li>ensure that dangerous HTML characters are encoded before they are logged to defend against malicious injection into logs 
+ * <li>Ensure that dangerous HTML characters are encoded before they are logged to defend against malicious injection into logs
  * that might be viewed in an HTML based log viewer.</li>
- * <li>encode any CRLF characters included in log data in order to prevent log injection attacks.</li>
- * <li>avoid logging the user's session ID. Rather, they should log something equivalent like a 
- * generated logging session ID, or a hashed value of the session ID so they can track session specific 
- * events without risking the exposure of a live session's ID.</li> 
- * <li>record the following information with each event:</li>
+ * <li>Encode any CRLF characters included in log data in order to prevent log injection attacks.</li>
+ * <li>Avoid logging the user's session ID. Rather, they should log something equivalent like a
+ * generated logging session ID, or a hashed value of the session ID so they can track session specific
+ * events without risking the exposure of a live session's ID.</li>
+ * <li>Record the following information with each event:</li>
  *   <ol type="a">
- *   <li>identity of the user that caused the event,</li>
- *   <li>a description of the event (supplied by the caller),</li>
- *   <li>whether the event succeeded or failed (indicated by the caller),</li>
- *   <li>severity level of the event (indicated by the caller),</li>
- *   <li>that this is a security relevant event (indicated by the caller),</li>
- *   <li>hostname or IP where the event occurred (and ideally the user's source IP as well),</li>
- *   <li>a time stamp</li>
+ *   <li>Identity of the user that caused the event.</li>
+ *   <li>A description of the event (supplied by the caller).</li>
+ *   <li>Whether the event succeeded or failed (indicated by the caller).</li>
+ *   <li>Severity level of the event (indicated by the caller).</li>
+ *   <li>That this is a security relevant event (indicated by the caller).</li>
+ *   <li>Hostname or IP where the event occurred (and ideally the user's source IP as well).</li>
+ *   <li>A date/time stamp.</li>
  *   </ol>
  * </ol>
- *  
+ *
  * Custom logger implementations might also:
  * <ol start="6">
- * <li>filter out any sensitive data specific to the current application or organization, such as credit cards, 
+ * <li>Filter out any sensitive data specific to the current application or organization, such as credit cards,
  * social security numbers, etc.</li>
  * </ol>
- * 
- * There are both Log4j and native Java Logging default implementations. JavaLogger uses the java.util.logging package as the basis for its logging 
- * implementation. Both default implementations implements requirements #1 thru #5 above.<br>
- * <br>
- * Customization: It is expected that most organizations will implement their own custom Logger class in 
- * order to integrate ESAPI logging with their logging infrastructure. The ESAPI Reference Implementation 
- * is intended to provide a simple functional example of an implementation.
- * 
+ *
+ * There are both SLF4J and native Java Logging (i.e., {@code java.util.logging}, aka JUL) implementations
+ * of the ESAPI logger with JUL being our default logger for our stock <b>ESAPI.properties</b> file that
+ * is delivered along with ESAPI releases in a separate <b>esapi-configuration</b> jar available from the
+ * releases mentioned on
+ * <a href="https://github.com/ESAPI/esapi-java-legacy/releases/">ESAPI's GitHub Releases page</a>.
+ * </p><p>
+ * The {@code org.owasp.esapi.logging.java.JavaLogger} class uses the {@code java.util.logging} package as
+ * the basis for its logging implementation. Both provided implementations implement requirements #1 through #5 above.
+ * </p><p>
+ * <i>Customization</i>: It is expected that most organizations may wish to implement their own custom {@code Logger} class in
+ * order to integrate ESAPI logging with their specific logging infrastructure. The ESAPI feference implementations
+ * can serve as a useful starting point to intended to provide a simple functional example of an implementation, but
+ * they are also largely usuable out-of-the-box with some additional minimal log configuration.
+ *
  * @author Jeff Williams (jeff.williams .at. aspectsecurity.com) <a
  * href="http://www.aspectsecurity.com">Aspect Security</a>
  * @since June 1, 2007
  */
 public interface Logger {
 
-	// All implied static final as this is an interface
-	
-	/**
+    // All implied static final as this is an interface
+
+    /**
      * A security type of log event that has succeeded. This is one of 6 predefined
      * ESAPI logging events. New events can be added.
      */
-	EventType SECURITY_SUCCESS = new EventType( "SECURITY SUCCESS", true);
+    EventType SECURITY_SUCCESS = new EventType( "SECURITY SUCCESS", true);
 
-	/**
+    /**
      * A security type of log event that has failed. This is one of 6 predefined
      * ESAPI logging events. New events can be added.
      */
-	EventType SECURITY_FAILURE = new EventType( "SECURITY FAILURE", false);
+    EventType SECURITY_FAILURE = new EventType( "SECURITY FAILURE", false);
 
-	/**
-	 * A security type of log event that is associated with an audit trail of some type,
-	 * but the log event is not specifically something that has either succeeded or failed
-	 * or that is irrelevant in the case of this logged message.
-	 */
-	// CHECKME: Should the Boolean for this be 'null' or 'true'? See EVENT_UNSPECIFIED.
-	EventType SECURITY_AUDIT = new EventType( "SECURITY AUDIT", null);
+    /**
+     * A security type of log event that is associated with an audit trail of some type,
+     * but the log event is not specifically something that has either succeeded or failed
+     * or that is irrelevant in the case of this logged message.
+     */
+    // CHECKME: Should the Boolean for this be 'null' or 'true'? See EVENT_UNSPECIFIED.
+    EventType SECURITY_AUDIT = new EventType( "SECURITY AUDIT", null);
 
-	/**
+    /**
      * A non-security type of log event that has succeeded. This is one of 6 predefined
      * ESAPI logging events. New events can be added.
      */
-	EventType EVENT_SUCCESS = new EventType( "EVENT SUCCESS", true);
-	
-	/**
+    EventType EVENT_SUCCESS = new EventType( "EVENT SUCCESS", true);
+
+    /**
      * A non-security type of log event that has failed. This is one of 6 predefined
      * ESAPI logging events. New events can be added.
      */
-	EventType EVENT_FAILURE = new EventType( "EVENT FAILURE", false);
+    EventType EVENT_FAILURE = new EventType( "EVENT FAILURE", false);
 
-	/**
+    /**
      * A non-security type of log event that is unspecified. This is one of 6 predefined
      * ESAPI logging events. New events can be added.
      */
-	EventType EVENT_UNSPECIFIED = new EventType( "EVENT UNSPECIFIED", null);
-
-	/**
-	 * Defines the type of log event that is being generated. The Logger interface defines 6 types of Log events:
-	 * SECURITY_SUCCESS, SECURITY_FAILURE, EVENT_SUCCESS, EVENT_FAILURE, EVENT_UNSPECIFIED.
-     * Your implementation can extend or change this list if desired. 
-	 */
-	class EventType {
-		
-		private String type;
-		private Boolean success = null;
-		
-		public EventType (String name, Boolean newSuccess) {
-			this.type = name;
-			this.success = newSuccess;
-		}
-		
-		public Boolean isSuccess() {
-			return success;
-		}
-		
+    EventType EVENT_UNSPECIFIED = new EventType( "EVENT UNSPECIFIED", null);
+
+    /**
+     * Defines the type of log event that is being generated. The Logger interface defines 6 types of Log events:
+     * SECURITY_SUCCESS, SECURITY_FAILURE, EVENT_SUCCESS, EVENT_FAILURE, EVENT_UNSPECIFIED.
+     * Your implementation can extend or change this list if desired.
+     */
+    class EventType {
+
+        private String type;
+        private Boolean success = null;
+
+        public EventType (String name, Boolean newSuccess) {
+            this.type = name;
+            this.success = newSuccess;
+        }
+
+        public Boolean isSuccess() {
+            return success;
+        }
+
         /**
          * Convert the {@code EventType} to a string.
          * @return The event type name.
          */
-		@Override
+        @Override
         public String toString() {
-			return this.type;
-		}
-	}
-	
-	/*
-     * The Logger interface defines 6 logging levels: FATAL, ERROR, WARNING, INFO, DEBUG, TRACE. It also 
+            return this.type;
+        }
+    }
+
+    /*
+     * The Logger interface defines 6 logging levels: FATAL, ERROR, WARNING, INFO, DEBUG, TRACE. It also
      * supports ALL, which logs all events, and OFF, which disables all logging.
-     * Your implementation can extend or change this list if desired. 
+     * Your implementation can extend or change this list if desired.
      */
-	
-	/** OFF indicates that no messages should be logged. This level is initialized to Integer.MAX_VALUE. */
-	int OFF = Integer.MAX_VALUE;
 
-	/** FATAL indicates that only FATAL messages should be logged. This level is initialized to 1000. */
-	int FATAL = 1000;
+    /** OFF indicates that no messages should be logged. This level is initialized to Integer.MAX_VALUE. */
+    int OFF = Integer.MAX_VALUE;
+
+    /** FATAL indicates that only FATAL messages should be logged. This level is initialized to 1000. */
+    int FATAL = 1000;
 
-	/** ERROR indicates that ERROR messages and above should be logged. 
-	 * This level is initialized to 800. */
+    /** ERROR indicates that ERROR messages and above should be logged.
+     * This level is initialized to 800. */
     int ERROR = 800;
 
-    /** WARNING indicates that WARNING messages and above should be logged. 
+    /** WARNING indicates that WARNING messages and above should be logged.
      * This level is initialized to 600. */
     int WARNING = 600;
 
-    /** INFO indicates that INFO messages and above should be logged. 
+    /** INFO indicates that INFO messages and above should be logged.
      * This level is initialized to 400. */
     int INFO = 400;
 
-    /** DEBUG indicates that DEBUG messages and above should be logged. 
+    /** DEBUG indicates that DEBUG messages and above should be logged.
      * This level is initialized to 200. */
     int DEBUG = 200;
 
-    /** TRACE indicates that TRACE messages and above should be logged. 
+    /** TRACE indicates that TRACE messages and above should be logged.
      * This level is initialized to 100. */
     int TRACE = 100;
 
     /** ALL indicates that all messages should be logged. This level is initialized to Integer.MIN_VALUE. */
     int ALL = Integer.MIN_VALUE;
-    
+
 
     /**
-     * Dynamically set the ESAPI logging severity level. All events of this level and higher will be logged from 
+     * Dynamically set the ESAPI logging severity level. All events of this level and higher will be logged from
      * this point forward for all logs. All events below this level will be discarded.
-     * 
-     * @param level The level to set the logging level to. 
+     *
+     * @param level The level to set the logging level to.
      */
     void setLevel(int level);
-    
-    /** Retrieve the current ESAPI logging level for this logger. See
-     * {@link org.owasp.esapi.logging.log4j.Log4JLogger} for an explanation of
-     * why this method is not simply called {@code getLevel()}.
-     * 
+
+    /** Retrieve the current ESAPI logging level for this logger.
+     *
      * @return The current logging level.
      */
     int getESAPILevel();
-    
-	/**
+
+    /**
      * Log a fatal event if 'fatal' level logging is enabled.
-     * 
-     * @param type 
-     * 		the type of event
-     * @param message 
-     * 		the message to log
+     *
+     * @param type
+     *         the type of event
+     * @param message
+     *         the message to log
      */
-	void fatal(EventType type, String message);
-	
-	/**
-     * Log a fatal level security event if 'fatal' level logging is enabled 
+    void fatal(EventType type, String message);
+
+    /**
+     * Log a fatal level security event if 'fatal' level logging is enabled
      * and also record the stack trace associated with the event.
-     * 
-     * @param type 
-     * 		the type of event
-     * @param message 
-     * 		the message to log
-     * @param throwable 
-     * 		the exception to be logged
+     *
+     * @param type
+     *         the type of event
+     * @param message
+     *         the message to log
+     * @param throwable
+     *         the exception to be logged
      */
-	void fatal(EventType type, String message, Throwable throwable);
+    void fatal(EventType type, String message, Throwable throwable);
 
-	/**
-	 * Allows the caller to determine if messages logged at this level
-	 * will be discarded, to avoid performing expensive processing.
-	 * 
-	 * @return true if fatal level messages will be output to the log
-	 */
-	boolean isFatalEnabled();
+    /**
+     * Allows the caller to determine if messages logged at this level
+     * will be discarded, to avoid performing expensive processing.
+     *
+     * @return true if fatal level messages will be output to the log
+     */
+    boolean isFatalEnabled();
 
-	/**
+    /**
      * Log an error level security event if 'error' level logging is enabled.
-     * 
-     * @param type 
-     * 		the type of event 
-     * @param message 
-     * 		the message to log
+     *
+     * @param type
+     *         the type of event
+     * @param message
+     *         the message to log
      */
-	void error(EventType type, String message);
-	
-	/**
-     * Log an error level security event if 'error' level logging is enabled 
+    void error(EventType type, String message);
+
+    /**
+     * Log an error level security event if 'error' level logging is enabled
      * and also record the stack trace associated with the event.
-     * 
-     * @param type 
-     * 		the type of event
-     * @param message 
-     * 		the message to log
-     * @param throwable 
-     * 		the exception to be logged
+     *
+     * @param type
+     *         the type of event
+     * @param message
+     *         the message to log
+     * @param throwable
+     *         the exception to be logged
      */
-	void error(EventType type, String message, Throwable throwable);
+    void error(EventType type, String message, Throwable throwable);
 
-	/**
-	 * Allows the caller to determine if messages logged at this level
-	 * will be discarded, to avoid performing expensive processing.
-	 * 
-	 * @return true if error level messages will be output to the log
-	 */
-	boolean isErrorEnabled();
+    /**
+     * Allows the caller to determine if messages logged at this level
+     * will be discarded, to avoid performing expensive processing.
+     *
+     * @return true if error level messages will be output to the log
+     */
+    boolean isErrorEnabled();
 
-	/**
+    /**
      * Log a warning level security event if 'warning' level logging is enabled.
-     * 
-     * @param type 
-     * 		the type of event 
-     * @param message 
-     * 		the message to log
+     *
+     * @param type
+     *         the type of event
+     * @param message
+     *         the message to log
      */
-	void warning(EventType type, String message);
-	
-	/**
-     * Log a warning level security event if 'warning' level logging is enabled 
+    void warning(EventType type, String message);
+
+    /**
+     * Log a warning level security event if 'warning' level logging is enabled
      * and also record the stack trace associated with the event.
-     * 
-     * @param type 
-     * 		the type of event 
-     * @param message 
-     * 		the message to log
-     * @param throwable 
-     * 		the exception to be logged
+     *
+     * @param type
+     *         the type of event
+     * @param message
+     *         the message to log
+     * @param throwable
+     *         the exception to be logged
      */
-	void warning(EventType type, String message, Throwable throwable);
+    void warning(EventType type, String message, Throwable throwable);
 
-	/**
-	 * Allows the caller to determine if messages logged at this level
-	 * will be discarded, to avoid performing expensive processing.
-	 * 
-	 * @return true if warning level messages will be output to the log
-	 */
-	boolean isWarningEnabled();
+    /**
+     * Allows the caller to determine if messages logged at this level
+     * will be discarded, to avoid performing expensive processing.
+     *
+     * @return true if warning level messages will be output to the log
+     */
+    boolean isWarningEnabled();
 
-	/**
+    /**
      * Log an info level security event if 'info' level logging is enabled.
-     * 
-     * @param type 
-     * 		the type of event 
-     * @param message 
-     * 		the message to log
+     *
+     * @param type
+     *         the type of event
+     * @param message
+     *         the message to log
      */
-	void info(EventType type, String message);
-	
-	/**
-     * Log an info level security event if 'info' level logging is enabled 
+    void info(EventType type, String message);
+
+    /**
+     * Log an info level security event if 'info' level logging is enabled
      * and also record the stack trace associated with the event.
-     * 
-     * @param type 
-     * 		the type of event
-     * @param message 
-     * 		the message to log
-     * @param throwable 
-     * 		the exception to be logged
+     *
+     * @param type
+     *         the type of event
+     * @param message
+     *         the message to log
+     * @param throwable
+     *         the exception to be logged
      */
-	void info(EventType type, String message, Throwable throwable);
+    void info(EventType type, String message, Throwable throwable);
 
-	/**
-	 * Allows the caller to determine if messages logged at this level
-	 * will be discarded, to avoid performing expensive processing.
-	 * 
-	 * @return true if info level messages will be output to the log
-	 */
-	boolean isInfoEnabled();
+    /**
+     * Allows the caller to determine if messages logged at this level
+     * will be discarded, to avoid performing expensive processing.
+     *
+     * @return true if info level messages will be output to the log
+     */
+    boolean isInfoEnabled();
 
-	/**
+    /**
      * Log a debug level security event if 'debug' level logging is enabled.
-     * 
-     * @param type 
-     * 		the type of event
-     * @param message 
-     * 		the message to log
+     *
+     * @param type
+     *         the type of event
+     * @param message
+     *         the message to log
      */
-	void debug(EventType type, String message);
-	
-	/**
-     * Log a debug level security event if 'debug' level logging is enabled 
+    void debug(EventType type, String message);
+
+    /**
+     * Log a debug level security event if 'debug' level logging is enabled
      * and also record the stack trace associated with the event.
-     * 
-     * @param type 
-     * 		the type of event
-     * @param message 
-     * 		the message to log
-     * @param throwable 
-     * 		the exception to be logged
+     *
+     * @param type
+     *         the type of event
+     * @param message
+     *         the message to log
+     * @param throwable
+     *         the exception to be logged
      */
-	void debug(EventType type, String message, Throwable throwable);
+    void debug(EventType type, String message, Throwable throwable);
 
-	/**
-	 * Allows the caller to determine if messages logged at this level
-	 * will be discarded, to avoid performing expensive processing.
-	 * 
-	 * @return true if debug level messages will be output to the log
-	 */
-	boolean isDebugEnabled();
+    /**
+     * Allows the caller to determine if messages logged at this level
+     * will be discarded, to avoid performing expensive processing.
+     *
+     * @return true if debug level messages will be output to the log
+     */
+    boolean isDebugEnabled();
 
-	/**
+    /**
      * Log a trace level security event if 'trace' level logging is enabled.
-     * 
-     * @param type 
-     * 		the type of event
-     * @param message 
-     * 		the message to log
+     *
+     * @param type
+     *         the type of event
+     * @param message
+     *         the message to log
      */
-	void trace(EventType type, String message);
-	
-	/**
-     * Log a trace level security event if 'trace' level logging is enabled 
+    void trace(EventType type, String message);
+
+    /**
+     * Log a trace level security event if 'trace' level logging is enabled
      * and also record the stack trace associated with the event.
-     * 
-     * @param type 
-     * 		the type of event 
-     * @param message 
-     * 		the message to log
-     * @param throwable 
-     * 		the exception to be logged
+     *
+     * @param type
+     *         the type of event
+     * @param message
+     *         the message to log
+     * @param throwable
+     *         the exception to be logged
      */
-	void trace(EventType type, String message, Throwable throwable);
+    void trace(EventType type, String message, Throwable throwable);
 
-	/**
-	 * Allows the caller to determine if messages logged at this level
-	 * will be discarded, to avoid performing expensive processing.
-	 * 
-	 * @return true if trace level messages will be output to the log
-	 */
-	boolean isTraceEnabled();
+    /**
+     * Allows the caller to determine if messages logged at this level
+     * will be discarded, to avoid performing expensive processing.
+     *
+     * @return true if trace level messages will be output to the log
+     */
+    boolean isTraceEnabled();
 
-	/**
+    /**
      * Log an event regardless of what logging level is enabled.
      * <br>
      * Note that logging will not occur if the underlying logging implementation has logging disabled.
-     * 
-     * @param type 
-     * 		the type of event
-     * @param message 
-     * 		the message to log
+     *
+     * @param type
+     *         the type of event
+     * @param message
+     *         the message to log
      */
-	void always(EventType type, String message);
-	
-	/**
+    void always(EventType type, String message);
+
+    /**
      * Log an event regardless of what logging level is enabled
      * and also record the stack trace associated with the event.
      * <br>
      * Note that logging will not occur if the underlying logging implementation has logging disabled.
-     * 
-     * @param type 
-     * 		the type of event 
-     * @param message 
-     * 		the message to log
-     * @param throwable 
-     * 		the exception to be logged
+     *
+     * @param type
+     *         the type of event
+     * @param message
+     *         the message to log
+     * @param throwable
+     *         the exception to be logged
      */
-	void always(EventType type, String message, Throwable throwable);
+    void always(EventType type, String message, Throwable throwable);
 }
diff --git a/src/main/java/org/owasp/esapi/PreparedString.java b/src/main/java/org/owasp/esapi/PreparedString.java
index ba26087..5102a32 100644
--- a/src/main/java/org/owasp/esapi/PreparedString.java
+++ b/src/main/java/org/owasp/esapi/PreparedString.java
@@ -1,15 +1,15 @@
 /**
  * OWASP Enterprise Security API (ESAPI)
- * 
+ *
  * This file is part of the Open Web Application Security Project (OWASP)
  * Enterprise Security API (ESAPI) project. For details, please see
  * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
  *
  * Copyright (c) 2007-2019 - The OWASP Foundation
- * 
+ *
  * The ESAPI is published by OWASP under the BSD license. You should read and accept the
  * LICENSE before you use, modify, and/or redistribute this software.
- * 
+ *
  * @author Jeff Williams <a href="http://www.aspectsecurity.com">Aspect Security</a>
  * @created 2009
  */
@@ -21,117 +21,117 @@ import org.owasp.esapi.codecs.Codec;
 /**
  * A parameterized string that uses escaping to make untrusted data safe before combining it with
  * a command or query intended for use in an interpreter.
- * <pre> 
+ * <pre>
  * PreparedString div = new PreparedString( "&lt;a href=\"http:\\\\example.com?id=?\" onmouseover=\"alert('?')\"&gt;test&lt;/a&gt;", new HTMLEntityCodec() );
  * div.setURL( 1, request.getParameter( "url" ), new PercentCodec() );
  * div.set( 2, request.getParameter( "message" ), new JavaScriptCodec() );
  * out.println( div.toString() );
- * 
+ *
  * // escaping for SQL
  * PreparedString query = new PreparedString( "SELECT * FROM users WHERE name='?' AND password='?'", new OracleCodec() );
  * query.set( 1, request.getParameter( "name" ) );
  * query.set( 2, request.getParameter( "pass" ) );
  * stmt.execute( query.toString() );
  * </pre>
- * 
+ *
  * @author Jeff Williams (jeff.williams .at. aspectsecurity.com) <a href="http://www.aspectsecurity.com">Aspect Security</a>
  * @since June 1, 2007
  */
 public class PreparedString {
-	char parameterCharacter = '?';
-	Codec codec = null;
-	String[] parameters = null;
-	ArrayList parts = new ArrayList();
-	private final static char[] IMMUNE = {};
+    char parameterCharacter = '?';
+    Codec codec = null;
+    String[] parameters = null;
+    ArrayList parts = new ArrayList();
+    private final static char[] IMMUNE = {};
+
+    /**
+     * Create a PreparedString with the supplied template and Codec. The template should use the
+     * default parameter placeholder character (?) in the place where actual parameters are to be inserted.
+     * The supplied Codec will be used to escape characters in calls to set, unless a specific Codec is
+     * provided to override it.
+     * @param template
+     * @param codec
+     */
+    public PreparedString( String template, Codec codec ) {
+        this.codec = codec;
+        split( template, parameterCharacter );
+    }
+
+    /**
+     * Create a PreparedString with the supplied template, parameter placeholder character, and Codec. The parameter character
+     * can be any character, but should not be one that will be used in the template. The parameter character can safely
+     * be used in a parameter passed into the set methods.
+     * @param template
+     * @param parameterCharacter
+     * @param codec
+     */
+    public PreparedString( String template, char parameterCharacter, Codec codec ) {
+        this.codec = codec;
+        this.parameterCharacter = parameterCharacter;
+        split( template, parameterCharacter );
+    }
+
+    /**
+     * Split a string with a particular character.
+     * @param str
+     * @param c
+     */
+    private void split( String str, char c ) {
+        int index = 0;
+        int pcount = 0;
+        for ( int i = 0; i < str.length(); i++ ) {
+            if ( str.charAt(i) == c ) {
+                pcount++;
+                parts.add( str.substring(index,i) );
+                index = i + 1;
+            }
+        }
+        parts.add( str.substring(index) );
+        parameters = new String[pcount];
+    }
 
-	/**
-	 * Create a PreparedString with the supplied template and Codec. The template should use the 
-	 * default parameter placeholder character (?) in the place where actual parameters are to be inserted.
-	 * The supplied Codec will be used to escape characters in calls to set, unless a specific Codec is
-	 * provided to override it.
-	 * @param template
-	 * @param codec
-	 */
-	public PreparedString( String template, Codec codec ) {
-		this.codec = codec;
-		split( template, parameterCharacter );
-	}
+    /**
+     * Set the parameter at index with supplied value using the default Codec to escape.
+     * @param index
+     * @param value
+     */
+    public void set( int index, String value ) {
+        if ( index < 1 || index > parameters.length ) {
+            throw new IllegalArgumentException( "Attempt to set parameter " + index + " on a PreparedString with only " + parameters.length + " placeholders" );
+        }
+        String encoded = codec.encode( IMMUNE, value );
+        parameters[index-1] = encoded;
+    }
 
-	/**
-	 * Create a PreparedString with the supplied template, parameter placeholder character, and Codec. The parameter character
-	 * can be any character, but should not be one that will be used in the template. The parameter character can safely
-	 * be used in a parameter passed into the set methods.
-	 * @param template
-	 * @param parameterCharacter
-	 * @param codec
-	 */
-	public PreparedString( String template, char parameterCharacter, Codec codec ) {
-		this.codec = codec;
-		this.parameterCharacter = parameterCharacter;
-		split( template, parameterCharacter );
-	}
+    /**
+     * Set the parameter at index with supplied value using the supplied Codec to escape.
+     * @param index
+     * @param value
+     * @param codec
+     */
+    public void set( int index, String value, Codec codec ) {
+        if ( index < 1 || index > parameters.length ) {
+            throw new IllegalArgumentException( "Attempt to set parameter " + index + " on a PreparedString with only " + parameters.length + " placeholders" );
+        }
+        String encoded = codec.encode( IMMUNE, value );
+        parameters[index-1] = encoded;
+    }
 
-	/**
-	 * Split a string with a particular character.
-	 * @param str
-	 * @param c
-	 */
-	private void split( String str, char c ) {
-		int index = 0;
-		int pcount = 0;
-		for ( int i = 0; i < str.length(); i++ ) {
-			if ( str.charAt(i) == c ) {
-				pcount++;
-				parts.add( str.substring(index,i) );
-				index = i + 1;
-			}
-		}
-		parts.add( str.substring(index) );
-		parameters = new String[pcount];
-	}
-	
-	/**
-	 * Set the parameter at index with supplied value using the default Codec to escape. 
-	 * @param index
-	 * @param value
-	 */
-	public void set( int index, String value ) {
-		if ( index < 1 || index > parameters.length ) {
-			throw new IllegalArgumentException( "Attempt to set parameter " + index + " on a PreparedString with only " + parameters.length + " placeholders" );
-		}
-		String encoded = codec.encode( IMMUNE, value );
-		parameters[index-1] = encoded;
-	}
-	
-	/**
-	 * Set the parameter at index with supplied value using the supplied Codec to escape. 
-	 * @param index
-	 * @param value
-	 * @param codec
-	 */
-	public void set( int index, String value, Codec codec ) {
-		if ( index < 1 || index > parameters.length ) {
-			throw new IllegalArgumentException( "Attempt to set parameter " + index + " on a PreparedString with only " + parameters.length + " placeholders" );
-		}
-		String encoded = codec.encode( IMMUNE, value );
-		parameters[index-1] = encoded;
-	}
-	
-	/**
-	 * Render the PreparedString by combining the template with properly escaped parameters.
-	 */
-	public String toString() {
-		for ( int ix = 0; ix < parameters.length; ix++ ) {
-			if ( parameters[ix] == null ) {
-				throw new RuntimeException( "Attempt to render PreparedString without setting parameter " + ( ix + 1 ));
-			}
-		}
-		StringBuilder sb = new StringBuilder();
-		int i = 0;
-		for ( int p=0; p < parts.size(); p++ ) {
-			sb.append( parts.get( p ) );
-			if ( i < parameters.length ) sb.append( parameters[i++] );
-		}
-		return sb.toString();
-	}
+    /**
+     * Render the PreparedString by combining the template with properly escaped parameters.
+     */
+    public String toString() {
+        for ( int ix = 0; ix < parameters.length; ix++ ) {
+            if ( parameters[ix] == null ) {
+                throw new RuntimeException( "Attempt to render PreparedString without setting parameter " + ( ix + 1 ));
+            }
+        }
+        StringBuilder sb = new StringBuilder();
+        int i = 0;
+        for ( int p=0; p < parts.size(); p++ ) {
+            sb.append( parts.get( p ) );
+            if ( i < parameters.length ) sb.append( parameters[i++] );
+        }
+        return sb.toString();
+    }
 }
diff --git a/src/main/java/org/owasp/esapi/PropNames.java b/src/main/java/org/owasp/esapi/PropNames.java
new file mode 100644
index 0000000..59deb89
--- /dev/null
+++ b/src/main/java/org/owasp/esapi/PropNames.java
@@ -0,0 +1,201 @@
+// TODO: Discuss: Should the name of this be PropConstants or PropertConstants
+//                since there are some property values included here? I don't
+//                really like that as much as PropNames, but I could live with
+//                it.
+/*
+ * OWASP Enterprise Security API (ESAPI)
+ *
+ * This file is part of the Open Web Application Security Project (OWASP)
+ * Enterprise Security API (ESAPI) project. For details, please see
+ * https://owasp.org/www-project-enterprise-security-api/.
+ *
+ * Copyright (c) 2022 - The OWASP Foundation
+ *
+ * The ESAPI is published by OWASP under the BSD license. You should read and accept the
+ * LICENSE before you use, modify, and/or redistribute this software.
+ *
+ */
+package org.owasp.esapi;
+
+
+/**
+ * This non-constructable class of public constants defines all the property names used in {@code ESAPI.properties} as
+ * well as some of the default property values for some of those properties. This class is not intended
+ * to be extended or instantiated. Technically, an interface would have worked here, but we
+ * also wanted to be able to prevent 'implements PropNames', which really does not make much
+ * sense since no specific behavior is promised here. Another alternative would have
+ * been to place all of these in the {@code org.owasp.esapi.SecurityConfiguration} interface,
+ * but that interface is already overly bloated. Hence this was decided as a compromise.
+ * </p><p>
+ * Note that the constants herein were originally all defined within
+ * {@code org.owasp.esapi.reference.DefaultSecurityConfiguration}, but those
+ * values are now marked deprecated and they are candidates for removal 2 years
+ * from the date of this release.
+ * </p><p>
+ * Mostly this is intended to prevent having to hard-code property names all
+ * over the place in implementation-level classes (e.g.,
+ * {@code org.owasp.esapi.reference.DefaultSecurityConfiguration}).
+ * It is suggested that this file be used as a 'static import';
+ * e.g.,
+ * <pre>
+ *      import static org.owasp.esapi.PropNames.*;                      // Import all properties, en masse
+ * or
+ *      import static org.owasp.esapi.PropNames.SomeSpecificPropName;   // Import specific property name
+ * </pre>
+ * This can be extremely useful when used with methods such as
+ * {@code SecurityConfiguration.getIntProp(String propName)},
+ * {@code SecurityConfiguration.getBooleanProp(String propName)},
+ * {@code SecurityConfiguration.getStringProp(String propName)}, etc.
+ *
+ * @author Kevin W. Wall (kevin.w.wall .at. gmail.com)
+ * @since 2.4.1.0
+ * @see org.owasp.esapi.reference.DefaultSecurityConfiguration
+ */
+
+public final class PropNames {
+
+    public static final String REMEMBER_TOKEN_DURATION                                                          = "Authenticator.RememberTokenDuration";
+    public static final String IDLE_TIMEOUT_DURATION                                                            = "Authenticator.IdleTimeoutDuration";
+    public static final String ABSOLUTE_TIMEOUT_DURATION                                                        = "Authenticator.AbsoluteTimeoutDuration";
+    public static final String ALLOWED_LOGIN_ATTEMPTS                                                           = "Authenticator.AllowedLoginAttempts";
+    public static final String USERNAME_PARAMETER_NAME                                                          = "Authenticator.UsernameParameterName";
+    public static final String PASSWORD_PARAMETER_NAME                                                          = "Authenticator.PasswordParameterName";
+    public static final String MAX_OLD_PASSWORD_HASHES                                                          = "Authenticator.MaxOldPasswordHashes";
+
+    public static final String ALLOW_MULTIPLE_ENCODING                                                          = "Encoder.AllowMultipleEncoding";
+    public static final String ALLOW_MIXED_ENCODING                                                             = "Encoder.AllowMixedEncoding";
+    public static final String CANONICALIZATION_CODECS                                                          = "Encoder.DefaultCodecList";
+
+    public static final String DISABLE_INTRUSION_DETECTION                                                      = "IntrusionDetector.Disable";
+
+    public static final String MASTER_KEY                                                                       = "Encryptor.MasterKey";
+    public static final String MASTER_SALT                                                                      = "Encryptor.MasterSalt";
+    public static final String KEY_LENGTH                                                                       = "Encryptor.EncryptionKeyLength";
+    public static final String ENCRYPTION_ALGORITHM                                                             = "Encryptor.EncryptionAlgorithm";
+    public static final String HASH_ALGORITHM                                                                   = "Encryptor.HashAlgorithm";
+    public static final String HASH_ITERATIONS                                                                  = "Encryptor.HashIterations";
+    public static final String CHARACTER_ENCODING                                                               = "Encryptor.CharacterEncoding";
+    public static final String RANDOM_ALGORITHM                                                                 = "Encryptor.RandomAlgorithm";
+    public static final String DIGITAL_SIGNATURE_ALGORITHM                                                      = "Encryptor.DigitalSignatureAlgorithm";
+    public static final String DIGITAL_SIGNATURE_KEY_LENGTH                                                     = "Encryptor.DigitalSignatureKeyLength";
+    public static final String PREFERRED_JCE_PROVIDER                                                           = "Encryptor.PreferredJCEProvider";
+    public static final String CIPHER_TRANSFORMATION_IMPLEMENTATION                                             = "Encryptor.CipherTransformation";
+    public static final String CIPHERTEXT_USE_MAC                                                               = "Encryptor.CipherText.useMAC";
+    public static final String PLAINTEXT_OVERWRITE                                                              = "Encryptor.PlainText.overwrite";
+    public static final String IV_TYPE                                                                          = "Encryptor.ChooseIVMethod";   // Will be removed in future release.
+    public static final String COMBINED_CIPHER_MODES                                                            = "Encryptor.cipher_modes.combined_modes";
+    public static final String ADDITIONAL_ALLOWED_CIPHER_MODES                                                  = "Encryptor.cipher_modes.additional_allowed";
+    public static final String KDF_PRF_ALG                                                                      = "Encryptor.KDF.PRF";
+    public static final String PRINT_PROPERTIES_WHEN_LOADED                                                     = "ESAPI.printProperties";
+
+    public static final String WORKING_DIRECTORY                                                                = "Executor.WorkingDirectory";
+    public static final String APPROVED_EXECUTABLES                                                             = "Executor.ApprovedExecutables";
+
+    public static final String FORCE_HTTPONLYSESSION                                                            = "HttpUtilities.ForceHttpOnlySession";
+    public static final String FORCE_SECURESESSION                                                              = "HttpUtilities.SecureSession";
+    public static final String FORCE_HTTPONLYCOOKIES                                                            = "HttpUtilities.ForceHttpOnlyCookies";
+    public static final String FORCE_SECURECOOKIES                                                              = "HttpUtilities.ForceSecureCookies";
+    public static final String MAX_HTTP_HEADER_SIZE                                                             = "HttpUtilities.MaxHeaderSize";
+    public static final String UPLOAD_DIRECTORY                                                                 = "HttpUtilities.UploadDir";
+    public static final String UPLOAD_TEMP_DIRECTORY                                                            = "HttpUtilities.UploadTempDir";
+    public static final String APPROVED_UPLOAD_EXTENSIONS                                                       = "HttpUtilities.ApprovedUploadExtensions";
+    public static final String MAX_UPLOAD_FILE_BYTES                                                            = "HttpUtilities.MaxUploadFileBytes";
+    public static final String RESPONSE_CONTENT_TYPE                                                            = "HttpUtilities.ResponseContentType";
+    public static final String HTTP_SESSION_ID_NAME                                                             = "HttpUtilities.HttpSessionIdName";
+
+    public static final String APPLICATION_NAME                                                                 = "Logger.ApplicationName";
+    public static final String LOG_USER_INFO                                                                    = "Logger.UserInfo";
+    public static final String LOG_CLIENT_INFO                                                                  = "Logger.ClientInfo";
+    public static final String LOG_ENCODING_REQUIRED                                                            = "Logger.LogEncodingRequired";
+    public static final String LOG_APPLICATION_NAME                                                             = "Logger.LogApplicationName";
+    public static final String LOG_SERVER_IP                                                                    = "Logger.LogServerIP";
+
+    public static final String VALIDATION_PROPERTIES                                                            = "Validator.ConfigurationFile";
+    public static final String VALIDATION_PROPERTIES_MULTIVALUED                                                = "Validator.ConfigurationFile.MultiValued";
+    public static final String ACCEPT_LENIENT_DATES                                                             = "Validator.AcceptLenientDates";
+    public static final String VALIDATOR_HTML_VALIDATION_ACTION                                                 = "Validator.HtmlValidationAction";
+    public static final String VALIDATOR_HTML_VALIDATION_CONFIGURATION_FILE                                     = "Validator.HtmlValidationConfigurationFile";
+
+    /**
+     * Special {@code java.lang.System} property that, if set to {@code true}, will
+     * disable logging from {@code DefaultSecurityConfiguration.logToStdout()}
+     * methods, which is called from various {@code logSpecial()} methods.
+     *
+     * @see org.owasp.esapi.reference.DefaultSecurityConfiguration#logToStdout(String msg, Throwable t)
+     */
+    public static final String DISCARD_LOGSPECIAL                                                               = "org.owasp.esapi.logSpecial.discard";
+
+    /*
+     * Implementation Keys
+     */
+    public static final String LOG_IMPLEMENTATION                                                               = "ESAPI.Logger";
+    public static final String AUTHENTICATION_IMPLEMENTATION                                                    = "ESAPI.Authenticator";
+    public static final String ENCODER_IMPLEMENTATION                                                           = "ESAPI.Encoder";
+    public static final String ACCESS_CONTROL_IMPLEMENTATION                                                    = "ESAPI.AccessControl";
+    public static final String ENCRYPTION_IMPLEMENTATION                                                        = "ESAPI.Encryptor";
+    public static final String INTRUSION_DETECTION_IMPLEMENTATION                                               = "ESAPI.IntrusionDetector";
+    public static final String RANDOMIZER_IMPLEMENTATION                                                        = "ESAPI.Randomizer";
+    public static final String EXECUTOR_IMPLEMENTATION                                                          = "ESAPI.Executor";
+    public static final String VALIDATOR_IMPLEMENTATION                                                         = "ESAPI.Validator";
+    public static final String HTTP_UTILITIES_IMPLEMENTATION                                                    = "ESAPI.HTTPUtilities";
+
+
+    //////////////////////////////////////////////////////////////////////////////
+    //                                                                          //
+    // These are not really property names, but the shouldn't really be in an   //
+    // implementation class that we want to only deal with via the              //
+    // SecurityConfiguration interface.                                         //
+    //                                                                          //
+    //////////////////////////////////////////////////////////////////////////////
+
+
+    /*
+     * These are default implementation classes.
+     */
+    public static final String DEFAULT_LOG_IMPLEMENTATION                                                       = "org.owasp.esapi.logging.java.JavaLogFactory";
+    public static final String DEFAULT_AUTHENTICATION_IMPLEMENTATION                                            = "org.owasp.esapi.reference.FileBasedAuthenticator";
+    public static final String DEFAULT_ENCODER_IMPLEMENTATION                                                   = "org.owasp.esapi.reference.DefaultEncoder";
+    public static final String DEFAULT_ACCESS_CONTROL_IMPLEMENTATION                                            = "org.owasp.esapi.reference.DefaultAccessController";
+    public static final String DEFAULT_ENCRYPTION_IMPLEMENTATION                                                = "org.owasp.esapi.reference.crypto.JavaEncryptor";
+    public static final String DEFAULT_INTRUSION_DETECTION_IMPLEMENTATION                                       = "org.owasp.esapi.reference.DefaultIntrusionDetector";
+    public static final String DEFAULT_RANDOMIZER_IMPLEMENTATION                                                = "org.owasp.esapi.reference.DefaultRandomizer";
+    public static final String DEFAULT_EXECUTOR_IMPLEMENTATION                                                  = "org.owasp.esapi.reference.DefaultExecutor";
+    public static final String DEFAULT_HTTP_UTILITIES_IMPLEMENTATION                                            = "org.owasp.esapi.reference.DefaultHTTPUtilities";
+    public static final String DEFAULT_VALIDATOR_IMPLEMENTATION                                                 = "org.owasp.esapi.reference.DefaultValidator";
+
+    /** The name of the ESAPI property file */
+    public static final String DEFAULT_RESOURCE_FILE                                                            = "ESAPI.properties";
+
+    //
+    // Private CTOR to prevent creation of PropName objects. We wouldn't need
+    // this if this were an interface, nor would we need the explict 'public static final'.
+    //
+    private PropNames() {
+        throw new AssertionError("Thought you'd cheat using reflection or JNI, huh? :)");
+    }
+
+
+    /** Enum used with the search paths used to locate an
+     * {@code ESAPI.properties} and/or a {@code validation.properties}
+     * file.
+     */
+    public enum DefaultSearchPath {
+
+        RESOURCE_DIRECTORY("resourceDirectory/"),
+        SRC_MAIN_RESOURCES("src/main/resources/"),
+        ROOT(""),
+        DOT_ESAPI(".esapi/"),
+        ESAPI("esapi/"),
+        RESOURCES("resources/");
+
+        private final String path;
+
+        private DefaultSearchPath(String s){
+            this.path = s;
+        }
+
+        public String value(){
+            return path;
+        }
+    }
+}
diff --git a/src/main/java/org/owasp/esapi/Randomizer.java b/src/main/java/org/owasp/esapi/Randomizer.java
index e1a0b81..bef0c4a 100644
--- a/src/main/java/org/owasp/esapi/Randomizer.java
+++ b/src/main/java/org/owasp/esapi/Randomizer.java
@@ -30,116 +30,116 @@ import org.owasp.esapi.errors.EncryptionException;
  */
 public interface Randomizer {
 
-	/**
-	 * Gets a random string of a desired length and character set.  The use of java.security.SecureRandom
-	 * is recommended because it provides a cryptographically strong pseudo-random number generator.
-	 * If SecureRandom is not used, the pseudo-random number generator used should comply with the
-	 * statistical random number generator tests specified in <a href="http://csrc.nist.gov/cryptval/140-2.htm">
-	 * FIPS 140-2, Security Requirements for Cryptographic Modules</a>, section 4.9.1.
-	 *
-	 * @param length
-	 * 		the length of the string
-	 * @param characterSet
-	 * 		the set of characters to include in the created random string
-	 *
-	 * @return
-	 * 		the random string of the desired length and character set
-	 */
-	String getRandomString(int length, char[] characterSet);
+    /**
+     * Gets a random string of a desired length and character set.  The use of java.security.SecureRandom
+     * is recommended because it provides a cryptographically strong pseudo-random number generator.
+     * If SecureRandom is not used, the pseudo-random number generator used should comply with the
+     * statistical random number generator tests specified in <a href="http://csrc.nist.gov/cryptval/140-2.htm">
+     * FIPS 140-2, Security Requirements for Cryptographic Modules</a>, section 4.9.1.
+     *
+     * @param length
+     *         the length of the string
+     * @param characterSet
+     *         the set of characters to include in the created random string
+     *
+     * @return
+     *         the random string of the desired length and character set
+     */
+    String getRandomString(int length, char[] characterSet);
 
-	/**
-	 * Returns a random boolean.  The use of java.security.SecureRandom
-	 * is recommended because it provides a cryptographically strong pseudo-random number generator.
-	 * If SecureRandom is not used, the pseudo-random number generator used should comply with the
-	 * statistical random number generator tests specified in <a href="http://csrc.nist.gov/cryptval/140-2.htm">
-	 * FIPS 140-2, Security Requirements for Cryptographic Modules</a>, section 4.9.1.
-	 *
-	 * @return
-	 * 		true or false, randomly
-	 */
-	boolean getRandomBoolean();
+    /**
+     * Returns a random boolean.  The use of java.security.SecureRandom
+     * is recommended because it provides a cryptographically strong pseudo-random number generator.
+     * If SecureRandom is not used, the pseudo-random number generator used should comply with the
+     * statistical random number generator tests specified in <a href="http://csrc.nist.gov/cryptval/140-2.htm">
+     * FIPS 140-2, Security Requirements for Cryptographic Modules</a>, section 4.9.1.
+     *
+     * @return
+     *         true or false, randomly
+     */
+    boolean getRandomBoolean();
 
-	/**
-	 * Gets the random integer in the range of [min, max). The use of java.security.SecureRandom
-	 * is recommended because it provides a cryptographically strong pseudo-random number generator.
-	 * If SecureRandom is not used, the pseudo-random number generator used should comply with the
-	 * statistical random number generator tests specified in <a href="http://csrc.nist.gov/cryptval/140-2.htm">
-	 * FIPS 140-2, Security Requirements for Cryptographic Modules</a>, section 4.9.1.
-	 *
-	 * @param min
-	 * 		the minimum integer that will be returned, inclusive
-	 * @param max
-	 * 		the maximum integer that will be returned, exclusive
-	 *
-	 * @return
-	 * 		the random integer
-	 */
-	int getRandomInteger(int min, int max);
+    /**
+     * Gets the random integer in the range of [min, max). The use of java.security.SecureRandom
+     * is recommended because it provides a cryptographically strong pseudo-random number generator.
+     * If SecureRandom is not used, the pseudo-random number generator used should comply with the
+     * statistical random number generator tests specified in <a href="http://csrc.nist.gov/cryptval/140-2.htm">
+     * FIPS 140-2, Security Requirements for Cryptographic Modules</a>, section 4.9.1.
+     *
+     * @param min
+     *         the minimum integer that will be returned, inclusive
+     * @param max
+     *         the maximum integer that will be returned, exclusive
+     *
+     * @return
+     *         the random integer
+     */
+    int getRandomInteger(int min, int max);
 
 
-	/**
-	 * Gets the random long. The use of java.security.SecureRandom
-	 * is recommended because it provides a cryptographically strong pseudo-random number generator.
-	 * If SecureRandom is not used, the pseudo-random number generator used should comply with the
-	 * statistical random number generator tests specified in <a href="http://csrc.nist.gov/cryptval/140-2.htm">
-	 * FIPS 140-2, Security Requirements for Cryptographic Modules</a>, section 4.9.1.
-	 *
-	 * @return
-	 * 		the random long
-	 */
+    /**
+     * Gets the random long. The use of java.security.SecureRandom
+     * is recommended because it provides a cryptographically strong pseudo-random number generator.
+     * If SecureRandom is not used, the pseudo-random number generator used should comply with the
+     * statistical random number generator tests specified in <a href="http://csrc.nist.gov/cryptval/140-2.htm">
+     * FIPS 140-2, Security Requirements for Cryptographic Modules</a>, section 4.9.1.
+     *
+     * @return
+     *         the random long
+     */
     long getRandomLong();
 
 
     /**
      * Returns an unguessable random filename with the specified extension.  This method could call
-     * getRandomString(length, charset) from this Class with the desired length and alphanumerics as the charset 
+     * getRandomString(length, charset) from this Class with the desired length and alphanumerics as the charset
      * then merely append "." + extension.
      *
      * @param extension
-     * 		extension to add to the random filename
+     *         extension to add to the random filename
      *
      * @return
-     * 		a random unguessable filename ending with the specified extension
+     *         a random unguessable filename ending with the specified extension
      */
     String getRandomFilename( String extension );
 
 
-	/**
-	 * Gets the random real in the range of [min, max].  The use of java.security.SecureRandom
-	 * is recommended because it provides a cryptographically strong pseudo-random number generator.
-	 * If SecureRandom is not used, the pseudo-random number generator used should comply with the
-	 * statistical random number generator tests specified in <a href="http://csrc.nist.gov/cryptval/140-2.htm">
-	 * FIPS 140-2, Security Requirements for Cryptographic Modules</a>, section 4.9.1.
-	 *
-	 * @param min
-	 * 		the minimum real number that will be returned, inclusive
-	 * @param max
-	 * 		the maximum real number that will be returned, inclusive
-	 *
-	 * @return
-	 * 		the random real
-	 */
-	float getRandomReal(float min, float max);
+    /**
+     * Gets the random real in the range of [min, max].  The use of java.security.SecureRandom
+     * is recommended because it provides a cryptographically strong pseudo-random number generator.
+     * If SecureRandom is not used, the pseudo-random number generator used should comply with the
+     * statistical random number generator tests specified in <a href="http://csrc.nist.gov/cryptval/140-2.htm">
+     * FIPS 140-2, Security Requirements for Cryptographic Modules</a>, section 4.9.1.
+     *
+     * @param min
+     *         the minimum real number that will be returned, inclusive
+     * @param max
+     *         the maximum real number that will be returned, inclusive
+     *
+     * @return
+     *         the random real
+     */
+    float getRandomReal(float min, float max);
 
     /**
      * Generates a random GUID.  This method could use a hash of random Strings, the current time,
-     * and any other random data available.  The format is a well-defined sequence of 32 hex digits 
+     * and any other random data available.  The format is a well-defined sequence of 32 hex digits
      * grouped into chunks of 8-4-4-4-12.
      * <p>
      * For more information including algorithms used to create <tt>UUID</tt>s,
      * see the Internet-Draft <a href="http://www.ietf.org/internet-drafts/draft-mealling-uuid-urn-03.txt">UUIDs and GUIDs</a>
      * or the standards body definition at <a href="http://www.iso.ch/cate/d2229.html">ISO/IEC 11578:1996</a>.
      * @return
-     * 		the GUID
+     *         the GUID
      *
      * @throws
-     * 		EncryptionException if hashing or encryption fails
+     *         EncryptionException if hashing or encryption fails
      */
     String getRandomGUID() throws EncryptionException;
 
     /**
      * Generates a specified number of random bytes.
-     * @param n	The requested number of random bytes.
+     * @param n    The requested number of random bytes.
      * @return The {@code n} random bytes are returned.
      */
     byte[] getRandomBytes(int n);
diff --git a/src/main/java/org/owasp/esapi/SafeFile.java b/src/main/java/org/owasp/esapi/SafeFile.java
index 7df86bb..e048e94 100644
--- a/src/main/java/org/owasp/esapi/SafeFile.java
+++ b/src/main/java/org/owasp/esapi/SafeFile.java
@@ -1,15 +1,15 @@
 /**
  * OWASP Enterprise Security API (ESAPI)
- * 
+ *
  * This file is part of the Open Web Application Security Project (OWASP)
  * Enterprise Security API (ESAPI) project. For details, please see
  * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
  *
  * Copyright (c) 2008 - The OWASP Foundation
- * 
+ *
  * The ESAPI is published by OWASP under the BSD license. You should read and accept the
  * LICENSE before you use, modify, and/or redistribute this software.
- * 
+ *
  * @author Arshan Dabirsiaghi <a href="http://www.aspectsecurity.com">Aspect Security</a>
  * @created 2008
  */
@@ -30,78 +30,78 @@ import org.owasp.esapi.errors.ValidationException;
  */
 public class SafeFile extends File {
 
-	private static final long serialVersionUID = 1L;
-	private static final Pattern PERCENTS_PAT = Pattern.compile("(%)([0-9a-fA-F])([0-9a-fA-F])");	
-	private static final Pattern FILE_BLACKLIST_PAT = Pattern.compile("([\\\\/:*?<>|^])");	
-	private static final Pattern DIR_BLACKLIST_PAT = Pattern.compile("([*?<>|^])");
-
-	public SafeFile(String path) throws ValidationException {
-		super(path);
-		doDirCheck(this.getParent());
-		doFileCheck(this.getName());
-	}
-
-	public SafeFile(String parent, String child) throws ValidationException {
-		super(parent, child);
-		doDirCheck(this.getParent());
-		doFileCheck(this.getName());
-	}
-
-	public SafeFile(File parent, String child) throws ValidationException {
-		super(parent, child);
-		doDirCheck(this.getParent());
-		doFileCheck(this.getName());
-	}
-
-	public SafeFile(URI uri) throws ValidationException {
-		super(uri);
-		doDirCheck(this.getParent());
-		doFileCheck(this.getName());
-	}
-
-	
-	private void doDirCheck(String path) throws ValidationException {
-		Matcher m1 = DIR_BLACKLIST_PAT.matcher( path );
-		if ( null != m1 && m1.find() ) {
-			throw new ValidationException( "Invalid directory", "Directory path (" + path + ") contains illegal character: " + m1.group() );
-		}
-
-		Matcher m2 = PERCENTS_PAT.matcher( path );
-		if (null != m2 &&  m2.find() ) {
-			throw new ValidationException( "Invalid directory", "Directory path (" + path + ") contains encoded characters: " + m2.group() );
-		}
-		
-		int ch = containsUnprintableCharacters(path);
-		if (ch != -1) {
-			throw new ValidationException("Invalid directory", "Directory path (" + path + ") contains unprintable character: " + ch);
-		}
-	}
-	
-	private void doFileCheck(String path) throws ValidationException {
-		Matcher m1 = FILE_BLACKLIST_PAT.matcher( path );
-		if ( m1.find() ) {
-			throw new ValidationException( "Invalid directory", "Directory path (" + path + ") contains illegal character: " + m1.group() );
-		}
-
-		Matcher m2 = PERCENTS_PAT.matcher( path );
-		if ( m2.find() ) {
-			throw new ValidationException( "Invalid file", "File path (" + path + ") contains encoded characters: " + m2.group() );
-		}
-		
-		int ch = containsUnprintableCharacters(path);
-		if (ch != -1) {
-			throw new ValidationException("Invalid file", "File path (" + path + ") contains unprintable character: " + ch);
-		}
-	}
-
-	private int containsUnprintableCharacters(String s) {
-		for (int i = 0; i < s.length(); i++) {
-			char ch = s.charAt(i);
-			if (((int) ch) < 32 || ((int) ch) > 126) {
-				return (int) ch;
-			}
-		}
-		return -1;
-	}
+    private static final long serialVersionUID = 1L;
+    private static final Pattern PERCENTS_PAT = Pattern.compile("(%)([0-9a-fA-F])([0-9a-fA-F])");
+    private static final Pattern FILE_BLACKLIST_PAT = Pattern.compile("([\\\\/:*?<>|^])");
+    private static final Pattern DIR_BLACKLIST_PAT = Pattern.compile("([*?<>|^])");
+
+    public SafeFile(String path) throws ValidationException {
+        super(path);
+        doDirCheck(this.getParent());
+        doFileCheck(this.getName());
+    }
+
+    public SafeFile(String parent, String child) throws ValidationException {
+        super(parent, child);
+        doDirCheck(this.getParent());
+        doFileCheck(this.getName());
+    }
+
+    public SafeFile(File parent, String child) throws ValidationException {
+        super(parent, child);
+        doDirCheck(this.getParent());
+        doFileCheck(this.getName());
+    }
+
+    public SafeFile(URI uri) throws ValidationException {
+        super(uri);
+        doDirCheck(this.getParent());
+        doFileCheck(this.getName());
+    }
+
+
+    private void doDirCheck(String path) throws ValidationException {
+        Matcher m1 = DIR_BLACKLIST_PAT.matcher( path );
+        if ( null != m1 && m1.find() ) {
+            throw new ValidationException( "Invalid directory", "Directory path (" + path + ") contains illegal character: " + m1.group() );
+        }
+
+        Matcher m2 = PERCENTS_PAT.matcher( path );
+        if (null != m2 &&  m2.find() ) {
+            throw new ValidationException( "Invalid directory", "Directory path (" + path + ") contains encoded characters: " + m2.group() );
+        }
+
+        int ch = containsUnprintableCharacters(path);
+        if (ch != -1) {
+            throw new ValidationException("Invalid directory", "Directory path (" + path + ") contains unprintable character: " + ch);
+        }
+    }
+
+    private void doFileCheck(String path) throws ValidationException {
+        Matcher m1 = FILE_BLACKLIST_PAT.matcher( path );
+        if ( m1.find() ) {
+            throw new ValidationException( "Invalid directory", "Directory path (" + path + ") contains illegal character: " + m1.group() );
+        }
+
+        Matcher m2 = PERCENTS_PAT.matcher( path );
+        if ( m2.find() ) {
+            throw new ValidationException( "Invalid file", "File path (" + path + ") contains encoded characters: " + m2.group() );
+        }
+
+        int ch = containsUnprintableCharacters(path);
+        if (ch != -1) {
+            throw new ValidationException("Invalid file", "File path (" + path + ") contains unprintable character: " + ch);
+        }
+    }
+
+    private int containsUnprintableCharacters(String s) {
+        for (int i = 0; i < s.length(); i++) {
+            char ch = s.charAt(i);
+            if (((int) ch) < 32 || ((int) ch) > 126) {
+                return (int) ch;
+            }
+        }
+        return -1;
+    }
 
 }
diff --git a/src/main/java/org/owasp/esapi/SecurityConfiguration.java b/src/main/java/org/owasp/esapi/SecurityConfiguration.java
index 27c4af9..564206d 100644
--- a/src/main/java/org/owasp/esapi/SecurityConfiguration.java
+++ b/src/main/java/org/owasp/esapi/SecurityConfiguration.java
@@ -1,15 +1,15 @@
 /**
  * OWASP Enterprise Security API (ESAPI)
- * 
+ *
  * This file is part of the Open Web Application Security Project (OWASP)
  * Enterprise Security API (ESAPI) project. For details, please see
  * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
  *
  * Copyright (c) 2007 - The OWASP Foundation
- * 
+ *
  * The ESAPI is published by OWASP under the BSD license. You should read and accept the
  * LICENSE before you use, modify, and/or redistribute this software.
- * 
+ *
  * @author Mike Fauzy <a href="http://www.aspectsecurity.com">Aspect Security</a>
  * @author Jeff Williams <a href="http://www.aspectsecurity.com">Aspect Security</a>
  * @created 2007
@@ -45,276 +45,276 @@ import java.util.regex.Pattern;
  * <br><br>
  * The ESAPI reference implementation (DefaultSecurityConfiguration.java) does
  * <i>not</i> encrypt its properties file.
- * 
+ *
  * @author Jeff Williams (jeff.williams .at. aspectsecurity.com) <a
  *         href="http://www.aspectsecurity.com">Aspect Security</a>
  * @since June 1, 2007
  */
 public interface SecurityConfiguration extends EsapiPropertyLoader {
 
-	/**
-	 * Gets the application name, used for logging
-	 * 
-	 * @return the name of the current application
+    /**
+     * Gets the application name, used for logging
+     *
+     * @return the name of the current application
      * @deprecated Use SecurityConfiguration.getStringProp("appropriate_esapi_prop_name") instead.
-	 */
-	@Deprecated
-	String getApplicationName();
-	
-	/**
-	 * Returns the fully qualified classname of the ESAPI Logging implementation.
+     */
+    @Deprecated
+    String getApplicationName();
+
+    /**
+     * Returns the fully qualified classname of the ESAPI Logging implementation.
      * @deprecated Use SecurityConfiguration.getStringProp("appropriate_esapi_prop_name") instead.
-	 */
-	@Deprecated
-	String getLogImplementation();
-	
-	/**
-	 * Returns the fully qualified classname of the ESAPI Authentication implementation.
+     */
+    @Deprecated
+    String getLogImplementation();
+
+    /**
+     * Returns the fully qualified classname of the ESAPI Authentication implementation.
      * @deprecated Use SecurityConfiguration.getStringProp("appropriate_esapi_prop_name") instead.
-	 */
-	@Deprecated
-	String getAuthenticationImplementation();
-	
-	/**
-	 * Returns the fully qualified classname of the ESAPI Encoder implementation.
+     */
+    @Deprecated
+    String getAuthenticationImplementation();
+
+    /**
+     * Returns the fully qualified classname of the ESAPI Encoder implementation.
      * @deprecated Use SecurityConfiguration.getStringProp("appropriate_esapi_prop_name") instead.
-	 */
-	@Deprecated
-	String getEncoderImplementation();
-	
-	/**
-	 * Returns the fully qualified classname of the ESAPI Access Control implementation.
+     */
+    @Deprecated
+    String getEncoderImplementation();
+
+    /**
+     * Returns the fully qualified classname of the ESAPI Access Control implementation.
      * @deprecated Use SecurityConfiguration.getStringProp("appropriate_esapi_prop_name") instead.
-	 */
-	@Deprecated
-	String getAccessControlImplementation();
-	
-	/**
-	 * Returns the fully qualified classname of the ESAPI Intrusion Detection implementation.
+     */
+    @Deprecated
+    String getAccessControlImplementation();
+
+    /**
+     * Returns the fully qualified classname of the ESAPI Intrusion Detection implementation.
      * @deprecated Use SecurityConfiguration.getStringProp("appropriate_esapi_prop_name") instead.
-	 */
-	@Deprecated
-	String getIntrusionDetectionImplementation();
-	
-	/**
-	 * Returns the fully qualified classname of the ESAPI Randomizer implementation.
+     */
+    @Deprecated
+    String getIntrusionDetectionImplementation();
+
+    /**
+     * Returns the fully qualified classname of the ESAPI Randomizer implementation.
      * @deprecated Use SecurityConfiguration.getStringProp("appropriate_esapi_prop_name") instead.
-	 */
-	@Deprecated
-	String getRandomizerImplementation();
-	
-	/**
-	 * Returns the fully qualified classname of the ESAPI Encryption implementation.
+     */
+    @Deprecated
+    String getRandomizerImplementation();
+
+    /**
+     * Returns the fully qualified classname of the ESAPI Encryption implementation.
      * @deprecated Use SecurityConfiguration.getStringProp("appropriate_esapi_prop_name") instead.
-	 */
-	@Deprecated
-	String getEncryptionImplementation();
-	
-	/**
-	 * Returns the fully qualified classname of the ESAPI Validation implementation.
+     */
+    @Deprecated
+    String getEncryptionImplementation();
+
+    /**
+     * Returns the fully qualified classname of the ESAPI Validation implementation.
      * @deprecated Use SecurityConfiguration.getStringProp("appropriate_esapi_prop_name") instead.
-	 */
-	@Deprecated
-	String getValidationImplementation();
-	
-	/**
-	 * Returns the validation pattern for a particular type
-	 * @param typeName
-	 * @return the validation pattern
-	 */
+     */
+    @Deprecated
+    String getValidationImplementation();
+
+    /**
+     * Returns the validation pattern for a particular type
+     * @param typeName
+     * @return the validation pattern
+     */
     Pattern getValidationPattern( String typeName );
-    
+
     /**
      * Determines whether ESAPI will accept "lenient" dates when attempt
      * to parse dates. Controlled by ESAPI property
      * {@code Validator.AcceptLenientDates}, which defaults to {@code false}
      * if unset.
-     * 
+     *
      * @return True if lenient dates are accepted; false otherwise.
      * @see java.text.DateFormat#setLenient(boolean)
      * @deprecated Use SecurityConfiguration.getBooleanProp("appropriate_esapi_prop_name") instead.
      */
-	@Deprecated
+    @Deprecated
     boolean getLenientDatesAccepted();
-	
-	/**
-	 * Returns the fully qualified classname of the ESAPI OS Execution implementation.
+
+    /**
+     * Returns the fully qualified classname of the ESAPI OS Execution implementation.
      * @deprecated Use SecurityConfiguration.getStringProp("appropriate_esapi_prop_name") instead.
-	 */
-	@Deprecated
-	String getExecutorImplementation();
-	
-	/**
-	 * Returns the fully qualified classname of the ESAPI HTTPUtilities implementation.
+     */
+    @Deprecated
+    String getExecutorImplementation();
+
+    /**
+     * Returns the fully qualified classname of the ESAPI HTTPUtilities implementation.
      * @deprecated Use SecurityConfiguration.getStringProp("appropriate_esapi_prop_name") instead.
-	 */
-	@Deprecated
-	String getHTTPUtilitiesImplementation();
-	
-	/**
-	 * Gets the master key. This password is used to encrypt/decrypt other files or types
-	 * of data that need to be protected by your application.
-	 * 
-	 * @return the current master key
+     */
+    @Deprecated
+    String getHTTPUtilitiesImplementation();
+
+    /**
+     * Gets the master key. This password is used to encrypt/decrypt other files or types
+     * of data that need to be protected by your application.
+     *
+     * @return the current master key
      * @deprecated Use SecurityConfiguration.getByteArrayProp("appropriate_esapi_prop_name") instead.
-	 */
-	@Deprecated
-	byte[] getMasterKey();
+     */
+    @Deprecated
+    byte[] getMasterKey();
 
-	/**
+    /**
      * Retrieves the upload directory as specified in the ESAPI.properties file.
      * @return the upload directory
      */
     File getUploadDirectory();
-	
+
     /**
      * Retrieves the temp directory to use when uploading files, as specified in ESAPI.properties.
      * @return the temp directory
      */
     File getUploadTempDirectory();
 
-	/**
-	 * Gets the key length to use in cryptographic operations declared in the ESAPI properties file.
+    /**
+     * Gets the key length to use in cryptographic operations declared in the ESAPI properties file.
      * Note that this corresponds to the ESAPI property <b>Encryptor.EncryptionKeyLength</b> which is
      * considered the <i>default</i> key size that ESAPI will use for symmetric
      * ciphers supporting multiple key sizes. (Note that there is also an <b>Encryptor.MinEncryptionKeyLength</b>,
      * which is the <i>minimum</i> key size (in bits) that ESAPI will support
      * for encryption. (There is no miminimum for decryption.)
-	 * 
-	 * @return the key length (in bits)
+     *
+     * @return the key length (in bits)
      * @deprecated Use SecurityConfiguration.getIntProp("appropriate_esapi_prop_name") instead.
-	 */
-	@Deprecated
+     */
+    @Deprecated
     int getEncryptionKeyLength();
-    
-	/**
-	 * Gets the master salt that is used to salt stored password hashes and any other location 
-	 * where a salt is needed.
-	 * 
-	 * @return the current master salt
+
+    /**
+     * Gets the master salt that is used to salt stored password hashes and any other location
+     * where a salt is needed.
+     *
+     * @return the current master salt
      * @deprecated Use SecurityConfiguration.getByteArrayProp("appropriate_esapi_prop_name") instead.
-	 */
-	@Deprecated
-	byte[] getMasterSalt();
-
-	/**
-	 * Gets the allowed executables to run with the Executor.
-	 * 
-	 * @return a list of the current allowed file extensions
-	 */
-	List<String> getAllowedExecutables();
-
-	/**
-	 * Gets the allowed file extensions for files that are uploaded to this application.
-	 * 
-	 * @return a list of the current allowed file extensions
-	 */
-	List<String> getAllowedFileExtensions();
-
-	/**
-	 * Gets the maximum allowed file upload size.
-	 * 
-	 * @return the current allowed file upload size
+     */
+    @Deprecated
+    byte[] getMasterSalt();
+
+    /**
+     * Gets the allowed executables to run with the Executor.
+     *
+     * @return a list of the current allowed file extensions
+     */
+    List<String> getAllowedExecutables();
+
+    /**
+     * Gets the allowed file extensions for files that are uploaded to this application.
+     *
+     * @return a list of the current allowed file extensions
+     */
+    List<String> getAllowedFileExtensions();
+
+    /**
+     * Gets the maximum allowed file upload size.
+     *
+     * @return the current allowed file upload size
      * @deprecated Use SecurityConfiguration.getIntProp("appropriate_esapi_prop_name") instead.
-	 */
-	@Deprecated
-	int getAllowedFileUploadSize();
-
-	/**
-	 * Gets the name of the password parameter used during user authentication.
-	 * 
-	 * @return the name of the password parameter
+     */
+    @Deprecated
+    int getAllowedFileUploadSize();
+
+    /**
+     * Gets the name of the password parameter used during user authentication.
+     *
+     * @return the name of the password parameter
      * @deprecated Use SecurityConfiguration.getStringProp("appropriate_esapi_prop_name") instead.
-	 */
-	@Deprecated
-	String getPasswordParameterName();
-
-	/**
-	 * Gets the name of the username parameter used during user authentication.
-	 * 
-	 * @return the name of the username parameter
+     */
+    @Deprecated
+    String getPasswordParameterName();
+
+    /**
+     * Gets the name of the username parameter used during user authentication.
+     *
+     * @return the name of the username parameter
      * @deprecated Use SecurityConfiguration.getStringProp("appropriate_esapi_prop_name") instead.
-	 */
-	@Deprecated
-	String getUsernameParameterName();
-
-	/**
-	 * Gets the encryption algorithm used by ESAPI to protect data. This is
-	 * mostly used for compatibility with ESAPI 1.4; ESAPI 2.0 prefers to
-	 * use "cipher transformation" since it supports multiple cipher modes
-	 * and padding schemes.
-	 * 
-	 * @return the current encryption algorithm
+     */
+    @Deprecated
+    String getUsernameParameterName();
+
+    /**
+     * Gets the encryption algorithm used by ESAPI to protect data. This is
+     * mostly used for compatibility with ESAPI 1.4; ESAPI 2.0 prefers to
+     * use "cipher transformation" since it supports multiple cipher modes
+     * and padding schemes.
+     *
+     * @return the current encryption algorithm
      * @deprecated Use SecurityConfiguration.getStringProp("appropriate_esapi_prop_name") instead.
-	 */
-	@Deprecated
-	String getEncryptionAlgorithm();
-
-	/**
-	 * Retrieve the <i>cipher transformation</i>. In general, the cipher transformation
-	 * is a specification of cipher algorithm, cipher mode, and padding scheme
-	 * and in general, is a {@code String} that takes the following form:
-	 * <pre>
-	 * 		<i>cipher_alg</i>/<i>cipher_mode[bits]</i>/<i>padding_scheme</i>
-	 * </pre>
-	 * where <i>cipher_alg</i> is the JCE cipher algorithm (e.g., "DESede"),
-	 * <i>cipher_mode</i> is the cipher mode (e.g., "CBC", "CFB", "CTR", etc.),
-	 * and <i>padding_scheme</i> is the cipher padding scheme (e.g., "NONE" for
-	 * no padding, "PKCS5Padding" for PKCS#5 padding, etc.) and where
-	 * <i>[bits]</i> is an optional bit size that applies to certain cipher
-	 * modes such as {@code CFB} and {@code OFB}. Using modes such as CFB and
-	 * OFB, block ciphers can encrypt data in units smaller than the cipher's
-	 * actual block size. When requesting such a mode, you may optionally
-	 * specify the number of bits to be processed at a time. This generally must
-	 * be an integral multiple of 8-bits so that it can specify a whole number
-	 * of octets. 
-	 * </p><p>
-	 * Examples are:
-	 * <pre>
-	 * 		"AES/ECB/NoPadding"		// Default for ESAPI Java 1.4 (insecure)
-	 * 		"AES/CBC/PKCS5Padding"	// Default for ESAPI Java 2.0
-	 * 		"DESede/OFB32/PKCS5Padding"
-	 * </pre>
-	 * <b>NOTE:</b> Occasionally, in cryptographic literature, you may also
-	 * see the key size (in bits) specified after the cipher algorithm in the
-	 * cipher transformation. Generally, this is done to account for cipher
-	 * algorithms that have variable key sizes. The Blowfish cipher for example
-	 * supports key sizes from 32 to 448 bits. So for Blowfish, you might see
-	 * a cipher transformation something like this:
-	 * <pre>
-	 * 		"Blowfish-192/CFB8/PKCS5Padding"
-	 * </pre>
-	 * in the cryptographic literature. It should be noted that the Java
-	 * Cryptography Extensions (JCE) do not generally support this (at least
-	 * not the reference JCE implementation of "SunJCE"), and therefore it
-	 * should be avoided.
-	 * @return	The cipher transformation.
+     */
+    @Deprecated
+    String getEncryptionAlgorithm();
+
+    /**
+     * Retrieve the <i>cipher transformation</i>. In general, the cipher transformation
+     * is a specification of cipher algorithm, cipher mode, and padding scheme
+     * and in general, is a {@code String} that takes the following form:
+     * <pre>
+     *         <i>cipher_alg</i>/<i>cipher_mode[bits]</i>/<i>padding_scheme</i>
+     * </pre>
+     * where <i>cipher_alg</i> is the JCE cipher algorithm (e.g., "DESede"),
+     * <i>cipher_mode</i> is the cipher mode (e.g., "CBC", "CFB", "CTR", etc.),
+     * and <i>padding_scheme</i> is the cipher padding scheme (e.g., "NONE" for
+     * no padding, "PKCS5Padding" for PKCS#5 padding, etc.) and where
+     * <i>[bits]</i> is an optional bit size that applies to certain cipher
+     * modes such as {@code CFB} and {@code OFB}. Using modes such as CFB and
+     * OFB, block ciphers can encrypt data in units smaller than the cipher's
+     * actual block size. When requesting such a mode, you may optionally
+     * specify the number of bits to be processed at a time. This generally must
+     * be an integral multiple of 8-bits so that it can specify a whole number
+     * of octets.
+     * </p><p>
+     * Examples are:
+     * <pre>
+     *         "AES/ECB/NoPadding"        // Default for ESAPI Java 1.4 (insecure)
+     *         "AES/CBC/PKCS5Padding"    // Default for ESAPI Java 2.0
+     *         "DESede/OFB32/PKCS5Padding"
+     * </pre>
+     * <b>NOTE:</b> Occasionally, in cryptographic literature, you may also
+     * see the key size (in bits) specified after the cipher algorithm in the
+     * cipher transformation. Generally, this is done to account for cipher
+     * algorithms that have variable key sizes. The Blowfish cipher for example
+     * supports key sizes from 32 to 448 bits. So for Blowfish, you might see
+     * a cipher transformation something like this:
+     * <pre>
+     *         "Blowfish-192/CFB8/PKCS5Padding"
+     * </pre>
+     * in the cryptographic literature. It should be noted that the Java
+     * Cryptography Extensions (JCE) do not generally support this (at least
+     * not the reference JCE implementation of "SunJCE"), and therefore it
+     * should be avoided.
+     * @return    The cipher transformation.
      * @deprecated Use SecurityConfiguration.getStringProp("appropriate_esapi_prop_name") instead.
-	 */
-	@Deprecated
+     */
+    @Deprecated
     String getCipherTransformation();
-    
+
     /**
      * Set the cipher transformation. This allows a different cipher transformation
      * to be used without changing the {@code ESAPI.properties} file. For instance
      * you may normally want to use AES/CBC/PKCS5Padding, but have some legacy
      * encryption where you have ciphertext that was encrypted using 3DES.
-     * 
-     * @param cipherXform	The new cipher transformation. See
-     * 						{@link #getCipherTransformation} for format. If
-     * 						{@code null} is passed as the parameter, the cipher
-     * 						transformation will be set to the the default taken
-     * 						from the property {@code Encryptor.CipherTransformation}
-     * 						in the {@code ESAPI.properties} file. <b>BEWARE:</b>
-     * 						there is <b>NO</b> sanity checking here (other than
-     * 						the empty string, and then, only if Java assertions are
-     * 						enabled), so if you set this wrong, you will not get
-     * 						any errors until you later try to use it to encrypt
-     * 						or decrypt data.
-     * @return	The previous cipher transformation is returned for convenience,
-     * 			with the assumption that you may wish to restore it once you have
-     * 			completed the encryption / decryption with the new cipher
-     * 			transformation.
+     *
+     * @param cipherXform    The new cipher transformation. See
+     *                         {@link #getCipherTransformation} for format. If
+     *                         {@code null} is passed as the parameter, the cipher
+     *                         transformation will be set to the the default taken
+     *                         from the property {@code Encryptor.CipherTransformation}
+     *                         in the {@code ESAPI.properties} file. <b>BEWARE:</b>
+     *                         there is <b>NO</b> sanity checking here (other than
+     *                         the empty string, and then, only if Java assertions are
+     *                         enabled), so if you set this wrong, you will not get
+     *                         any errors until you later try to use it to encrypt
+     *                         or decrypt data.
+     * @return    The previous cipher transformation is returned for convenience,
+     *             with the assumption that you may wish to restore it once you have
+     *             completed the encryption / decryption with the new cipher
+     *             transformation.
      * @deprecated To be replaced by new class in ESAPI 2.1, but here if you need it
      *          until then. Details of replacement forthcoming to ESAPI-Dev
      *          list. Most likely to be replaced by a new CTOR for
@@ -340,12 +340,12 @@ public interface SecurityConfiguration extends EsapiPropertyLoader {
      * @see org.owasp.esapi.crypto.SecurityProviderLoader
      * @deprecated Use SecurityConfiguration.getStringProp("appropriate_esapi_prop_name") instead.
      */
-	@Deprecated
+    @Deprecated
     String getPreferredJCEProvider();
-    
+
 // TODO - DISCUSS: Where should this web page (below) go? Maybe with the Javadoc? But where?
-//				   Think it makes more sense as part of the release notes, but OTOH, I
-//				   really don't want to rewrite this as a Wiki page either.
+//                   Think it makes more sense as part of the release notes, but OTOH, I
+//                   really don't want to rewrite this as a Wiki page either.
     /**
      * Determines whether the {@code CipherText} should be used with a Message
      * Authentication Code (MAC). Generally this makes for a more robust cryptographic
@@ -356,10 +356,10 @@ public interface SecurityConfiguration extends EsapiPropertyLoader {
      * <a href="http://www.owasp.org/ESAPI_2.0_ReleaseNotes_CryptoChanges.html">
      * "Why Is OWASP Changing ESAPI Encryption?"</a>.
      * </p>
-     * @return	{@code true} if a you want a MAC to be used, otherwise {@code false}.
+     * @return    {@code true} if a you want a MAC to be used, otherwise {@code false}.
      * @deprecated Use SecurityConfiguration.getBooleanProp("appropriate_esapi_prop_name") instead.
      */
-	@Deprecated
+    @Deprecated
     boolean useMACforCipherText();
 
     /**
@@ -373,13 +373,13 @@ public interface SecurityConfiguration extends EsapiPropertyLoader {
      * Controlled by the property {@code Encryptor.PlainText.overwrite} in
      * the {@code ESAPI.properties} file.
      * </p>
-     * @return	True if it is OK to overwrite the {@code PlainText} objects
-     *			after encrypting, false otherwise.
+     * @return    True if it is OK to overwrite the {@code PlainText} objects
+     *            after encrypting, false otherwise.
      * @deprecated Use SecurityConfiguration.getBooleanProp("appropriate_esapi_prop_name") instead.
      */
-	@Deprecated
+    @Deprecated
     boolean overwritePlainText();
-    
+
     /**
      * Get a string indicating how to compute an Initialization Vector (IV).
      * Currently supported modes are "random" to generate a random IV or
@@ -390,21 +390,20 @@ public interface SecurityConfiguration extends EsapiPropertyLoader {
      * especially for any supported cipher mode that is considered a streaming mode
      * (which is basically anything except CBC for modes that support require an IV).
      * For this reason, 'fixed' has now been removed (it was considered <b>deprecated</b>
-     * since release 2.2.0.0). An <b>ESAPI.properties</b> value of {@Code fixed} for the property
-     * {@Code Encryptor.ChooseIVMethod} will now result in a {@Code ConfigurationException}
+     * since release 2.2.0.0). An <b>ESAPI.properties</b> value of {@code fixed} for the property
+     * {@code Encryptor.ChooseIVMethod} will now result in a {@code ConfigurationException}
      * being thrown.
-     * 
+     *
      * @return A string specifying the IV type. Should be "random". Anything
-     * else should fail with a {@Code ConfigurationException} being thrown.
-     * 
-     * @see #getFixedIV()
+     * else should fail with a {@code ConfigurationException} being thrown.
+     *
      * @deprecated Use SecurityConfiguration.getStringProp("appropriate_esapi_prop_name") instead.
      *             This method will be removed in a future release as it is now moot since
-     *             it can only legitimately have the single value of "random".
+     *             it can <i>only</i> legitimately have the single value of "random".
      */
-	@Deprecated
+    @Deprecated
     String getIVType();
-    
+
     /**
      * Return a {@code List} of strings of combined cipher modes that support
      * <b>both</b> confidentiality and authenticity. These would be preferred
@@ -416,7 +415,7 @@ public interface SecurityConfiguration extends EsapiPropertyLoader {
      * The list is taken from the comma-separated list of cipher modes specified
      * by the ESAPI property
      * {@code Encryptor.cipher_modes.combined_modes}.
-     * 
+     *
      * @return The parsed list of comma-separated cipher modes if the property
      * was specified in {@code ESAPI.properties}; otherwise the empty list is
      * returned.
@@ -432,7 +431,7 @@ public interface SecurityConfiguration extends EsapiPropertyLoader {
      * The list is taken from the comma-separated list of cipher modes specified
      * by the ESAPI property
      * {@code Encryptor.cipher_modes.additional_allowed}.
-     * 
+     *
      * @return The parsed list of comma-separated cipher modes if the property
      * was specified in {@code ESAPI.properties}; otherwise the empty list is
      * returned.
@@ -441,185 +440,185 @@ public interface SecurityConfiguration extends EsapiPropertyLoader {
      */
     List<String> getAdditionalAllowedCipherModes();
 
-	/**
-	 * Gets the hashing algorithm used by ESAPI to hash data.
-	 * 
-	 * @return the current hashing algorithm
+    /**
+     * Gets the hashing algorithm used by ESAPI to hash data.
+     *
+     * @return the current hashing algorithm
      * @deprecated Use SecurityConfiguration.getStringProp("appropriate_esapi_prop_name") instead.
-	 */
-	@Deprecated
-	String getHashAlgorithm();
-
-	/**
-	 * Gets the hash iterations used by ESAPI to hash data.
-	 * 
-	 * @return the current hashing algorithm
+     */
+    @Deprecated
+    String getHashAlgorithm();
+
+    /**
+     * Gets the hash iterations used by ESAPI to hash data.
+     *
+     * @return the current hashing algorithm
      * @deprecated Use SecurityConfiguration.getIntProp("appropriate_esapi_prop_name") instead.
-	 */
-	@Deprecated
-	int getHashIterations();
-
-	/**
-	 * Retrieve the Pseudo Random Function (PRF) used by the ESAPI
-	 * Key Derivation Function (KDF).
-	 * 
-	 * @return	The KDF PRF algorithm name.
+     */
+    @Deprecated
+    int getHashIterations();
+
+    /**
+     * Retrieve the Pseudo Random Function (PRF) used by the ESAPI
+     * Key Derivation Function (KDF).
+     *
+     * @return    The KDF PRF algorithm name.
      * @deprecated Use SecurityConfiguration.getStringProp("appropriate_esapi_prop_name") instead.
-	 */
-	@Deprecated
-	String getKDFPseudoRandomFunction();
-	
-	/**
-	 * Gets the character encoding scheme supported by this application. This is used to set the
-	 * character encoding scheme on requests and responses when setCharacterEncoding() is called
-	 * on SafeRequests and SafeResponses. This scheme is also used for encoding/decoding URLs 
-	 * and any other place where the current encoding scheme needs to be known.
-	 * <br><br>
-	 * Note: This does not get the configured response content type. That is accessed by calling 
-	 * getResponseContentType().
-	 * 
-	 * @return the current character encoding scheme
+     */
+    @Deprecated
+    String getKDFPseudoRandomFunction();
+
+    /**
+     * Gets the character encoding scheme supported by this application. This is used to set the
+     * character encoding scheme on requests and responses when setCharacterEncoding() is called
+     * on SafeRequests and SafeResponses. This scheme is also used for encoding/decoding URLs
+     * and any other place where the current encoding scheme needs to be known.
+     * <br><br>
+     * Note: This does not get the configured response content type. That is accessed by calling
+     * getResponseContentType().
+     *
+     * @return the current character encoding scheme
      * @deprecated Use SecurityConfiguration.getStringProp("appropriate_esapi_prop_name") instead.
-	 */
-	@Deprecated
-	String getCharacterEncoding();
-
-	/**
-	 * Return true if multiple encoding is allowed
-	 *
-	 * @return whether multiple encoding is allowed when canonicalizing data
+     */
+    @Deprecated
+    String getCharacterEncoding();
+
+    /**
+     * Return true if multiple encoding is allowed
+     *
+     * @return whether multiple encoding is allowed when canonicalizing data
      * @deprecated Use SecurityConfiguration.getBooleanProp("appropriate_esapi_prop_name") instead.
-	 */
-	@Deprecated
-	boolean getAllowMultipleEncoding();
-
-	/**
-	 * Return true if mixed encoding is allowed
-	 *
-	 * @return whether mixed encoding is allowed when canonicalizing data
+     */
+    @Deprecated
+    boolean getAllowMultipleEncoding();
+
+    /**
+     * Return true if mixed encoding is allowed
+     *
+     * @return whether mixed encoding is allowed when canonicalizing data
      * @deprecated Use SecurityConfiguration.getBooleanProp("appropriate_esapi_prop_name") instead.
-	 */
-	@Deprecated
-	boolean getAllowMixedEncoding();
-
-	/**
-	 * Returns the List of Codecs to use when canonicalizing data
-	 * 
-	 * @return the codec list
-	 */
-	List<String> getDefaultCanonicalizationCodecs();
-
-	/**
-	 * Gets the digital signature algorithm used by ESAPI to generate and verify signatures.
-	 * 
-	 * @return the current digital signature algorithm
+     */
+    @Deprecated
+    boolean getAllowMixedEncoding();
+
+    /**
+     * Returns the List of Codecs to use when canonicalizing data
+     *
+     * @return the codec list
+     */
+    List<String> getDefaultCanonicalizationCodecs();
+
+    /**
+     * Gets the digital signature algorithm used by ESAPI to generate and verify signatures.
+     *
+     * @return the current digital signature algorithm
      * @deprecated Use SecurityConfiguration.getStringProp("appropriate_esapi_prop_name") instead.
-	 */
-	@Deprecated
-	String getDigitalSignatureAlgorithm();
-
-	/**
-	 * Gets the digital signature key length used by ESAPI to generate and verify signatures.
-	 * 
-	 * @return the current digital signature key length
+     */
+    @Deprecated
+    String getDigitalSignatureAlgorithm();
+
+    /**
+     * Gets the digital signature key length used by ESAPI to generate and verify signatures.
+     *
+     * @return the current digital signature key length
      * @deprecated Use SecurityConfiguration.getIntProp("appropriate_esapi_prop_name") instead.
-	 */
-	@Deprecated
-	int getDigitalSignatureKeyLength();
-		   
-	/**
-	 * Gets the random number generation algorithm used to generate random numbers where needed.
-	 * 
-	 * @return the current random number generation algorithm
+     */
+    @Deprecated
+    int getDigitalSignatureKeyLength();
+
+    /**
+     * Gets the random number generation algorithm used to generate random numbers where needed.
+     *
+     * @return the current random number generation algorithm
      * @deprecated Use SecurityConfiguration.getStringProp("appropriate_esapi_prop_name") instead.
-	 */
-	@Deprecated
-	String getRandomAlgorithm();
-
-	/**
-	 * Gets the number of login attempts allowed before the user's account is locked. If this 
-	 * many failures are detected within the alloted time period, the user's account will be locked.
-	 * 
-	 * @return the number of failed login attempts that cause an account to be locked
+     */
+    @Deprecated
+    String getRandomAlgorithm();
+
+    /**
+     * Gets the number of login attempts allowed before the user's account is locked. If this
+     * many failures are detected within the alloted time period, the user's account will be locked.
+     *
+     * @return the number of failed login attempts that cause an account to be locked
      * @deprecated Use SecurityConfiguration.getIntProp("appropriate_esapi_prop_name") instead.
-	 */
-	@Deprecated
-	int getAllowedLoginAttempts();
-
-	/**
-	 * Gets the maximum number of old password hashes that should be retained. These hashes can 
-	 * be used to ensure that the user doesn't reuse the specified number of previous passwords
-	 * when they change their password.
-	 * 
-	 * @return the number of old hashed passwords to retain
+     */
+    @Deprecated
+    int getAllowedLoginAttempts();
+
+    /**
+     * Gets the maximum number of old password hashes that should be retained. These hashes can
+     * be used to ensure that the user doesn't reuse the specified number of previous passwords
+     * when they change their password.
+     *
+     * @return the number of old hashed passwords to retain
      * @deprecated Use SecurityConfiguration.getIntProp("appropriate_esapi_prop_name") instead.
-	 */
-	@Deprecated
-	int getMaxOldPasswordHashes();
-
-	/**
-	 * Allows for complete disabling of all intrusion detection mechanisms
-	 * 
-	 * @return true if intrusion detection should be disabled
+     */
+    @Deprecated
+    int getMaxOldPasswordHashes();
+
+    /**
+     * Allows for complete disabling of all intrusion detection mechanisms
+     *
+     * @return true if intrusion detection should be disabled
      * @deprecated Use SecurityConfiguration.getBooleanProp("appropriate_esapi_prop_name") instead.
-	 */
-	@Deprecated
-	boolean getDisableIntrusionDetection();
-	
-	/**
-	 * Gets the intrusion detection quota for the specified event.
-	 * 
-	 * @param eventName the name of the event whose quota is desired
-	 * 
-	 * @return the Quota that has been configured for the specified type of event
-	 */
-	Threshold getQuota(String eventName);
-
-	/**
-	 * Gets a file from the resource directory
+     */
+    @Deprecated
+    boolean getDisableIntrusionDetection();
+
+    /**
+     * Gets the intrusion detection quota for the specified event.
+     *
+     * @param eventName the name of the event whose quota is desired
+     *
+     * @return the Quota that has been configured for the specified type of event
+     */
+    Threshold getQuota(String eventName);
+
+    /**
+     * Gets a file from the resource directory
      *
      * @param filename The file name resource.
      * @return A {@code File} object representing the specified file name or null if not found.
      */
     File getResourceFile( String filename );
-    
-	/**
-	 * Returns true if session cookies are required to have HttpOnly flag set.
+
+    /**
+     * Returns true if session cookies are required to have HttpOnly flag set.
      * @deprecated Use SecurityConfiguration.getBooleanProp("appropriate_esapi_prop_name") instead.
      */
-	@Deprecated
+    @Deprecated
     boolean getForceHttpOnlySession() ;
 
-	/**
-	 * Returns true if session cookies are required to have Secure flag set.
+    /**
+     * Returns true if session cookies are required to have Secure flag set.
      * @deprecated Use SecurityConfiguration.getBooleanProp("appropriate_esapi_prop_name") instead.
      */
-	@Deprecated
+    @Deprecated
     boolean getForceSecureSession() ;
 
-	/**
-	 * Returns true if new cookies are required to have HttpOnly flag set.
+    /**
+     * Returns true if new cookies are required to have HttpOnly flag set.
      * @deprecated Use SecurityConfiguration.getBooleanProp("appropriate_esapi_prop_name") instead.
      */
-	@Deprecated
+    @Deprecated
     boolean getForceHttpOnlyCookies() ;
 
-	/**
-	 * Returns true if new cookies are required to have Secure flag set.
+    /**
+     * Returns true if new cookies are required to have Secure flag set.
      * @deprecated Use SecurityConfiguration.getBooleanProp("appropriate_esapi_prop_name") instead.
      */
-	@Deprecated
+    @Deprecated
     boolean getForceSecureCookies() ;
 
-	/**
-	 * Returns the maximum allowable HTTP header size.
+    /**
+     * Returns the maximum allowable HTTP header size.
      * @deprecated Use SecurityConfiguration.getIntProp("appropriate_esapi_prop_name") instead.
-	 */
-	@Deprecated
-	int getMaxHttpHeaderSize() ;
+     */
+    @Deprecated
+    int getMaxHttpHeaderSize() ;
 
-	/**
-	 * Gets an InputStream to a file in the resource directory
+    /**
+     * Gets an InputStream to a file in the resource directory
      *
      * @param filename A file name in the resource directory.
      * @return An {@code InputStream} to the specified file name in the resource directory.
@@ -627,142 +626,142 @@ public interface SecurityConfiguration extends EsapiPropertyLoader {
      */
     InputStream getResourceStream( String filename ) throws IOException;
 
-	/**
-	 * Sets the ESAPI resource directory.
-	 * 
-	 * @param dir The location of the resource directory.
-	 */
-	void setResourceDirectory(String dir);
-	
-	/**
-	 * Gets the content type for responses used when setSafeContentType() is called.
-	 * <br><br>
-	 * Note: This does not get the configured character encoding scheme. That is accessed by calling 
-	 * getCharacterEncoding().
-	 * 
-	 * @return The current content-type set for responses.
+    /**
+     * Sets the ESAPI resource directory.
+     *
+     * @param dir The location of the resource directory.
+     */
+    void setResourceDirectory(String dir);
+
+    /**
+     * Gets the content type for responses used when setSafeContentType() is called.
+     * <br><br>
+     * Note: This does not get the configured character encoding scheme. That is accessed by calling
+     * getCharacterEncoding().
+     *
+     * @return The current content-type set for responses.
      * @deprecated Use SecurityConfiguration.getStringProp("appropriate_esapi_prop_name") instead.
-	 */
-	@Deprecated
-	String getResponseContentType();
-
-	/**
-	 * This method returns the configured name of the session identifier, 
-	 * likely "JSESSIONID" though this can be overridden.
-	 * 
-	 * @return The name of the session identifier, like "JSESSIONID"
+     */
+    @Deprecated
+    String getResponseContentType();
+
+    /**
+     * This method returns the configured name of the session identifier,
+     * likely "JSESSIONID" though this can be overridden.
+     *
+     * @return The name of the session identifier, like "JSESSIONID"
      * @deprecated Use SecurityConfiguration.getStringProp("appropriate_esapi_prop_name") instead.
-	 */
-	@Deprecated
-	String getHttpSessionIdName();
-	
-	/**
-	 * Gets the length of the time to live window for remember me tokens (in milliseconds).
-	 * 
-	 * @return The time to live length for generated "remember me" tokens.
-	 */
+     */
+    @Deprecated
+    String getHttpSessionIdName();
+
+    /**
+     * Gets the length of the time to live window for remember me tokens (in milliseconds).
+     *
+     * @return The time to live length for generated "remember me" tokens.
+     */
     // OPEN ISSUE: Can we replace w/ SecurityConfiguration.getIntProp("appropriate_esapi_prop_name") instead?
-	long getRememberTokenDuration();
-
-	
-	/**
-	 * Gets the idle timeout length for sessions (in milliseconds). This is the amount of time that a session
-	 * can live before it expires due to lack of activity. Applications or frameworks could provide a reauthenticate
-	 * function that enables a session to continue after reauthentication.
-	 * 
-	 * @return The session idle timeout length.
+    long getRememberTokenDuration();
+
+
+    /**
+     * Gets the idle timeout length for sessions (in milliseconds). This is the amount of time that a session
+     * can live before it expires due to lack of activity. Applications or frameworks could provide a reauthenticate
+     * function that enables a session to continue after reauthentication.
+     *
+     * @return The session idle timeout length.
      * @deprecated Use SecurityConfiguration.getIntProp("appropriate_esapi_prop_name") instead.
-	 */
-	@Deprecated
-	int getSessionIdleTimeoutLength();
-	
-	/**
-	 * Gets the absolute timeout length for sessions (in milliseconds). This is the amount of time that a session
-	 * can live before it expires regardless of the amount of user activity. Applications or frameworks could 
-	 * provide a reauthenticate function that enables a session to continue after reauthentication.
-	 * 
-	 * @return The session absolute timeout length.
+     */
+    @Deprecated
+    int getSessionIdleTimeoutLength();
+
+    /**
+     * Gets the absolute timeout length for sessions (in milliseconds). This is the amount of time that a session
+     * can live before it expires regardless of the amount of user activity. Applications or frameworks could
+     * provide a reauthenticate function that enables a session to continue after reauthentication.
+     *
+     * @return The session absolute timeout length.
      * @deprecated Use SecurityConfiguration.getIntProp("appropriate_esapi_prop_name") instead.
-	 */
-	@Deprecated
-	int getSessionAbsoluteTimeoutLength();
-	
-	
-	/**
-	 * Returns whether HTML entity encoding should be applied to log entries.
-	 * 
-	 * @return True if log entries are to be HTML Entity encoded. False otherwise.
+     */
+    @Deprecated
+    int getSessionAbsoluteTimeoutLength();
+
+
+    /**
+     * Returns whether HTML entity encoding should be applied to log entries.
+     *
+     * @return True if log entries are to be HTML Entity encoded. False otherwise.
      * @deprecated Use SecurityConfiguration.getBooleanProp("appropriate_esapi_prop_name") instead.
-	 */
-	@Deprecated
-	boolean getLogEncodingRequired();
-	
-	/**
-	 * Returns whether ESAPI should log the application name. This might be clutter in some
-	 * single-server/single-app environments.
-	 * 
-	 * @return True if ESAPI should log the application name, False otherwise
+     */
+    @Deprecated
+    boolean getLogEncodingRequired();
+
+    /**
+     * Returns whether ESAPI should log the application name. This might be clutter in some
+     * single-server/single-app environments.
+     *
+     * @return True if ESAPI should log the application name, False otherwise
      * @deprecated Use SecurityConfiguration.getBooleanProp("appropriate_esapi_prop_name") instead.
-	 */
-	@Deprecated
-	boolean getLogApplicationName();
-
-	/**
-	 * Returns whether ESAPI should log the server IP. This might be clutter in some
-	 * single-server environments.
-	 * 
-	 * @return True if ESAPI should log the server IP and port, False otherwise
+     */
+    @Deprecated
+    boolean getLogApplicationName();
+
+    /**
+     * Returns whether ESAPI should log the server IP. This might be clutter in some
+     * single-server environments.
+     *
+     * @return True if ESAPI should log the server IP and port, False otherwise
      * @deprecated Use SecurityConfiguration.getBooleanProp("appropriate_esapi_prop_name") instead.
-	 */
-	@Deprecated
-	boolean getLogServerIP();
-
-	/**
-	 * Models a simple threshold as a count and an interval, along with a set of actions to take if 
-	 * the threshold is exceeded. These thresholds are used to define when the accumulation of a particular event
-	 * has met a set number within the specified time period. Once a threshold value has been met, various
-	 * actions can be taken at that point.
-	 */
-	class Threshold {
-		
-		/** The name of this threshold. */
-		public String name = null;
-		
-		/** The count at which this threshold is triggered. */
-		public int count = 0;
-		
-		/** 
-		 * The time frame within which 'count' number of actions has to be detected in order to
-		 * trigger this threshold.
-		 */
-		public long interval = 0;
-		
-		/**
-		 * The list of actions to take if the threshold is met. It is expected that this is a list of Strings, but 
-		 * your implementation could have this be a list of any type of 'actions' you wish to define. 
-		 */
-		public List<String> actions = null;
-
-		/**
-		 * Constructs a threshold that is composed of its name, its threshold count, the time window for
-		 * the threshold, and the actions to take if the threshold is triggered.
-		 * 
-		 * @param name The name of this threshold.
-		 * @param count The count at which this threshold is triggered.
-		 * @param interval The time frame within which 'count' number of actions has to be detected in order to
-		 * trigger this threshold.
-		 * @param actions The list of actions to take if the threshold is met.
-		 */
-		public Threshold(String name, int count, long interval, List<String> actions) {
-			this.name = name;
-			this.count = count;
-			this.interval = interval;
-			this.actions = actions;
-		}
-	}
-
-	/**
-	 * Returns the default working directory for executing native processes with Runtime.exec().
-	 */
-	File getWorkingDirectory();
+     */
+    @Deprecated
+    boolean getLogServerIP();
+
+    /**
+     * Models a simple threshold as a count and an interval, along with a set of actions to take if
+     * the threshold is exceeded. These thresholds are used to define when the accumulation of a particular event
+     * has met a set number within the specified time period. Once a threshold value has been met, various
+     * actions can be taken at that point.
+     */
+    class Threshold {
+
+        /** The name of this threshold. */
+        public String name = null;
+
+        /** The count at which this threshold is triggered. */
+        public int count = 0;
+
+        /**
+         * The time frame within which 'count' number of actions has to be detected in order to
+         * trigger this threshold.
+         */
+        public long interval = 0;
+
+        /**
+         * The list of actions to take if the threshold is met. It is expected that this is a list of Strings, but
+         * your implementation could have this be a list of any type of 'actions' you wish to define.
+         */
+        public List<String> actions = null;
+
+        /**
+         * Constructs a threshold that is composed of its name, its threshold count, the time window for
+         * the threshold, and the actions to take if the threshold is triggered.
+         *
+         * @param name The name of this threshold.
+         * @param count The count at which this threshold is triggered.
+         * @param interval The time frame within which 'count' number of actions has to be detected in order to
+         * trigger this threshold.
+         * @param actions The list of actions to take if the threshold is met.
+         */
+        public Threshold(String name, int count, long interval, List<String> actions) {
+            this.name = name;
+            this.count = count;
+            this.interval = interval;
+            this.actions = actions;
+        }
+    }
+
+    /**
+     * Returns the default working directory for executing native processes with Runtime.exec().
+     */
+    File getWorkingDirectory();
 }
diff --git a/src/main/java/org/owasp/esapi/StringUtilities.java b/src/main/java/org/owasp/esapi/StringUtilities.java
index 634287a..55f8c55 100644
--- a/src/main/java/org/owasp/esapi/StringUtilities.java
+++ b/src/main/java/org/owasp/esapi/StringUtilities.java
@@ -1,15 +1,15 @@
 /**
  * OWASP Enterprise Security API (ESAPI)
- * 
+ *
  * This file is part of the Open Web Application Security Project (OWASP)
  * Enterprise Security API (ESAPI) project. For details, please see
  * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
  *
  * Copyright (c) 2007 - The OWASP Foundation
- * 
+ *
  * The ESAPI is published by OWASP under the BSD license. You should read and accept the
  * LICENSE before you use, modify, and/or redistribute this software.
- * 
+ *
  * @author Jeff Williams <a href="http://www.aspectsecurity.com">Aspect Security</a>
  * @created 2007
  */
@@ -20,53 +20,53 @@ import java.util.regex.Pattern;
 
 /**
  * String utilities used in various filters.
- * 
+ *
  * @author Jeff Williams (jeff.williams .at. aspectsecurity.com) <a
  * href="http://www.aspectsecurity.com">Aspect Security</a>
  * @since June 1, 2007
  */
 public class StringUtilities {
 
-	private static final Pattern p = Pattern.compile( "\\s");
-	public static String replaceLinearWhiteSpace( String input ) {
-		return p.matcher(input).replaceAll( " " );
-	}
-	
-	/**
-	 * Removes all unprintable characters from a string 
-	 * and replaces with a space.
-	 * @param input
-	 * @return the stripped value
-	 */
-	public static String stripControls( String input ) {
-		StringBuilder sb = new StringBuilder();
-		for ( int i=0; i<input.length(); i++ ) {
-			char c = input.charAt( i );
-			if ( c > 0x20 && c < 0x7f ) {
-				sb.append( c );
-			} else {
-				sb.append( ' ' );
-			}
-		}
-		return sb.toString();
-	}
-
-	
+    private static final Pattern p = Pattern.compile( "\\s");
+    public static String replaceLinearWhiteSpace( String input ) {
+        return p.matcher(input).replaceAll( " " );
+    }
+
+    /**
+     * Removes all unprintable characters from a string
+     * and replaces with a space.
+     * @param input
+     * @return the stripped value
+     */
+    public static String stripControls( String input ) {
+        StringBuilder sb = new StringBuilder();
+        for ( int i=0; i<input.length(); i++ ) {
+            char c = input.charAt( i );
+            if ( c > 0x20 && c < 0x7f ) {
+                sb.append( c );
+            } else {
+                sb.append( ' ' );
+            }
+        }
+        return sb.toString();
+    }
+
+
     /**
      * Union multiple character arrays.
-     * 
+     *
      * @param list the char[]s to union
      * @return the union of the char[]s
      */
     public static char[] union(char[]... list) {
-    	StringBuilder sb = new StringBuilder();
-    	
-		for (char[] characters : list) {
-			for ( char c : characters ) {
-				if ( !contains( sb, c ) )
-					sb.append( c );
-			}
-		}
+        StringBuilder sb = new StringBuilder();
+
+        for (char[] characters : list) {
+            for ( char c : characters ) {
+                if ( !contains( sb, c ) )
+                    sb.append( c );
+            }
+        }
 
         char[] toReturn = new char[sb.length()];
         sb.getChars(0, sb.length(), toReturn, 0);
@@ -75,11 +75,11 @@ public class StringUtilities {
     }
 
 
-	/**
+    /**
      * Returns true if the character is contained in the provided StringBuilder.
-     * @param input 	The input
-     * @param c 		The character to check for to see if {@code input} contains.
-     * @return			True if the specified character is contained; false otherwise.
+     * @param input     The input
+     * @param c         The character to check for to see if {@code input} contains.
+     * @return            True if the specified character is contained; false otherwise.
      */
     public static boolean contains(StringBuilder input, char c) {
         for (int i = 0; i < input.length(); i++) {
@@ -171,24 +171,24 @@ public class StringUtilities {
      * trimming of leading and trailing whitespace). Usually used with
      * assertions, as in
      * <pre>
-     * 		assert StringUtils.notNullOrEmpty(cipherXform, true) :
-     * 								"Cipher transformation may not be null or empty!";
+     *         assert StringUtils.notNullOrEmpty(cipherXform, true) :
+     *                                 "Cipher transformation may not be null or empty!";
      * </pre>
      * or an equivalent runtime check that throws an {@code IllegalArgumentException}.
      *
-     * @param str	The {@code String} to be checked.
-     * @param trim	If {@code true}, the string is first trimmed before checking
-     * 				to see if it is empty, otherwise it is not.
-     * @return		True if the string is null or empty (after possible
-     * 				trimming); otherwise false.
+     * @param str    The {@code String} to be checked.
+     * @param trim    If {@code true}, the string is first trimmed before checking
+     *                 to see if it is empty, otherwise it is not.
+     * @return        True if the string is null or empty (after possible
+     *                 trimming); otherwise false.
      * @since 2.0
      */
     public static boolean notNullOrEmpty(String str, boolean trim) {
-    	if ( trim ) {
-    		return !( str == null || str.trim().equals("") );
-    	} else {
-    		return !( str == null || str.equals("") );
-    	}
+        if ( trim ) {
+            return !( str == null || str.trim().equals("") );
+        } else {
+            return !( str == null || str.equals("") );
+        }
     }
 
     /**
diff --git a/src/main/java/org/owasp/esapi/User.java b/src/main/java/org/owasp/esapi/User.java
index 480e971..fa30ca3 100644
--- a/src/main/java/org/owasp/esapi/User.java
+++ b/src/main/java/org/owasp/esapi/User.java
@@ -1,15 +1,15 @@
 /**
  * OWASP Enterprise Security API (ESAPI)
- * 
+ *
  * This file is part of the Open Web Application Security Project (OWASP)
  * Enterprise Security API (ESAPI) project. For details, please see
  * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
  *
  * Copyright (c) 2007 - The OWASP Foundation
- * 
+ *
  * The ESAPI is published by OWASP under the BSD license. You should read and accept the
  * LICENSE before you use, modify, and/or redistribute this software.
- * 
+ *
  * @author Jeff Williams <a href="http://www.aspectsecurity.com">Aspect Security</a>
  * @created 2007
  */
@@ -34,59 +34,59 @@ import java.util.*;
  * number of reasons, most commonly because they have failed login for too many times. Finally, the account can expire
  * after the expiration date has been reached. The User must be enabled, not expired, and unlocked in order to pass
  * authentication.
- * 
+ *
  * @author <a href="mailto:jeff.williams@aspectsecurity.com?subject=ESAPI question">Jeff Williams</a> at <a href="http://www.aspectsecurity.com">Aspect Security</a>
  * @author Chris Schmidt (chrisisbeef .at. gmail.com) <a href="http://www.digital-ritual.com">Digital Ritual Software</a>
  * @since June 1, 2007
  */
 
 public interface User extends Principal, Serializable {
-	/**
-	 * @return the locale
-	 */
-	Locale getLocale();
+    /**
+     * @return the locale
+     */
+    Locale getLocale();
 
-	/**
-	 * @param locale the locale to set
-	 */
-	void setLocale(Locale locale);
+    /**
+     * @param locale the locale to set
+     */
+    void setLocale(Locale locale);
 
     /**
      * Adds a role to this user's account.
-     * 
-     * @param role 
-     * 		the role to add
-     * 
-     * @throws AuthenticationException 
-     * 		the authentication exception
+     *
+     * @param role
+     *         the role to add
+     *
+     * @throws AuthenticationException
+     *         the authentication exception
      */
     void addRole(String role) throws AuthenticationException;
 
     /**
      * Adds a set of roles to this user's account.
-     * 
-     * @param newRoles 
-     * 		the new roles to add
-     * 
-     * @throws AuthenticationException 
-     * 		the authentication exception
+     *
+     * @param newRoles
+     *         the new roles to add
+     *
+     * @throws AuthenticationException
+     *         the authentication exception
      */
     void addRoles(Set<String> newRoles) throws AuthenticationException;
 
     /**
      * Sets the user's password, performing a verification of the user's old password, the equality of the two new
      * passwords, and the strength of the new password.
-     * 
-     * @param oldPassword 
-     * 		the old password
-     * @param newPassword1 
-     * 		the new password
-     * @param newPassword2 
-     * 		the new password - used to verify that the new password was typed correctly
-     * 
-     * @throws AuthenticationException 
-     * 		if newPassword1 does not match newPassword2, if oldPassword does not match the stored old password, or if the new password does not meet complexity requirements 
-     * @throws EncryptionException 
+     *
+     * @param oldPassword
+     *         the old password
+     * @param newPassword1
+     *         the new password
+     * @param newPassword2
+     *         the new password - used to verify that the new password was typed correctly
+     *
+     * @throws AuthenticationException
+     *         if newPassword1 does not match newPassword2, if oldPassword does not match the stored old password, or if the new password does not meet complexity requirements
+     * @throws EncryptionException
      */
     void changePassword(String oldPassword, String newPassword1, String newPassword2) throws AuthenticationException, EncryptionException;
 
@@ -102,21 +102,21 @@ public interface User extends Principal, Serializable {
 
     /**
      * Gets this user's account id number.
-     * 
+     *
      * @return the account id
      */
     long getAccountId();
-    
+
     /**
      * Gets this user's account name.
-     * 
+     *
      * @return the account name
      */
     String getAccountName();
 
     /**
      * Gets the CSRF token for this user's current sessions.
-     * 
+     *
      * @return the CSRF token
      */
     String getCSRFToken();
@@ -133,7 +133,7 @@ public interface User extends Principal, Serializable {
      * intended to be used as a part of the account lockout feature, to help protect against brute force attacks.
      * However, the implementor should be aware that lockouts can be used to prevent access to an application by a
      * legitimate user, and should consider the risk of denial of service.
-     * 
+     *
      * @return the number of failed login attempts since the last successful login
      */
     int getFailedLoginCount();
@@ -141,73 +141,73 @@ public interface User extends Principal, Serializable {
     /**
      * Returns the last host address used by the user. This will be used in any log messages generated by the processing
      * of this request.
-     * 
+     *
      * @return the last host address used by the user
      */
     String getLastHostAddress();
 
-	/**
+    /**
      * Returns the date of the last failed login time for a user. This date should be used in a message to users after a
      * successful login, to notify them of potential attack activity on their account.
-     * 
+     *
      * @return date of the last failed login
-     * 
-     * @throws AuthenticationException 
-     * 		the authentication exception
+     *
+     * @throws AuthenticationException
+     *         the authentication exception
      */
     Date getLastFailedLoginTime() throws AuthenticationException;
 
     /**
      * Returns the date of the last successful login time for a user. This date should be used in a message to users
      * after a successful login, to notify them of potential attack activity on their account.
-     * 
+     *
      * @return date of the last successful login
      */
     Date getLastLoginTime();
 
     /**
      * Gets the date of user's last password change.
-     * 
+     *
      * @return the date of last password change
      */
     Date getLastPasswordChangeTime();
 
     /**
      * Gets the roles assigned to a particular account.
-     * 
+     *
      * @return an immutable set of roles
      */
     Set<String> getRoles();
 
     /**
      * Gets the screen name (alias) for the current user.
-     * 
+     *
      * @return the screen name
      */
     String getScreenName();
 
     /**
      * Adds a session for this User.
-     * 
+     *
      * @param s
-     * 			The session to associate with this user.
+     *             The session to associate with this user.
      */
     void addSession( HttpSession s );
-    
+
     /**
      * Removes a session for this User.
-     * 
+     *
      * @param s
-     * 			The session to remove from being associated with this user.
+     *             The session to remove from being associated with this user.
      */
     void removeSession( HttpSession s );
-    
+
     /**
      * Returns a Set containing the sessions associated with this User.
      * @return The Set of sessions for this User.
      */
     Set getSessions();
-    
+
     /**
      * Increment failed login count.
      */
@@ -215,70 +215,70 @@ public interface User extends Principal, Serializable {
 
     /**
      * Checks if user is anonymous.
-     * 
+     *
      * @return true, if user is anonymous
      */
     boolean isAnonymous();
 
     /**
      * Checks if this user's account is currently enabled.
-     * 
-     * @return true, if account is enabled 
+     *
+     * @return true, if account is enabled
      */
     boolean isEnabled();
 
     /**
      * Checks if this user's account is expired.
-     * 
+     *
      * @return true, if account is expired
      */
     boolean isExpired();
 
     /**
      * Checks if this user's account is assigned a particular role.
-     * 
-     * @param role 
-     * 		the role for which to check
-     * 
+     *
+     * @param role
+     *         the role for which to check
+     *
      * @return true, if role has been assigned to user
      */
     boolean isInRole(String role);
 
     /**
      * Checks if this user's account is locked.
-     * 
+     *
      * @return true, if account is locked
      */
     boolean isLocked();
 
     /**
      * Tests to see if the user is currently logged in.
-     * 
+     *
      * @return true, if the user is logged in
      */
     boolean isLoggedIn();
 
     /**
-     * Tests to see if this user's session has exceeded the absolute time out based 
+     * Tests to see if this user's session has exceeded the absolute time out based
       * on ESAPI's configuration settings.
-     * 
+     *
      * @return true, if user's session has exceeded the absolute time out
      */
     boolean isSessionAbsoluteTimeout();
 
     /**
-      * Tests to see if the user's session has timed out from inactivity based 
+      * Tests to see if the user's session has timed out from inactivity based
       * on ESAPI's configuration settings.
-      * 
-      * A session may timeout prior to ESAPI's configuration setting due to 
-      * the servlet container setting for session-timeout in web.xml. The 
-      * following is an example of a web.xml session-timeout set for one hour. 	
+      *
+      * A session may timeout prior to ESAPI's configuration setting due to
+      * the servlet container setting for session-timeout in web.xml. The
+      * following is an example of a web.xml session-timeout set for one hour.
       *
       * <session-config>
-      *   <session-timeout>60</session-timeout> 
+      *   <session-timeout>60</session-timeout>
       * </session-config>
-      * 
-      * @return true, if user's session has timed out from inactivity based 
+      *
+      * @return true, if user's session has timed out from inactivity based
       *               on ESAPI configuration
       */
      boolean isSessionTimeout();
@@ -290,11 +290,11 @@ public interface User extends Principal, Serializable {
 
     /**
      * Login with password.
-     * 
-     * @param password 
-     * 		the password
-     * @throws AuthenticationException 
-     * 		if login fails
+     *
+     * @param password
+     *         the password
+     * @throws AuthenticationException
+     *         if login fails
      */
     void loginWithPassword(String password) throws AuthenticationException;
 
@@ -305,11 +305,11 @@ public interface User extends Principal, Serializable {
 
     /**
      * Removes a role from this user's account.
-     * 
-     * @param role 
-     * 		the role to remove
-     * @throws AuthenticationException 
-     * 		the authentication exception
+     *
+     * @param role
+     *         the role to remove
+     * @throws AuthenticationException
+     *         the authentication exception
      */
     void removeRole(String role) throws AuthenticationException;
 
@@ -318,42 +318,42 @@ public interface User extends Principal, Serializable {
      * forms. The application should verify that all requests contain the token, or they may have been generated by a
      * CSRF attack. It is generally best to perform the check in a centralized location, either a filter or controller.
      * See the verifyCSRFToken method.
-     * 
+     *
      * @return the new CSRF token
-     * 
-     * @throws AuthenticationException 
-     * 		the authentication exception
+     *
+     * @throws AuthenticationException
+     *         the authentication exception
      */
     String resetCSRFToken() throws AuthenticationException;
 
     /**
      * Sets this user's account name.
-     * 
+     *
      * @param accountName the new account name
      */
     void setAccountName(String accountName);
 
     /**
      * Sets the date and time when this user's account will expire.
-     * 
+     *
      * @param expirationTime the new expiration time
      */
-	void setExpirationTime(Date expirationTime);
+    void setExpirationTime(Date expirationTime);
 
-	/**
+    /**
      * Sets the roles for this account.
-     * 
-     * @param roles 
-     * 		the new roles
-     * 
-     * @throws AuthenticationException 
-     * 		the authentication exception
+     *
+     * @param roles
+     *         the new roles
+     *
+     * @throws AuthenticationException
+     *         the authentication exception
      */
     void setRoles(Set<String> roles) throws AuthenticationException;
 
     /**
      * Sets the screen name (username alias) for this user.
-     * 
+     *
      * @param screenName the new screen name
      */
     void setScreenName(String screenName);
@@ -363,80 +363,80 @@ public interface User extends Principal, Serializable {
      */
     void unlock();
 
-	/**
-	 * Verify that the supplied password matches the password for this user. This method
-	 * is typically used for "reauthentication" for the most sensitive functions, such
-	 * as transactions, changing email address, and changing other account information.
-	 * 
-	 * @param password 
-	 * 		the password that the user entered
-	 * 
-	 * @return true, if the password passed in matches the account's password
-	 * 
-	 * @throws EncryptionException 
-	 */
-	boolean verifyPassword(String password) throws EncryptionException;
-
-	/**
-	 * Set the time of the last failed login for this user.
-	 * 
-	 * @param lastFailedLoginTime the date and time when the user just failed to login correctly.
-	 */
-	void setLastFailedLoginTime(Date lastFailedLoginTime);
-	
-	/**
-	 * Set the last remote host address used by this user.
-	 * 
-	 * @param remoteHost The address of the user's current source host.
-	 */
-	void setLastHostAddress(String remoteHost) throws AuthenticationHostException;
-	
-	/**
-	 * Set the time of the last successful login for this user.
-	 * 
-	 * @param lastLoginTime the date and time when the user just successfully logged in.
-	 */
-	void setLastLoginTime(Date lastLoginTime);
-	
-	/**
-	 * Set the time of the last password change for this user.
-	 * 
-	 * @param lastPasswordChangeTime the date and time when the user just successfully changed his/her password.
-	 */
-	void setLastPasswordChangeTime(Date lastPasswordChangeTime);
-
-	/**
-	 * Returns the hashmap used to store security events for this user. Used by the
-	 * IntrusionDetector.
-	 */
-	HashMap getEventMap();
-	
-
-	/**
-	 * The ANONYMOUS user is used to represent an unidentified user. Since there is
-	 * always a real user, the ANONYMOUS user is better than using null to represent
-	 * this.
-	 */
+    /**
+     * Verify that the supplied password matches the password for this user. This method
+     * is typically used for "reauthentication" for the most sensitive functions, such
+     * as transactions, changing email address, and changing other account information.
+     *
+     * @param password
+     *         the password that the user entered
+     *
+     * @return true, if the password passed in matches the account's password
+     *
+     * @throws EncryptionException
+     */
+    boolean verifyPassword(String password) throws EncryptionException;
+
+    /**
+     * Set the time of the last failed login for this user.
+     *
+     * @param lastFailedLoginTime the date and time when the user just failed to login correctly.
+     */
+    void setLastFailedLoginTime(Date lastFailedLoginTime);
+
+    /**
+     * Set the last remote host address used by this user.
+     *
+     * @param remoteHost The address of the user's current source host.
+     */
+    void setLastHostAddress(String remoteHost) throws AuthenticationHostException;
+
+    /**
+     * Set the time of the last successful login for this user.
+     *
+     * @param lastLoginTime the date and time when the user just successfully logged in.
+     */
+    void setLastLoginTime(Date lastLoginTime);
+
+    /**
+     * Set the time of the last password change for this user.
+     *
+     * @param lastPasswordChangeTime the date and time when the user just successfully changed his/her password.
+     */
+    void setLastPasswordChangeTime(Date lastPasswordChangeTime);
+
+    /**
+     * Returns the hashmap used to store security events for this user. Used by the
+     * IntrusionDetector.
+     */
+    HashMap getEventMap();
+
+
+    /**
+     * The ANONYMOUS user is used to represent an unidentified user. Since there is
+     * always a real user, the ANONYMOUS user is better than using null to represent
+     * this.
+     */
     User ANONYMOUS = new User() {
 
-		private static final long serialVersionUID = -1850916950784965502L;
+        private static final long serialVersionUID = -1850916950784965502L;
 
-		private String csrfToken = "";
-    	private Set<Object> sessions = new HashSet<Object>();
-		private Locale locale = null;
-    	
-    	/**
+        private String csrfToken = "";
+        private Set<Object> sessions = new HashSet<Object>();
+        private Locale locale = null;
+
+        /**
          * {@inheritDoc}
          */
         public void addRole(String role) throws AuthenticationException {
-        	throw new RuntimeException("Invalid operation for the anonymous user");
+            throw new RuntimeException("Invalid operation for the anonymous user");
         }
 
         /**
          * {@inheritDoc}
          */
         public void addRoles(Set newRoles) throws AuthenticationException {
-        	throw new RuntimeException("Invalid operation for the anonymous user");
+            throw new RuntimeException("Invalid operation for the anonymous user");
         }
 
         /**
@@ -445,107 +445,107 @@ public interface User extends Principal, Serializable {
         public void changePassword(String oldPassword, String newPassword1,
                 String newPassword2) throws AuthenticationException,
                 EncryptionException {
-        	throw new RuntimeException("Invalid operation for the anonymous user");
+            throw new RuntimeException("Invalid operation for the anonymous user");
         }
 
         /**
          * {@inheritDoc}
          */
         public void disable() {
-        	throw new RuntimeException("Invalid operation for the anonymous user");
+            throw new RuntimeException("Invalid operation for the anonymous user");
         }
 
         /**
          * {@inheritDoc}
          */
         public void enable() {
-        	throw new RuntimeException("Invalid operation for the anonymous user");
+            throw new RuntimeException("Invalid operation for the anonymous user");
         }
 
         /**
          * {@inheritDoc}
          */
         public long getAccountId() {
-	        return 0;
+            return 0;
         }
 
         /**
          * {@inheritDoc}
          */
         public String getAccountName() {
-	        return "Anonymous";
+            return "Anonymous";
         }
 
-		/**
-		 * Alias method that is equivalent to getAccountName()
-		 * 
-		 * @return the name of the current user's account
+        /**
+         * Alias method that is equivalent to getAccountName()
+         *
+         * @return the name of the current user's account
          */
         public String getName() {
-        	return getAccountName();
+            return getAccountName();
         }
-        
+
         /**
          * {@inheritDoc}
          */
         public String getCSRFToken() {
-	        return csrfToken;
+            return csrfToken;
         }
 
         /**
          * {@inheritDoc}
          */
         public Date getExpirationTime() {
-	        return null;
+            return null;
         }
 
         /**
          * {@inheritDoc}
          */
         public int getFailedLoginCount() {
-	        return 0;
+            return 0;
         }
 
         /**
          * {@inheritDoc}
          */
         public Date getLastFailedLoginTime() throws AuthenticationException {
-	        return null;
+            return null;
         }
 
         /**
          * {@inheritDoc}
          */
         public String getLastHostAddress() {
-	        return "unknown";
+            return "unknown";
         }
 
         /**
          * {@inheritDoc}
          */
         public Date getLastLoginTime() {
-	        return null;
+            return null;
         }
 
         /**
          * {@inheritDoc}
          */
         public Date getLastPasswordChangeTime() {
-	        return null;
+            return null;
         }
 
         /**
          * {@inheritDoc}
          */
         public Set<String> getRoles() {
-	        return new HashSet<String>();
+            return new HashSet<String>();
         }
 
         /**
          * {@inheritDoc}
          */
         public String getScreenName() {
-	        return "Anonymous";
+            return "Anonymous";
         }
 
         /**
@@ -571,70 +571,70 @@ public interface User extends Principal, Serializable {
          * {@inheritDoc}
          */
         public void incrementFailedLoginCount() {
-        	throw new RuntimeException("Invalid operation for the anonymous user");
+            throw new RuntimeException("Invalid operation for the anonymous user");
         }
 
         /**
          * {@inheritDoc}
          */
         public boolean isAnonymous() {
-	        return true;
+            return true;
         }
 
         /**
          * {@inheritDoc}
          */
         public boolean isEnabled() {
-	        return false;
+            return false;
         }
 
         /**
          * {@inheritDoc}
          */
         public boolean isExpired() {
-	        return false;
+            return false;
         }
 
         /**
          * {@inheritDoc}
          */
         public boolean isInRole(String role) {
-	        return false;
+            return false;
         }
 
         /**
          * {@inheritDoc}
          */
         public boolean isLocked() {
-	        return false;
+            return false;
         }
 
         /**
          * {@inheritDoc}
          */
         public boolean isLoggedIn() {
-	        return false;
+            return false;
         }
 
         /**
          * {@inheritDoc}
          */
         public boolean isSessionAbsoluteTimeout() {
-	        return false;
+            return false;
         }
 
         /**
          * {@inheritDoc}
          */
         public boolean isSessionTimeout() {
-	        return false;
+            return false;
         }
 
         /**
          * {@inheritDoc}
          */
         public void lock() {
-        	throw new RuntimeException("Invalid operation for the anonymous user");
+            throw new RuntimeException("Invalid operation for the anonymous user");
         }
 
         /**
@@ -642,119 +642,119 @@ public interface User extends Principal, Serializable {
          */
         public void loginWithPassword(String password)
                 throws AuthenticationException {
-        	throw new RuntimeException("Invalid operation for the anonymous user");
+            throw new RuntimeException("Invalid operation for the anonymous user");
         }
 
         /**
          * {@inheritDoc}
          */
         public void logout() {
-        	throw new RuntimeException("Invalid operation for the anonymous user");
+            throw new RuntimeException("Invalid operation for the anonymous user");
         }
 
         /**
          * {@inheritDoc}
          */
         public void removeRole(String role) throws AuthenticationException {
-        	throw new RuntimeException("Invalid operation for the anonymous user");
+            throw new RuntimeException("Invalid operation for the anonymous user");
         }
 
         /**
          * {@inheritDoc}
          */
         public String resetCSRFToken() throws AuthenticationException {
-    		csrfToken = ESAPI.randomizer().getRandomString(8, EncoderConstants.CHAR_ALPHANUMERICS);
-    		return csrfToken;
+            csrfToken = ESAPI.randomizer().getRandomString(8, EncoderConstants.CHAR_ALPHANUMERICS);
+            return csrfToken;
         }
 
         /**
          * {@inheritDoc}
          */
         public void setAccountName(String accountName) {
-        	throw new RuntimeException("Invalid operation for the anonymous user");
+            throw new RuntimeException("Invalid operation for the anonymous user");
         }
 
         /**
          * {@inheritDoc}
          */
-    	public void setExpirationTime(Date expirationTime) {
-        	throw new RuntimeException("Invalid operation for the anonymous user");
+        public void setExpirationTime(Date expirationTime) {
+            throw new RuntimeException("Invalid operation for the anonymous user");
         }
-        
-    	/**
+
+        /**
          * {@inheritDoc}
          */
         public void setRoles(Set roles) throws AuthenticationException {
-        	throw new RuntimeException("Invalid operation for the anonymous user");
+            throw new RuntimeException("Invalid operation for the anonymous user");
         }
 
         /**
          * {@inheritDoc}
          */
         public void setScreenName(String screenName) {
-        	throw new RuntimeException("Invalid operation for the anonymous user");
+            throw new RuntimeException("Invalid operation for the anonymous user");
         }
 
         /**
          * {@inheritDoc}
          */
         public void unlock() {
-        	throw new RuntimeException("Invalid operation for the anonymous user");
+            throw new RuntimeException("Invalid operation for the anonymous user");
         }
 
         /**
          * {@inheritDoc}
          */
         public boolean verifyPassword(String password) throws EncryptionException {
-        	throw new RuntimeException("Invalid operation for the anonymous user");
+            throw new RuntimeException("Invalid operation for the anonymous user");
         }
 
         /**
          * {@inheritDoc}
          */
         public void setLastFailedLoginTime(Date lastFailedLoginTime) {
-        	throw new RuntimeException("Invalid operation for the anonymous user");
+            throw new RuntimeException("Invalid operation for the anonymous user");
         }
-        
+
         /**
          * {@inheritDoc}
          */
-    	public void setLastLoginTime(Date lastLoginTime) {
-    		throw new RuntimeException("Invalid operation for the anonymous user");
-    	}
+        public void setLastLoginTime(Date lastLoginTime) {
+            throw new RuntimeException("Invalid operation for the anonymous user");
+        }
 
-    	/**
+        /**
          * {@inheritDoc}
          */
-     	public void setLastHostAddress(String remoteHost) {
-        	throw new RuntimeException("Invalid operation for the anonymous user");
+         public void setLastHostAddress(String remoteHost) {
+            throw new RuntimeException("Invalid operation for the anonymous user");
         }
-                
-     	/**
+
+         /**
          * {@inheritDoc}
          */
         public void setLastPasswordChangeTime(Date lastPasswordChangeTime) {
-        	throw new RuntimeException("Invalid operation for the anonymous user");
+            throw new RuntimeException("Invalid operation for the anonymous user");
         }
-        
+
         /**
          *  {@inheritDoc}
          */
         public HashMap getEventMap() {
-        	throw new RuntimeException("Invalid operation for the anonymous user");
+            throw new RuntimeException("Invalid operation for the anonymous user");
         }
          /**
-    	 * @return the locale
-    	 */
-    	public Locale getLocale() {
-    		return locale;
-    	}
-
-    	/**
-    	 * @param locale the locale to set
-    	 */
-    	public void setLocale(Locale locale) {
-    		this.locale = locale;
-    	}
+         * @return the locale
+         */
+        public Locale getLocale() {
+            return locale;
+        }
+
+        /**
+         * @param locale the locale to set
+         */
+        public void setLocale(Locale locale) {
+            this.locale = locale;
+        }
     };
 }
diff --git a/src/main/java/org/owasp/esapi/ValidationErrorList.java b/src/main/java/org/owasp/esapi/ValidationErrorList.java
index 6479ff3..a56ae1e 100644
--- a/src/main/java/org/owasp/esapi/ValidationErrorList.java
+++ b/src/main/java/org/owasp/esapi/ValidationErrorList.java
@@ -1,17 +1,17 @@
 /**
  * OWASP Enterprise Security API (ESAPI)
- * 
+ *
  * This file is part of the Open Web Application Security Project (OWASP)
  * Enterprise Security API (ESAPI) project. For details, please see
  * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
  *
  * Copyright (c) 2007 - The OWASP Foundation
- * 
+ *
  * The ESAPI is published by OWASP under the BSD license. You should read and accept the
  * LICENSE before you use, modify, and/or redistribute this software.
- * 
+ *
  * @author Jeff Williams <a href="http://www.aspectsecurity.com">Aspect Security</a>
- * 
+ *
  * @created 2007
  */
 package org.owasp.esapi;
@@ -23,13 +23,13 @@ import java.util.List;
 import org.owasp.esapi.errors.ValidationException;
 
 /**
- * The ValidationErrorList class defines a well-formed collection of 
- * ValidationExceptions so that groups of validation functions can be 
+ * The ValidationErrorList class defines a well-formed collection of
+ * ValidationExceptions so that groups of validation functions can be
  * called in a non-blocking fashion.
  * <P>
- * To use the ValidationErrorList to execute groups of validation 
+ * To use the ValidationErrorList to execute groups of validation
  * attempts, your controller code would look something like:
- * 
+ *
  * <PRE>
  * ValidationErrorList() errorList = new ValidationErrorList();.
  * String name  = getValidInput("Name", form.getName(), "SomeESAPIRegExName1", 255, false, errorList);
@@ -38,23 +38,23 @@ import org.owasp.esapi.errors.ValidationException;
  * Integer sortOrder = getValidInteger("Sort Order", form.getSortOrder(), -100000, +100000, false, errorList);
  * request.setAttribute( "ERROR_LIST", errorList );
  * </PRE>
- * 
+ *
  * The at your view layer you would be able to retrieve all
  * of your error messages via a helper function like:
- * 
+ *
  * <PRE>
- * public static ValidationErrorList getErrors() {          
+ * public static ValidationErrorList getErrors() {
  *     HttpServletRequest request = ESAPI.httpUtilities().getCurrentRequest();
  *     ValidationErrorList errors = new ValidationErrorList();
  *     if (request.getAttribute(Constants.ERROR_LIST) != null) {
  *        errors = (ValidationErrorList)request.getAttribute("ERROR_LIST");
  *     }
- * 	   return errors;
+ *        return errors;
  * }
  * </PRE>
- * 
+ *
  * You can list all errors like:
- * 
+ *
  * <PRE>
  * <%
  *      for (Object vo : errorList.errors()) {
@@ -65,73 +65,73 @@ import org.owasp.esapi.errors.ValidationException;
  *     }
  * %>
  * </PRE>
- * 
+ *
  * And even check if a specific UI component is in error via calls like:
- * 
+ *
  * <PRE>
  * ValidationException e = errorList.getError("Name");
  * </PRE>
- * 
+ *
  * @author Jim Manico (jim@manico.net) <a href="http://www.manico.net">Manico.net</a>
  * @since August 15, 2008
  */
 public class ValidationErrorList {
 
-	/**
-	 * Error list of ValidationException's
-	 */
-	private HashMap<String, ValidationException> errorList = new HashMap<String, ValidationException>();
+    /**
+     * Error list of ValidationException's
+     */
+    private HashMap<String, ValidationException> errorList = new HashMap<String, ValidationException>();
+
+    /**
+     * Adds a new error to list with a unique named context.
+     * No action taken if either element is null.
+     * Existing contexts will be overwritten.
+     *
+     * @param context Unique named context for this {@code ValidationErrorList}.
+     * @param vex    A {@code ValidationException}.
+     */
+    public void addError(String context, ValidationException vex) {
+        if ( context == null ) throw new RuntimeException( "Context cannot be null: " + vex.getLogMessage(), vex );
+        if ( vex == null ) throw new RuntimeException( "ValidationException cannot be null for context  (" + context + ")" );
+        if (getError(context) != null) throw new RuntimeException("Context (" + context + ") already exists, must be unique");
+        errorList.put(context, vex);
+    }
 
-	/**
-	 * Adds a new error to list with a unique named context.
-	 * No action taken if either element is null. 
-	 * Existing contexts will be overwritten.
-	 * 
-	 * @param context Unique named context for this {@code ValidationErrorList}.
-	 * @param vex	A {@code ValidationException}.
-	 */
-	public void addError(String context, ValidationException vex) {
-		if ( context == null ) throw new RuntimeException( "Context cannot be null: " + vex.getLogMessage(), vex );
-		if ( vex == null ) throw new RuntimeException( "ValidationException cannot be null for context  (" + context + ")" );
-		if (getError(context) != null) throw new RuntimeException("Context (" + context + ") already exists, must be unique");
-		errorList.put(context, vex);
-	}
+    /**
+     * Returns list of ValidationException, or empty list of no errors exist.
+     *
+     * @return List
+     */
+    public List<ValidationException> errors() {
+        return new ArrayList<ValidationException>( errorList.values() );
+    }
 
-	/**
-	 * Returns list of ValidationException, or empty list of no errors exist.
-	 * 
-	 * @return List
-	 */
-	public List<ValidationException> errors() {
-		return new ArrayList<ValidationException>( errorList.values() );
-	}
+    /**
+     * Retrieves ValidationException for given context if one exists.
+     *
+     * @param context unique name for each error
+     * @return ValidationException or null for given context
+     */
+    public ValidationException getError(String context) {
+        if (context == null) return null;
+        return errorList.get(context);
+    }
 
-	/**
-	 * Retrieves ValidationException for given context if one exists.
-	 * 
-	 * @param context unique name for each error
-	 * @return ValidationException or null for given context
-	 */
-	public ValidationException getError(String context) {
-		if (context == null) return null;		
-		return errorList.get(context);
-	}
+    /**
+     * Returns true if no error are present.
+     *
+     * @return boolean
+     */
+    public boolean isEmpty() {
+        return errorList.isEmpty();
+    }
 
-	/**
-	 * Returns true if no error are present.
-	 * 
-	 * @return boolean
-	 */
-	public boolean isEmpty() {
-		return errorList.isEmpty();
-	}
-	
-	/**
-	 * Returns the numbers of errors present.
-	 * 
-	 * @return boolean
-	 */
-	public int size() {
-		return errorList.size();
-	}
+    /**
+     * Returns the numbers of errors present.
+     *
+     * @return boolean
+     */
+    public int size() {
+        return errorList.size();
+    }
 }
diff --git a/src/main/java/org/owasp/esapi/ValidationRule.java b/src/main/java/org/owasp/esapi/ValidationRule.java
index 9299ef8..3f9c3d4 100644
--- a/src/main/java/org/owasp/esapi/ValidationRule.java
+++ b/src/main/java/org/owasp/esapi/ValidationRule.java
@@ -6,16 +6,16 @@ import org.owasp.esapi.errors.ValidationException;
 
 public interface ValidationRule {
 
-	/**
-	 * Parse the input, throw exceptions if validation fails
-	 * 
-	 * @param context
-	 *            for logging
-	 * @param input
-	 *            the value to be parsed
-	 * @return a validated value
-	 * @throws ValidationException
-	 *             if any validation rules fail, <i>except</i> if the
+    /**
+     * Parse the input, throw exceptions if validation fails
+     *
+     * @param context
+     *            for logging
+     * @param input
+     *            the value to be parsed
+     * @return a validated value
+     * @throws ValidationException
+     *             if any validation rules fail, <i>except</i> if the
      *             <b>{@code ESAPI.properties}></b> property
      *             "Validator.ValidationRule.getValid.ignore509Fix" is set to
      *             {@code true}, which is the default behavior for ESAPI 2.x
@@ -25,67 +25,67 @@ public interface ValidationRule {
      *             for futher details.
      *
      * @see #getValid(String context, String input, ValidationErrorList errorList)
-	 */
-	Object getValid(String context, String input)
-			throws ValidationException;
+     */
+    Object getValid(String context, String input)
+            throws ValidationException;
 
-	/**
-	 * Whether or not a valid valid can be null. {@code getValid} will throw an
-	 * Exception and {#code getSafe} will return the default value if flag is set to
-	 * true
-	 * 
-	 * @param flag
-	 *            whether or not null values are valid/safe
-	 */
-	void setAllowNull(boolean flag);
+    /**
+     * Whether or not a valid valid can be null. {@code getValid} will throw an
+     * Exception and {#code getSafe} will return the default value if flag is set to
+     * true
+     *
+     * @param flag
+     *            whether or not null values are valid/safe
+     */
+    void setAllowNull(boolean flag);
 
-	/**
-	 * Programmatically supplied name for the validator
-	 * @return a name, describing the validator
-	 */
-	String getTypeName();
+    /**
+     * Programmatically supplied name for the validator
+     * @return a name, describing the validator
+     */
+    String getTypeName();
 
-	/**
-	 * @param typeName a name, describing the validator
-	 */
-	void setTypeName(String typeName);
+    /**
+     * @param typeName a name, describing the validator
+     */
+    void setTypeName(String typeName);
 
-	/**
-	 * @param encoder the encoder to use
-	 */
-	void setEncoder(Encoder encoder);
+    /**
+     * @param encoder the encoder to use
+     */
+    void setEncoder(Encoder encoder);
 
-	/**
-	 * Check if the input is valid, throw an Exception otherwise 
-	 */
-	void assertValid(String context, String input)
-			throws ValidationException;
+    /**
+     * Check if the input is valid, throw an Exception otherwise
+     */
+    void assertValid(String context, String input)
+            throws ValidationException;
 
-	/**
-	 * Get a validated value, add the errors to an existing error list
-	 */
-	Object getValid(String context, String input,
-			ValidationErrorList errorList) throws ValidationException;
+    /**
+     * Get a validated value, add the errors to an existing error list
+     */
+    Object getValid(String context, String input,
+            ValidationErrorList errorList) throws ValidationException;
 
-	/**
-	 * Try to call {@code getvalid}, then call a 'sanitize' method for sanitization (if one exists),
+    /**
+     * Try to call {@code getvalid}, then call a 'sanitize' method for sanitization (if one exists),
      * finally return a default value.
-	 */
-	Object getSafe(String context, String input);
-	
-	/**
-	 * @return true if the input passes validation
-	 */
-	boolean isValid(String context, String input);
+     */
+    Object getSafe(String context, String input);
+
+    /**
+     * @return true if the input passes validation
+     */
+    boolean isValid(String context, String input);
+
+    /**
+     * String the input of all chars contained in the list
+     */
+    String whitelist(String input, char[] list);
 
-	/**
-	 * String the input of all chars contained in the list
-	 */
-	String whitelist(String input, char[] list);
-	
-	/**
-	 * String the input of all chars contained in the list
-	 */
-	String whitelist(String input, Set<Character> list);
+    /**
+     * String the input of all chars contained in the list
+     */
+    String whitelist(String input, Set<Character> list);
 
 }
diff --git a/src/main/java/org/owasp/esapi/Validator.java b/src/main/java/org/owasp/esapi/Validator.java
index e4ae1a6..df7d035 100644
--- a/src/main/java/org/owasp/esapi/Validator.java
+++ b/src/main/java/org/owasp/esapi/Validator.java
@@ -48,679 +48,1019 @@ import org.owasp.esapi.errors.ValidationException;
  */
 public interface Validator {
 
-	/**
-	 * Add a validation rule to the registry using the "type name" of the rule as the key.
-	 */
-	void addRule( ValidationRule rule );
-
-	/**
-	 * Get a validation rule from the registry with the "type name" of the rule as the key.
-	 */
-	ValidationRule getRule( String name );
-
-	/**
-	 * Calls isValidInput and returns true if no exceptions are thrown.
-	 */
-	boolean isValidInput(String context, String input, String type, int maxLength, boolean allowNull) throws IntrusionException;
-
-	/**
-	 * Calls isValidInput and returns true if no exceptions are thrown.
-	 */
-	boolean isValidInput(String context, String input, String type, int maxLength, boolean allowNull, ValidationErrorList errorList) throws IntrusionException;
-
-	/**
-	 * Calls isValidInput and returns true if no exceptions are thrown.
-	 */
-	boolean isValidInput(String context, String input, String type, int maxLength, boolean allowNull, boolean canonicalize) throws IntrusionException;
-
-	/**
-	 * Calls isValidInput and returns true if no exceptions are thrown.
-	 */
-	boolean isValidInput(String context, String input, String type, int maxLength, boolean allowNull, boolean canonicalize, ValidationErrorList errorList) throws IntrusionException;
-
-	/**
-	 * Returns canonicalized and validated input as a String. Invalid input will generate a descriptive ValidationException,
-	 * and input that is clearly an attack will generate a descriptive IntrusionException.
-	 *
-	 * @param context
-	 * 		A descriptive name of the parameter that you are validating (e.g., LoginPage_UsernameField). This value is used by any logging or error handling that is done with respect to the value passed in.
-	 * @param input
-	 * 		The actual user input data to validate.
-	 * @param type
-	 * 		The regular expression name that maps to the actual regular expression from "ESAPI.properties".
-	 * @param maxLength
-	 * 		The maximum post-canonicalized String length allowed.
-	 * @param allowNull
-	 * 		If allowNull is true then an input that is NULL or an empty string will be legal. If allowNull is false then NULL or an empty String will throw a ValidationException.
-	 *
-	 * @return The canonicalized user input.
-	 *
-	 * @throws ValidationException
-	 * @throws IntrusionException
-	 */
-	String getValidInput(String context, String input, String type, int maxLength, boolean allowNull) throws ValidationException, IntrusionException;
-
-	/**
-	 * Returns validated input as a String with optional canonicalization. Invalid input will generate a descriptive ValidationException,
-	 * and input that is clearly an attack will generate a descriptive IntrusionException.
-	 *
-	 * @param context
-	 * 		A descriptive name of the parameter that you are validating (e.g., LoginPage_UsernameField). This value is used by any logging or error handling that is done with respect to the value passed in.
-	 * @param input
-	 * 		The actual user input data to validate.
-	 * @param type
-	 * 		The regular expression name that maps to the actual regular expression from "ESAPI.properties".
-	 * @param maxLength
-	 * 		The maximum post-canonicalized String length allowed.
-	 * @param allowNull
-	 * 		If allowNull is true then an input that is NULL or an empty string will be legal. If allowNull is false then NULL or an empty String will throw a ValidationException.
-	 * @param canonicalize
-	 *      If canonicalize is true then input will be canonicalized before validation
-	 *
-	 * @return The canonicalized user input.
-	 *
-	 * @throws ValidationException
-	 * @throws IntrusionException
-	 */
-	String getValidInput(String context, String input, String type, int maxLength, boolean allowNull, boolean canonicalize) throws ValidationException, IntrusionException;
-
-	/**
-	 * Calls getValidInput with the supplied errorList to capture ValidationExceptions
-	 */
-	String getValidInput(String context, String input, String type, int maxLength, boolean allowNull, ValidationErrorList errorList) throws IntrusionException;
-
-	/**
-	 * Calls getValidInput with the supplied errorList to capture ValidationExceptions
-	 */
-	String getValidInput(String context, String input, String type, int maxLength, boolean allowNull, boolean canonicalize, ValidationErrorList errorList) throws IntrusionException;
-
-	/**
-	 * Calls isValidDate and returns true if no exceptions are thrown.
-	 */
-	boolean isValidDate(String context, String input, DateFormat format, boolean allowNull) throws IntrusionException;
-
-	/**
-	 * Calls isValidDate and returns true if no exceptions are thrown.
-	 */
-	boolean isValidDate(String context, String input, DateFormat format, boolean allowNull, ValidationErrorList errorList) throws IntrusionException;
-
-	/**
-	 * Returns a valid date as a Date. Invalid input will generate a descriptive ValidationException, and input that is clearly an attack
-	 * will generate a descriptive IntrusionException.
-	 *
-	 * @param context
-	 * 		A descriptive name of the parameter that you are validating (e.g., LoginPage_UsernameField). This value is used by any logging or error handling that is done with respect to the value passed in.
-	 * @param input
-	 * 		The actual user input data to validate.
-	 * @param format
-	 * 		Required formatting of date inputted.
-	 * @param allowNull
-	 * 		If allowNull is true then an input that is NULL or an empty string will be legal. If allowNull is false then NULL or an empty String will throw a ValidationException.
-	 *
-	 * @return A valid date as a Date
-	 *
-	 * @throws ValidationException
-	 * @throws IntrusionException
-	 */
-	Date getValidDate(String context, String input, DateFormat format, boolean allowNull) throws ValidationException, IntrusionException;
-
-	/**
-	 * Calls getValidDate with the supplied errorList to capture ValidationExceptions
-	 */
-	Date getValidDate(String context, String input, DateFormat format, boolean allowNull, ValidationErrorList errorList) throws IntrusionException;
-
-	/**
-	 * Calls getValidSafeHTML and returns true if no exceptions are thrown.
-	 */
-	boolean isValidSafeHTML(String context, String input, int maxLength, boolean allowNull) throws IntrusionException;
-
-	/**
-	 * Calls getValidSafeHTML and returns true if no exceptions are thrown.
-	 */
-	boolean isValidSafeHTML(String context, String input, int maxLength, boolean allowNull, ValidationErrorList errorList) throws IntrusionException;
-
-	/**
-	 * Returns canonicalized and validated "safe" HTML that does not contain unwanted scripts in the body, attributes, CSS, URLs, or anywhere else.
-	 * Implementors should reference the OWASP AntiSamy project for ideas
-	 * on how to do HTML validation in a whitelist way, as this is an extremely difficult problem.
-	 *
-	 * @param context
-	 * 		A descriptive name of the parameter that you are validating (e.g., LoginPage_UsernameField). This value is used by any logging or error handling that is done with respect to the value passed in.
-	 * @param input
-	 * 		The actual user input data to validate.
-	 * @param maxLength
-	 * 		The maximum String length allowed.
-	 * @param allowNull
-	 * 		If allowNull is true then an input that is NULL or an empty string will be legal. If allowNull is false then NULL or an empty String will throw a ValidationException.
-	 *
-	 * @return Valid safe HTML
-	 *
-	 * @throws ValidationException
-	 * @throws IntrusionException
-	 */
-	String getValidSafeHTML(String context, String input, int maxLength, boolean allowNull) throws ValidationException, IntrusionException;
-
-	/**
-	 * Calls getValidSafeHTML with the supplied errorList to capture ValidationExceptions
-	 */
-	String getValidSafeHTML(String context, String input, int maxLength, boolean allowNull, ValidationErrorList errorList) throws IntrusionException;
-
-	/**
-	 * Calls getValidCreditCard and returns true if no exceptions are thrown.
-	 */
-	boolean isValidCreditCard(String context, String input, boolean allowNull) throws IntrusionException;
-
-	/**
-	 * Calls getValidCreditCard and returns true if no exceptions are thrown.
-	 */
-	boolean isValidCreditCard(String context, String input, boolean allowNull, ValidationErrorList errorList) throws IntrusionException;
-
-	/**
-	 * Returns a canonicalized and validated credit card number as a String. Invalid input
-	 * will generate a descriptive ValidationException, and input that is clearly an attack
-	 * will generate a descriptive IntrusionException.
-	 *
-	 * @param context
-	 * 		A descriptive name of the parameter that you are validating (e.g., LoginPage_UsernameField). This value is used by any logging or error handling that is done with respect to the value passed in.
-	 * @param input
-	 * 		The actual user input data to validate.
-	 * @param allowNull
-	 * 		If allowNull is true then an input that is NULL or an empty string will be legal. If allowNull is false then NULL or an empty String will throw a ValidationException.
-	 *
-	 * @return A valid credit card number
-	 *
-	 * @throws ValidationException
-	 * @throws IntrusionException
-	 */
-	String getValidCreditCard(String context, String input, boolean allowNull) throws ValidationException, IntrusionException;
-
-	/**
-	 * Calls getValidCreditCard with the supplied errorList to capture ValidationExceptions
-	 */
-	String getValidCreditCard(String context, String input, boolean allowNull, ValidationErrorList errorList) throws IntrusionException;
-
-	/**
-	 * Calls getValidDirectoryPath and returns true if no exceptions are thrown.
-	 */
-	boolean isValidDirectoryPath(String context, String input, File parent, boolean allowNull) throws IntrusionException;
-
-	/**
-	 * Calls getValidDirectoryPath and returns true if no exceptions are thrown.
-	 */
-	boolean isValidDirectoryPath(String context, String input, File parent, boolean allowNull, ValidationErrorList errorList) throws IntrusionException;
-
-	/**
-	 * Returns a canonicalized and validated directory path as a String, provided that the input
-	 * maps to an existing directory that is an existing subdirectory (at any level) of the specified parent. Invalid input
-	 * will generate a descriptive ValidationException, and input that is clearly an attack
-	 * will generate a descriptive IntrusionException. Instead of throwing a ValidationException
-	 * on error, this variant will store the exception inside of the ValidationErrorList.
-	 *
-	 * @param context
-	 * 		A descriptive name of the parameter that you are validating (e.g., LoginPage_UsernameField). This value is used by any logging or error handling that is done with respect to the value passed in.
-	 * @param input
-	 * 		The actual input data to validate.
-	 * @param allowNull
-	 * 		If allowNull is true then an input that is NULL or an empty string will be legal. If allowNull is false then NULL or an empty String will throw a ValidationException.
-	 *
-	 * @return A valid directory path
-	 *
-	 * @throws ValidationException
-	 * @throws IntrusionException
-	 */
-	String getValidDirectoryPath(String context, String input, File parent, boolean allowNull) throws ValidationException, IntrusionException;
-
-	/**
-	 * Calls getValidDirectoryPath with the supplied errorList to capture ValidationExceptions
-	 */
-	String getValidDirectoryPath(String context, String input, File parent, boolean allowNull, ValidationErrorList errorList) throws IntrusionException;
-
-	/**
-	 * Calls getValidFileName with the default list of allowedExtensions
-	 */
-	boolean isValidFileName(String context, String input, boolean allowNull) throws IntrusionException;
-
-	/**
-	 * Calls getValidFileName with the default list of allowedExtensions
-	 */
-	boolean isValidFileName(String context, String input, boolean allowNull, ValidationErrorList errorList) throws IntrusionException;
-
-	/**
-	 * Calls getValidFileName and returns true if no exceptions are thrown.
-	 */
-	boolean isValidFileName(String context, String input, List<String> allowedExtensions, boolean allowNull) throws IntrusionException;
-
-	/**
-	 * Calls getValidFileName and returns true if no exceptions are thrown.
-	 */
-	boolean isValidFileName(String context, String input, List<String> allowedExtensions, boolean allowNull, ValidationErrorList errorList) throws IntrusionException;
-
-	/**
-	 * Returns a canonicalized and validated file name as a String. Implementors should check for allowed file extensions here, as well as allowed file name characters, as declared in "ESAPI.properties". Invalid input
-	 * will generate a descriptive ValidationException, and input that is clearly an attack
-	 * will generate a descriptive IntrusionException.
-	 *
-	 * @param context
-	 * 		A descriptive name of the parameter that you are validating (e.g., LoginPage_UsernameField). This value is used by any logging or error handling that is done with respect to the value passed in.
+    /**
+     * Add a validation rule to the registry using the "type name" of the rule as the key.
+     */
+    void addRule( ValidationRule rule );
+
+    /**
+     * Get a validation rule from the registry with the "type name" of the rule as the key.
+     */
+    ValidationRule getRule( String name );
+
+    /**
+     * Returns true if canonicalized input is valid.
+     * <p>
+     * Calls {@link #getValidInput(String, String, String, int, boolean, boolean)} with {@code canonicalize=true}
+     * and returns true if no exceptions are thrown.
+     *
+     * @throws IntrusionException Input likely indicates an attack.
+     */
+    boolean isValidInput(String context, String input, String type, int maxLength, boolean allowNull) throws IntrusionException;
+
+    /**
+     * Returns true if canonicalized input is valid,
+     * any validation exceptions are added to the supplied {@code errorList}.
+     * <p>
+     * Calls {@link #getValidInput(String, String, String, int, boolean, boolean)} with {@code canonicalize=true}
+     * and returns true if no exceptions are thrown.
+     *
+     * @throws IntrusionException Input likely indicates an attack.
+     */
+    boolean isValidInput(String context, String input, String type, int maxLength, boolean allowNull, ValidationErrorList errorList) throws IntrusionException;
+
+    /**
+     * Returns true if {@code input} is valid.
+     * <p>
+     * Calls {@link #getValidInput(String, String, String, int, boolean, boolean)}
+     * and returns true if no exceptions are thrown.
+     *
+     * @throws IntrusionException Input likely indicates an attack.
+     */
+    boolean isValidInput(String context, String input, String type, int maxLength, boolean allowNull, boolean canonicalize) throws IntrusionException;
+
+    /**
+     * Returns true if {@code input} is valid,
+     * any validation exceptions are added to the supplied {@code errorList}.
+     * <p>
+     * Calls {@link #getValidInput(String, String, String, int, boolean, boolean)}
+     * and returns true if no exceptions are thrown.
+     *
+     * @throws IntrusionException Input likely indicates an attack.
+     */
+    boolean isValidInput(String context, String input, String type, int maxLength, boolean allowNull, boolean canonicalize, ValidationErrorList errorList) throws IntrusionException;
+
+    /**
+     * Returns validated canonicalized {@code input} as a String.
+     * <p>
+     * Calls {@link #getValidInput(String, String, String, int, boolean, boolean)}
+     * with {@code canonicalize=true}.
+     *
+     * @throws ValidationException Input is invalid.
+     * @throws IntrusionException Input likely indicates an attack.
+     */
+    String getValidInput(String context, String input, String type, int maxLength, boolean allowNull) throws ValidationException, IntrusionException;
+
+    /**
+     * Returns validated {@code input} as a String with optional canonicalization.
+     * <p>
+     * Invalid input will generate a descriptive ValidationException,
+     * and input that is clearly an attack will generate a descriptive IntrusionException.
+     *
+     * @param context
+     *        A descriptive name of the parameter that you are validating (e.g., LoginPage_UsernameField).
+     *        This value is used by any logging or error handling that is done with respect to the value passed in.
+     * @param input
+     *        The actual user input data to validate.
+     * @param type
+     *        The regular expression name which maps to the actual regular expression from "ESAPI.properties".
+     * @param maxLength
+     *        The maximum post-canonicalized String length allowed.
+     * @param allowNull
+     *        If {@code allowNull} is true then an input that is NULL or an empty string will be legal.
+     *        If {@code allowNull} is false then NULL or an empty String will throw a ValidationException.
+     * @param canonicalize
+     *        If canonicalize is true then input will be canonicalized before validation.
+     *
+     * @return The canonicalized user input.
+     *
+     * @throws ValidationException Input is invalid.
+     * @throws IntrusionException Input likely indicates an attack.
+     */
+    String getValidInput(String context, String input, String type, int maxLength, boolean allowNull, boolean canonicalize) throws ValidationException, IntrusionException;
+
+    /**
+     * Returns canonicalized validated {@code input} as a String,
+     * and adds validation exceptions to the supplied {@code errorList}.
+     * <p>
+     * Calls {@link #getValidInput(String, String, String, int, boolean, boolean)}.
+     *
+     * @throws IntrusionException Input likely indicates an attack.
+     */
+    String getValidInput(String context, String input, String type, int maxLength, boolean allowNull, ValidationErrorList errorList) throws IntrusionException;
+
+    /**
+     * Returns validated {@code input} as a String with optional canonicalization,
+     * and adds validation exceptions to the supplied {@code errorList}.
+     * <p>
+     * Returns the result of calling {@link #getValidInput(String, String, String, int, boolean, boolean)}
+     * with {@code canonicalize=true}.
+     *
+     * @throws IntrusionException Input likely indicates an attack.
+     */
+    String getValidInput(String context, String input, String type, int maxLength, boolean allowNull, boolean canonicalize, ValidationErrorList errorList) throws IntrusionException;
+
+    /**
+     * Returns true if {@code input} is valid.
+     * <p>
+     * Calls {@link #getValidDate(String, String, DateFormat, boolean)},
+     * and returns true if no exceptions are thrown.
+     *
+     * @throws IntrusionException Input likely indicates an attack.
+     */
+    boolean isValidDate(String context, String input, DateFormat format, boolean allowNull) throws IntrusionException;
+
+    /**
+     * Returns true if {@code input} is valid,
+     * any validation exceptions are added to the supplied {@code errorList}.
+     * <p>
+     * Calls {@link #getValidDate(String, String, DateFormat, boolean)}
+     * and returns true if no exceptions are thrown.
+     *
+     * @throws IntrusionException Input likely indicates an attack.
+     */
+    boolean isValidDate(String context, String input, DateFormat format, boolean allowNull, ValidationErrorList errorList) throws IntrusionException;
+
+    /**
+     * Returns a valid date as a {@link java.util.Date}.
+     * <p>
+     * Invalid input will generate a descriptive ValidationException,
+     * and input that is clearly an attack will generate a descriptive IntrusionException.
+     *
+     * @param context
+     *         A descriptive name of the parameter that you are validating (e.g., LoginPage_UsernameField).
+     *         This value is used by any logging or error handling that is done with respect to the value passed in.
+     * @param input
+     *         The actual user input data to validate.
+     * @param format
+     *         Required formatting of date inputted.
+     * @param allowNull
+     *         If {@code allowNull} is true then an input that is NULL or an empty string will be legal.
+     *         If {@code allowNull} is false then NULL or an empty String will throw a ValidationException.
+     *
+     * @return A valid date as a {@link java.util.Date}
+     *
+     * @throws ValidationException Input is invalid.
+     * @throws IntrusionException Input likely indicates an attack.
+     */
+    Date getValidDate(String context, String input, DateFormat format, boolean allowNull) throws ValidationException, IntrusionException;
+
+    /**
+     * Returns a valid date as a {@link java.util.Date},
+     * any validation exceptions are added to the supplied {@code errorList}.
+     * <p>
+     * Calls {@link #getValidDate(String, String, DateFormat, boolean)}.
+     *
+     * @throws IntrusionException Input likely indicates an attack.
+     */
+    Date getValidDate(String context, String input, DateFormat format, boolean allowNull, ValidationErrorList errorList) throws IntrusionException;
+
+    /**
+     * Returns true if {@code input} is valid.
+     * <p>
+     * Calls {@link #getValidSafeHTML(String, String, int, boolean)},
+     * and returns true if no exceptions are thrown.
+     *
+     * @throws IntrusionException Input likely indicates an attack.
+     */
+    boolean isValidSafeHTML(String context, String input, int maxLength, boolean allowNull) throws IntrusionException;
+
+    /**
+     * Returns true if {@code input} is valid,
+     * any validation exceptions are added to the supplied {@code errorList}.
+     * <p>
+     * Calls {@link #getValidSafeHTML(String, String, int, boolean)}
+     * and returns true if no exceptions are thrown.
+     *
+     * @throws IntrusionException Input likely indicates an attack.
+     */
+    boolean isValidSafeHTML(String context, String input, int maxLength, boolean allowNull, ValidationErrorList errorList) throws IntrusionException;
+
+    /**
+     * Returns canonicalized and validated "safe" HTML that does not contain unwanted scripts in the body, attributes, CSS, URLs, or anywhere else.
+     * <p>
+     * The default behavior of this check depends on the {@code antisamy-esapi.xml} configuration.
+     * Implementors should reference the <a href="https://owasp.org/www-project-antisamy/">OWASP AntiSamy project</a> for ideas
+     * on how to do HTML validation in a whitelist way, as this is an extremely difficult problem.
+     *
+     * @param context
+     *         A descriptive name of the parameter that you are validating (e.g., LoginPage_UsernameField).
+     *         This value is used by any logging or error handling that is done with respect to the value passed in.
+     * @param input
+     *         The actual user input data to validate.
+     * @param maxLength
+     *         The maximum String length allowed.
+     * @param allowNull
+     *         If {@code allowNull} is true then an input that is NULL or an empty string will be legal.
+     *         If {@code allowNull} is false then NULL or an empty String will throw a ValidationException.
+     *
+     * @return Valid safe HTML
+     *
+     * @throws ValidationException Input is invalid.
+     * @throws IntrusionException Input likely indicates an attack.
+     */
+    String getValidSafeHTML(String context, String input, int maxLength, boolean allowNull) throws ValidationException, IntrusionException;
+
+    /**
+     * Returns canonicalized and validated "safe" HTML that does not contain unwanted scripts in the body, attributes, CSS, URLs, or anywhere else,
+     * any validation exceptions are added to the supplied {@code errorList}.
+     * <p>
+     * The default behavior of this check depends on the {@code antisamy-esapi.xml} configuration.
+     * Implementors should reference the <a href="https://owasp.org/www-project-antisamy/">OWASP AntiSamy project</a> for ideas
+     * on how to do HTML validation in a whitelist way, as this is an extremely difficult problem.
+     * <p>
+     * Calls {@link #getValidSafeHTML(String, String, int, boolean)}.
+     *
+     * @throws IntrusionException Input likely indicates an attack.
+     */
+    String getValidSafeHTML(String context, String input, int maxLength, boolean allowNull, ValidationErrorList errorList) throws IntrusionException;
+
+    /**
+     * Returns true if {@code input} matches the pattern for a valid credit card number.
+     * <p>
+     * Calls {@link #getValidCreditCard(String, String, boolean)},
+     * and returns true if no exceptions are thrown.
+     *
+     * @throws IntrusionException Input likely indicates an attack.
+     */
+    boolean isValidCreditCard(String context, String input, boolean allowNull) throws IntrusionException;
+
+    /**
+     * Returns true if {@code input} matches the pattern for a valid credit card number,
+     * any validation exceptions are added to the supplied {@code errorList}.
+     * <p>
+     * Calls {@link #getValidCreditCard(String, String, boolean)}
+     * and returns true if no exceptions are thrown.
+     *
+     * @throws IntrusionException Input likely indicates an attack.
+     */
+    boolean isValidCreditCard(String context, String input, boolean allowNull, ValidationErrorList errorList) throws IntrusionException;
+
+    /**
+     * Returns a canonicalized and validated credit card number as a String.
+     * <p>
+     * Invalid input will generate a descriptive ValidationException,
+     * and input that is clearly an attack will generate a descriptive IntrusionException.
+     *
+     * @param context
+     *         A descriptive name of the parameter that you are validating (e.g., LoginPage_UsernameField).
+     *         This value is used by any logging or error handling that is done with respect to the value passed in.
      * @param input
-     * 		The actual input data to validate.
+     *         The actual user input data to validate.
      * @param allowNull
-     * 		If allowNull is true then an input that is NULL or an empty string will be legal. If allowNull is false then NULL or an empty String will throw a ValidationException.
+     *         If {@code allowNull} is true then an input that is NULL or an empty string will be legal.
+     *         If {@code allowNull} is false then NULL or an empty String will throw a ValidationException.
+     *
+     * @return A valid credit card number
+     *
+     * @throws ValidationException Input is invalid.
+     * @throws IntrusionException Input likely indicates an attack.
+     */
+    String getValidCreditCard(String context, String input, boolean allowNull) throws ValidationException, IntrusionException;
+
+    /**
+     * Returns a canonicalized and validated credit card number as a String,
+     * any validation exceptions are added to the supplied {@code errorList}.
+     * <p>
+     * Calls {@link #getValidCreditCard(String, String, boolean)}.
+     *
+     * @throws IntrusionException Input likely indicates an attack.
+     */
+    String getValidCreditCard(String context, String input, boolean allowNull, ValidationErrorList errorList) throws IntrusionException;
+
+    /**
+     * Returns true if {@code input} is valid.
+     * <p>
+     * Calls {@link #getValidDirectoryPath(String, String, File, boolean)},
+     * and returns true if no exceptions are thrown.
+     *
+     * @throws IntrusionException Input likely indicates an attack.
+     */
+    boolean isValidDirectoryPath(String context, String input, File parent, boolean allowNull) throws IntrusionException;
+
+    /**
+     * Returns true if {@code input} is valid,
+     * any validation exceptions are added to the supplied {@code errorList}.
+     * <p>
+     * Calls {@link #getValidDirectoryPath(String, String, File, boolean)}
+     * and returns true if no exceptions are thrown.
+     *
+     * @throws IntrusionException Input likely indicates an attack.
+     */
+    boolean isValidDirectoryPath(String context, String input, File parent, boolean allowNull, ValidationErrorList errorList) throws IntrusionException;
+
+    /**
+     * Returns a canonicalized and validated directory path as a String, provided that the input
+     * maps to an existing directory that is an existing subdirectory (at any level) of the specified parent.
+     * <p>
+     * Invalid input will generate a descriptive ValidationException,
+     * and input that is clearly an attack will generate a descriptive IntrusionException.
+     *
+     * @param context
+     *         A descriptive name of the parameter that you are validating (e.g., LoginPage_UsernameField).
+     *         This value is used by any logging or error handling that is done with respect to the value passed in.
+     * @param input
+     *         The actual input data to validate.
+     * @param allowNull
+     *         If {@code allowNull} is true then an input that is NULL or an empty string will be legal.
+     *         If {@code allowNull} is false then NULL or an empty String will throw a ValidationException.
+     *
+     * @return A valid directory path
+     *
+     * @throws ValidationException Input is invalid.
+     * @throws IntrusionException Input likely indicates an attack.
+     */
+    String getValidDirectoryPath(String context, String input, File parent, boolean allowNull) throws ValidationException, IntrusionException;
+
+    /**
+     * Returns a canonicalized and validated directory path as a String, provided that the input
+     * maps to an existing directory that is an existing subdirectory (at any level) of the specified parent;
+     * any validation exceptions are added to the supplied {@code errorList}.
+     * <p>
+     * Calls {@link #getValidDirectoryPath(String, String, File, boolean)}.
+     *
+     * @throws IntrusionException Input likely indicates an attack.
+     */
+    String getValidDirectoryPath(String context, String input, File parent, boolean allowNull, ValidationErrorList errorList) throws IntrusionException;
+
+    /**
+     * Returns true if {@code input} is valid.
+     * <p>
+     * Calls {@link #getValidFileName(String, String, List, boolean)}
+     * with allowedExtensions set to the configured {@code ESAPI.securityConfiguration().getAllowedFileExtensions()}
+     * and returns true if no exceptions are thrown.
+     *
+     * @throws IntrusionException Input likely indicates an attack.
+     *
+     * @see ESAPI#securityConfiguration()
+     * @see SecurityConfiguration#getAllowedFileExtensions()
+     */
+    boolean isValidFileName(String context, String input, boolean allowNull) throws IntrusionException;
+
+    /**
+     * Returns true if {@code input} is valid,
+     * any validation exceptions are added to the supplied {@code errorList}.
+     * <p>
+     * Calls {@link #getValidFileName(String, String, List, boolean)}
+     * with allowedExtensions set to the configured {@code ESAPI.securityConfiguration().getAllowedFileExtensions()}
+     * and returns true if no exceptions are thrown.
+     *
+     * @throws IntrusionException Input likely indicates an attack.
+     *
+     * @see ESAPI#securityConfiguration()
+     * @see SecurityConfiguration#getAllowedFileExtensions()
+     */
+    boolean isValidFileName(String context, String input, boolean allowNull, ValidationErrorList errorList) throws IntrusionException;
+
+    /**
+     * Returns true if {@code input} is valid.
+     * <p>
+     * Calls {@link #getValidFileName(String, String, List, boolean)},
+     * and returns true if no exceptions are thrown.
+     *
+     * @throws IntrusionException Input likely indicates an attack.
+     *
+     * @see ESAPI#securityConfiguration()
+     * @see SecurityConfiguration#getAllowedFileExtensions()
+     */
+    boolean isValidFileName(String context, String input, List<String> allowedExtensions, boolean allowNull) throws IntrusionException;
+
+    /**
+     * Returns true if {@code input} is valid,
+     * any validation exceptions are added to the supplied {@code errorList}.
+     * <p>
+     * Calls {@link #getValidFileName(String, String, List, boolean)}
+     * and returns true if no exceptions are thrown.
+     *
+     * @throws IntrusionException Input likely indicates an attack.
+     *
+     * @see ESAPI#securityConfiguration()
+     * @see SecurityConfiguration#getAllowedFileExtensions()
+     */
+    boolean isValidFileName(String context, String input, List<String> allowedExtensions, boolean allowNull, ValidationErrorList errorList) throws IntrusionException;
+
+    /**
+     * Returns a canonicalized and validated file name as a String.
+     * Implementors should check for allowed file extensions here,
+     * as well as allowed file name characters, as declared in "ESAPI.properties".
+     * Invalid input will generate a descriptive ValidationException,
+     * and input that is clearly an attack will generate a descriptive IntrusionException.
+     *
+     * @param context
+     *         A descriptive name of the parameter that you are validating (e.g., LoginPage_UsernameField).
+     *         This value is used by any logging or error handling that is done with respect to the value passed in.
+     * @param input
+     *         The actual input data to validate.
+     * @param allowedExtensions
+     *         List of file extensions which will be accepted.
+     * @param allowNull
+     *         If {@code allowNull} is true then an input that is NULL or an empty string will be legal.
+     *         If {@code allowNull} is false then NULL or an empty String will throw a ValidationException.
      *
      * @return A valid file name
      *
-     * @throws ValidationException
-     * @throws IntrusionException
-	 */
-	String getValidFileName(String context, String input, List<String> allowedExtensions, boolean allowNull) throws ValidationException, IntrusionException;
-
-	/**
-	 * Calls getValidFileName with the supplied errorList to capture ValidationExceptions
-	 */
-	String getValidFileName(String context, String input, List<String> allowedExtensions, boolean allowNull, ValidationErrorList errorList) throws IntrusionException;
-
-	/**
-	 * Calls getValidNumber and returns true if no exceptions are thrown.
-	 */
-	boolean isValidNumber(String context, String input, long minValue, long maxValue, boolean allowNull) throws IntrusionException;
-
-	/**
-	 * Calls getValidNumber and returns true if no exceptions are thrown.
-	 */
-	boolean isValidNumber(String context, String input, long minValue, long maxValue, boolean allowNull, ValidationErrorList errorList) throws IntrusionException;
-
-	/**
-	 * Returns a validated number as a double within the range of minValue to maxValue. Invalid input
-	 * will generate a descriptive ValidationException, and input that is clearly an attack
-	 * will generate a descriptive IntrusionException.
-	 *
-	 * @param context
-	 * 		A descriptive name of the parameter that you are validating (e.g., LoginPage_UsernameField). This value is used by any logging or error handling that is done with respect to the value passed in.
+     * @throws ValidationException Input is invalid.
+     * @throws IntrusionException Input likely indicates an attack.
+     */
+    String getValidFileName(String context, String input, List<String> allowedExtensions, boolean allowNull) throws ValidationException, IntrusionException;
+
+    /**
+     * Returns a canonicalized and validated file name as a String,
+     * any validation exceptions are added to the supplied {@code errorList}.
+     * <p>
+     * Calls {@link #getValidFileName(String, String, List, boolean)},
+     * the supplied {@code errorList} is used to capture ValidationExceptions.
+     *
+     * @throws IntrusionException Input likely indicates an attack.
+     */
+    String getValidFileName(String context, String input, List<String> allowedExtensions, boolean allowNull, ValidationErrorList errorList) throws IntrusionException;
+
+    /**
+     * Returns true if {@code input} is valid.
+     * <p>
+     * Calls {@link #getValidNumber(String, String, long, long, boolean)},
+     * and returns true if no exceptions are thrown.
+     *
+     * @throws IntrusionException Input likely indicates an attack.
+     */
+    boolean isValidNumber(String context, String input, long minValue, long maxValue, boolean allowNull) throws IntrusionException;
+
+    /**
+     * Returns true if {@code input} is valid,
+     * any validation exceptions are added to the supplied {@code errorList}.
+     * <p>
+     * Calls {@link #getValidNumber(String, String, long, long, boolean)}
+     * and returns true if no exceptions are thrown.
+     *
+     * @throws IntrusionException Input likely indicates an attack.
+     */
+    boolean isValidNumber(String context, String input, long minValue, long maxValue, boolean allowNull, ValidationErrorList errorList) throws IntrusionException;
+
+    /**
+     * Returns a validated number as a double within the range of minValue to maxValue.
+     * Invalid input will generate a descriptive ValidationException,
+     * and input that is clearly an attack will generate a descriptive IntrusionException.
+     *
+     * @param context
+     *         A descriptive name of the parameter that you are validating (e.g., LoginPage_UsernameField).
+     *         This value is used by any logging or error handling that is done with respect to the value passed in.
      * @param input
-     * 		The actual input data to validate.
+     *         The actual input data to validate.
      * @param allowNull
-     * 		If allowNull is true then an input that is NULL or an empty string will be legal. If allowNull is false then NULL or an empty String will throw a ValidationException.
+     *         If {@code allowNull} is true then an input that is NULL or an empty string will be legal.
+     *         If {@code allowNull} is false then NULL or an empty String will throw a ValidationException.
      * @param minValue
-     * 		Lowest legal value for input.
+     *         Lowest legal value for input.
      * @param maxValue
-     * 		Highest legal value for input.
+     *         Highest legal value for input.
      *
      * @return A validated number as a double.
      *
-     * @throws ValidationException
-     * @throws IntrusionException
-	 */
-	Double getValidNumber(String context, String input, long minValue, long maxValue, boolean allowNull) throws ValidationException, IntrusionException;
-
-	/**
-	 * Calls getValidSafeHTML with the supplied errorList to capture ValidationExceptions
-	 */
-	Double getValidNumber(String context, String input, long minValue, long maxValue, boolean allowNull, ValidationErrorList errorList) throws IntrusionException;
-
-	/**
-	 * Calls getValidInteger and returns true if no exceptions are thrown.
-	 */
-	boolean isValidInteger(String context, String input, int minValue, int maxValue, boolean allowNull) throws IntrusionException;
-
-	/**
-	 * Calls getValidInteger and returns true if no exceptions are thrown.
-	 */
-	boolean isValidInteger(String context, String input, int minValue, int maxValue, boolean allowNull, ValidationErrorList errorList) throws IntrusionException;
-
-	/**
-	 * Returns a validated integer. Invalid input
-	 * will generate a descriptive ValidationException, and input that is clearly an attack
-	 * will generate a descriptive IntrusionException.
-	 *
-	 * @param context
-	 * 		A descriptive name of the parameter that you are validating (e.g., LoginPage_UsernameField). This value is used by any logging or error handling that is done with respect to the value passed in.
+     * @throws ValidationException Input is invalid.
+     * @throws IntrusionException Input likely indicates an attack.
+     */
+    Double getValidNumber(String context, String input, long minValue, long maxValue, boolean allowNull) throws ValidationException, IntrusionException;
+
+    /**
+     * Returns a validated number as a double within the range of minValue to maxValue,
+     * any validation exceptions are added to the supplied {@code errorList}.
+     * <p>
+     * Calls {@link #getValidNumber(String, String, long, long, boolean)}.
+     *
+     * @throws IntrusionException Input likely indicates an attack.
+     */
+    Double getValidNumber(String context, String input, long minValue, long maxValue, boolean allowNull, ValidationErrorList errorList) throws IntrusionException;
+
+    /**
+     * Returns true if {@code input} is a valid integer between {@code minValue} and {@code maxValue} inclusive.
+     * <p>
+     * Calls {@link #getValidInteger(String, String, int, int, boolean)},
+     * and returns true if no exceptions are thrown.
+     *
+     * @throws IntrusionException Input likely indicates an attack.
+     */
+    boolean isValidInteger(String context, String input, int minValue, int maxValue, boolean allowNull) throws IntrusionException;
+
+    /**
+     * Returns true if {@code input} is a valid integer between {@code minValue} and {@code maxValue} inclusive,
+     * any validation exceptions are added to the supplied {@code errorList}.
+     * <p>
+     * Calls {@link #getValidInteger(String, String, int, int, boolean)}
+     * and returns true if no exceptions are thrown.
+     *
+     * @throws IntrusionException Input likely indicates an attack.
+     */
+    boolean isValidInteger(String context, String input, int minValue, int maxValue, boolean allowNull, ValidationErrorList errorList) throws IntrusionException;
+
+    /**
+     * Returns a validated integer,
+     * {@code input} is a valid integer if it is between {@code minValue} and {@code maxValue} inclusive.
+     * Invalid input will generate a descriptive ValidationException,
+     * and input that is clearly an attack will generate a descriptive IntrusionException.
+     *
+     * @param context
+     *         A descriptive name of the parameter that you are validating (e.g., LoginPage_UsernameField).
+     *         This value is used by any logging or error handling that is done with respect to the value passed in.
      * @param input
-     * 		The actual input data to validate.
+     *         The actual input data to validate.
      * @param allowNull
-     * 		If allowNull is true then an input that is NULL or an empty string will be legal. If allowNull is false then NULL or an empty String will throw a ValidationException.
+     *         If {@code allowNull} is true then an input that is NULL or an empty string will be legal.
+     *         If {@code allowNull} is false then NULL or an empty String will throw a ValidationException.
      * @param minValue
-     * 		Lowest legal value for input.
+     *         Lowest legal value for input.
      * @param maxValue
-     * 		Highest legal value for input.
+     *         Highest legal value for input.
      *
      * @return A validated number as an integer.
      *
-     * @throws ValidationException
-     * @throws IntrusionException
-	 */
-	Integer getValidInteger(String context, String input, int minValue, int maxValue, boolean allowNull) throws ValidationException, IntrusionException;
-
-	/**
-	 * Calls getValidInteger with the supplied errorList to capture ValidationExceptions
-	 */
-	Integer getValidInteger(String context, String input, int minValue, int maxValue, boolean allowNull, ValidationErrorList errorList) throws IntrusionException;
-
-	/**
-	 * Calls getValidDouble and returns true if no exceptions are thrown.
-	 */
-	boolean isValidDouble(String context, String input, double minValue, double maxValue, boolean allowNull) throws IntrusionException;
-
-	/**
-	 * Calls getValidDouble and returns true if no exceptions are thrown.
-	 */
-	boolean isValidDouble(String context, String input, double minValue, double maxValue, boolean allowNull, ValidationErrorList errorList) throws IntrusionException;
-
-	/**
-	 * Returns a validated real number as a double. Invalid input
-	 * will generate a descriptive ValidationException, and input that is clearly an attack
-	 * will generate a descriptive IntrusionException.
-	 *
-	 * @param context
-	 * 		A descriptive name of the parameter that you are validating (e.g., LoginPage_UsernameField). This value is used by any logging or error handling that is done with respect to the value passed in.
+     * @throws ValidationException Input is invalid.
+     * @throws IntrusionException Input likely indicates an attack.
+     */
+    Integer getValidInteger(String context, String input, int minValue, int maxValue, boolean allowNull) throws ValidationException, IntrusionException;
+
+    /**
+     * Returns a validated integer,
+     * any validation exceptions are added to the supplied {@code errorList}.
+     * <p>
+     * Calls {@link #getValidInteger(String, String, int, int, boolean)}.
+     *
+     * @throws IntrusionException Input likely indicates an attack.
+     */
+    Integer getValidInteger(String context, String input, int minValue, int maxValue, boolean allowNull, ValidationErrorList errorList) throws IntrusionException;
+
+    /**
+     * Returns true if {@code input} is valid.
+     * <p>
+     * Calls {@link #getValidDouble(String, String, double, double, boolean)},
+     * and returns true if no exceptions are thrown.
+     *
+     * @throws IntrusionException Input likely indicates an attack.
+     */
+    boolean isValidDouble(String context, String input, double minValue, double maxValue, boolean allowNull) throws IntrusionException;
+
+    /**
+     * Returns true if {@code input} is valid,
+     * any validation exceptions are added to the supplied {@code errorList}.
+     * <p>
+     * Calls {@link #getValidDouble(String, String, double, double, boolean)}
+     * and returns true if no exceptions are thrown.
+     *
+     * @throws IntrusionException Input likely indicates an attack.
+     */
+    boolean isValidDouble(String context, String input, double minValue, double maxValue, boolean allowNull, ValidationErrorList errorList) throws IntrusionException;
+
+    /**
+     * Returns a validated real number as a double.
+     * Invalid input will generate a descriptive ValidationException,
+     * and input that is clearly an attack will generate a descriptive IntrusionException.
+     *
+     * @param context
+     *         A descriptive name of the parameter that you are validating (e.g., LoginPage_UsernameField).
+     *         This value is used by any logging or error handling that is done with respect to the value passed in.
      * @param input
-     * 		The actual input data to validate.
+     *         The actual input data to validate.
      * @param allowNull
-     * 		If allowNull is true then an input that is NULL or an empty string will be legal. If allowNull is false then NULL or an empty String will throw a ValidationException.
+     *         If {@code allowNull} is true then an input that is NULL or an empty string will be legal.
+     *         If {@code allowNull} is false then NULL or an empty String will throw a ValidationException.
      * @param minValue
-     * 		Lowest legal value for input.
+     *         Lowest legal value for input.
      * @param maxValue
-     * 		Highest legal value for input.
+     *         Highest legal value for input.
      *
      * @return A validated real number as a double.
      *
-     * @throws ValidationException
-     * @throws IntrusionException
-	 */
-	Double getValidDouble(String context, String input, double minValue, double maxValue, boolean allowNull) throws ValidationException, IntrusionException;
-
-	/**
-	 * Calls getValidDouble with the supplied errorList to capture ValidationExceptions
-	 */
-	Double getValidDouble(String context, String input, double minValue, double maxValue, boolean allowNull, ValidationErrorList errorList) throws IntrusionException;
-
-	/**
-	 * Calls getValidFileContent and returns true if no exceptions are thrown.
-	 */
-	boolean isValidFileContent(String context, byte[] input, int maxBytes, boolean allowNull) throws IntrusionException;
-
-	/**
-	 * Calls getValidFileContent and returns true if no exceptions are thrown.
-	 */
-	boolean isValidFileContent(String context, byte[] input, int maxBytes, boolean allowNull, ValidationErrorList errorList) throws IntrusionException;
-
-	/**
-	 * Returns validated file content as a byte array. This is a good place to check for max file size, allowed character sets, and do virus scans.  Invalid input
-	 * will generate a descriptive ValidationException, and input that is clearly an attack
-	 * will generate a descriptive IntrusionException.
-	 *
-	 * @param context
-	 * 		A descriptive name of the parameter that you are validating (e.g., LoginPage_UsernameField). This value is used by any logging or error handling that is done with respect to the value passed in.
-	 * @param input
-	 * 		The actual input data to validate.
-	 * @param maxBytes
-	 * 		The maximum number of bytes allowed in a legal file.
-	 * @param allowNull
-	 * 		If allowNull is true then an input that is NULL or an empty string will be legal. If allowNull is false then NULL or an empty String will throw a ValidationException.
-	 *
-	 * @return A byte array containing valid file content.
-	 *
-	 * @throws ValidationException
-	 * @throws IntrusionException
-	 */
-	byte[] getValidFileContent(String context, byte[] input, int maxBytes, boolean allowNull) throws ValidationException, IntrusionException;
-
-	/**
-	 * Calls getValidFileContent with the supplied errorList to capture ValidationExceptions
-	 */
-	byte[] getValidFileContent(String context, byte[] input, int maxBytes, boolean allowNull, ValidationErrorList errorList) throws IntrusionException;
-
-	/**
-	 * Calls getValidFileUpload and returns true if no exceptions are thrown.
-	 */
-	boolean isValidFileUpload(String context, String filepath, String filename, File parent, byte[] content, int maxBytes, boolean allowNull) throws IntrusionException;
-
-	/**
-	 * Calls getValidFileUpload and returns true if no exceptions are thrown.
-	 */
-	boolean isValidFileUpload(String context, String filepath, String filename, File parent, byte[] content, int maxBytes, boolean allowNull, ValidationErrorList errorList) throws IntrusionException;
-
-	/**
-	 * Validates the filepath, filename, and content of a file. Invalid input
-	 * will generate a descriptive ValidationException, and input that is clearly an attack
-	 * will generate a descriptive IntrusionException.
-	 *
-	 * @param context
-	 * 		A descriptive name of the parameter that you are validating (e.g., LoginPage_UsernameField). This value is used by any logging or error handling that is done with respect to the value passed in.
-	 * @param filepath
-	 * 		The file path of the uploaded file.
-	 * @param filename
-	 * 		The filename of the uploaded file
-	 * @param content
-	 * 		A byte array containing the content of the uploaded file.
-	 * @param maxBytes
-	 * 		The max number of bytes allowed for a legal file upload.
-	 * @param allowNull
-	 * 		If allowNull is true then an input that is NULL or an empty string will be legal. If allowNull is false then NULL or an empty String will throw a ValidationException.
-	 *
-	 * @throws ValidationException
-	 * @throws IntrusionException
-	 */
-	void assertValidFileUpload(String context, String filepath, String filename, File parent, byte[] content, int maxBytes, List<String> allowedExtensions, boolean allowNull) throws ValidationException, IntrusionException;
-
-	/**
-	 * Calls getValidFileUpload with the supplied errorList to capture ValidationExceptions
-	 */
-	void assertValidFileUpload(String context, String filepath, String filename, File parent, byte[] content, int maxBytes, List<String> allowedExtensions, boolean allowNull, ValidationErrorList errorList) throws IntrusionException;
-
-	/**
-	 * Calls getValidListItem and returns true if no exceptions are thrown.
-	 */
-	boolean isValidListItem(String context, String input, List<String> list) throws IntrusionException;
-
-	/**
-	 * Calls getValidListItem and returns true if no exceptions are thrown.
-	 */
-	boolean isValidListItem(String context, String input, List<String> list, ValidationErrorList errorList) throws IntrusionException;
-
-	/**
-	 * Returns the list item that exactly matches the canonicalized input. Invalid or non-matching input
-	 * will generate a descriptive ValidationException, and input that is clearly an attack
-	 * will generate a descriptive IntrusionException.
-	 *
-	 * @param context
-	 * 		A descriptive name of the parameter that you are validating (e.g., LoginPage_UsernameField). This value is used by any logging or error handling that is done with respect to the value passed in.
-	 * @param input
-	 * 		The value to search 'list' for.
-	 * @param list
-	 * 		The list to search for 'input'.
-	 *
-	 * @return The list item that exactly matches the canonicalized input.
-	 *
-	 * @throws ValidationException
-	 * @throws IntrusionException
-	 */
-	String getValidListItem(String context, String input, List<String> list) throws ValidationException, IntrusionException;
-
-	/**
-	 * Calls getValidListItem with the supplied errorList to capture ValidationExceptions
-	 */
-	String getValidListItem(String context, String input, List<String> list, ValidationErrorList errorList) throws IntrusionException;
-
-	/**
-	 * Calls assertValidHTTPRequestParameterSet and returns true if no exceptions are thrown.
-	 */
-	boolean isValidHTTPRequestParameterSet(String context, HttpServletRequest request, Set<String> required, Set<String> optional) throws IntrusionException;
-
-	/**
-	 * Calls assertValidHTTPRequestParameterSet and returns true if no exceptions are thrown.
-	 */
-	boolean isValidHTTPRequestParameterSet(String context, HttpServletRequest request, Set<String> required, Set<String> optional, ValidationErrorList errorList) throws IntrusionException;
-
-	/**
-	 * Validates that the parameters in the current request contain all required parameters and only optional ones in
-	 * addition. Invalid input will generate a descriptive ValidationException, and input that is clearly an attack
-	 * will generate a descriptive IntrusionException.
-	 *
-	 * @param context
-	 * 		A descriptive name of the parameter that you are validating (e.g., LoginPage_UsernameField). This value is used by any logging or error handling that is done with respect to the value passed in.
-	 * @param required
-	 * 		parameters that are required to be in HTTP request
-	 * @param optional
-	 * 		additional parameters that may be in HTTP request
-	 *
-	 * @throws ValidationException
-	 * @throws IntrusionException
-	 */
-	void assertValidHTTPRequestParameterSet(String context, HttpServletRequest request, Set<String> required, Set<String> optional) throws ValidationException, IntrusionException;
-
-	/**
-	 * Calls getValidHTTPRequestParameterSet with the supplied errorList to capture ValidationExceptions
-	 */
-	void assertValidHTTPRequestParameterSet(String context, HttpServletRequest request, Set<String> required, Set<String> optional, ValidationErrorList errorList) throws IntrusionException;
-
-	/**
-	 * Calls getValidPrintable and returns true if no exceptions are thrown.
-	 */
-	boolean isValidPrintable(String context, char[] input, int maxLength, boolean allowNull) throws IntrusionException;
-
-        /**
-	 * Calls getValidPrintable and returns true if no exceptions are thrown.
-	 */
-	boolean isValidPrintable(String context, char[] input, int maxLength, boolean allowNull, ValidationErrorList errorList) throws IntrusionException;
-
-	/**
-	 * Returns canonicalized and validated printable characters as a byte array. Invalid input will generate a descriptive ValidationException, and input that is clearly an attack
-	 * will generate a descriptive IntrusionException.
-	 *
-	 *  @param context
-	 *  		A descriptive name of the parameter that you are validating (e.g., LoginPage_UsernameField). This value is used by any logging or error handling that is done with respect to the value passed in.
-	 *  @param input
-	 *  		data to be returned as valid and printable
-	 *  @param maxLength
-	 *  		Maximum number of bytes stored in 'input'
-	 *  @param allowNull
-	 *  		If allowNull is true then an input that is NULL or an empty string will be legal. If allowNull is false then NULL or an empty String will throw a ValidationException.
-	 *
-	 *  @return a byte array containing only printable characters, made up of data from 'input'
-	 *
-	 *  @throws ValidationException
-	 */
-	char[] getValidPrintable(String context, char[] input, int maxLength, boolean allowNull) throws ValidationException;
-
-	/**
-	 * Calls getValidPrintable with the supplied errorList to capture ValidationExceptions
-	 */
-	char[] getValidPrintable(String context, char[] input, int maxLength, boolean allowNull, ValidationErrorList errorList) throws IntrusionException;
-
-
-	/**
-	 * Calls getValidPrintable and returns true if no exceptions are thrown.
-	 */
-	boolean isValidPrintable(String context, String input, int maxLength, boolean allowNull) throws IntrusionException;
-
-        /**
-	 * Calls getValidPrintable and returns true if no exceptions are thrown.
-	 */
-	boolean isValidPrintable(String context, String input, int maxLength, boolean allowNull, ValidationErrorList errorList) throws IntrusionException;
-
-	/**
-	 * Returns canonicalized and validated printable characters as a String. Invalid input will generate a descriptive ValidationException, and input that is clearly an attack
-	 * will generate a descriptive IntrusionException.
-	 *
-	 *  @param context
-	 *  		A descriptive name of the parameter that you are validating (e.g., LoginPage_UsernameField). This value is used by any logging or error handling that is done with respect to the value passed in.
-	 *  @param input
-	 *  		data to be returned as valid and printable
-	 *  @param maxLength
-	 *  		Maximum number of bytes stored in 'input' after canonicalization
-	 *  @param allowNull
-	 *  		If allowNull is true then an input that is NULL or an empty string will be legal. If allowNull is false then NULL or an empty String will throw a ValidationException.
-	 *
-	 *  @return a String containing only printable characters, made up of data from 'input'
-	 *
-	 *  @throws ValidationException
-	 */
-	String getValidPrintable(String context, String input, int maxLength, boolean allowNull) throws ValidationException;
-
-	/**
-	 * Calls getValidPrintable with the supplied errorList to capture ValidationExceptions
-	 */
-	String getValidPrintable(String context, String input, int maxLength, boolean allowNull, ValidationErrorList errorList) throws IntrusionException;
-
-	/**
-	 * Calls getValidRedirectLocation and returns true if no exceptions are thrown.
-	 */
-	boolean isValidRedirectLocation(String context, String input, boolean allowNull);
-
-        /**
-	 * Calls getValidRedirectLocation and returns true if no exceptions are thrown.
-	 */
-	boolean isValidRedirectLocation(String context, String input, boolean allowNull, ValidationErrorList errorList);
-
-	/**
-	 * Returns a canonicalized and validated redirect location as a String. Invalid input will generate a descriptive ValidationException, and input that is clearly an attack
-	 * will generate a descriptive IntrusionException.
-	 *
-	 *  @param context
-	 *  		A descriptive name of the parameter that you are validating (e.g., LoginPage_UsernameField). This value is used by any logging or error handling that is done with respect to the value passed in.
-	 *  @param input
-	 *  		redirect location to be returned as valid, according to encoding rules set in "ESAPI.properties"
-	 *  @param allowNull
-	 *  		If allowNull is true then an input that is NULL or an empty string will be legal. If allowNull is false then NULL or an empty String will throw a ValidationException.
-	 *
-	 *  @return A canonicalized and validated redirect location, as defined in "ESAPI.properties"
-	 *
-	 *  @throws ValidationException
-	 *  @throws IntrusionException
-	 */
-	String getValidRedirectLocation(String context, String input, boolean allowNull) throws ValidationException, IntrusionException;
-
-	/**
-	 * Calls getValidRedirectLocation with the supplied errorList to capture ValidationExceptions
-	 */
-	String getValidRedirectLocation(String context, String input, boolean allowNull, ValidationErrorList errorList) throws IntrusionException;
-
-	/**
-	 * Reads from an input stream until end-of-line or a maximum number of
-	 * characters. This method protects against the inherent denial of service
-	 * attack in reading until the end of a line. If an attacker doesn't ever
-	 * send a newline character, then a normal input stream reader will read
-	 * until all memory is exhausted and the platform throws an OutOfMemoryError
-	 * and probably terminates.
-	 *
-	 * @param inputStream
-	 * 		The InputStream from which to read data
-	 * @param maxLength
-	 * 		Maximum characters allowed to be read in per line
-	 *
-	 * @return a String containing the current line of inputStream
-	 *
-	 * @throws ValidationException
-	 */
-	String safeReadLine(InputStream inputStream, int maxLength) throws ValidationException;
-
-	/**
-	 * Parses and ensures that the URI in question is a valid RFC-3986 URI.  This simplifies
-	 * the kind of regex required for subsequent validation to mitigate regex-based DoS attacks.  
-	 * 
-	 * @see <a href="https://www.ietf.org/rfc/rfc3986.txt">RFC-3986.</a>
-	 * 
- 	 *	@param context
-	 *  		A descriptive name of the parameter that you are validating (e.g., LoginPage_UsernameField). This value is used by any 
-	 *          logging or error handling that is done with respect to the value passed in.
-	 *  @param input
-	 *  		redirect location to be returned as valid, according to encoding rules set in "ESAPI.properties"
-	 *  @param allowNull
-	 *  		If allowNull is true then an input that is NULL or an empty string will be legal. If allowNull is false then NULL or an 
-	 *          empty String will throw a ValidationException.
-	 *
-	 * @return True if the URI is valid
-	 * @throws ValidationException 
-	 */
-	boolean isValidURI(String context, String input, boolean allowNull);
-
-	/**
-	 * Will return a {@code URI} object that will represent a fully parsed and legal URI
-	 * as specified in RFC-3986.  
-	 *  
-	 * @param input String
-	 * @return URI object representing a parsed URI, or {@code null} if the URI was non-compliant in some way.  
-	 */
-	URI getRfcCompliantURI(String input);
-	
+     * @throws ValidationException Input is invalid.
+     * @throws IntrusionException Input likely indicates an attack.
+     */
+    Double getValidDouble(String context, String input, double minValue, double maxValue, boolean allowNull) throws ValidationException, IntrusionException;
+
+    /**
+     * Returns a validated real number as a double,
+     * any validation exceptions are added to the supplied {@code errorList}.
+     * <p>
+     * Calls {@link #getValidDouble(String, String, double, double, boolean)},
+     * the supplied {@code errorList} is used to capture ValidationExceptions.
+     *
+     * @throws IntrusionException Input likely indicates an attack.
+     */
+    Double getValidDouble(String context, String input, double minValue, double maxValue, boolean allowNull, ValidationErrorList errorList) throws IntrusionException;
+
+    /**
+     * Returns true if {@code input} is valid.
+     * <p>
+     * Calls {@link #getValidFileContent(String, byte[], int, boolean)},
+     * and returns true if no exceptions are thrown.
+     *
+     * @throws IntrusionException Input likely indicates an attack.
+     */
+    boolean isValidFileContent(String context, byte[] input, int maxBytes, boolean allowNull) throws IntrusionException;
+
+    /**
+     * Returns true if {@code input} is valid,
+     * any validation exceptions are added to the supplied {@code errorList}.
+     * <p>
+     * Calls {@link #getValidFileContent(String, byte[], int, boolean)}
+     * and returns true if no exceptions are thrown.
+     *
+     * @throws IntrusionException Input likely indicates an attack.
+     */
+    boolean isValidFileContent(String context, byte[] input, int maxBytes, boolean allowNull, ValidationErrorList errorList) throws IntrusionException;
+
+    /**
+     * Returns validated file content as a byte array.
+     * This is a good place to check for max file size, allowed character sets, and do virus scans.
+     * Invalid input will generate a descriptive ValidationException,
+     * and input that is clearly an attack will generate a descriptive IntrusionException.
+     *
+     * @param context
+     *         A descriptive name of the parameter that you are validating (e.g., LoginPage_UsernameField).
+     *         This value is used by any logging or error handling that is done with respect to the value passed in.
+     * @param input
+     *         The actual input data to validate.
+     * @param maxBytes
+     *         The maximum number of bytes allowed in a legal file.
+     * @param allowNull
+     *         If {@code allowNull} is true then an input that is NULL or an empty string will be legal.
+     *         If {@code allowNull} is false then NULL or an empty String will throw a ValidationException.
+     *
+     * @return A byte array containing valid file content.
+     *
+     * @throws ValidationException Input is invalid.
+     * @throws IntrusionException Input likely indicates an attack.
+     */
+    byte[] getValidFileContent(String context, byte[] input, int maxBytes, boolean allowNull) throws ValidationException, IntrusionException;
+
+    /**
+     * Returns validated file content as a byte array,
+     * any validation exceptions are added to the supplied {@code errorList}.
+     * <p>
+     * Calls {@link #getValidFileContent(String, byte[], int, boolean)},
+     * the supplied {@code errorList} is used to capture ValidationExceptions.
+     *
+     * @throws IntrusionException Input likely indicates an attack.
+     */
+    byte[] getValidFileContent(String context, byte[] input, int maxBytes, boolean allowNull, ValidationErrorList errorList) throws IntrusionException;
+
+    /**
+     * Returns true if {@code filepath}, {@code filename}, and {@code content} of a file are valid.
+     * <p>
+     * Calls {@link #isValidFileName(String, String, boolean)},
+     * {@link #isValidDirectoryPath(String, String, File, boolean)},
+     * and {@link #isValidFileContent(String, byte[], int, boolean)},
+     * and returns true if all three checks pass.
+     *
+     * @throws IntrusionException Input likely indicates an attack.
+     */
+    boolean isValidFileUpload(String context, String filepath, String filename, File parent, byte[] content, int maxBytes, boolean allowNull) throws IntrusionException;
+
+    /**
+     * Returns true if {@code filepath}, {@code filename}, and {@code content} of a file are valid,
+     * any validation exceptions are added to the supplied {@code errorList}.
+     * <p>
+     * Calls {@link #isValidFileName(String, String, boolean, ValidationErrorList)}
+     * {@link #isValidDirectoryPath(String, String, File, boolean, ValidationErrorList)}
+     * and {@link #isValidFileContent(String, byte[], int, boolean, ValidationErrorList)},
+     * and returns true if all three checks pass.
+     *
+     * @throws IntrusionException Input likely indicates an attack.
+     */
+    boolean isValidFileUpload(String context, String filepath, String filename, File parent, byte[] content, int maxBytes, boolean allowNull, ValidationErrorList errorList) throws IntrusionException;
+
+    /**
+     * Validates the {@code filepath}, {@code filename}, and {@code content} of a file.
+     * Invalid input will generate a descriptive ValidationException,
+     * and input that is clearly an attack will generate a descriptive IntrusionException.
+     *
+     * @param context
+     *         A descriptive name of the parameter that you are validating (e.g., LoginPage_UsernameField).
+     *         This value is used by any logging or error handling that is done with respect to the value passed in.
+     * @param filepath
+     *         The file path of the uploaded file.
+     * @param filename
+     *         The filename of the uploaded file
+     * @param content
+     *         A byte array containing the content of the uploaded file.
+     * @param maxBytes
+     *         The max number of bytes allowed for a legal file upload.
+     * @param allowNull
+     *         If {@code allowNull} is true then an input that is NULL or an empty string will be legal.
+     *         If {@code allowNull} is false then NULL or an empty String will throw a ValidationException.
+     *
+     * @throws ValidationException Input is invalid.
+     * @throws IntrusionException Input likely indicates an attack.
+     */
+    void assertValidFileUpload(String context, String filepath, String filename, File parent, byte[] content, int maxBytes, List<String> allowedExtensions, boolean allowNull) throws ValidationException, IntrusionException;
+
+    /**
+     * Validates the {@code filepath}, {@code filename}, and {@code content} of a file,
+     * any validation exceptions are added to the supplied {@code errorList}.
+     * <p>
+     * Calls {@link #assertValidFileUpload(String, String, String, File, byte[], int, List, boolean)},
+     * the supplied {@code errorList} is used to capture ValidationExceptions.
+     *
+     * @throws IntrusionException Input likely indicates an attack.
+     */
+    void assertValidFileUpload(String context, String filepath, String filename, File parent, byte[] content, int maxBytes, List<String> allowedExtensions, boolean allowNull, ValidationErrorList errorList) throws IntrusionException;
+
+    /**
+     * Returns true if {@code input} is valid.
+     * <p>
+     * Calls {@link #getValidListItem(String, String, List)}
+     * and returns true if no exceptions are thrown.
+     *
+     * @throws IntrusionException Input likely indicates an attack.
+     */
+    boolean isValidListItem(String context, String input, List<String> list) throws IntrusionException;
+
+    /**
+     * Returns true if {@code input} is valid,
+     * any validation exceptions are added to the supplied {@code errorList}.
+     * <p>
+     * Calls {@link #getValidListItem(String, String, List)}
+     * and returns true if no exceptions are thrown.
+     *
+     * @throws IntrusionException Input likely indicates an attack.
+     */
+    boolean isValidListItem(String context, String input, List<String> list, ValidationErrorList errorList) throws IntrusionException;
+
+    /**
+     * Returns the list item that exactly matches the canonicalized input.
+     * Invalid or non-matching input will generate a descriptive ValidationException,
+     * and input that is clearly an attack will generate a descriptive IntrusionException.
+     *
+     * @param context
+     *         A descriptive name of the parameter that you are validating (e.g., LoginPage_UsernameField). This value is used by any logging or error handling that is done with respect to the value passed in.
+     * @param input
+     *         The value to search 'list' for.
+     * @param list
+     *         The list to search for 'input'.
+     *
+     * @return The list item that exactly matches the canonicalized input.
+     *
+     * @throws ValidationException Input is invalid.
+     * @throws IntrusionException Input likely indicates an attack.
+     */
+    String getValidListItem(String context, String input, List<String> list) throws ValidationException, IntrusionException;
+
+    /**
+     * Returns the list item that exactly matches the canonicalized input,
+     * any validation exceptions are added to the supplied {@code errorList}.
+     * <p>
+     * Calls {@link #getValidListItem(String, String, List)}
+     *
+     * @throws IntrusionException Input likely indicates an attack.
+     */
+    String getValidListItem(String context, String input, List<String> list, ValidationErrorList errorList) throws IntrusionException;
+
+    /**
+     * Returns true if only required and optional parameters are in the request.
+     * <p>
+     * Calls {@link #assertValidHTTPRequestParameterSet(String, HttpServletRequest, Set, Set)}
+     * and returns true if no exceptions are thrown.
+     *
+     * @throws IntrusionException Input likely indicates an attack.
+     */
+    boolean isValidHTTPRequestParameterSet(String context, HttpServletRequest request, Set<String> required, Set<String> optional) throws IntrusionException;
+
+    /**
+     * Returns true if only required and optional parameters are in the request,
+     * any validation exceptions are added to the supplied {@code errorList}.
+     * <p>
+     * Calls {@link #assertValidHTTPRequestParameterSet(String, HttpServletRequest, Set, Set)}
+     * and returns true if no exceptions are thrown.
+     *
+     * @throws IntrusionException Input likely indicates an attack.
+     */
+    boolean isValidHTTPRequestParameterSet(String context, HttpServletRequest request, Set<String> required, Set<String> optional, ValidationErrorList errorList) throws IntrusionException;
+
+    /**
+     * Validates that the parameters in the current request contain all required parameters
+     * and only optional ones in addition.
+     * Invalid input will generate a descriptive ValidationException,
+     * and input that is clearly an attack will generate a descriptive IntrusionException.
+     *
+     * @param context
+     *         A descriptive name of the parameter that you are validating (e.g., LoginPage_UsernameField). This value is used by any logging or error handling that is done with respect to the value passed in.
+     * @param required
+     *         parameters that are required to be in HTTP request
+     * @param optional
+     *         additional parameters that may be in HTTP request
+     *
+     * @throws ValidationException Input is invalid.
+     * @throws IntrusionException Input likely indicates an attack.
+     */
+    void assertValidHTTPRequestParameterSet(String context, HttpServletRequest request, Set<String> required, Set<String> optional) throws ValidationException, IntrusionException;
+
+    /**
+     * Validates that the parameters in the current request contain all required parameters
+     * and only optional ones in addition,
+     * any validation exceptions are added to the supplied {@code errorList}.
+     * <p>
+     * Calls {@link #assertValidHTTPRequestParameterSet(String, HttpServletRequest, Set, Set)}.
+     *
+     * @throws IntrusionException Input likely indicates an attack.
+     */
+    void assertValidHTTPRequestParameterSet(String context, HttpServletRequest request, Set<String> required, Set<String> optional, ValidationErrorList errorList) throws IntrusionException;
+
+    /**
+     * Returns true if {@code input} is valid.
+     * <p>
+     * Calls {@link #getValidPrintable(String, char[], int, boolean)}
+     * and returns true if no exceptions are thrown.
+     *
+     * @throws IntrusionException Input likely indicates an attack.
+     */
+    boolean isValidPrintable(String context, char[] input, int maxLength, boolean allowNull) throws IntrusionException;
+
+    /**
+     * Returns true if {@code input} is valid,
+     * any validation exceptions are added to the supplied {@code errorList}.
+     * <p>
+     * Calls {@link #getValidPrintable(String, char[], int, boolean)}
+     * and returns true if no exceptions are thrown.
+     *
+     * @throws IntrusionException Input likely indicates an attack.
+     */
+    boolean isValidPrintable(String context, char[] input, int maxLength, boolean allowNull, ValidationErrorList errorList) throws IntrusionException;
+
+    /**
+     * Returns canonicalized and validated printable characters as a byte array.
+     * Invalid input will generate a descriptive ValidationException,
+     * and input that is clearly an attack will generate a descriptive IntrusionException.
+     *
+     * @param context
+     *         A descriptive name of the parameter that you are validating (e.g., LoginPage_UsernameField).
+     *         This value is used by any logging or error handling that is done with respect to the value passed in.
+     * @param input
+     *         data to be returned as valid and printable
+     * @param maxLength
+     *         Maximum number of bytes stored in 'input'
+     * @param allowNull
+     *         If {@code allowNull} is true then an input that is NULL or an empty string will be legal.
+     *         If {@code allowNull} is false then NULL or an empty String will throw a ValidationException.
+     *
+     * @return a byte array containing only printable characters, made up of data from 'input'
+     *
+     * @throws ValidationException Input is invalid.
+     */
+    char[] getValidPrintable(String context, char[] input, int maxLength, boolean allowNull) throws ValidationException;
+
+    /**
+     * Returns canonicalized and validated printable characters as a byte array,
+     * any validation exceptions are added to the supplied {@code errorList}.
+     * <p>
+     * Calls {@link #getValidPrintable(String, char[], int, boolean)}.
+     *
+     * @throws IntrusionException Input likely indicates an attack.
+     */
+    char[] getValidPrintable(String context, char[] input, int maxLength, boolean allowNull, ValidationErrorList errorList) throws IntrusionException;
+
+    /**
+     * Returns true if {@code input} is valid.
+     * <p>
+     * Calls {@link #getValidPrintable(String, String, int, boolean)}
+     * and returns true if no exceptions are thrown.
+     *
+     * @throws IntrusionException Input likely indicates an attack.
+     */
+    boolean isValidPrintable(String context, String input, int maxLength, boolean allowNull) throws IntrusionException;
+
+    /**
+     * Returns true if {@code input} is valid,
+     * any validation exceptions are added to the supplied {@code errorList}.
+     * <p>
+     * Calls {@link #getValidPrintable(String, String, int, boolean)}
+     * and returns true if no exceptions are thrown.
+     *
+     * @throws IntrusionException Input likely indicates an attack.
+     */
+    boolean isValidPrintable(String context, String input, int maxLength, boolean allowNull, ValidationErrorList errorList) throws IntrusionException;
+
+    /**
+     * Returns canonicalized and validated printable characters as a String.
+     * Invalid input will generate a descriptive ValidationException,
+     * and input that is clearly an attack will generate a descriptive IntrusionException.
+     *
+     * @param context
+     *         A descriptive name of the parameter that you are validating (e.g., LoginPage_UsernameField).
+     *         This value is used by any logging or error handling that is done with respect to the value passed in.
+     * @param input
+     *         data to be returned as valid and printable
+     * @param maxLength
+     *         Maximum number of bytes stored in 'input' after canonicalization
+     * @param allowNull
+     *         If {@code allowNull} is true then an input that is NULL or an empty string will be legal.
+     *         If {@code allowNull} is false then NULL or an empty String will throw a ValidationException.
+     *
+     * @return a String containing only printable characters, made up of data from 'input'
+     *
+     * @throws ValidationException Input is invalid.
+     */
+    String getValidPrintable(String context, String input, int maxLength, boolean allowNull) throws ValidationException;
+
+    /**
+     * Returns canonicalized and validated printable characters as a String,
+     * any validation exceptions are added to the supplied {@code errorList}.
+     * <p>
+     * Calls {@link #getValidPrintable(String, String, int, boolean)}.
+     *
+     * @throws IntrusionException Input likely indicates an attack.
+     */
+    String getValidPrintable(String context, String input, int maxLength, boolean allowNull, ValidationErrorList errorList) throws IntrusionException;
+
+    /**
+     * Returns true if {@code input} is valid.
+     * <p>
+     * Calls {@link #getValidRedirectLocation(String, String, boolean)}
+     * and returns true if no exceptions are thrown.
+     */
+    boolean isValidRedirectLocation(String context, String input, boolean allowNull);
+
+    /**
+     * Returns true if {@code input} is valid,
+     * any validation exceptions are added to the supplied {@code errorList}.
+     * <p>
+     * Calls {@link #getValidRedirectLocation(String, String, boolean)}
+     * and returns true if no exceptions are thrown.
+     */
+    boolean isValidRedirectLocation(String context, String input, boolean allowNull, ValidationErrorList errorList);
+
+    /**
+     * Returns a canonicalized and validated redirect location as a String.
+     * Invalid input will generate a descriptive ValidationException,
+     * and input that is clearly an attack will generate a descriptive IntrusionException.
+     *
+     * @param context
+     *         A descriptive name of the parameter that you are validating (e.g., LoginPage_UsernameField).
+     *         This value is used by any logging or error handling that is done with respect to the value passed in.
+     * @param input
+     *         redirect location to be returned as valid, according to encoding rules set in "ESAPI.properties"
+     * @param allowNull
+     *         If {@code allowNull} is true then an input that is NULL or an empty string will be legal.
+     *         If {@code allowNull} is false then NULL or an empty String will throw a ValidationException.
+     *
+     * @return A canonicalized and validated redirect location, as defined in "ESAPI.properties"
+     *
+     * @throws ValidationException Input is invalid.
+     * @throws IntrusionException Input likely indicates an attack.
+     */
+    String getValidRedirectLocation(String context, String input, boolean allowNull) throws ValidationException, IntrusionException;
+
+    /**
+     * Returns a canonicalized and validated redirect location as a String,
+     * any validation exceptions are added to the supplied {@code errorList}.
+     * <p>
+     * Calls {@link #getValidRedirectLocation(String, String, boolean)}.
+     *
+     * @throws IntrusionException Input likely indicates an attack.
+     */
+    String getValidRedirectLocation(String context, String input, boolean allowNull, ValidationErrorList errorList) throws IntrusionException;
+
+    /**
+     * Reads from an input stream until end-of-line or a maximum number of
+     * characters. This method protects against the inherent denial of service
+     * attack in reading until the end of a line. If an attacker doesn't ever
+     * send a newline character, then a normal input stream reader will read
+     * until all memory is exhausted and the platform throws an OutOfMemoryError
+     * and probably terminates.
+     *
+     * @param inputStream
+     *         The InputStream from which to read data
+     * @param maxLength
+     *         Maximum characters allowed to be read in per line
+     *
+     * @return a String containing the current line of inputStream
+     *
+     * @throws ValidationException Input is invalid.
+     */
+    String safeReadLine(InputStream inputStream, int maxLength) throws ValidationException;
+
+    /**
+     * Parses and ensures that the URI in question is a valid RFC-3986 URI.  This simplifies
+     * the kind of regex required for subsequent validation to mitigate regex-based DoS attacks.
+     *
+     * @see <a href="https://www.ietf.org/rfc/rfc3986.txt">RFC-3986.</a>
+     *
+     * @param context
+     *          A descriptive name of the parameter that you are validating (e.g., LoginPage_UsernameField).
+     *          This value is used by any logging or error handling that is done with respect to the value passed in.
+     * @param input
+     *          redirect location to be returned as valid, according to encoding rules set in "ESAPI.properties"
+     * @param allowNull
+     *          If {@code allowNull} is true then an input that is NULL or an empty string will be legal.
+     *          If {@code allowNull} is false then NULL or an empty String will throw a ValidationException.
+     *
+     * @return True if the URI is valid
+     */
+    boolean isValidURI(String context, String input, boolean allowNull);
+
+    /**
+     * Will return a {@code URI} object that will represent a fully parsed and legal URI
+     * as specified in RFC-3986.
+     *
+     * @param input String
+     * @return URI object representing a parsed URI, or {@code null} if the URI was non-compliant in some way.
+     */
+    URI getRfcCompliantURI(String input);
+
 }
diff --git a/src/main/java/org/owasp/esapi/codecs/AbstractCharacterCodec.java b/src/main/java/org/owasp/esapi/codecs/AbstractCharacterCodec.java
index ed73e4b..8595cb6 100644
--- a/src/main/java/org/owasp/esapi/codecs/AbstractCharacterCodec.java
+++ b/src/main/java/org/owasp/esapi/codecs/AbstractCharacterCodec.java
@@ -1,18 +1,18 @@
 /**
  * OWASP Enterprise Security API (ESAPI)
- * 
+ *
  * This file is part of the Open Web Application Security Project (OWASP)
  * Enterprise Security API (ESAPI) project. For details, please see
  * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
  *
  * Copyright (c) 2017 - The OWASP Foundation
- * 
+ *
  * The ESAPI is published by OWASP under the BSD license. You should read and accept the
  * LICENSE before you use, modify, and/or redistribute this software.
- * 
+ *
  * @author Matt Seil (mseil .at. owasp.org)
  * @created 2017
- * 
+ *
  * @author Jeff Williams (jeff.williams .at. aspectsecurity.com) <a
  *         href="http://www.aspectsecurity.com">Aspect Security</a>
  * @created 2007
@@ -21,27 +21,27 @@
 package org.owasp.esapi.codecs;
 
 /**
- * 
- * This abstract Impl is broken off from the original {@code Codec} class and 
- * provides the {@code Character} parsing logic that has been with ESAPI from the beginning.  
+ *
+ * This abstract Impl is broken off from the original {@code Codec} class and
+ * provides the {@code Character} parsing logic that has been with ESAPI from the beginning.
  *
  */
 public abstract class AbstractCharacterCodec extends AbstractCodec<Character> {
-	/* (non-Javadoc)
-	 * @see org.owasp.esapi.codecs.Codec#decode(java.lang.String)
-	 */
-	@Override
-	public String decode(String input) {
-		StringBuilder sb = new StringBuilder();
-		PushbackSequence<Character> pbs = new PushbackString(input);
-		while (pbs.hasNext()) {
-			Character c = decodeCharacter(pbs);
-			if (c != null) {
-				sb.append(c);
-			} else {
-				sb.append(pbs.next());
-			}
-		}
-		return sb.toString();
-	}
+    /* (non-Javadoc)
+     * @see org.owasp.esapi.codecs.Codec#decode(java.lang.String)
+     */
+    @Override
+    public String decode(String input) {
+        StringBuilder sb = new StringBuilder();
+        PushbackSequence<Character> pbs = new PushbackString(input);
+        while (pbs.hasNext()) {
+            Character c = decodeCharacter(pbs);
+            if (c != null) {
+                sb.append(c);
+            } else {
+                sb.append(pbs.next());
+            }
+        }
+        return sb.toString();
+    }
 }
diff --git a/src/main/java/org/owasp/esapi/codecs/AbstractCodec.java b/src/main/java/org/owasp/esapi/codecs/AbstractCodec.java
index 7192bae..77c153f 100644
--- a/src/main/java/org/owasp/esapi/codecs/AbstractCodec.java
+++ b/src/main/java/org/owasp/esapi/codecs/AbstractCodec.java
@@ -1,15 +1,15 @@
 /**
  * OWASP Enterprise Security API (ESAPI)
- * 
+ *
  * This file is part of the Open Web Application Security Project (OWASP)
  * Enterprise Security API (ESAPI) project. For details, please see
  * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
  *
  * Copyright (c) 2017 - The OWASP Foundation
- * 
+ *
  * The ESAPI is published by OWASP under the BSD license. You should read and accept the
  * LICENSE before you use, modify, and/or redistribute this software.
- * 
+ *
  * @author Matt Seil (mseil .at. owasp.org)
  * @created 2017
  */
@@ -17,12 +17,16 @@ package org.owasp.esapi.codecs;
 
 
 /**
- * The Codec interface defines a set of methods for encoding and decoding application level encoding schemes,
- * such as HTML entity encoding and percent encoding (aka URL encoding). Codecs are used in output encoding
+ * The {@code Coded} interface defines a set of methods for encoding and decoding application level encoding schemes,
+ * such as HTML entity encoding and percent encoding (aka URL encoding). {@code Coded}s are used in output encoding
  * and canonicalization.  The design of these codecs allows for character-by-character decoding, which is
  * necessary to detect double-encoding and the use of multiple encoding schemes, both of which are techniques
  * used by attackers to bypass validation and bury encoded attacks in data.
- * 
+ * <p>
+ * Be sure to see the several <b>WARNING</b>s associated with the detailed
+ * method descriptions. You will not find that in the "Method Summary" section
+ * of the javadoc because that only shows the intial sentence.
+ *
  * @author Jeff Williams (jeff.williams .at. aspectsecurity.com) <a
  *         href="http://www.aspectsecurity.com">Aspect Security</a>
  * @param <T>
@@ -31,131 +35,141 @@ package org.owasp.esapi.codecs;
  */
 public abstract class AbstractCodec<T> implements Codec<T> {
 
-	/**
-	 * Initialize an array to mark which characters are to be encoded. Store the hex
-	 * string for that character to save time later. If the character shouldn't be
-	 * encoded, then store null.
-	 */
-	private final String[] hex = new String[256];
-
-	/**
-	 * Default constructor
-	 */
-	public AbstractCodec() {
-		for ( char c = 0; c < 0xFF; c++ ) {
-			if ( c >= 0x30 && c <= 0x39 || c >= 0x41 && c <= 0x5A || c >= 0x61 && c <= 0x7A ) {
-				hex[c] = null;
-			} else {
-				hex[c] = toHex(c).intern();
-			}
-		}
-	}
-
-	/**
-	 * WARNING!!  {@code Character} based Codecs will silently transform code points that are not 
-	 * legal UTF code points into garbage data as they will cast them to {@code char}s.  
-	 * </br></br>
-	 * If you are implementing an {@code Integer} based codec, these will be silently discarded
-	 * based on the return from {@code Character.isValidCodePoint( int )}.  This is the preferred
-	 * behavior moving forward.  
-	 * 
-	 * 
-	 * {@inheritDoc}
-	 */
-	@Override
-	public String encode(char[] immune, String input) {
-		StringBuilder sb = new StringBuilder();
-		for(int offset  = 0; offset < input.length(); ) {
-			final int point = input.codePointAt(offset);
-			if (Character.isBmpCodePoint(point)) {
-				//We can then safely cast this to char and maintain legacy behavior.
-				sb.append(encodeCharacter(immune, new Character((char) point)));
-			} else {
-				sb.append(encodeCharacter(immune, point));	
-			}
-			offset += Character.charCount(point);
-		}
-		return sb.toString();
-	}
-
-	/**
-	 * WARNING!!!!  Passing a standard char to this method will resolve to the 
-	 * @see #encodeCharacter( char[], int )
-	 * method instead of this one!!!  YOU HAVE BEEN WARNED!!!!
-	 * 
-	 * {@inheritDoc}
-	 */
-	@Override
-	public String encodeCharacter( char[] immune, Character c ) {
-		return ""+c;
-	}
-	
-	public String encodeCharacter(char[] immune, char c) {
-		throw new IllegalArgumentException("You tried to call encodeCharacter with a char.  Nope.  Use Character instead!");
-	}
-	
-	/* (non-Javadoc)
-	 * @see org.owasp.esapi.codecs.Codec#encodeCharacter(char[], int)
-	 */
-	@Override
-	public String encodeCharacter( char[] immune, int codePoint ) {
-		String rval = "";
-		if(Character.isValidCodePoint(codePoint)){
-			rval = new StringBuilder().appendCodePoint(codePoint).toString();
-		}
-		return rval;
-	}
-
-
-
-	/* (non-Javadoc)
-	 * @see org.owasp.esapi.codecs.Codec#decodeCharacter(org.owasp.esapi.codecs.PushbackString)
-	 */
-	@Override
-	public T decodeCharacter( PushbackSequence<T> input ) {
-		return input.next();
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	public String getHexForNonAlphanumeric(char c) {
-		if(c<0xFF)
-			return hex[c];
-		return toHex(c);
-	}
-	
-	/**
-	 * {@inheritDoc}
-	 */
-	public String getHexForNonAlphanumeric(int c) {
-		if (c<0xFF) {
-			return hex[c];
-		} else {
-			return toHex(c);
-		}
-	}
-
-	public String toOctal(char c) {
-		return Integer.toOctalString(c);
-	}
-
-	public String toHex(char c) {
-		return Integer.toHexString(c);
-	}
-	
-	public String toHex(int c) {
-		return Integer.toHexString(c);
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	public boolean containsCharacter( char c, char[] array ) {
-		for (char ch : array) {
-			if (c == ch) return true;
-		}
-		return false;
-	}
+    /**
+     * Initialize an array to mark which characters are to be encoded. Store the hex
+     * string for that character to save time later. If the character shouldn't be
+     * encoded, then store null.
+     */
+    private final String[] hex = new String[256];
+
+    /**
+     * Default constructor
+     */
+    public AbstractCodec() {
+        for ( char c = 0; c < 0xFF; c++ ) {
+            if ( c >= 0x30 && c <= 0x39 || c >= 0x41 && c <= 0x5A || c >= 0x61 && c <= 0x7A ) {
+                hex[c] = null;
+            } else {
+                hex[c] = toHex(c).intern();
+            }
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     * </p><p>
+     * <b>WARNING!!</b>  {@code Character} based {@code Codec}s will only handle the byte range of
+     * 0-65535 (0x0-0xffff).  Passing any data represented by a higher numerical value will result in
+     * a downcast thus destroying the original data with undefined results.
+     * <p>
+     * Also, if you are implementing an {@code Integer} based codec, these will be silently discarded
+     * based on the return from {@code Character.isValidCodePoint( int )}.  This is the preferred
+     * behavior moving forward.
+     */
+    @Override
+    public String encode(char[] immune, String input) {
+        StringBuilder sb = new StringBuilder();
+        for(int offset  = 0; offset < input.length(); ) {
+            final int point = input.codePointAt(offset);
+            if (Character.isBmpCodePoint(point)) {
+                //We can then safely cast this to char and maintain legacy behavior.
+                sb.append(encodeCharacter(immune, new Character((char) point)));
+            } else {
+                sb.append(encodeCharacter(immune, point));
+            }
+            offset += Character.charCount(point);
+        }
+        return sb.toString();
+    }
+
+    /**
+     * {@inheritDoc}
+     * <p>
+     * <b>WARNING!!!!</b>  Passing a standard {@code char} rather than {@code Character} to this method will resolve to the
+     * {@link #encodeCharacter( char[], char )} method, which will throw an {@code IllegalArgumentException} instead.
+     * YOU HAVE BEEN WARNED!!!!
+     */
+    @Override
+    public String encodeCharacter( char[] immune, Character c ) {
+        return ""+c;
+    }
+
+
+    /**
+     * To prevent accidental footgun usage and calling
+     * {@link #encodeCharacter( char[], int)} when called with {@code char} and
+     * {@code char} is first silently converted to {@code int} and then the
+     * unexpected method is called.
+     *
+     * @throws IllegalArgumentException to indicate that you called the incorrect method.
+     */
+    public String encodeCharacter(char[] immune, char c) {
+        throw new IllegalArgumentException("You tried to call encodeCharacter() with a char.  Nope.  " +
+                                           "Use 'encodeCharacter( char[] immune, Character c)' instead!");
+    }
+
+    /* (non-Javadoc)
+     * @see org.owasp.esapi.codecs.Codec#encodeCharacter(char[], int)
+     */
+    @Override
+    public String encodeCharacter( char[] immune, int codePoint ) {
+        String rval = "";
+        if(Character.isValidCodePoint(codePoint)){
+            rval = new StringBuilder().appendCodePoint(codePoint).toString();
+        }
+        return rval;
+    }
+
+
+
+    /* (non-Javadoc)
+     * @see org.owasp.esapi.codecs.Codec#decodeCharacter(org.owasp.esapi.codecs.PushbackString)
+     */
+    @Override
+    public T decodeCharacter( PushbackSequence<T> input ) {
+        return input.next();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public String getHexForNonAlphanumeric(char c) {
+        if(c<0xFF)
+            return hex[c];
+        return toHex(c);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public String getHexForNonAlphanumeric(int c) {
+        if (c<0xFF) {
+            return hex[c];
+        } else {
+            return toHex(c);
+        }
+    }
+
+    public String toOctal(char c) {
+        return Integer.toOctalString(c);
+    }
+
+    public String toHex(char c) {
+        return Integer.toHexString(c);
+    }
+
+    public String toHex(int c) {
+        return Integer.toHexString(c);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean containsCharacter( char c, char[] array ) {
+        for (char ch : array) {
+            if (c == ch) return true;
+        }
+        return false;
+    }
 
 }
diff --git a/src/main/java/org/owasp/esapi/codecs/AbstractIntegerCodec.java b/src/main/java/org/owasp/esapi/codecs/AbstractIntegerCodec.java
index cf522e9..5bf9038 100644
--- a/src/main/java/org/owasp/esapi/codecs/AbstractIntegerCodec.java
+++ b/src/main/java/org/owasp/esapi/codecs/AbstractIntegerCodec.java
@@ -1,18 +1,18 @@
 /**
  * OWASP Enterprise Security API (ESAPI)
- * 
+ *
  * This file is part of the Open Web Application Security Project (OWASP)
  * Enterprise Security API (ESAPI) project. For details, please see
  * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
  *
  * Copyright (c) 2017 - The OWASP Foundation
- * 
+ *
  * The ESAPI is published by OWASP under the BSD license. You should read and accept the
  * LICENSE before you use, modify, and/or redistribute this software.
- * 
+ *
  * @author Matt Seil (mseil .at. owasp.org)
  * @created 2017
- * 
+ *
  * @author Jeff Williams (jeff.williams .at. aspectsecurity.com) <a
  *         href="http://www.aspectsecurity.com">Aspect Security</a>
  * @created 2007
@@ -24,27 +24,30 @@ package org.owasp.esapi.codecs;
  * data by focusing on {@code int} as opposed to {@code Character}.  Because non-BMP code
  * points cannot be represented by a {@code char}, this class remedies that by parsing string
  * data as codePoints as opposed to a stream of {@code char}s.
- * 
+ *
+ * WARNING:  This class will silently discard an invalid code point according to
+ * the result of {@code Character.isValidCodePoint( int )} method.
+ *
  * @author Matt Seil (mseil .at. owasp.org)
- * @since 2017 -- Adapted from Jeff Williams' original {@code Codec} class.  
+ * @since 2017 -- Adapted from Jeff Williams' original {@code Codec} class.
  */
 public class AbstractIntegerCodec extends AbstractCodec<Integer> {
 
-	/**
-	 * {@inheritDoc}
-	 */
-	@Override
-	public String decode(String input) {
-		StringBuilder sb = new StringBuilder();
-		PushbackSequence<Integer> pbs = new PushBackSequenceImpl(input);
-		while (pbs.hasNext()) {
-			Integer c = decodeCharacter(pbs);
-			if (c != null && Character.isValidCodePoint(c)) {
-				sb.appendCodePoint(c);
-			} else {
-				sb.appendCodePoint(pbs.next());
-			}
-		}
-		return sb.toString();
-	}
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public String decode(String input) {
+        StringBuilder sb = new StringBuilder();
+        PushbackSequence<Integer> pbs = new PushBackSequenceImpl(input);
+        while (pbs.hasNext()) {
+            Integer c = decodeCharacter(pbs);
+            if (c != null && Character.isValidCodePoint(c)) {
+                sb.appendCodePoint(c);
+            } else {
+                sb.appendCodePoint(pbs.next());
+            }
+        }
+        return sb.toString();
+    }
 }
diff --git a/src/main/java/org/owasp/esapi/codecs/AbstractPushbackSequence.java b/src/main/java/org/owasp/esapi/codecs/AbstractPushbackSequence.java
index 7ebe0f4..f90e07d 100644
--- a/src/main/java/org/owasp/esapi/codecs/AbstractPushbackSequence.java
+++ b/src/main/java/org/owasp/esapi/codecs/AbstractPushbackSequence.java
@@ -1,18 +1,18 @@
 /**
  * OWASP Enterprise Security API (ESAPI)
- * 
+ *
  * This file is part of the Open Web Application Security Project (OWASP)
  * Enterprise Security API (ESAPI) project. For details, please see
  * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
  *
  * Copyright (c) 2017 - The OWASP Foundation
- * 
+ *
  * The ESAPI is published by OWASP under the BSD license. You should read and accept the
  * LICENSE before you use, modify, and/or redistribute this software.
- * 
+ *
  * @author Matt Seil (mseil .at. owasp.org)
  * @created 2017
- * 
+ *
  */
 
 package org.owasp.esapi.codecs;
@@ -21,50 +21,50 @@ package org.owasp.esapi.codecs;
  * This Abstract class provides the generic logic for using a {@link PushbackSequence}
  * in regards to iterating strings.  The final Impl is intended for the user to supply
  * a type T such that the pushback interface can be utilized for sequences
- * of type T.  Presently this generic class is limited by the fact that 
- * input is a String.  
- *  
+ * of type T.  Presently this generic class is limited by the fact that
+ * input is a String.
+ *
  * @author Matt Seil
  *
  * @param <T>
  */
 public abstract class AbstractPushbackSequence<T> implements PushbackSequence<T> {
-	protected String input;
-	protected T pushback;
-	protected T temp;
-	protected int index = 0;
-	protected int mark = 0;
+    protected String input;
+    protected T pushback;
+    protected T temp;
+    protected int index = 0;
+    protected int mark = 0;
 
-	public AbstractPushbackSequence(String input) {
-		this.input = input;
-	}
+    public AbstractPushbackSequence(String input) {
+        this.input = input;
+    }
 
-	/**
-	 * {@inheritDoc}
-	 */
-	public void pushback(T c) {
-		pushback = c;
-	}
+    /**
+     * {@inheritDoc}
+     */
+    public void pushback(T c) {
+        pushback = c;
+    }
 
-	/**
-	 * {@inheritDoc}
-	 */
-	public int index() {
-		return index;
-	}
+    /**
+     * {@inheritDoc}
+     */
+    public int index() {
+        return index;
+    }
 
-	/**
-	 * {@inheritDoc}
-	 */
-	public boolean hasNext() {
-		if (pushback != null)
-			return true;
-		if (input == null)
-			return false;
-		if (input.length() == 0)
-			return false;
-		if (index >= input.length())
-			return false;
-		return true;
-	}
+    /**
+     * {@inheritDoc}
+     */
+    public boolean hasNext() {
+        if (pushback != null)
+            return true;
+        if (input == null)
+            return false;
+        if (input.length() == 0)
+            return false;
+        if (index >= input.length())
+            return false;
+        return true;
+    }
 }
diff --git a/src/main/java/org/owasp/esapi/codecs/CSSCodec.java b/src/main/java/org/owasp/esapi/codecs/CSSCodec.java
index 152aa20..9ffb60f 100644
--- a/src/main/java/org/owasp/esapi/codecs/CSSCodec.java
+++ b/src/main/java/org/owasp/esapi/codecs/CSSCodec.java
@@ -1,15 +1,15 @@
 /**
  * OWASP Enterprise Security API (ESAPI)
- * 
+ *
  * This file is part of the Open Web Application Security Project (OWASP) Enterprise Security API
  * (ESAPI) project. For details, please see <a
  * href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
- * 
+ *
  * Copyright (c) 2007 - The OWASP Foundation
- * 
+ *
  * The ESAPI is published by OWASP under the BSD license. You should read and accept the LICENSE
  * before you use, modify, and/or redistribute this software.
- * 
+ *
  * @author Jeff Williams <a href="http://www.aspectsecurity.com">Aspect Security</a>
  * @created 2007
  */
@@ -21,7 +21,7 @@ import org.owasp.esapi.codecs.ref.EncodingPatternPreservation;
 
 /**
  * Implementation of the Codec interface for backslash encoding used in CSS.
- * 
+ *
  * @author Jeff Williams (jeff.williams .at. aspectsecurity.com) <a
  *         href="http://www.aspectsecurity.com">Aspect Security</a>
  * @since June 1, 2007
@@ -29,171 +29,171 @@ import org.owasp.esapi.codecs.ref.EncodingPatternPreservation;
  */
 public class CSSCodec extends AbstractCharacterCodec
 {
-	private static final Character REPLACEMENT = '\ufffd';
-	//rgb (###,###,###) OR rgb(###%,###%,###%)
-	//([rR][gG][bB])\s*\(\s*\d{1,3}\s*(\%)?\s*,\s*\d{1,3}\s*(\%)?\s*,\s*\d{1,3}\s*(\%)?\s*\)
-	private static final String RGB_TRPLT = "([rR][gG][bB])\\s*\\(\\s*\\d{1,3}\\s*(\\%)?\\s*,\\s*\\d{1,3}\\s*(\\%)?\\s*,\\s*\\d{1,3}\\s*(\\%)?\\s*\\)";
-	private static final Pattern RGB_TRPLT_PATTERN = Pattern.compile(RGB_TRPLT); 
-	
-	@Override
-	public String encode(char[] immune, String input) {
-		 EncodingPatternPreservation tripletCheck = new EncodingPatternPreservation(RGB_TRPLT_PATTERN);
-		 
-		 String inputChk = tripletCheck.captureAndReplaceMatches(input);
-		 
-		 String result = super.encode(immune, inputChk);
-		 
-		 return tripletCheck.restoreOriginalContent(result);
-	}
+    private static final Character REPLACEMENT = '\ufffd';
+    //rgb (###,###,###) OR rgb(###%,###%,###%)
+    //([rR][gG][bB])\s*\(\s*\d{1,3}\s*(\%)?\s*,\s*\d{1,3}\s*(\%)?\s*,\s*\d{1,3}\s*(\%)?\s*\)
+    private static final String RGB_TRPLT = "([rR][gG][bB])\\s*\\(\\s*\\d{1,3}\\s*(\\%)?\\s*,\\s*\\d{1,3}\\s*(\\%)?\\s*,\\s*\\d{1,3}\\s*(\\%)?\\s*\\)";
+    private static final Pattern RGB_TRPLT_PATTERN = Pattern.compile(RGB_TRPLT);
+
+    @Override
+    public String encode(char[] immune, String input) {
+         EncodingPatternPreservation tripletCheck = new EncodingPatternPreservation(RGB_TRPLT_PATTERN);
+
+         String inputChk = tripletCheck.captureAndReplaceMatches(input);
+
+         String result = super.encode(immune, inputChk);
+
+         return tripletCheck.restoreOriginalContent(result);
+    }
     /**
-	 * {@inheritDoc}
-	 *
+     * {@inheritDoc}
+     *
      * Returns backslash encoded character.
      *
      * @param immune
      */
     public String encodeCharacter(char[] immune, Character c) {
-		// check for immune characters
-		if ( containsCharacter(c, immune ) ) {
-			return ""+c;
-		}
-		
-		// check for alphanumeric characters
-		String hex = super.getHexForNonAlphanumeric(c);
-		if ( hex == null ) {
-			return ""+c;
-		}
-		
-		// return the hex and end in whitespace to terminate
+        // check for immune characters
+        if ( containsCharacter(c, immune ) ) {
+            return ""+c;
+        }
+
+        // check for alphanumeric characters
+        String hex = super.getHexForNonAlphanumeric(c);
+        if ( hex == null ) {
+            return ""+c;
+        }
+
+        // return the hex and end in whitespace to terminate
         return "\\" + hex + " ";
     }
 
-    
-	/**
-	 * {@inheritDoc}
-	 * 
-	 * Returns the decoded version of the character starting at index,
-	 * or null if no decoding is possible.
-	 */
+
+    /**
+     * {@inheritDoc}
+     *
+     * Returns the decoded version of the character starting at index,
+     * or null if no decoding is possible.
+     */
     @SuppressWarnings("fallthrough")
     public Character decodeCharacter(PushbackSequence<Character> input)
-	{
-		input.mark();
-		Character first = input.next();
-		if (first == null || first != '\\')
-		{
-			input.reset();
-			return null;
-		}
-
-		Character second = input.next();
-		if (second == null) {
-			input.reset();
-			return null;
-		}
-
-		/* From css 2.1 spec:
-		 * http://www.w3.org/TR/CSS21/syndata.html#characters
-		 *
-		 * First, inside a string, a backslash followed by a
-		 * newline is ignored (i.e., the string is deemed not
-		 * to contain either the backslash or the newline).
-		 *
-		 * Second, it cancels the meaning of special CSS
-		 * characters. Except within CSS comments, any character
-		 * (except a hexadecimal digit, linefeed, carriage return,
-		 * or form feed) can be escaped with a backslash to
-		 * remove its special meaning. For example, "\"" is a string
-		 * consisting of one double quote. Style sheet
-		 * preprocessors must not remove these backslashes
-		 * from a style sheet since that would change the style
-		 * sheet's meaning.
-		 *
-		 * Third, backslash escapes allow authors to refer to
-		 * characters they cannot easily put in a document. In
-		 * this case, the backslash is followed by at most six
-		 * hexadecimal digits (0..9A..F), which stand for the ISO
-		 * 10646 ([ISO10646]) character with that number, which
-		 * must not be zero. (It is undefined in CSS 2.1 what
-		 * happens if a style sheet does contain a character with
-		 * Unicode codepoint zero.) If a character in the range
-		 * [0-9a-fA-F] follows the hexadecimal number, the end
-		 * of the number needs to be made clear. There are two
-		 * ways to do that:
-		 *
-		 *	1. with a space (or other white space character):
-		 *	"\26 B" ("&B"). In this case, user agents should
-		 *	treat a "CR/LF" pair (U+000D/U+000A) as a single
-		 *	white space character.
-		 *
-		 *	2. by providing exactly 6 hexadecimal digits:
-		 *	"\000026B" ("&B")
-		 *
-		 * In fact, these two methods may be combined. Only one
-		 * white space character is ignored after a hexadecimal
-		 * escape. Note that this means that a "real" space
-		 * after the escape sequence must itself either be
-		 * escaped or doubled.
-		 *
-		 * If the number is outside the range allowed by Unicode
-		 * (e.g., "\110000" is above the maximum 10FFFF allowed in
-		 * current Unicode), the UA may replace the escape with
-		 * the "replacement character" (U+FFFD). If the character
-		 * is to be displayed, the UA should show a visible
-		 * symbol, such as a "missing character" glyph (cf. 15.2,
-		 * point 5).
-		 */
-
-		switch(second)
-		{	// special whitespace cases. I assume they mean
-			// for all of these to qualify as a "new
-			// line." Otherwise there is no specification
-			// of what to do for \f
-			case '\r':
-				if(input.peek('\n'))
-					input.next();
-				// fall through
-			case '\n':  // Intentional fall through
-			case '\f':  // Intentional fall through
-				// bs followed by new line replaced by nothing
-			case '\u0000':	// skip NUL for now too
-				return decodeCharacter(input);
-		}
-
-		if (!PushbackString.isHexDigit(second))
-		{	// non hex digit
-			return second;
-		}
-
-		// Search for up to 6 hex digits following until a space
-		StringBuilder sb = new StringBuilder();
-		sb.append(second);
-		for (int i = 0; i < 5; i++)
-		{
-			Character c = input.next();
-			if(c == null || Character.isWhitespace(c))
-				break;
-			if(PushbackString.isHexDigit(c))
-				sb.append(c);
-			else
-			{
-				input.pushback(c);
-				break;
-			}
-		}
-		try
-		{
-			// parse the hex digit and create a character
-			int i = Integer.parseInt(sb.toString(), 16);
-	
-			if (Character.isValidCodePoint(i))
-				return (char)i;
-			return REPLACEMENT;
-		}
-		catch (NumberFormatException e)
-		{
-			throw new IllegalStateException("Received a NumberFormateException parsing a string verified to be hex", e);
-        	}
-	}
+    {
+        input.mark();
+        Character first = input.next();
+        if (first == null || first != '\\')
+        {
+            input.reset();
+            return null;
+        }
+
+        Character second = input.next();
+        if (second == null) {
+            input.reset();
+            return null;
+        }
+
+        /* From css 2.1 spec:
+         * http://www.w3.org/TR/CSS21/syndata.html#characters
+         *
+         * First, inside a string, a backslash followed by a
+         * newline is ignored (i.e., the string is deemed not
+         * to contain either the backslash or the newline).
+         *
+         * Second, it cancels the meaning of special CSS
+         * characters. Except within CSS comments, any character
+         * (except a hexadecimal digit, linefeed, carriage return,
+         * or form feed) can be escaped with a backslash to
+         * remove its special meaning. For example, "\"" is a string
+         * consisting of one double quote. Style sheet
+         * preprocessors must not remove these backslashes
+         * from a style sheet since that would change the style
+         * sheet's meaning.
+         *
+         * Third, backslash escapes allow authors to refer to
+         * characters they cannot easily put in a document. In
+         * this case, the backslash is followed by at most six
+         * hexadecimal digits (0..9A..F), which stand for the ISO
+         * 10646 ([ISO10646]) character with that number, which
+         * must not be zero. (It is undefined in CSS 2.1 what
+         * happens if a style sheet does contain a character with
+         * Unicode codepoint zero.) If a character in the range
+         * [0-9a-fA-F] follows the hexadecimal number, the end
+         * of the number needs to be made clear. There are two
+         * ways to do that:
+         *
+         *    1. with a space (or other white space character):
+         *    "\26 B" ("&B"). In this case, user agents should
+         *    treat a "CR/LF" pair (U+000D/U+000A) as a single
+         *    white space character.
+         *
+         *    2. by providing exactly 6 hexadecimal digits:
+         *    "\000026B" ("&B")
+         *
+         * In fact, these two methods may be combined. Only one
+         * white space character is ignored after a hexadecimal
+         * escape. Note that this means that a "real" space
+         * after the escape sequence must itself either be
+         * escaped or doubled.
+         *
+         * If the number is outside the range allowed by Unicode
+         * (e.g., "\110000" is above the maximum 10FFFF allowed in
+         * current Unicode), the UA may replace the escape with
+         * the "replacement character" (U+FFFD). If the character
+         * is to be displayed, the UA should show a visible
+         * symbol, such as a "missing character" glyph (cf. 15.2,
+         * point 5).
+         */
+
+        switch(second)
+        {    // special whitespace cases. I assume they mean
+            // for all of these to qualify as a "new
+            // line." Otherwise there is no specification
+            // of what to do for \f
+            case '\r':
+                if(input.peek('\n'))
+                    input.next();
+                // fall through
+            case '\n':  // Intentional fall through
+            case '\f':  // Intentional fall through
+                // bs followed by new line replaced by nothing
+            case '\u0000':    // skip NUL for now too
+                return decodeCharacter(input);
+        }
+
+        if (!PushbackString.isHexDigit(second))
+        {    // non hex digit
+            return second;
+        }
+
+        // Search for up to 6 hex digits following until a space
+        StringBuilder sb = new StringBuilder();
+        sb.append(second);
+        for (int i = 0; i < 5; i++)
+        {
+            Character c = input.next();
+            if(c == null || Character.isWhitespace(c))
+                break;
+            if(PushbackString.isHexDigit(c))
+                sb.append(c);
+            else
+            {
+                input.pushback(c);
+                break;
+            }
+        }
+        try
+        {
+            // parse the hex digit and create a character
+            int i = Integer.parseInt(sb.toString(), 16);
+
+            if (Character.isValidCodePoint(i))
+                return (char)i;
+            return REPLACEMENT;
+        }
+        catch (NumberFormatException e)
+        {
+            throw new IllegalStateException("Received a NumberFormateException parsing a string verified to be hex", e);
+            }
+    }
 
 }
diff --git a/src/main/java/org/owasp/esapi/codecs/Codec.java b/src/main/java/org/owasp/esapi/codecs/Codec.java
index 1d6f2d0..52c49c1 100644
--- a/src/main/java/org/owasp/esapi/codecs/Codec.java
+++ b/src/main/java/org/owasp/esapi/codecs/Codec.java
@@ -1,15 +1,15 @@
 /**
  * OWASP Enterprise Security API (ESAPI)
- * 
+ *
  * This file is part of the Open Web Application Security Project (OWASP)
  * Enterprise Security API (ESAPI) project. For details, please see
  * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
  *
  * Copyright (c) 2007 - The OWASP Foundation
- * 
+ *
  * The ESAPI is published by OWASP under the BSD license. You should read and accept the
  * LICENSE before you use, modify, and/or redistribute this software.
- * 
+ *
  * @author Jeff Williams <a href="http://www.aspectsecurity.com">Aspect Security</a>
  * @created 2007
  */
@@ -22,97 +22,112 @@ package org.owasp.esapi.codecs;
  * and canonicalization.  The design of these codecs allows for character-by-character decoding, which is
  * necessary to detect double-encoding and the use of multiple encoding schemes, both of which are techniques
  * used by attackers to bypass validation and bury encoded attacks in data.
- * 
+ *
  * @author Jeff Williams (jeff.williams .at. aspectsecurity.com) <a
  *         href="http://www.aspectsecurity.com">Aspect Security</a>
  * @since June 1, 2007
- * 
- * @author Matt Seil (mseil .at. owasp.org) 
+ *
+ * @author Matt Seil (mseil .at. owasp.org)
  * @since June 1, 2017
  * @see org.owasp.esapi.Encoder
  */
 public interface Codec<T> {
-	/**
-	 * Encode a String so that it can be safely used in a specific context.
-	 * 
-	 * @param immune
-	 * @param input
-	 * 		the String to encode
-	 * @return the encoded String
-	 */
-	public String encode(char[] immune, String input);
+    /**
+     * Encode a String so that it can be safely used in a specific context.
+     *
+     * @param immune
+     * @param input
+     *         the String to encode
+     * @return the encoded String
+     */
+    public String encode(char[] immune, String input);
+
+    /**
+     * Default implementation that should be overridden in specific codecs.
+     *
+     * @param immune
+     *         array of chars to NOT encode.  Use with caution.
+     * @param c
+     *         the Character to encode
+     * @return
+     *         the encoded Character
+     */
+    public String encodeCharacter( char[] immune, Character c );
+
+    /**
+     * Default codepoint implementation that should be overridden in specific codecs.
+     *
+     * @param immune
+     * @param codePoint
+     *         the integer to encode
+     * @return
+     *         the encoded Character
+     */
+    public String encodeCharacter( char[] immune, int codePoint );
+
+    /**
+     * Decode a String that was encoded using the encode method in this Class
+     *
+     * @param input
+     *         the String to decode
+     * @return
+     *        the decoded String
+     */
+    public String decode(String input);
 
-	/**
-	 * Default implementation that should be overridden in specific codecs.
-	 * 
-	 * @param immune 
-	 * 		array of chars to NOT encode.  Use with caution.
-	 * @param c
-	 * 		the Character to encode
-	 * @return
-	 * 		the encoded Character
-	 */
-	public String encodeCharacter( char[] immune, Character c );
-	
-	/**
-	 * Default codepoint implementation that should be overridden in specific codecs.
-	 * 
-	 * @param immune
-	 * @param codePoint
-	 * 		the integer to encode
-	 * @return
-	 * 		the encoded Character
-	 */
-	public String encodeCharacter( char[] immune, int codePoint );
+    /**
+     * Returns the decoded version of the next character from the input string and advances the
+     * current character in the {@code PushbackSequence}.  If the current character is not encoded, this
+     * method <i>MUST</i> reset the {@code PushbackString}.
+     *
+     * @param input    the Character to decode
+     *
+     * @return the decoded Character
+     */
+    public T decodeCharacter( PushbackSequence<T> input );
 
-	/**
-	 * Decode a String that was encoded using the encode method in this Class
-	 * 
-	 * @param input
-	 * 		the String to decode
-	 * @return
-	 *		the decoded String
-	 */
-	public String decode(String input);
+    /**
+     * Lookup the hex value of any character that is not alphanumeric.
+     * @param c The character to lookup.
+     * @return return null if alphanumeric or the character code in hex.
+     */
+    public String getHexForNonAlphanumeric(char c);
 
-	/**
-	 * Returns the decoded version of the next character from the input string and advances the
-	 * current character in the PushbackSequence.  If the current character is not encoded, this 
-	 * method MUST reset the PushbackString.
-	 * 
-	 * @param input	the Character to decode
-	 * 
-	 * @return the decoded Character
-	 */
-	public T decodeCharacter( PushbackSequence<T> input );
+    /**
+     * Lookup the hex value of any character that is not alphanumeric.
+     * @param c The character to lookup.
+     * @return return null if alphanumeric or the character code in hex.
+     */
+    public String getHexForNonAlphanumeric(int c);
 
-	/**
-	 * Lookup the hex value of any character that is not alphanumeric.
-	 * @param c The character to lookup.
-	 * @return return null if alphanumeric or the character code in hex.
-	 */
-	public String getHexForNonAlphanumeric(char c);
-	
-	/**
-	 * Lookup the hex value of any character that is not alphanumeric.
-	 * @param c The character to lookup.
-	 * @return return null if alphanumeric or the character code in hex.
-	 */
-	public String getHexForNonAlphanumeric(int c);
+    /**
+     * Convert the {@code char} parameter to its octal representation.
+     * @param c the character for which to return the new representation.
+     * @return the octal representation.
+     */
+    public String toOctal(char c);
 
-	public String toOctal(char c);
+    /**
+     * Convert the {@code char} parameter to its hexadecimal representation.
+     * @param c the character for which to return the new representation.
+     * @return the hexadecimal representation.
+     */
+    public String toHex(char c);
 
-	public String toHex(char c);
-	
-	public String toHex(int c);
+    /**
+     * Convert the {@code int} parameter to its hexadecimal representation.
+     * @param c the character for which to return the new representation.
+     * @return the hexadecimal representation.
+     */
+    public String toHex(int c);
 
-	/**
-	 * Utility to search a char[] for a specific char.
-	 * 
-	 * @param c
-	 * @param array
-	 * @return True if the supplied array contains the specified character. False otherwise.
-	 */
-	public boolean containsCharacter( char c, char[] array );
+    /**
+     * Utility to search a char[] for a specific char.
+     *
+     * @param c
+     * @param array
+     * @return True if the supplied array contains the specified character. False otherwise.
+     */
+    public boolean containsCharacter( char c, char[] array );
 
 }
diff --git a/src/main/java/org/owasp/esapi/codecs/DB2Codec.java b/src/main/java/org/owasp/esapi/codecs/DB2Codec.java
index 850d9a6..8df61bc 100644
--- a/src/main/java/org/owasp/esapi/codecs/DB2Codec.java
+++ b/src/main/java/org/owasp/esapi/codecs/DB2Codec.java
@@ -15,54 +15,54 @@ package org.owasp.esapi.codecs;
 
 /**
  * Implementation of the Codec interface for DB2 strings. This function will only protect you from SQLi in limited situations.
- * 
+ *
  * @author Sivasankar Tanakala (stanakal@TRS.NYC.NY.US)
  * @since October 26, 2010
  * @see org.owasp.esapi.Encoder
  */
 public class DB2Codec extends AbstractCharacterCodec {
 
-	public String encodeCharacter(char[] immune, Character c) {
+    public String encodeCharacter(char[] immune, Character c) {
 
-		if (c.charValue() == '\'')
-			return "\'\'";
+        if (c.charValue() == '\'')
+            return "\'\'";
 
-		if (c.charValue() == ';')
-			return ".";
+        if (c.charValue() == ';')
+            return ".";
 
-		return "" + c;
-	}
+        return "" + c;
+    }
 
-	public Character decodeCharacter(PushbackString input) {
+    public Character decodeCharacter(PushbackString input) {
 
-		input.mark();
-		Character first = input.next();
+        input.mark();
+        Character first = input.next();
 
-		if (first == null) {
-			input.reset();
-			return null;
-		}
+        if (first == null) {
+            input.reset();
+            return null;
+        }
 
-		// if this is not an encoded character, return null
+        // if this is not an encoded character, return null
 
-		if (first.charValue() != '\'') {
-			input.reset();
-			return null;
-		}
+        if (first.charValue() != '\'') {
+            input.reset();
+            return null;
+        }
 
-		Character second = input.next();
+        Character second = input.next();
 
-		if (second == null) {
-			input.reset();
-			return null;
-		}
+        if (second == null) {
+            input.reset();
+            return null;
+        }
 
-		// if this is not an encoded character, return null
-		if (second.charValue() != '\'') {
-			input.reset();
-			return null;
-		}
+        // if this is not an encoded character, return null
+        if (second.charValue() != '\'') {
+            input.reset();
+            return null;
+        }
 
-		return (Character.valueOf('\''));
-	}
+        return (Character.valueOf('\''));
+    }
 }
\ No newline at end of file
diff --git a/src/main/java/org/owasp/esapi/codecs/HTMLEntityCodec.java b/src/main/java/org/owasp/esapi/codecs/HTMLEntityCodec.java
index 7fc8059..84ccb2c 100644
--- a/src/main/java/org/owasp/esapi/codecs/HTMLEntityCodec.java
+++ b/src/main/java/org/owasp/esapi/codecs/HTMLEntityCodec.java
@@ -1,18 +1,18 @@
 /**
  * OWASP Enterprise Security API (ESAPI)
- * 
+ *
  * This file is part of the Open Web Application Security Project (OWASP)
  * Enterprise Security API (ESAPI) project. For details, please see
  * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
  *
  * Copyright (c) 2017 - The OWASP Foundation
- * 
+ *
  * The ESAPI is published by OWASP under the BSD license. You should read and accept the
  * LICENSE before you use, modify, and/or redistribute this software.
- * 
+ *
  * @author Matt Seil (mseil .at. owasp.org)
- * @created 2017 
- * 
+ * @created 2017
+ *
  * @author Jeff Williams (jeff.williams .at. aspectsecurity.com) <a
  *         href="http://www.aspectsecurity.com">Aspect Security</a>
  * @created 2007
@@ -26,573 +26,573 @@ import java.util.Map.Entry;
 
 /**
  * Implementation of the Codec interface for HTML entity encoding.
- * 
+ *
  * @author Jeff Williams (jeff.williams .at. aspectsecurity.com) <a
  *         href="http://www.aspectsecurity.com">Aspect Security</a>
  * @since June 1, 2007
- * 
- * @author Matt Seil (mseil .at. owasp.org) (mseil .at. owasp.org) 
- * 
+ *
+ * @author Matt Seil (mseil .at. owasp.org) (mseil .at. owasp.org)
+ *
  * @see org.owasp.esapi.Encoder
  */
 public class HTMLEntityCodec extends AbstractIntegerCodec
 {
-	private static final char REPLACEMENT_CHAR = '\ufffd';
-	private static final String REPLACEMENT_HEX = "fffd";
-	private static final String REPLACEMENT_STR = "" + REPLACEMENT_CHAR;
-	private static final Map<Integer,String> characterToEntityMap = mkCharacterToEntityMap();
+    private static final char REPLACEMENT_CHAR = '\ufffd';
+    private static final String REPLACEMENT_HEX = "fffd";
+    private static final String REPLACEMENT_STR = "" + REPLACEMENT_CHAR;
+    private static final Map<Integer,String> characterToEntityMap = mkCharacterToEntityMap();
 
-	private static final Trie<Integer> entityToCharacterTrie = mkEntityToCharacterTrie();
+    private static final Trie<Integer> entityToCharacterTrie = mkEntityToCharacterTrie();
 
     /**
      *
      */
     public HTMLEntityCodec() {
-	}
+    }
 
     /**
      * Given an array of {@code char}, scan the input {@code String} and encode unsafe
-     * codePoints, except for codePoints passed into the {@code char} array.  
+     * codePoints, except for codePoints passed into the {@code char} array.
      * <br/><br/>
-     * WARNING:  This method will silently discard any code point per the 
-     * call to {@code Character.isValidCodePoint( int )} method.  
-     * 
+     * WARNING: This method will silently discard an invalid code point according to
+     * the result of {@code Character.isValidCodePoint( int )} method.
+     *
      * {@inheritDoc}
      */
-	@Override
-	public String encode(char[] immune, String input) {
-		StringBuilder sb = new StringBuilder();
-		for(int offset  = 0; offset < input.length(); ){
-			final int point = input.codePointAt(offset);
-			if(Character.isValidCodePoint(point)){
-				sb.append(encodeCharacter(immune, point));	
-			}
-			offset += Character.charCount(point);
-		}
-		return sb.toString();
-	}
-	
-	/**
-	 * {@inheritDoc}
-	 * 
+    @Override
+    public String encode(char[] immune, String input) {
+        StringBuilder sb = new StringBuilder();
+        for(int offset  = 0; offset < input.length(); ){
+            final int point = input.codePointAt(offset);
+            if(Character.isValidCodePoint(point)){
+                sb.append(encodeCharacter(immune, point));
+            }
+            offset += Character.charCount(point);
+        }
+        return sb.toString();
+    }
+
+    /**
+     * {@inheritDoc}
+     *
      * Encodes a codePoint for safe use in an HTML entity field.
      * @param immune
      */
-	@Override
-	public String encodeCharacter( char[] immune, int codePoint ) {
-
-		// check for immune characters
-		// Cast the codePoint to a char because we want to limit immunity to the BMP field only.  
-		if ( containsCharacter( (char) codePoint, immune ) && Character.isValidCodePoint(codePoint)) {
-			return new StringBuilder().appendCodePoint(codePoint).toString();
-		}
-		
-		// check for alphanumeric characters
-		String hex = super.getHexForNonAlphanumeric(codePoint);
-		if ( hex == null && Character.isValidCodePoint(codePoint)) {
-			return new StringBuilder().appendCodePoint(codePoint).toString();
-		}
-		// check for illegal characters
-		if ( ( codePoint <= 0x1f 
-				&& codePoint != '\t' 
-				&& codePoint != '\n' 
-				&& codePoint != '\r' ) 
-				|| ( codePoint >= 0x7f && codePoint <= 0x9f ) )
-		{
-			hex = REPLACEMENT_HEX;	// Let's entity encode this instead of returning it
-			codePoint = REPLACEMENT_CHAR;
-		}
-		
-		// check if there's a defined entity
-		String entityName = characterToEntityMap.get(codePoint);
-		if (entityName != null) {
-			return "&" + entityName + ";";
-		}
-		
-		// return the hex entity as suggested in the spec
-		return "&#x" + hex + ";";
-	}
-	
-	/**
-	 * {@inheritDoc}
-	 * 
-	 * Returns the decoded version of the character starting at index, or
-	 * null if no decoding is possible.
-	 * 
-	 * Formats all are legal both with and without semi-colon, upper/lower case:
-	 *   &#dddd;
-	 *   &#xhhhh;
-	 *   &name;
-	 */
-	public Integer decodeCharacter( PushbackSequence<Integer> input ) {
-		input.mark();
-		Integer first = input.next();
-		if ( first == null ) {
-			input.reset();
-			return null;
-		}
-		
-		// if this is not an encoded character, return null
-		if (first != '&' ) {
-			input.reset();
-			return null;
-		}
-		
-		// test for numeric encodings
-		Integer second = input.next();
-		if ( second == null ) {
-			input.reset();
-			return null;
-		}
-		
-		if (second == '#' ) {
-			// handle numbers
-			Integer c = getNumericEntity( input );
-			if ( c != null ) return c;
-		} else if ( Character.isLetter( second ) ) {
-			// handle entities
-			input.pushback( second );
-			Integer c = getNamedEntity( input );
-			if ( c != null ) return c;
-		}
-		input.reset();
-		return null;
-	}
-	
-	/**
-	 * getNumericEntry checks input to see if it is a numeric entity
-	 * 
-	 * @param input
-	 * 			The input to test for being a numeric entity
-	 *  
-	 * @return
-	 * 			null if input is null, the character of input after decoding
-	 */
-	private Integer getNumericEntity( PushbackSequence<Integer> input ) {
-		Integer first = input.peek();
-		if ( first == null ) return null;
-
-		if (first == 'x' || first == 'X' ) {
-			input.next();
-			return parseHex( input );
-		}
-		return parseNumber( input );
-	}
-
-	/**
-	 * Parse a decimal number, such as those from JavaScript's String.fromCharCode(value)
-	 * 
-	 * @param input
-	 * 			decimal encoded string, such as 65
-	 * @return
-	 * 			character representation of this decimal value, e.g. A 
-	 * @throws NumberFormatException
-	 */
-	private Integer parseNumber( PushbackSequence<Integer> input ) {
-		StringBuilder sb = new StringBuilder();
-		while( input.hasNext() ) {
-			Integer c = input.peek();
-			
-			// if character is a digit then add it on and keep going
-			if ( Character.isDigit( c ) && Character.isValidCodePoint(c) ) {
-				sb.appendCodePoint( c );
-				input.next();
-				
-			// if character is a semi-colon, eat it and quit
-			} else if (c == ';' ) {
-				input.next();
-				break;
-				
-			// otherwise just quit
-			} else {
-				break;
-			}
-		}
-		try {
-			int i = Integer.parseInt(sb.toString());
+    @Override
+    public String encodeCharacter( char[] immune, int codePoint ) {
+
+        // check for immune characters
+        // Cast the codePoint to a char because we want to limit immunity to the BMP field only.
+        if ( containsCharacter( (char) codePoint, immune ) && Character.isValidCodePoint(codePoint)) {
+            return new StringBuilder().appendCodePoint(codePoint).toString();
+        }
+
+        // check for alphanumeric characters
+        String hex = super.getHexForNonAlphanumeric(codePoint);
+        if ( hex == null && Character.isValidCodePoint(codePoint)) {
+            return new StringBuilder().appendCodePoint(codePoint).toString();
+        }
+        // check for illegal characters
+        if ( ( codePoint <= 0x1f
+                && codePoint != '\t'
+                && codePoint != '\n'
+                && codePoint != '\r' )
+                || ( codePoint >= 0x7f && codePoint <= 0x9f ) )
+        {
+            hex = REPLACEMENT_HEX;    // Let's entity encode this instead of returning it
+            codePoint = REPLACEMENT_CHAR;
+        }
+
+        // check if there's a defined entity
+        String entityName = characterToEntityMap.get(codePoint);
+        if (entityName != null) {
+            return "&" + entityName + ";";
+        }
+
+        // return the hex entity as suggested in the spec
+        return "&#x" + hex + ";";
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * Returns the decoded version of the character starting at index, or
+     * null if no decoding is possible.
+     *
+     * Formats all are legal both with and without semi-colon, upper/lower case:
+     *   &#dddd;
+     *   &#xhhhh;
+     *   &name;
+     */
+    public Integer decodeCharacter( PushbackSequence<Integer> input ) {
+        input.mark();
+        Integer first = input.next();
+        if ( first == null ) {
+            input.reset();
+            return null;
+        }
+
+        // if this is not an encoded character, return null
+        if (first != '&' ) {
+            input.reset();
+            return null;
+        }
+
+        // test for numeric encodings
+        Integer second = input.next();
+        if ( second == null ) {
+            input.reset();
+            return null;
+        }
+
+        if (second == '#' ) {
+            // handle numbers
+            Integer c = getNumericEntity( input );
+            if ( c != null ) return c;
+        } else if ( Character.isLetter( second ) ) {
+            // handle entities
+            input.pushback( second );
+            Integer c = getNamedEntity( input );
+            if ( c != null ) return c;
+        }
+        input.reset();
+        return null;
+    }
+
+    /**
+     * getNumericEntry checks input to see if it is a numeric entity
+     *
+     * @param input
+     *             The input to test for being a numeric entity
+     *
+     * @return
+     *             null if input is null, the character of input after decoding
+     */
+    private Integer getNumericEntity( PushbackSequence<Integer> input ) {
+        Integer first = input.peek();
+        if ( first == null ) return null;
+
+        if (first == 'x' || first == 'X' ) {
+            input.next();
+            return parseHex( input );
+        }
+        return parseNumber( input );
+    }
+
+    /**
+     * Parse a decimal number, such as those from JavaScript's String.fromCharCode(value)
+     *
+     * @param input
+     *             decimal encoded string, such as 65
+     * @return
+     *             character representation of this decimal value, e.g. A
+     * @throws NumberFormatException
+     */
+    private Integer parseNumber( PushbackSequence<Integer> input ) {
+        StringBuilder sb = new StringBuilder();
+        while( input.hasNext() ) {
+            Integer c = input.peek();
+
+            // if character is a digit then add it on and keep going
+            if ( Character.isDigit( c ) && Character.isValidCodePoint(c) ) {
+                sb.appendCodePoint( c );
+                input.next();
+
+            // if character is a semi-colon, eat it and quit
+            } else if (c == ';' ) {
+                input.next();
+                break;
+
+            // otherwise just quit
+            } else {
+                break;
+            }
+        }
+        try {
+            int i = Integer.parseInt(sb.toString());
             if (Character.isValidCodePoint(i)) {
                 return i;
             }
-		} catch( NumberFormatException e ) {
-			// throw an exception for malformed entity?
-		}
-			return null;
-		}
-	
-	/**
-	 * Parse a hex encoded entity
-	 * 
-	 * @param input
-	 * 			Hex encoded input (such as 437ae;)
-	 * @return
-	 * 			A single character from the string
-	 * @throws NumberFormatException
-	 */
-	private Integer parseHex( PushbackSequence<Integer> input ) {
-		StringBuilder sb = new StringBuilder();
-		while( input.hasNext() ) {
-			Integer c = input.peek();
-			
-			// if character is a hex digit then add it on and keep going
-			//This statement implicitly tests for Character.isValidCodePoint(int)
-			if ( "0123456789ABCDEFabcdef".indexOf(c) != -1 ) {
-				sb.appendCodePoint( c );
-				input.next();
-				
-			// if character is a semi-colon, eat it and quit
-			} else if (c == ';' ) {
-				input.next();
-				break;
-				
-			// otherwise just quit
-			} else {
-				break;
-			}
-		}
-		try {
-			int i = Integer.parseInt(sb.toString(), 16);
+        } catch( NumberFormatException e ) {
+            // throw an exception for malformed entity?
+        }
+            return null;
+        }
+
+    /**
+     * Parse a hex encoded entity
+     *
+     * @param input
+     *             Hex encoded input (such as 437ae;)
+     * @return
+     *             A single character from the string
+     * @throws NumberFormatException
+     */
+    private Integer parseHex( PushbackSequence<Integer> input ) {
+        StringBuilder sb = new StringBuilder();
+        while( input.hasNext() ) {
+            Integer c = input.peek();
+
+            // if character is a hex digit then add it on and keep going
+            //This statement implicitly tests for Character.isValidCodePoint(int)
+            if ( "0123456789ABCDEFabcdef".indexOf(c) != -1 ) {
+                sb.appendCodePoint( c );
+                input.next();
+
+            // if character is a semi-colon, eat it and quit
+            } else if (c == ';' ) {
+                input.next();
+                break;
+
+            // otherwise just quit
+            } else {
+                break;
+            }
+        }
+        try {
+            int i = Integer.parseInt(sb.toString(), 16);
             if (Character.isValidCodePoint(i)) {
                 return i;
             }
-		} catch( NumberFormatException e ) {
-			// throw an exception for malformed entity?
-		}
-			return null;
-		}
-	
-	/**
-	 * 
-	 * Returns the decoded version of the character starting at index, or
-	 * null if no decoding is possible.
-	 * 
-	 * Formats all are legal both with and without semi-colon, upper/lower case:
-	 *   &aa;
-	 *   &aaa;
-	 *   &aaaa;
-	 *   &aaaaa;
-	 *   &aaaaaa;
-	 *   &aaaaaaa;
-	 *
-	 * @param input
-	 * 		A string containing a named entity like &quot;
-	 * @return
-	 * 		Returns the decoded version of the character starting at index, or null if no decoding is possible.
-	 */
-	private Integer getNamedEntity( PushbackSequence<Integer> input ) {
-		StringBuilder possible = new StringBuilder();
-		Entry<CharSequence, Integer> entry;
-		int len;
-		
-		// kludge around PushbackString....
-		len = Math.min(input.remainder().length(), entityToCharacterTrie.getMaxKeyLength());
-		for(int i=0;i<len;i++){
-			Integer next = input.next();
-			if(null != next && Character.isValidCodePoint(next)){
-				possible.appendCodePoint(next);
-			}
-		}
-		// look up the longest match
-		entry = entityToCharacterTrie.getLongestMatch(possible);
-		if(entry == null) {
-			// We are lowercasing & comparing the result because of this all the upper case named entities are getting converted lowercase named entities.
-			// check is there any exact match https://github.com/ESAPI/esapi-java-legacy/issues/302
-			String possibleString = possible.toString();
-			String possibleStringLowerCase = possibleString.toLowerCase();
-		        if(!possibleString.equals(possibleStringLowerCase)) {
-		           Map.Entry<CharSequence,Integer> exactEntry = entityToCharacterTrie.getLongestMatch(possibleStringLowerCase);
-		           if(exactEntry != null) entry = exactEntry;
-		        }
-		        if(entry == null) return null; // no match, caller will reset input
-		}
-
-		// fixup input
-		input.reset();
-		input.next();	// read &
-		len = entry.getKey().length();	// what matched's length
-		for(int i=0;i<len;i++)
-			input.next();
-
-		// check for a trailing semicolen
-		if(input.peek(Integer.valueOf(';')))
-			input.next();
-
-		return entry.getValue();
-	}
-
-	/**
-	 * Build a unmodifiable Map from entity Character to Name.
-	 * @return Unmodifiable map.
-	 */
-	private static synchronized Map<Integer,String> mkCharacterToEntityMap()
-	{
-		Map<Integer, String> map = new HashMap<Integer,String>(252);
-
-		map.put(34,	"quot");	/* quotation mark */
-		map.put(38,	"amp");		/* ampersand */
-		map.put(60,	"lt");		/* less-than sign */
-		map.put(62,	"gt");		/* greater-than sign */
-		map.put(160,	"nbsp");	/* no-break space */
-		map.put(161,	"iexcl");	/* inverted exclamation mark */
-		map.put(162,	"cent");	/* cent sign */
-		map.put(163,	"pound");	/* pound sign */
-		map.put(164,	"curren");	/* currency sign */
-		map.put(165,	"yen");		/* yen sign */
-		map.put(166,	"brvbar");	/* broken bar */
-		map.put(167,	"sect");	/* section sign */
-		map.put(168,	"uml");		/* diaeresis */
-		map.put(169,	"copy");	/* copyright sign */
-		map.put(170,	"ordf");	/* feminine ordinal indicator */
-		map.put(171,	"laquo");	/* left-pointing double angle quotation mark */
-		map.put(172,	"not");		/* not sign */
-		map.put(173,	"shy");		/* soft hyphen */
-		map.put(174,	"reg");		/* registered sign */
-		map.put(175,	"macr");	/* macron */
-		map.put(176,	"deg");		/* degree sign */
-		map.put(177,	"plusmn");	/* plus-minus sign */
-		map.put(178,	"sup2");	/* superscript two */
-		map.put(179,	"sup3");	/* superscript three */
-		map.put(180,	"acute");	/* acute accent */
-		map.put(181,	"micro");	/* micro sign */
-		map.put(182,	"para");	/* pilcrow sign */
-		map.put(183,	"middot");	/* middle dot */
-		map.put(184,	"cedil");	/* cedilla */
-		map.put(185,	"sup1");	/* superscript one */
-		map.put(186,	"ordm");	/* masculine ordinal indicator */
-		map.put(187,	"raquo");	/* right-pointing double angle quotation mark */
-		map.put(188,	"frac14");	/* vulgar fraction one quarter */
-		map.put(189,	"frac12");	/* vulgar fraction one half */
-		map.put(190,	"frac34");	/* vulgar fraction three quarters */
-		map.put(191,	"iquest");	/* inverted question mark */
-		map.put(192,	"Agrave");	/* Latin capital letter a with grave */
-		map.put(193,	"Aacute");	/* Latin capital letter a with acute */
-		map.put(194,	"Acirc");	/* Latin capital letter a with circumflex */
-		map.put(195,	"Atilde");	/* Latin capital letter a with tilde */
-		map.put(196,	"Auml");	/* Latin capital letter a with diaeresis */
-		map.put(197,	"Aring");	/* Latin capital letter a with ring above */
-		map.put(198,	"AElig");	/* Latin capital letter ae */
-		map.put(199,	"Ccedil");	/* Latin capital letter c with cedilla */
-		map.put(200,	"Egrave");	/* Latin capital letter e with grave */
-		map.put(201,	"Eacute");	/* Latin capital letter e with acute */
-		map.put(202,	"Ecirc");	/* Latin capital letter e with circumflex */
-		map.put(203,	"Euml");	/* Latin capital letter e with diaeresis */
-		map.put(204,	"Igrave");	/* Latin capital letter i with grave */
-		map.put(205,	"Iacute");	/* Latin capital letter i with acute */
-		map.put(206,	"Icirc");	/* Latin capital letter i with circumflex */
-		map.put(207,	"Iuml");	/* Latin capital letter i with diaeresis */
-		map.put(208,	"ETH");		/* Latin capital letter eth */
-		map.put(209,	"Ntilde");	/* Latin capital letter n with tilde */
-		map.put(210,	"Ograve");	/* Latin capital letter o with grave */
-		map.put(211,	"Oacute");	/* Latin capital letter o with acute */
-		map.put(212,	"Ocirc");	/* Latin capital letter o with circumflex */
-		map.put(213,	"Otilde");	/* Latin capital letter o with tilde */
-		map.put(214,	"Ouml");	/* Latin capital letter o with diaeresis */
-		map.put(215,	"times");	/* multiplication sign */
-		map.put(216,	"Oslash");	/* Latin capital letter o with stroke */
-		map.put(217,	"Ugrave");	/* Latin capital letter u with grave */
-		map.put(218,	"Uacute");	/* Latin capital letter u with acute */
-		map.put(219,	"Ucirc");	/* Latin capital letter u with circumflex */
-		map.put(220,	"Uuml");	/* Latin capital letter u with diaeresis */
-		map.put(221,	"Yacute");	/* Latin capital letter y with acute */
-		map.put(222,	"THORN");	/* Latin capital letter thorn */
-		map.put(223,	"szlig");	/* Latin small letter sharp sXCOMMAX German Eszett */
-		map.put(224,	"agrave");	/* Latin small letter a with grave */
-		map.put(225,	"aacute");	/* Latin small letter a with acute */
-		map.put(226,	"acirc");	/* Latin small letter a with circumflex */
-		map.put(227,	"atilde");	/* Latin small letter a with tilde */
-		map.put(228,	"auml");	/* Latin small letter a with diaeresis */
-		map.put(229,	"aring");	/* Latin small letter a with ring above */
-		map.put(230,	"aelig");	/* Latin lowercase ligature ae */
-		map.put(231,	"ccedil");	/* Latin small letter c with cedilla */
-		map.put(232,	"egrave");	/* Latin small letter e with grave */
-		map.put(233,	"eacute");	/* Latin small letter e with acute */
-		map.put(234,	"ecirc");	/* Latin small letter e with circumflex */
-		map.put(235,	"euml");	/* Latin small letter e with diaeresis */
-		map.put(236,	"igrave");	/* Latin small letter i with grave */
-		map.put(237,	"iacute");	/* Latin small letter i with acute */
-		map.put(238,	"icirc");	/* Latin small letter i with circumflex */
-		map.put(239,	"iuml");	/* Latin small letter i with diaeresis */
-		map.put(240,	"eth");		/* Latin small letter eth */
-		map.put(241,	"ntilde");	/* Latin small letter n with tilde */
-		map.put(242,	"ograve");	/* Latin small letter o with grave */
-		map.put(243,	"oacute");	/* Latin small letter o with acute */
-		map.put(244,	"ocirc");	/* Latin small letter o with circumflex */
-		map.put(245,	"otilde");	/* Latin small letter o with tilde */
-		map.put(246,	"ouml");	/* Latin small letter o with diaeresis */
-		map.put(247,	"divide");	/* division sign */
-		map.put(248,	"oslash");	/* Latin small letter o with stroke */
-		map.put(249,	"ugrave");	/* Latin small letter u with grave */
-		map.put(250,	"uacute");	/* Latin small letter u with acute */
-		map.put(251,	"ucirc");	/* Latin small letter u with circumflex */
-		map.put(252,	"uuml");	/* Latin small letter u with diaeresis */
-		map.put(253,	"yacute");	/* Latin small letter y with acute */
-		map.put(254,	"thorn");	/* Latin small letter thorn */
-		map.put(255,	"yuml");	/* Latin small letter y with diaeresis */
-		map.put(338,	"OElig");	/* Latin capital ligature oe */
-		map.put(339,	"oelig");	/* Latin small ligature oe */
-		map.put(352,	"Scaron");	/* Latin capital letter s with caron */
-		map.put(353,	"scaron");	/* Latin small letter s with caron */
-		map.put(376,	"Yuml");	/* Latin capital letter y with diaeresis */
-		map.put(402,	"fnof");	/* Latin small letter f with hook */
-		map.put(710,	"circ");	/* modifier letter circumflex accent */
-		map.put(732,	"tilde");	/* small tilde */
-		map.put(913,	"Alpha");	/* Greek capital letter alpha */
-		map.put(914,	"Beta");	/* Greek capital letter beta */
-		map.put(915,	"Gamma");	/* Greek capital letter gamma */
-		map.put(916,	"Delta");	/* Greek capital letter delta */
-		map.put(917,	"Epsilon");	/* Greek capital letter epsilon */
-		map.put(918,	"Zeta");	/* Greek capital letter zeta */
-		map.put(919,	"Eta");		/* Greek capital letter eta */
-		map.put(920,	"Theta");	/* Greek capital letter theta */
-		map.put(921,	"Iota");	/* Greek capital letter iota */
-		map.put(922,	"Kappa");	/* Greek capital letter kappa */
-		map.put(923,	"Lambda");	/* Greek capital letter lambda */
-		map.put(924,	"Mu");		/* Greek capital letter mu */
-		map.put(925,	"Nu");		/* Greek capital letter nu */
-		map.put(926,	"Xi");		/* Greek capital letter xi */
-		map.put(927,	"Omicron");	/* Greek capital letter omicron */
-		map.put(928,	"Pi");		/* Greek capital letter pi */
-		map.put(929,	"Rho");		/* Greek capital letter rho */
-		map.put(931,	"Sigma");	/* Greek capital letter sigma */
-		map.put(932,	"Tau");		/* Greek capital letter tau */
-		map.put(933,	"Upsilon");	/* Greek capital letter upsilon */
-		map.put(934,	"Phi");		/* Greek capital letter phi */
-		map.put(935,	"Chi");		/* Greek capital letter chi */
-		map.put(936,	"Psi");		/* Greek capital letter psi */
-		map.put(937,	"Omega");	/* Greek capital letter omega */
-		map.put(945,	"alpha");	/* Greek small letter alpha */
-		map.put(946,	"beta");	/* Greek small letter beta */
-		map.put(947,	"gamma");	/* Greek small letter gamma */
-		map.put(948,	"delta");	/* Greek small letter delta */
-		map.put(949,	"epsilon");	/* Greek small letter epsilon */
-		map.put(950,	"zeta");	/* Greek small letter zeta */
-		map.put(951,	"eta");		/* Greek small letter eta */
-		map.put(952,	"theta");	/* Greek small letter theta */
-		map.put(953,	"iota");	/* Greek small letter iota */
-		map.put(954,	"kappa");	/* Greek small letter kappa */
-		map.put(955,	"lambda");	/* Greek small letter lambda */
-		map.put(956,	"mu");		/* Greek small letter mu */
-		map.put(957,	"nu");		/* Greek small letter nu */
-		map.put(958,	"xi");		/* Greek small letter xi */
-		map.put(959,	"omicron");	/* Greek small letter omicron */
-		map.put(960,	"pi");		/* Greek small letter pi */
-		map.put(961,	"rho");		/* Greek small letter rho */
-		map.put(962,	"sigmaf");	/* Greek small letter final sigma */
-		map.put(963,	"sigma");	/* Greek small letter sigma */
-		map.put(964,	"tau");		/* Greek small letter tau */
-		map.put(965,	"upsilon");	/* Greek small letter upsilon */
-		map.put(966,	"phi");		/* Greek small letter phi */
-		map.put(967,	"chi");		/* Greek small letter chi */
-		map.put(968,	"psi");		/* Greek small letter psi */
-		map.put(969,	"omega");	/* Greek small letter omega */
-		map.put(977,	"thetasym");	/* Greek theta symbol */
-		map.put(978,	"upsih");	/* Greek upsilon with hook symbol */
-		map.put(982,	"piv");		/* Greek pi symbol */
-		map.put(8194,	"ensp");	/* en space */
-		map.put(8195,	"emsp");	/* em space */
-		map.put(8201,	"thinsp");	/* thin space */
-		map.put(8204,	"zwnj");	/* zero width non-joiner */
-		map.put(8205,	"zwj");		/* zero width joiner */
-		map.put(8206,	"lrm");		/* left-to-right mark */
-		map.put(8207,	"rlm");		/* right-to-left mark */
-		map.put(8211,	"ndash");	/* en dash */
-		map.put(8212,	"mdash");	/* em dash */
-		map.put(8216,	"lsquo");	/* left single quotation mark */
-		map.put(8217,	"rsquo");	/* right single quotation mark */
-		map.put(8218,	"sbquo");	/* single low-9 quotation mark */
-		map.put(8220,	"ldquo");	/* left double quotation mark */
-		map.put(8221,	"rdquo");	/* right double quotation mark */
-		map.put(8222,	"bdquo");	/* double low-9 quotation mark */
-		map.put(8224,	"dagger");	/* dagger */
-		map.put(8225,	"Dagger");	/* double dagger */
-		map.put(8226,	"bull");	/* bullet */
-		map.put(8230,	"hellip");	/* horizontal ellipsis */
-		map.put(8240,	"permil");	/* per mille sign */
-		map.put(8242,	"prime");	/* prime */
-		map.put(8243,	"Prime");	/* double prime */
-		map.put(8249,	"lsaquo");	/* single left-pointing angle quotation mark */
-		map.put(8250,	"rsaquo");	/* single right-pointing angle quotation mark */
-		map.put(8254,	"oline");	/* overline */
-		map.put(8260,	"frasl");	/* fraction slash */
-		map.put(8364,	"euro");	/* euro sign */
-		map.put(8465,	"image");	/* black-letter capital i */
-		map.put(8472,	"weierp");	/* script capital pXCOMMAX Weierstrass p */
-		map.put(8476,	"real");	/* black-letter capital r */
-		map.put(8482,	"trade");	/* trademark sign */
-		map.put(8501,	"alefsym");	/* alef symbol */
-		map.put(8592,	"larr");	/* leftwards arrow */
-		map.put(8593,	"uarr");	/* upwards arrow */
-		map.put(8594,	"rarr");	/* rightwards arrow */
-		map.put(8595,	"darr");	/* downwards arrow */
-		map.put(8596,	"harr");	/* left right arrow */
-		map.put(8629,	"crarr");	/* downwards arrow with corner leftwards */
-		map.put(8656,	"lArr");	/* leftwards double arrow */
-		map.put(8657,	"uArr");	/* upwards double arrow */
-		map.put(8658,	"rArr");	/* rightwards double arrow */
-		map.put(8659,	"dArr");	/* downwards double arrow */
-		map.put(8660,	"hArr");	/* left right double arrow */
-		map.put(8704,	"forall");	/* for all */
-		map.put(8706,	"part");	/* partial differential */
-		map.put(8707,	"exist");	/* there exists */
-		map.put(8709,	"empty");	/* empty set */
-		map.put(8711,	"nabla");	/* nabla */
-		map.put(8712,	"isin");	/* element of */
-		map.put(8713,	"notin");	/* not an element of */
-		map.put(8715,	"ni");		/* contains as member */
-		map.put(8719,	"prod");	/* n-ary product */
-		map.put(8721,	"sum");		/* n-ary summation */
-		map.put(8722,	"minus");	/* minus sign */
-		map.put(8727,	"lowast");	/* asterisk operator */
-		map.put(8730,	"radic");	/* square root */
-		map.put(8733,	"prop");	/* proportional to */
-		map.put(8734,	"infin");	/* infinity */
-		map.put(8736,	"ang");		/* angle */
-		map.put(8743,	"and");		/* logical and */
-		map.put(8744,	"or");		/* logical or */
-		map.put(8745,	"cap");		/* intersection */
-		map.put(8746,	"cup");		/* union */
-		map.put(8747,	"int");		/* integral */
-		map.put(8756,	"there4");	/* therefore */
-		map.put(8764,	"sim");		/* tilde operator */
-		map.put(8773,	"cong");	/* congruent to */
-		map.put(8776,	"asymp");	/* almost equal to */
-		map.put(8800,	"ne");		/* not equal to */
-		map.put(8801,	"equiv");	/* identical toXCOMMAX equivalent to */
-		map.put(8804,	"le");		/* less-than or equal to */
-		map.put(8805,	"ge");		/* greater-than or equal to */
-		map.put(8834,	"sub");		/* subset of */
-		map.put(8835,	"sup");		/* superset of */
-		map.put(8836,	"nsub");	/* not a subset of */
-		map.put(8838,	"sube");	/* subset of or equal to */
-		map.put(8839,	"supe");	/* superset of or equal to */
-		map.put(8853,	"oplus");	/* circled plus */
-		map.put(8855,	"otimes");	/* circled times */
-		map.put(8869,	"perp");	/* up tack */
-		map.put(8901,	"sdot");	/* dot operator */
-		map.put(8968,	"lceil");	/* left ceiling */
-		map.put(8969,	"rceil");	/* right ceiling */
-		map.put(8970,	"lfloor");	/* left floor */
-		map.put(8971,	"rfloor");	/* right floor */
-		map.put(9001,	"lang");	/* left-pointing angle bracket */
-		map.put(9002,	"rang");	/* right-pointing angle bracket */
-		map.put(9674,	"loz");		/* lozenge */
-		map.put(9824,	"spades");	/* black spade suit */
-		map.put(9827,	"clubs");	/* black club suit */
-		map.put(9829,	"hearts");	/* black heart suit */
-		map.put(9830,	"diams");	/* black diamond suit */
-
-		return Collections.unmodifiableMap(map);
-	}
-
-	/**
-	 * Build a unmodifiable Trie from entitiy Name to Character
-	 * @return Unmodifiable trie.
-	 */
-	private static synchronized Trie<Integer> mkEntityToCharacterTrie()
-	{
-		Trie<Integer> trie = new HashTrie<Integer>();
-
-		for(Map.Entry<Integer,String> entry : characterToEntityMap.entrySet())
-			trie.put(entry.getValue(),entry.getKey());
-		return Trie.Util.unmodifiable(trie);
-	}
+        } catch( NumberFormatException e ) {
+            // throw an exception for malformed entity?
+        }
+            return null;
+        }
+
+    /**
+     *
+     * Returns the decoded version of the character starting at index, or
+     * null if no decoding is possible.
+     *
+     * Formats all are legal both with and without semi-colon, upper/lower case:
+     *   &aa;
+     *   &aaa;
+     *   &aaaa;
+     *   &aaaaa;
+     *   &aaaaaa;
+     *   &aaaaaaa;
+     *
+     * @param input
+     *         A string containing a named entity like &quot;
+     * @return
+     *         Returns the decoded version of the character starting at index, or null if no decoding is possible.
+     */
+    private Integer getNamedEntity( PushbackSequence<Integer> input ) {
+        StringBuilder possible = new StringBuilder();
+        Entry<CharSequence, Integer> entry;
+        int len;
+
+        // kludge around PushbackString....
+        len = Math.min(input.remainder().length(), entityToCharacterTrie.getMaxKeyLength());
+        for(int i=0;i<len;i++){
+            Integer next = input.next();
+            if(null != next && Character.isValidCodePoint(next)){
+                possible.appendCodePoint(next);
+            }
+        }
+        // look up the longest match
+        entry = entityToCharacterTrie.getLongestMatch(possible);
+        if(entry == null) {
+            // We are lowercasing & comparing the result because of this all the upper case named entities are getting converted lowercase named entities.
+            // check is there any exact match https://github.com/ESAPI/esapi-java-legacy/issues/302
+            String possibleString = possible.toString();
+            String possibleStringLowerCase = possibleString.toLowerCase();
+                if(!possibleString.equals(possibleStringLowerCase)) {
+                   Map.Entry<CharSequence,Integer> exactEntry = entityToCharacterTrie.getLongestMatch(possibleStringLowerCase);
+                   if(exactEntry != null) entry = exactEntry;
+                }
+                if(entry == null) return null; // no match, caller will reset input
+        }
+
+        // fixup input
+        input.reset();
+        input.next();    // read &
+        len = entry.getKey().length();    // what matched's length
+        for(int i=0;i<len;i++)
+            input.next();
+
+        // check for a trailing semicolen
+        if(input.peek(Integer.valueOf(';')))
+            input.next();
+
+        return entry.getValue();
+    }
+
+    /**
+     * Build a unmodifiable Map from entity Character to Name.
+     * @return Unmodifiable map.
+     */
+    private static synchronized Map<Integer,String> mkCharacterToEntityMap()
+    {
+        Map<Integer, String> map = new HashMap<Integer,String>(252);
+
+        map.put(34,    "quot");    /* quotation mark */
+        map.put(38,    "amp");        /* ampersand */
+        map.put(60,    "lt");        /* less-than sign */
+        map.put(62,    "gt");        /* greater-than sign */
+        map.put(160,    "nbsp");    /* no-break space */
+        map.put(161,    "iexcl");    /* inverted exclamation mark */
+        map.put(162,    "cent");    /* cent sign */
+        map.put(163,    "pound");    /* pound sign */
+        map.put(164,    "curren");    /* currency sign */
+        map.put(165,    "yen");        /* yen sign */
+        map.put(166,    "brvbar");    /* broken bar */
+        map.put(167,    "sect");    /* section sign */
+        map.put(168,    "uml");        /* diaeresis */
+        map.put(169,    "copy");    /* copyright sign */
+        map.put(170,    "ordf");    /* feminine ordinal indicator */
+        map.put(171,    "laquo");    /* left-pointing double angle quotation mark */
+        map.put(172,    "not");        /* not sign */
+        map.put(173,    "shy");        /* soft hyphen */
+        map.put(174,    "reg");        /* registered sign */
+        map.put(175,    "macr");    /* macron */
+        map.put(176,    "deg");        /* degree sign */
+        map.put(177,    "plusmn");    /* plus-minus sign */
+        map.put(178,    "sup2");    /* superscript two */
+        map.put(179,    "sup3");    /* superscript three */
+        map.put(180,    "acute");    /* acute accent */
+        map.put(181,    "micro");    /* micro sign */
+        map.put(182,    "para");    /* pilcrow sign */
+        map.put(183,    "middot");    /* middle dot */
+        map.put(184,    "cedil");    /* cedilla */
+        map.put(185,    "sup1");    /* superscript one */
+        map.put(186,    "ordm");    /* masculine ordinal indicator */
+        map.put(187,    "raquo");    /* right-pointing double angle quotation mark */
+        map.put(188,    "frac14");    /* vulgar fraction one quarter */
+        map.put(189,    "frac12");    /* vulgar fraction one half */
+        map.put(190,    "frac34");    /* vulgar fraction three quarters */
+        map.put(191,    "iquest");    /* inverted question mark */
+        map.put(192,    "Agrave");    /* Latin capital letter a with grave */
+        map.put(193,    "Aacute");    /* Latin capital letter a with acute */
+        map.put(194,    "Acirc");    /* Latin capital letter a with circumflex */
+        map.put(195,    "Atilde");    /* Latin capital letter a with tilde */
+        map.put(196,    "Auml");    /* Latin capital letter a with diaeresis */
+        map.put(197,    "Aring");    /* Latin capital letter a with ring above */
+        map.put(198,    "AElig");    /* Latin capital letter ae */
+        map.put(199,    "Ccedil");    /* Latin capital letter c with cedilla */
+        map.put(200,    "Egrave");    /* Latin capital letter e with grave */
+        map.put(201,    "Eacute");    /* Latin capital letter e with acute */
+        map.put(202,    "Ecirc");    /* Latin capital letter e with circumflex */
+        map.put(203,    "Euml");    /* Latin capital letter e with diaeresis */
+        map.put(204,    "Igrave");    /* Latin capital letter i with grave */
+        map.put(205,    "Iacute");    /* Latin capital letter i with acute */
+        map.put(206,    "Icirc");    /* Latin capital letter i with circumflex */
+        map.put(207,    "Iuml");    /* Latin capital letter i with diaeresis */
+        map.put(208,    "ETH");        /* Latin capital letter eth */
+        map.put(209,    "Ntilde");    /* Latin capital letter n with tilde */
+        map.put(210,    "Ograve");    /* Latin capital letter o with grave */
+        map.put(211,    "Oacute");    /* Latin capital letter o with acute */
+        map.put(212,    "Ocirc");    /* Latin capital letter o with circumflex */
+        map.put(213,    "Otilde");    /* Latin capital letter o with tilde */
+        map.put(214,    "Ouml");    /* Latin capital letter o with diaeresis */
+        map.put(215,    "times");    /* multiplication sign */
+        map.put(216,    "Oslash");    /* Latin capital letter o with stroke */
+        map.put(217,    "Ugrave");    /* Latin capital letter u with grave */
+        map.put(218,    "Uacute");    /* Latin capital letter u with acute */
+        map.put(219,    "Ucirc");    /* Latin capital letter u with circumflex */
+        map.put(220,    "Uuml");    /* Latin capital letter u with diaeresis */
+        map.put(221,    "Yacute");    /* Latin capital letter y with acute */
+        map.put(222,    "THORN");    /* Latin capital letter thorn */
+        map.put(223,    "szlig");    /* Latin small letter sharp sXCOMMAX German Eszett */
+        map.put(224,    "agrave");    /* Latin small letter a with grave */
+        map.put(225,    "aacute");    /* Latin small letter a with acute */
+        map.put(226,    "acirc");    /* Latin small letter a with circumflex */
+        map.put(227,    "atilde");    /* Latin small letter a with tilde */
+        map.put(228,    "auml");    /* Latin small letter a with diaeresis */
+        map.put(229,    "aring");    /* Latin small letter a with ring above */
+        map.put(230,    "aelig");    /* Latin lowercase ligature ae */
+        map.put(231,    "ccedil");    /* Latin small letter c with cedilla */
+        map.put(232,    "egrave");    /* Latin small letter e with grave */
+        map.put(233,    "eacute");    /* Latin small letter e with acute */
+        map.put(234,    "ecirc");    /* Latin small letter e with circumflex */
+        map.put(235,    "euml");    /* Latin small letter e with diaeresis */
+        map.put(236,    "igrave");    /* Latin small letter i with grave */
+        map.put(237,    "iacute");    /* Latin small letter i with acute */
+        map.put(238,    "icirc");    /* Latin small letter i with circumflex */
+        map.put(239,    "iuml");    /* Latin small letter i with diaeresis */
+        map.put(240,    "eth");        /* Latin small letter eth */
+        map.put(241,    "ntilde");    /* Latin small letter n with tilde */
+        map.put(242,    "ograve");    /* Latin small letter o with grave */
+        map.put(243,    "oacute");    /* Latin small letter o with acute */
+        map.put(244,    "ocirc");    /* Latin small letter o with circumflex */
+        map.put(245,    "otilde");    /* Latin small letter o with tilde */
+        map.put(246,    "ouml");    /* Latin small letter o with diaeresis */
+        map.put(247,    "divide");    /* division sign */
+        map.put(248,    "oslash");    /* Latin small letter o with stroke */
+        map.put(249,    "ugrave");    /* Latin small letter u with grave */
+        map.put(250,    "uacute");    /* Latin small letter u with acute */
+        map.put(251,    "ucirc");    /* Latin small letter u with circumflex */
+        map.put(252,    "uuml");    /* Latin small letter u with diaeresis */
+        map.put(253,    "yacute");    /* Latin small letter y with acute */
+        map.put(254,    "thorn");    /* Latin small letter thorn */
+        map.put(255,    "yuml");    /* Latin small letter y with diaeresis */
+        map.put(338,    "OElig");    /* Latin capital ligature oe */
+        map.put(339,    "oelig");    /* Latin small ligature oe */
+        map.put(352,    "Scaron");    /* Latin capital letter s with caron */
+        map.put(353,    "scaron");    /* Latin small letter s with caron */
+        map.put(376,    "Yuml");    /* Latin capital letter y with diaeresis */
+        map.put(402,    "fnof");    /* Latin small letter f with hook */
+        map.put(710,    "circ");    /* modifier letter circumflex accent */
+        map.put(732,    "tilde");    /* small tilde */
+        map.put(913,    "Alpha");    /* Greek capital letter alpha */
+        map.put(914,    "Beta");    /* Greek capital letter beta */
+        map.put(915,    "Gamma");    /* Greek capital letter gamma */
+        map.put(916,    "Delta");    /* Greek capital letter delta */
+        map.put(917,    "Epsilon");    /* Greek capital letter epsilon */
+        map.put(918,    "Zeta");    /* Greek capital letter zeta */
+        map.put(919,    "Eta");        /* Greek capital letter eta */
+        map.put(920,    "Theta");    /* Greek capital letter theta */
+        map.put(921,    "Iota");    /* Greek capital letter iota */
+        map.put(922,    "Kappa");    /* Greek capital letter kappa */
+        map.put(923,    "Lambda");    /* Greek capital letter lambda */
+        map.put(924,    "Mu");        /* Greek capital letter mu */
+        map.put(925,    "Nu");        /* Greek capital letter nu */
+        map.put(926,    "Xi");        /* Greek capital letter xi */
+        map.put(927,    "Omicron");    /* Greek capital letter omicron */
+        map.put(928,    "Pi");        /* Greek capital letter pi */
+        map.put(929,    "Rho");        /* Greek capital letter rho */
+        map.put(931,    "Sigma");    /* Greek capital letter sigma */
+        map.put(932,    "Tau");        /* Greek capital letter tau */
+        map.put(933,    "Upsilon");    /* Greek capital letter upsilon */
+        map.put(934,    "Phi");        /* Greek capital letter phi */
+        map.put(935,    "Chi");        /* Greek capital letter chi */
+        map.put(936,    "Psi");        /* Greek capital letter psi */
+        map.put(937,    "Omega");    /* Greek capital letter omega */
+        map.put(945,    "alpha");    /* Greek small letter alpha */
+        map.put(946,    "beta");    /* Greek small letter beta */
+        map.put(947,    "gamma");    /* Greek small letter gamma */
+        map.put(948,    "delta");    /* Greek small letter delta */
+        map.put(949,    "epsilon");    /* Greek small letter epsilon */
+        map.put(950,    "zeta");    /* Greek small letter zeta */
+        map.put(951,    "eta");        /* Greek small letter eta */
+        map.put(952,    "theta");    /* Greek small letter theta */
+        map.put(953,    "iota");    /* Greek small letter iota */
+        map.put(954,    "kappa");    /* Greek small letter kappa */
+        map.put(955,    "lambda");    /* Greek small letter lambda */
+        map.put(956,    "mu");        /* Greek small letter mu */
+        map.put(957,    "nu");        /* Greek small letter nu */
+        map.put(958,    "xi");        /* Greek small letter xi */
+        map.put(959,    "omicron");    /* Greek small letter omicron */
+        map.put(960,    "pi");        /* Greek small letter pi */
+        map.put(961,    "rho");        /* Greek small letter rho */
+        map.put(962,    "sigmaf");    /* Greek small letter final sigma */
+        map.put(963,    "sigma");    /* Greek small letter sigma */
+        map.put(964,    "tau");        /* Greek small letter tau */
+        map.put(965,    "upsilon");    /* Greek small letter upsilon */
+        map.put(966,    "phi");        /* Greek small letter phi */
+        map.put(967,    "chi");        /* Greek small letter chi */
+        map.put(968,    "psi");        /* Greek small letter psi */
+        map.put(969,    "omega");    /* Greek small letter omega */
+        map.put(977,    "thetasym");    /* Greek theta symbol */
+        map.put(978,    "upsih");    /* Greek upsilon with hook symbol */
+        map.put(982,    "piv");        /* Greek pi symbol */
+        map.put(8194,    "ensp");    /* en space */
+        map.put(8195,    "emsp");    /* em space */
+        map.put(8201,    "thinsp");    /* thin space */
+        map.put(8204,    "zwnj");    /* zero width non-joiner */
+        map.put(8205,    "zwj");        /* zero width joiner */
+        map.put(8206,    "lrm");        /* left-to-right mark */
+        map.put(8207,    "rlm");        /* right-to-left mark */
+        map.put(8211,    "ndash");    /* en dash */
+        map.put(8212,    "mdash");    /* em dash */
+        map.put(8216,    "lsquo");    /* left single quotation mark */
+        map.put(8217,    "rsquo");    /* right single quotation mark */
+        map.put(8218,    "sbquo");    /* single low-9 quotation mark */
+        map.put(8220,    "ldquo");    /* left double quotation mark */
+        map.put(8221,    "rdquo");    /* right double quotation mark */
+        map.put(8222,    "bdquo");    /* double low-9 quotation mark */
+        map.put(8224,    "dagger");    /* dagger */
+        map.put(8225,    "Dagger");    /* double dagger */
+        map.put(8226,    "bull");    /* bullet */
+        map.put(8230,    "hellip");    /* horizontal ellipsis */
+        map.put(8240,    "permil");    /* per mille sign */
+        map.put(8242,    "prime");    /* prime */
+        map.put(8243,    "Prime");    /* double prime */
+        map.put(8249,    "lsaquo");    /* single left-pointing angle quotation mark */
+        map.put(8250,    "rsaquo");    /* single right-pointing angle quotation mark */
+        map.put(8254,    "oline");    /* overline */
+        map.put(8260,    "frasl");    /* fraction slash */
+        map.put(8364,    "euro");    /* euro sign */
+        map.put(8465,    "image");    /* black-letter capital i */
+        map.put(8472,    "weierp");    /* script capital pXCOMMAX Weierstrass p */
+        map.put(8476,    "real");    /* black-letter capital r */
+        map.put(8482,    "trade");    /* trademark sign */
+        map.put(8501,    "alefsym");    /* alef symbol */
+        map.put(8592,    "larr");    /* leftwards arrow */
+        map.put(8593,    "uarr");    /* upwards arrow */
+        map.put(8594,    "rarr");    /* rightwards arrow */
+        map.put(8595,    "darr");    /* downwards arrow */
+        map.put(8596,    "harr");    /* left right arrow */
+        map.put(8629,    "crarr");    /* downwards arrow with corner leftwards */
+        map.put(8656,    "lArr");    /* leftwards double arrow */
+        map.put(8657,    "uArr");    /* upwards double arrow */
+        map.put(8658,    "rArr");    /* rightwards double arrow */
+        map.put(8659,    "dArr");    /* downwards double arrow */
+        map.put(8660,    "hArr");    /* left right double arrow */
+        map.put(8704,    "forall");    /* for all */
+        map.put(8706,    "part");    /* partial differential */
+        map.put(8707,    "exist");    /* there exists */
+        map.put(8709,    "empty");    /* empty set */
+        map.put(8711,    "nabla");    /* nabla */
+        map.put(8712,    "isin");    /* element of */
+        map.put(8713,    "notin");    /* not an element of */
+        map.put(8715,    "ni");        /* contains as member */
+        map.put(8719,    "prod");    /* n-ary product */
+        map.put(8721,    "sum");        /* n-ary summation */
+        map.put(8722,    "minus");    /* minus sign */
+        map.put(8727,    "lowast");    /* asterisk operator */
+        map.put(8730,    "radic");    /* square root */
+        map.put(8733,    "prop");    /* proportional to */
+        map.put(8734,    "infin");    /* infinity */
+        map.put(8736,    "ang");        /* angle */
+        map.put(8743,    "and");        /* logical and */
+        map.put(8744,    "or");        /* logical or */
+        map.put(8745,    "cap");        /* intersection */
+        map.put(8746,    "cup");        /* union */
+        map.put(8747,    "int");        /* integral */
+        map.put(8756,    "there4");    /* therefore */
+        map.put(8764,    "sim");        /* tilde operator */
+        map.put(8773,    "cong");    /* congruent to */
+        map.put(8776,    "asymp");    /* almost equal to */
+        map.put(8800,    "ne");        /* not equal to */
+        map.put(8801,    "equiv");    /* identical toXCOMMAX equivalent to */
+        map.put(8804,    "le");        /* less-than or equal to */
+        map.put(8805,    "ge");        /* greater-than or equal to */
+        map.put(8834,    "sub");        /* subset of */
+        map.put(8835,    "sup");        /* superset of */
+        map.put(8836,    "nsub");    /* not a subset of */
+        map.put(8838,    "sube");    /* subset of or equal to */
+        map.put(8839,    "supe");    /* superset of or equal to */
+        map.put(8853,    "oplus");    /* circled plus */
+        map.put(8855,    "otimes");    /* circled times */
+        map.put(8869,    "perp");    /* up tack */
+        map.put(8901,    "sdot");    /* dot operator */
+        map.put(8968,    "lceil");    /* left ceiling */
+        map.put(8969,    "rceil");    /* right ceiling */
+        map.put(8970,    "lfloor");    /* left floor */
+        map.put(8971,    "rfloor");    /* right floor */
+        map.put(9001,    "lang");    /* left-pointing angle bracket */
+        map.put(9002,    "rang");    /* right-pointing angle bracket */
+        map.put(9674,    "loz");        /* lozenge */
+        map.put(9824,    "spades");    /* black spade suit */
+        map.put(9827,    "clubs");    /* black club suit */
+        map.put(9829,    "hearts");    /* black heart suit */
+        map.put(9830,    "diams");    /* black diamond suit */
+
+        return Collections.unmodifiableMap(map);
+    }
+
+    /**
+     * Build a unmodifiable Trie from entitiy Name to Character
+     * @return Unmodifiable trie.
+     */
+    private static synchronized Trie<Integer> mkEntityToCharacterTrie()
+    {
+        Trie<Integer> trie = new HashTrie<Integer>();
+
+        for(Map.Entry<Integer,String> entry : characterToEntityMap.entrySet())
+            trie.put(entry.getValue(),entry.getKey());
+        return Trie.Util.unmodifiable(trie);
+    }
 }
diff --git a/src/main/java/org/owasp/esapi/codecs/HashTrie.java b/src/main/java/org/owasp/esapi/codecs/HashTrie.java
index fef14ae..b72b8c1 100644
--- a/src/main/java/org/owasp/esapi/codecs/HashTrie.java
+++ b/src/main/java/org/owasp/esapi/codecs/HashTrie.java
@@ -18,591 +18,591 @@ import org.owasp.esapi.util.NullSafe;
  *
  * <b>NOTE:</b><br>
  * <ul>
- *	<li>@see java.util.Map.remove(Object) is not supported.</li>
- *	<li>
- *		If deletion support is added, the max key length will need work or removal.
- *	</li>
- *	<li>Null values are not supported.</li>
+ *    <li>@see java.util.Map.remove(Object) is not supported.</li>
+ *    <li>
+ *        If deletion support is added, the max key length will need work or removal.
+ *    </li>
+ *    <li>Null values are not supported.</li>
  * </ul>
  *
  * @author Ed Schaller
  */
 public class HashTrie<T> implements Trie<T>
 {
-	private static class Entry<T> implements Map.Entry<CharSequence,T>
-	{
-		private CharSequence key;
-		private T value;
-
-		Entry(CharSequence key, T value)
-		{
-			this.key = key;
-			this.value = value;
-		}
-
-		/**
-		 * Convenience instantiator.
-		 * @param key The key for the new instance
-		 * @param keyLength The length of the key to use
-		 * @param value The value for the new instance
-		 * @return null if key or value is null
-		 *	new Entry(key,value) if {@link CharSequence#length()} == keyLength
-		 *	new Entry(key.subSequence(0,keyLength),value) otherwise
-		 */
-		static <T> Entry<T> newInstanceIfNeeded(CharSequence key, int keyLength, T value)
-		{
-			if(value == null || key == null)
-				return null;
-			if(key.length() > keyLength)
-				key = key.subSequence(0,keyLength);
-			return new Entry<T>(key,value);
-		}
-
-		/**
-		 * Convenience instantiator.
-		 * @param key The key for the new instance
-		 * @param value The value for the new instance
-		 * @return null if key or value is null
-		 *	new Entry(key,value) otherwise
-		 */
-		static <T> Entry<T> newInstanceIfNeeded(CharSequence key, T value)
-		{
-			if(value == null || key == null)
-				return null;
-			return new Entry<T>(key,value);
-		}
+    private static class Entry<T> implements Map.Entry<CharSequence,T>
+    {
+        private CharSequence key;
+        private T value;
+
+        Entry(CharSequence key, T value)
+        {
+            this.key = key;
+            this.value = value;
+        }
+
+        /**
+         * Convenience instantiator.
+         * @param key The key for the new instance
+         * @param keyLength The length of the key to use
+         * @param value The value for the new instance
+         * @return null if key or value is null
+         *    new Entry(key,value) if {@link CharSequence#length()} == keyLength
+         *    new Entry(key.subSequence(0,keyLength),value) otherwise
+         */
+        static <T> Entry<T> newInstanceIfNeeded(CharSequence key, int keyLength, T value)
+        {
+            if(value == null || key == null)
+                return null;
+            if(key.length() > keyLength)
+                key = key.subSequence(0,keyLength);
+            return new Entry<T>(key,value);
+        }
+
+        /**
+         * Convenience instantiator.
+         * @param key The key for the new instance
+         * @param value The value for the new instance
+         * @return null if key or value is null
+         *    new Entry(key,value) otherwise
+         */
+        static <T> Entry<T> newInstanceIfNeeded(CharSequence key, T value)
+        {
+            if(value == null || key == null)
+                return null;
+            return new Entry<T>(key,value);
+        }
 
                 /*************/
                 /* Map.Entry */
                 /*************/
 
-		public CharSequence getKey()
-		{
-			return key;
-		}
+        public CharSequence getKey()
+        {
+            return key;
+        }
 
-		public T getValue()
-		{
-			return value;
-		}
+        public T getValue()
+        {
+            return value;
+        }
 
-		public T setValue(T value)
-		{
-			throw new UnsupportedOperationException();
-		}
+        public T setValue(T value)
+        {
+            throw new UnsupportedOperationException();
+        }
 
                 /********************/
                 /* java.lang.Object */
                 /********************/
 
-		public boolean equals(Map.Entry other)
-		{
-			return (NullSafe.equals(key, other.getKey()) && NullSafe.equals(value, other.getValue()));
-		}
-
-		@Override
-		public boolean equals(Object o)
-		{
-			if(o instanceof Map.Entry)
-				return equals((Map.Entry)o);
-			return false;
-		}
-
-		@Override
-		public int hashCode()
-		{
-			return NullSafe.hashCode(key) ^ NullSafe.hashCode(value);
-		}
-
-		@Override
-		public String toString()
-		{
-			return NullSafe.toString(key) + " => " + NullSafe.toString(value);
-		}
-	}
-
-	/**
-	 * Node inside the trie.
-	 */
-	private static class Node<T>
-	{
-		private T value = null;
-		private Map<Character,Node<T>> nextMap;
-
-		/**
-		 * Create a new Map for a node level. This is here so
-		 * that if the underlying * Map implementation needs to
-		 * be switched it is easily done.
-		 * @return A new Map for use.
-		 */
-		private static <T> Map<Character,Node<T>> newNodeMap()
-		{
-			return new HashMap<Character,Node<T>>();
-		}
-
-		/**
-		 * Create a new Map for a node level. This is here so
-		 * that if the underlying * Map implementation needs to
-		 * be switched it is easily done.
-		 * @param prev Previous map to use to populate the
-		 * new map.
-		 * @return A new Map for use.
-		 */
-		private static <T> Map<Character,Node<T>> newNodeMap(Map<Character,Node<T>> prev)
-		{
-			return new HashMap<Character,Node<T>>(prev);
-		}
-
-		/** 
-		 * Set the value for the key terminated at this node.
-		 * @param value The value for this key.
-		 */
-		void setValue(T value)
-		{
-			this.value = value;
-		}
-
-		/**
-		 * Get the node for the specified character.
-		 * @param ch The next character to look for.
-		 * @return The node requested or null if it is not
-		 *	present.
-		 */
-		Node<T> getNextNode(Character ch)
-		{
-			if(nextMap == null)
-				return null;
-			return nextMap.get(ch);
-		}
-
-		/**
-		 * Recursively add a key.
-		 * @param key The key being added.
-		 * @param pos The position in key that is being handled
-		 *	at this level.
-		 */
-		T put(CharSequence key, int pos, T addValue)
-		{
-			Node<T> nextNode;
-			Character ch;
-			T old;
-
-			if(key.length() == pos)
-			{	// at terminating node
-				old = value;
-				setValue(addValue);
-				return old;
-			}
-			ch = key.charAt(pos);
-			if(nextMap == null)
-			{
-				nextMap = newNodeMap();
-				nextNode = new Node();
-				nextMap.put(ch, nextNode);
-			}
-			else if((nextNode = nextMap.get(ch))==null)
-			{
-				nextNode = new Node();
-				nextMap.put(ch,nextNode);
-			}
-			return nextNode.put(key,pos+1,addValue);
-		}
-
-		/**
-		 * Recursively lookup a key's value.
-		 * @param key The key being looked up.
-		 * @param pos The position in the key that is being
-		 *	looked up at this level.
-		 * @return The value associated with the key or null if none exists.
-		 */
-		T get(CharSequence key, int pos)
-		{
-			Node<T> nextNode;
-
-			if(key.length() <= pos)	// <= instead of == just in case
-				return value;	// no value is null which is also not found
-			if((nextNode = getNextNode(key.charAt(pos)))==null)
-				return null;
-			return nextNode.get(key,pos+1);
-		}
-			
-		/**
-		 * Recursively lookup the longest key match.
-		 * @param key The key being looked up.
-		 * @param pos The position in the key that is being
-		 *	looked up at this level.
-		 * @return The Entry associated with the longest key match or null if none exists.
-		 */
-		Entry<T> getLongestMatch(CharSequence key, int pos)
-		{
-			Node<T> nextNode;
-			Entry<T> ret;
-
-			if(key.length() <= pos)	// <= instead of == just in case
-				return Entry.newInstanceIfNeeded(key,value);
-			if((nextNode = getNextNode(key.charAt(pos)))==null)
-			{	// last in trie... return ourselves
-				return Entry.newInstanceIfNeeded(key,pos,value);
-			}
-			if((ret = nextNode.getLongestMatch(key, pos+1))!=null)
-				return ret;
-			return Entry.newInstanceIfNeeded(key,pos,value);
-		}
-
-		/**
-		 * Recursively lookup the longest key match.
-		 * @param keyIn Where to read the key from
-		 * @param key The key that is being looked up at this level.
-		 * @return The Entry associated with the longest key
-		 *	match or null if none exists.
-		 */
-		Entry<T> getLongestMatch(PushbackReader keyIn, StringBuilder key) throws IOException
-		{
-			Node<T> nextNode;
-			Entry<T> ret;
-			int c;
-			char ch;
-			int prevLen;
-
-			// read next key char and append to key...
-			if((c = keyIn.read())<0)
-				// end of input, return what we have currently
-				return Entry.newInstanceIfNeeded(key,value);
-			ch = (char)c;
-			prevLen = key.length();
-			key.append(ch);
-
-			if((nextNode = getNextNode(ch))==null)
-			{	// last in trie... return ourselves
-				return Entry.newInstanceIfNeeded(key,value);
-			}
-			if((ret = nextNode.getLongestMatch(keyIn, key))!=null)
-				return ret;
-
-			// undo reading of key char and appending to key...
-			key.setLength(prevLen);
-			keyIn.unread(c);
-
-			return Entry.newInstanceIfNeeded(key,value);
-		}
-
-		/**
-		 * Recursively rebuild the internal maps.
-		 */
-		void remap()
-		{
-			if(nextMap == null)
-				return;
-			nextMap = newNodeMap(nextMap);
-			for(Node<T> node : nextMap.values())
-				node.remap();
-		}
-
-		/**
-		 * Recursively search for a value.
-		 * @param toFind The value to search for
-		 * @return true if the value was found
-		 *	false otherwise
-		 */
-		boolean containsValue(Object toFind)
-		{
-			if(value != null && toFind.equals(value))
-				return true;
-			if(nextMap == null)
-				return false;
-			for(Node<T> node : nextMap.values())
-				if(node.containsValue(toFind))
-					return true;
-			return false;
-		}
-
-		/**
-		 * Recursively build values.
-		 * @param values List being built.
-		 * @return true if the value was found
-		 *	false otherwise
-		 */
-		Collection<T> values(Collection<T> values)
-		{
-			if(value != null)
-				values.add(value);
-			if(nextMap == null)
-				return values;
-			for(Node<T> node : nextMap.values())
-				node.values(values);
-			return values;
-		}
-
-		/**
-		 * Recursively build a key set.
-		 * @param key StringBuilder with our key.
-		 * @param keys Set to add to
-		 * @return keys with additions
-		 */
-		Set<CharSequence> keySet(StringBuilder key, Set<CharSequence> keys)
-		{
-			int len = key.length();
-
-			if(value != null)
-				// MUST toString here
-				keys.add(key.toString());
-			if(nextMap != null && nextMap.size() > 0)
-			{
-				key.append('X');
-				for(Map.Entry<Character,Node<T>> entry : nextMap.entrySet())
-				{
-					key.setCharAt(len,entry.getKey());
-					entry.getValue().keySet(key,keys);
-				}
-				key.setLength(len);
-			}
-			return keys;
-		}
-
-		/**
-		 * Recursively build a entry set.
-		 * @param key StringBuilder with our key.
-		 * @param entries Set to add to
-		 * @return entries with additions
-		 */
-		Set<Map.Entry<CharSequence,T>> entrySet(StringBuilder key, Set<Map.Entry<CharSequence,T>> entries)
-		{
-			int len = key.length();
-
-			if(value != null)
-				// MUST toString here
-				entries.add(new Entry(key.toString(),value));
-			if(nextMap != null && nextMap.size() > 0)
-			{
-				key.append('X');
-				for(Map.Entry<Character,Node<T>> entry : nextMap.entrySet())
-				{
-					key.setCharAt(len,entry.getKey());
-					entry.getValue().entrySet(key,entries);
-				}
-				key.setLength(len);
-			}
-			return entries;
-		}
-	}
-
-	private Node<T> root;
-	private int maxKeyLen;
-	private int size;
-
-	public HashTrie()
-	{
-		clear();
-	}
-
-	/**
-	 * Get the key value entry who's key is the longest prefix match.
-	 * @param key The key to lookup
-	 * @return Entry with the longest matching key.
-	 */
-	public Map.Entry<CharSequence,T> getLongestMatch(CharSequence key)
-	{
-		if(root == null || key == null)
-			return null;
-		return root.getLongestMatch(key, 0);
-	}
-
-	/**
-	 * Get the key value entry who's key is the longest prefix match.
-	 * @param keyIn Pushback reader to read the key from. This should
-	 * have a buffer at least as large as {@link #getMaxKeyLength()}
-	 * or an IOException may be thrown backing up.
-	 * @return Entry with the longest matching key.
-	 * @throws IOException if keyIn.read() or keyIn.unread() does.
-	 */
-	public Map.Entry<CharSequence,T> getLongestMatch(PushbackReader keyIn) throws IOException
-	{
-		if(root == null || keyIn == null)
-			return null;
-		return root.getLongestMatch(keyIn, new StringBuilder());
-	}
-
-	/**
-	 * Get the maximum key length.
-	 * @return max key length.
-	 */
-	public int getMaxKeyLength()
-	{
-		return maxKeyLen;
-	}
+        public boolean equals(Map.Entry other)
+        {
+            return (NullSafe.equals(key, other.getKey()) && NullSafe.equals(value, other.getValue()));
+        }
+
+        @Override
+        public boolean equals(Object o)
+        {
+            if(o instanceof Map.Entry)
+                return equals((Map.Entry)o);
+            return false;
+        }
+
+        @Override
+        public int hashCode()
+        {
+            return NullSafe.hashCode(key) ^ NullSafe.hashCode(value);
+        }
+
+        @Override
+        public String toString()
+        {
+            return NullSafe.toString(key) + " => " + NullSafe.toString(value);
+        }
+    }
+
+    /**
+     * Node inside the trie.
+     */
+    private static class Node<T>
+    {
+        private T value = null;
+        private Map<Character,Node<T>> nextMap;
+
+        /**
+         * Create a new Map for a node level. This is here so
+         * that if the underlying * Map implementation needs to
+         * be switched it is easily done.
+         * @return A new Map for use.
+         */
+        private static <T> Map<Character,Node<T>> newNodeMap()
+        {
+            return new HashMap<Character,Node<T>>();
+        }
+
+        /**
+         * Create a new Map for a node level. This is here so
+         * that if the underlying * Map implementation needs to
+         * be switched it is easily done.
+         * @param prev Previous map to use to populate the
+         * new map.
+         * @return A new Map for use.
+         */
+        private static <T> Map<Character,Node<T>> newNodeMap(Map<Character,Node<T>> prev)
+        {
+            return new HashMap<Character,Node<T>>(prev);
+        }
+
+        /**
+         * Set the value for the key terminated at this node.
+         * @param value The value for this key.
+         */
+        void setValue(T value)
+        {
+            this.value = value;
+        }
+
+        /**
+         * Get the node for the specified character.
+         * @param ch The next character to look for.
+         * @return The node requested or null if it is not
+         *    present.
+         */
+        Node<T> getNextNode(Character ch)
+        {
+            if(nextMap == null)
+                return null;
+            return nextMap.get(ch);
+        }
+
+        /**
+         * Recursively add a key.
+         * @param key The key being added.
+         * @param pos The position in key that is being handled
+         *    at this level.
+         */
+        T put(CharSequence key, int pos, T addValue)
+        {
+            Node<T> nextNode;
+            Character ch;
+            T old;
+
+            if(key.length() == pos)
+            {    // at terminating node
+                old = value;
+                setValue(addValue);
+                return old;
+            }
+            ch = key.charAt(pos);
+            if(nextMap == null)
+            {
+                nextMap = newNodeMap();
+                nextNode = new Node();
+                nextMap.put(ch, nextNode);
+            }
+            else if((nextNode = nextMap.get(ch))==null)
+            {
+                nextNode = new Node();
+                nextMap.put(ch,nextNode);
+            }
+            return nextNode.put(key,pos+1,addValue);
+        }
+
+        /**
+         * Recursively lookup a key's value.
+         * @param key The key being looked up.
+         * @param pos The position in the key that is being
+         *    looked up at this level.
+         * @return The value associated with the key or null if none exists.
+         */
+        T get(CharSequence key, int pos)
+        {
+            Node<T> nextNode;
+
+            if(key.length() <= pos)    // <= instead of == just in case
+                return value;    // no value is null which is also not found
+            if((nextNode = getNextNode(key.charAt(pos)))==null)
+                return null;
+            return nextNode.get(key,pos+1);
+        }
+
+        /**
+         * Recursively lookup the longest key match.
+         * @param key The key being looked up.
+         * @param pos The position in the key that is being
+         *    looked up at this level.
+         * @return The Entry associated with the longest key match or null if none exists.
+         */
+        Entry<T> getLongestMatch(CharSequence key, int pos)
+        {
+            Node<T> nextNode;
+            Entry<T> ret;
+
+            if(key.length() <= pos)    // <= instead of == just in case
+                return Entry.newInstanceIfNeeded(key,value);
+            if((nextNode = getNextNode(key.charAt(pos)))==null)
+            {    // last in trie... return ourselves
+                return Entry.newInstanceIfNeeded(key,pos,value);
+            }
+            if((ret = nextNode.getLongestMatch(key, pos+1))!=null)
+                return ret;
+            return Entry.newInstanceIfNeeded(key,pos,value);
+        }
+
+        /**
+         * Recursively lookup the longest key match.
+         * @param keyIn Where to read the key from
+         * @param key The key that is being looked up at this level.
+         * @return The Entry associated with the longest key
+         *    match or null if none exists.
+         */
+        Entry<T> getLongestMatch(PushbackReader keyIn, StringBuilder key) throws IOException
+        {
+            Node<T> nextNode;
+            Entry<T> ret;
+            int c;
+            char ch;
+            int prevLen;
+
+            // read next key char and append to key...
+            if((c = keyIn.read())<0)
+                // end of input, return what we have currently
+                return Entry.newInstanceIfNeeded(key,value);
+            ch = (char)c;
+            prevLen = key.length();
+            key.append(ch);
+
+            if((nextNode = getNextNode(ch))==null)
+            {    // last in trie... return ourselves
+                return Entry.newInstanceIfNeeded(key,value);
+            }
+            if((ret = nextNode.getLongestMatch(keyIn, key))!=null)
+                return ret;
+
+            // undo reading of key char and appending to key...
+            key.setLength(prevLen);
+            keyIn.unread(c);
+
+            return Entry.newInstanceIfNeeded(key,value);
+        }
+
+        /**
+         * Recursively rebuild the internal maps.
+         */
+        void remap()
+        {
+            if(nextMap == null)
+                return;
+            nextMap = newNodeMap(nextMap);
+            for(Node<T> node : nextMap.values())
+                node.remap();
+        }
+
+        /**
+         * Recursively search for a value.
+         * @param toFind The value to search for
+         * @return true if the value was found
+         *    false otherwise
+         */
+        boolean containsValue(Object toFind)
+        {
+            if(value != null && toFind.equals(value))
+                return true;
+            if(nextMap == null)
+                return false;
+            for(Node<T> node : nextMap.values())
+                if(node.containsValue(toFind))
+                    return true;
+            return false;
+        }
+
+        /**
+         * Recursively build values.
+         * @param values List being built.
+         * @return true if the value was found
+         *    false otherwise
+         */
+        Collection<T> values(Collection<T> values)
+        {
+            if(value != null)
+                values.add(value);
+            if(nextMap == null)
+                return values;
+            for(Node<T> node : nextMap.values())
+                node.values(values);
+            return values;
+        }
+
+        /**
+         * Recursively build a key set.
+         * @param key StringBuilder with our key.
+         * @param keys Set to add to
+         * @return keys with additions
+         */
+        Set<CharSequence> keySet(StringBuilder key, Set<CharSequence> keys)
+        {
+            int len = key.length();
+
+            if(value != null)
+                // MUST toString here
+                keys.add(key.toString());
+            if(nextMap != null && nextMap.size() > 0)
+            {
+                key.append('X');
+                for(Map.Entry<Character,Node<T>> entry : nextMap.entrySet())
+                {
+                    key.setCharAt(len,entry.getKey());
+                    entry.getValue().keySet(key,keys);
+                }
+                key.setLength(len);
+            }
+            return keys;
+        }
+
+        /**
+         * Recursively build a entry set.
+         * @param key StringBuilder with our key.
+         * @param entries Set to add to
+         * @return entries with additions
+         */
+        Set<Map.Entry<CharSequence,T>> entrySet(StringBuilder key, Set<Map.Entry<CharSequence,T>> entries)
+        {
+            int len = key.length();
+
+            if(value != null)
+                // MUST toString here
+                entries.add(new Entry(key.toString(),value));
+            if(nextMap != null && nextMap.size() > 0)
+            {
+                key.append('X');
+                for(Map.Entry<Character,Node<T>> entry : nextMap.entrySet())
+                {
+                    key.setCharAt(len,entry.getKey());
+                    entry.getValue().entrySet(key,entries);
+                }
+                key.setLength(len);
+            }
+            return entries;
+        }
+    }
+
+    private Node<T> root;
+    private int maxKeyLen;
+    private int size;
+
+    public HashTrie()
+    {
+        clear();
+    }
+
+    /**
+     * Get the key value entry who's key is the longest prefix match.
+     * @param key The key to lookup
+     * @return Entry with the longest matching key.
+     */
+    public Map.Entry<CharSequence,T> getLongestMatch(CharSequence key)
+    {
+        if(root == null || key == null)
+            return null;
+        return root.getLongestMatch(key, 0);
+    }
+
+    /**
+     * Get the key value entry who's key is the longest prefix match.
+     * @param keyIn Pushback reader to read the key from. This should
+     * have a buffer at least as large as {@link #getMaxKeyLength()}
+     * or an IOException may be thrown backing up.
+     * @return Entry with the longest matching key.
+     * @throws IOException if keyIn.read() or keyIn.unread() does.
+     */
+    public Map.Entry<CharSequence,T> getLongestMatch(PushbackReader keyIn) throws IOException
+    {
+        if(root == null || keyIn == null)
+            return null;
+        return root.getLongestMatch(keyIn, new StringBuilder());
+    }
+
+    /**
+     * Get the maximum key length.
+     * @return max key length.
+     */
+    public int getMaxKeyLength()
+    {
+        return maxKeyLen;
+    }
 
         /*****************/
         /* java.util.Map */
         /*****************/
 
-	/**
-	 * Clear all entries.
-	 */
-	public void clear()
-	{
-		root = null;
-		maxKeyLen = -1;
-		size = 0;
-	}
-
-	/** {@inheritDoc} */
-	public boolean containsKey(Object key)
-	{
-		return (get(key) != null);
-	}
-
-	/** {@inheritDoc} */
-	public boolean containsValue(Object value)
-	{
-		if(root == null)
-			return false;
-		return root.containsValue(value);
-	}
-
-	/**
-	 * Add mapping.
-	 * @param key The mapping's key.
-	 * @value value The mapping's value
-	 * @throws NullPointerException if key or value is null.
-	 */
-	public T put(CharSequence key, T value) throws NullPointerException
-	{
-		int len;
-		T old;
-
-		if(key == null)
-			throw new NullPointerException("Null keys are not handled");
-		if(value == null)
-			throw new NullPointerException("Null values are not handled");
-		if(root == null)
-			root = new Node<T>();
-		if((old = root.put(key,0,value))!=null)
-			return old;
-
-		// after in case of replacement
-		if((len = key.length()) > maxKeyLen)
-			maxKeyLen = len;
-		size++;
-		return null;
-	}
-
-	/**
-	 * Remove a entry.
-	 * @return previous value
-	 * @throws UnsupportedOperationException always.
-	 */
-	public T remove(Object key) throws UnsupportedOperationException
-	{
-		throw new UnsupportedOperationException();
-	}
-
-	/** {@inheritDoc} */
-	public void putAll(Map<? extends CharSequence, ? extends T> map)
-	{
-		for(Map.Entry<? extends CharSequence, ? extends T> entry : map.entrySet())
-			put(entry.getKey(),entry.getValue());
-	}
-
-	/** {@inheritDoc} */
-	public Set<CharSequence> keySet()
-	{
-		Set<CharSequence> keys = new HashSet<CharSequence>(size);
-		
-		if(root == null)
-			return keys;
-		return root.keySet(new StringBuilder(), keys);
-	}
-
-	/** {@inheritDoc} */
-	public Collection<T> values()
-	{
-		ArrayList<T> values = new ArrayList<T>(size());
-
-		if(root == null)
-			return values;
-		return root.values(values);
-	}
-
-	/** {@inheritDoc} */
-	public Set<Map.Entry<CharSequence,T>> entrySet()
-	{
-		Set<Map.Entry<CharSequence,T>> entries = new HashSet<Map.Entry<CharSequence,T>>(size());
-
-		if(root == null)
-			return entries;
-		return root.entrySet(new StringBuilder(), entries);
-	}
-
-	/**
-	 * Get the value for a key.
-	 * @param key The key to look up.
-	 * @return The value for key or null if the key is not found.
-	 */
-	public T get(Object key)
-	{
-		if(root == null || key == null)
-			return null;
-		if(!(key instanceof CharSequence))
-			return null;
-		return root.get((CharSequence)key,0);
-	}
-
-	/**
-	 * Get the number of entries.
-	 * @return the number or entries.
-	 */
-	public int size()
-	{
-		return size;
-	}
-
-	/** {@inheritDoc} */
-	@Override
-	public boolean equals(Object other)
-	{
-		if(other == null)
-			return false;
-		if(!(other instanceof Map))
-			return false;
-		// per spec
-		return entrySet().equals(((Map)other).entrySet());
-	}
-
-	/** {@inheritDoc} */
-	@Override
-	public int hashCode()
-	{
-		// per spec
-		return entrySet().hashCode();
-	}
-
-	/** {@inheritDoc} */
-	@Override
-	public String toString()
-	{
-		StringBuilder sb;
-		boolean first;
-
-		if(isEmpty())
-			return "{}";
-		sb = new StringBuilder();
-		first = true;
-		sb.append("{ ");
-		for(Map.Entry<CharSequence,T> entry : entrySet())
-		{
-			if(first)
-				first = false;
-			else
-				sb.append(", ");
-			sb.append(entry.toString());
-		}
-		sb.append(" }");
-		return sb.toString();
-	}
-
-	/** {@inheritDoc} */
-	public boolean isEmpty()
-	{
-		return(size() == 0);
-	}
+    /**
+     * Clear all entries.
+     */
+    public void clear()
+    {
+        root = null;
+        maxKeyLen = -1;
+        size = 0;
+    }
+
+    /** {@inheritDoc} */
+    public boolean containsKey(Object key)
+    {
+        return (get(key) != null);
+    }
+
+    /** {@inheritDoc} */
+    public boolean containsValue(Object value)
+    {
+        if(root == null)
+            return false;
+        return root.containsValue(value);
+    }
+
+    /**
+     * Add mapping.
+     * @param key The mapping's key.
+     * @value value The mapping's value
+     * @throws NullPointerException if key or value is null.
+     */
+    public T put(CharSequence key, T value) throws NullPointerException
+    {
+        int len;
+        T old;
+
+        if(key == null)
+            throw new NullPointerException("Null keys are not handled");
+        if(value == null)
+            throw new NullPointerException("Null values are not handled");
+        if(root == null)
+            root = new Node<T>();
+        if((old = root.put(key,0,value))!=null)
+            return old;
+
+        // after in case of replacement
+        if((len = key.length()) > maxKeyLen)
+            maxKeyLen = len;
+        size++;
+        return null;
+    }
+
+    /**
+     * Remove a entry.
+     * @return previous value
+     * @throws UnsupportedOperationException always.
+     */
+    public T remove(Object key) throws UnsupportedOperationException
+    {
+        throw new UnsupportedOperationException();
+    }
+
+    /** {@inheritDoc} */
+    public void putAll(Map<? extends CharSequence, ? extends T> map)
+    {
+        for(Map.Entry<? extends CharSequence, ? extends T> entry : map.entrySet())
+            put(entry.getKey(),entry.getValue());
+    }
+
+    /** {@inheritDoc} */
+    public Set<CharSequence> keySet()
+    {
+        Set<CharSequence> keys = new HashSet<CharSequence>(size);
+
+        if(root == null)
+            return keys;
+        return root.keySet(new StringBuilder(), keys);
+    }
+
+    /** {@inheritDoc} */
+    public Collection<T> values()
+    {
+        ArrayList<T> values = new ArrayList<T>(size());
+
+        if(root == null)
+            return values;
+        return root.values(values);
+    }
+
+    /** {@inheritDoc} */
+    public Set<Map.Entry<CharSequence,T>> entrySet()
+    {
+        Set<Map.Entry<CharSequence,T>> entries = new HashSet<Map.Entry<CharSequence,T>>(size());
+
+        if(root == null)
+            return entries;
+        return root.entrySet(new StringBuilder(), entries);
+    }
+
+    /**
+     * Get the value for a key.
+     * @param key The key to look up.
+     * @return The value for key or null if the key is not found.
+     */
+    public T get(Object key)
+    {
+        if(root == null || key == null)
+            return null;
+        if(!(key instanceof CharSequence))
+            return null;
+        return root.get((CharSequence)key,0);
+    }
+
+    /**
+     * Get the number of entries.
+     * @return the number or entries.
+     */
+    public int size()
+    {
+        return size;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public boolean equals(Object other)
+    {
+        if(other == null)
+            return false;
+        if(!(other instanceof Map))
+            return false;
+        // per spec
+        return entrySet().equals(((Map)other).entrySet());
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public int hashCode()
+    {
+        // per spec
+        return entrySet().hashCode();
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String toString()
+    {
+        StringBuilder sb;
+        boolean first;
+
+        if(isEmpty())
+            return "{}";
+        sb = new StringBuilder();
+        first = true;
+        sb.append("{ ");
+        for(Map.Entry<CharSequence,T> entry : entrySet())
+        {
+            if(first)
+                first = false;
+            else
+                sb.append(", ");
+            sb.append(entry.toString());
+        }
+        sb.append(" }");
+        return sb.toString();
+    }
+
+    /** {@inheritDoc} */
+    public boolean isEmpty()
+    {
+        return(size() == 0);
+    }
 }
diff --git a/src/main/java/org/owasp/esapi/codecs/Hex.java b/src/main/java/org/owasp/esapi/codecs/Hex.java
index 17ab4bf..5ca0b68 100644
--- a/src/main/java/org/owasp/esapi/codecs/Hex.java
+++ b/src/main/java/org/owasp/esapi/codecs/Hex.java
@@ -1,6 +1,6 @@
 /*
  * OWASP Enterprise Security API (ESAPI)
- * 
+ *
  * This file is part of the Open Web Application Security Project (OWASP)
  * Enterprise Security API (ESAPI) project. For details, please see
  * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
@@ -13,10 +13,10 @@ package org.owasp.esapi.codecs;
 public class Hex {
 
     /** Output byte representation as hexadecimal representation.
-     * 
-     * @param b				Bytes to encode to hexadecimal representation.
-     * @param leading0x		If true, return with leading "0x".
-     * @return				Hexadecimal representation of specified bytes.
+     *
+     * @param b                Bytes to encode to hexadecimal representation.
+     * @param leading0x        If true, return with leading "0x".
+     * @return                Hexadecimal representation of specified bytes.
      */
     public static String toHex(byte[] b, boolean leading0x) {
         StringBuffer hexString = new StringBuffer();
@@ -37,10 +37,10 @@ public class Hex {
     /**
      * Output byte representation as hexadecimal representation.
      * Alias for <code>toHex()</code> method.
-     * 
-     * @param b				Bytes to encode to hexadecimal representation.
-     * @param leading0x		If true, return with leading "0x".
-     * @return				Hexadecimal representation of specified bytes.
+     *
+     * @param b                Bytes to encode to hexadecimal representation.
+     * @param leading0x        If true, return with leading "0x".
+     * @return                Hexadecimal representation of specified bytes.
      */
     public static String encode(byte[] b, boolean leading0x) {
         return toHex(b, leading0x);
@@ -53,9 +53,9 @@ public class Hex {
      * in dealing with things like keys, initialization vectors, etc. For
      * example, the string "0x0000face" is going to return a byte array
      * whose length is 4, not 2.
-     * 
-     * @param hexStr	Hexadecimal-encoded string, with or without leading "0x".
-     * @return			The equivalent byte array.
+     *
+     * @param hexStr    Hexadecimal-encoded string, with or without leading "0x".
+     * @return            The equivalent byte array.
      */
     public static byte[] fromHex(String hexStr) {
         String hexRep = hexStr;
@@ -74,9 +74,9 @@ public class Hex {
 
     /** Decode hexadecimal-encoded string and return raw byte array.
      * Alias for <code>fromHex()</code> method.
-     * 
-     * @param hexStr	Hexadecimal-encoded string, with or without leading "0x".
-     * @return			The equivalent byte array. 
+     *
+     * @param hexStr    Hexadecimal-encoded string, with or without leading "0x".
+     * @return            The equivalent byte array.
      */
     public static byte[] decode(String hexStr) {
         return fromHex(hexStr);
diff --git a/src/main/java/org/owasp/esapi/codecs/JSONCodec.java b/src/main/java/org/owasp/esapi/codecs/JSONCodec.java
new file mode 100644
index 0000000..524b2fa
--- /dev/null
+++ b/src/main/java/org/owasp/esapi/codecs/JSONCodec.java
@@ -0,0 +1,245 @@
+/**
+ * OWASP Enterprise Security API (ESAPI)
+ *
+ * This file is part of the Open Web Application Security Project (OWASP)
+ * Enterprise Security API (ESAPI) project. For details, please see
+ * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
+ *
+ * Copyright (c) 2022 - The OWASP Foundation
+ *
+ * The ESAPI is published by OWASP under the BSD license. You should read and accept the
+ * LICENSE before you use, modify, and/or redistribute this software.
+ *
+ * @author Jeffrey Walton (noloader .at. gmail.com)
+ * @author Kevin Wall (kevin.w.wall .at. gmail.com)
+ * @author Matt Seil (matt.seil .at. owasp.org)
+ * @created 2022
+ */
+package org.owasp.esapi.codecs;
+
+/**
+ * Implementation of the Codec interface for JSON strings.
+ * This class performs <a
+ * href="https://datatracker.ietf.org/doc/html/rfc8259#section-7">String escaping</a>
+ * on the entire string according to RFC 8259, Section 7.
+ *
+ * RFC 8259 requires conforming implementations use UTF-8. However, the ESAPI interfaces
+ * utilize Java strings, which are UTF-16. This may cause problems during encoding and
+ * decoding operations. To avoid some of the problems, convert the string to UTF-8 before
+ * encoding and from UTF-8 after decoding. Ultimately the ESAPI encoder interfaces will
+ * need modification to provide byte array arguments and return values.
+ *
+ * @see <a href="https://datatracker.ietf.org/doc/html/rfc8259#section-7">RFC 8259,
+ * The JavaScript Object Notation (JSON) Data Interchange Format, Section 7</a>
+ *
+ * @author Jeffrey Walton (noloader .at. gmail.com)
+ * @author Kevin Wall (kevin.w.wall .at. gmail.com)
+ * @author Matt Seil (matt.seil .at. owasp.org)
+ * @since July 31, 2022
+ * @see org.owasp.esapi.Encoder
+ */
+public class JSONCodec extends AbstractIntegerCodec {
+
+
+    /**
+     * {@inheritDoc}
+     *
+     * Escape special characters in JSON strings.
+     *
+     * encodeCharacter will escape the characters Backspace (\b), Form Feed (\f),
+     * Carriage Return (\r), Line Feed (\n), Tab (\t), Double Quote (") and Backslash (\).
+     * If the character is a control character (U+0000 through U+001f), then it will be
+     * Unicode encoded (\u0000 through \u001f). If the character is not special or in the
+     * user supplied immune list, then the character is returned unescaped. If the
+     * character is null then an empty string is returned.
+     *
+     * WARNING: This method will silently discard an invalid code point according to
+     * the result of {@code Character.isValidCodePoint( int )} method.
+     *
+     * @param immune character array of whitelist characters which should not be encoded
+     * @param c the character to encode if not in the immune list
+     * @return encoded character if the character is special, and the character otherwise.
+     */
+    public String encodeCharacter( char[] immune, Character c ) {
+        if ( c == null ) {
+            return "";
+        }
+
+        return encodeCharacter(immune, charToCodepoint( c ));
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * Escape special characters in JSON strings.
+     *
+     * encodeCharacter will escape the characters Backspace (\b), Form Feed (\f),
+     * Carriage Return (\r), Line Feed (\n), Tab (\t), Double Quote (") and Backslash (\).
+     * If the character is a control character (U+0000 through U+001f), then it will be
+     * Unicode encoded (\u0000 through \u001f). If the character is not special or in the
+     * user supplied immune list, then the character is returned unescaped. If the
+     * character is null then an empty string is returned.
+     *
+     * WARNING: This method will silently discard an invalid code point according to
+     * the result of {@code Character.isValidCodePoint( int )} method.
+     *
+     * @param immune character array of whitelist characters which should not be encoded
+     * @param codePoint the character codepoint to encode if not in the immune list
+     * @return encoded character if the character is special, and the character otherwise.
+     */
+    public String encodeCharacter( char[] immune, int codePoint )
+        throws IllegalArgumentException {
+
+        // Per the docs for HTMLEntityCodec: "WARNING: This method will silently discard
+        // invalid code points per the call to Character.isValidCodePoint( int ) method.
+
+        // WARNING!! Character based Codecs will only handle the byte range of 0-65535 (0x0-0xffff).
+        // Passing any data represented by a higher numerical value will result in a downcast thus
+        // destroying the original data with undefined results.
+        if ( Character.isValidCodePoint( codePoint ) == false ) {
+            // throw new IllegalArgumentException( "Invalid codepoint '" + String.format("0x%04X", codePoint) + "'." );
+            return "";
+        }
+
+        if ( immune != null ) {
+            // More efficient than sort and binary search. If the immune array
+            // was presorted, then this could be O(log n). But we can't add the
+            // precondition now. It is too late in the game.
+            for ( Character ch : immune ) {
+                if ( charToCodepoint( ch ) == codePoint ) {
+                    return new String(Character.toChars(codePoint));
+                }
+            }
+        }
+
+        // Per the RFC... Two-character sequence escape representations of some
+        // popular characters
+        switch ( codePoint ) {
+            case '\b': return "\\b";
+            case '\f': return "\\f";
+            case '\r': return "\\r";
+            case '\n': return "\\n";
+            case '\t': return "\\t";
+            case '"':  return "\\\"";
+            case '/':  return  "\\/";
+            case '\\': return "\\\\";
+        }
+
+        // Per the RFC... All Unicode characters may be placed within the
+        // quotation marks, except for the characters that MUST be escaped:
+        // quotation mark, reverse solidus, and the control characters
+        // (U+0000 through U+001F).
+        if ( codePoint <=  0x1f ) {
+
+            return String.format("\\u%04x", codePoint);
+        }
+
+        return new String(Character.toChars(codePoint));
+    }
+
+
+    /**
+     * {@inheritDoc}
+     *
+     * Decodes special characters in encoded JSON strings.
+     *
+     * decodeCharacter will decode the encoded character sequences for popular characters
+     * Backspace (\b), Form Feed (\f), Carriage Return (\r), Line Feed (\n), Tab (\t),
+     * Double Quote ("), Forward slash (/) and Backslash (\). The function will also decode
+     * six-character sequences of \u0000 - \uffff. If the character is not encoded then a
+     * null character is returned.
+     *
+     * @param input a character sequence to decode
+     * @return the decoded version of the encoded character starting at index,
+     *     or null otherwise
+     *
+     * @throws IllegalArgumentException
+     *     if an invalid character sequence is encountered
+     */
+    public Integer decodeCharacter( PushbackSequence<Integer> input )
+            throws IllegalArgumentException {
+
+        input.mark();
+
+        Integer first = input.next(), second = null;
+
+        //Ensure both first and second characters are not null before attempting to decode.
+        if ( first == null || first.intValue() != '\\' ) {
+            input.reset();
+            return null;
+        }
+        if ( (second = input.next()) == null ) {
+            throw new IllegalArgumentException( "Invalid JSON escape representation");
+        }
+
+        Integer decodedRef = null;
+
+        // Per the RFC... Two-character sequence escape representations of some popular characters
+        switch ( second.intValue() ) {
+        case 'b':
+            decodedRef = (int)'\b';
+            break;
+        case 'f':
+            decodedRef = (int)'\f';
+            break;
+        case 'r':
+            decodedRef = (int)'\r';
+            break;
+        case 'n':
+            decodedRef = (int)'\n';
+            break;
+        case 't':
+            decodedRef = (int)'\t';
+            break;
+        case '"':
+            decodedRef = (int)'\"';
+            break;
+        case '/':
+            decodedRef =  (int)'/';
+            break;
+        case '\\':
+            decodedRef = (int)'\\';
+            break;
+        case 'u':
+            // Per the RFC... All characters may be escaped as a six-character sequence: a reverse solidus,
+            // followed by the lowercase letter u, followed by four hexadecimal digits that encode the
+            // character's code point. The hexadecimal letters A through F can be uppercase or lowercase.
+            // So, for example, a string containing only a single reverse solidus character may be represented
+            // as "\u005C".
+            decodedRef = (convertToInt( input.next() ) << 12) +
+                (convertToInt( input.next() ) <<  8) +
+                (convertToInt( input.next() ) <<  4) +
+                (convertToInt( input.next() ) <<  0);
+            break;
+        default:
+            input.reset();
+            throw new IllegalArgumentException( "Invalid JSON two-character escape representation: " + String.format("'%c%c'", (char) first.intValue(), (char) second.intValue()) );
+        }
+
+        return decodedRef;
+    }
+
+    protected int charToCodepoint( Character ch ) {
+
+        final String s = Character.toString(ch);
+        assert (s.length() == 1) : "Ooops";
+
+        return s.codePointAt(0);
+    }
+
+    protected int convertToInt( Integer hexDigit ) {
+
+        if ( hexDigit == null ) {
+            throw new IllegalArgumentException( "Cannot convert from '<null>' to int." );
+        }
+
+        final int value = Character.digit( hexDigit.intValue(), 16 );
+
+        if ( value < 0 || value >= 16 ) {
+            throw new IllegalArgumentException( "Cannot convert from hexadecimal '" + hexDigit.toString() + "' to int." );
+        }
+
+        return value;
+    }
+
+}
diff --git a/src/main/java/org/owasp/esapi/codecs/JavaScriptCodec.java b/src/main/java/org/owasp/esapi/codecs/JavaScriptCodec.java
index 65ee517..39f2d64 100644
--- a/src/main/java/org/owasp/esapi/codecs/JavaScriptCodec.java
+++ b/src/main/java/org/owasp/esapi/codecs/JavaScriptCodec.java
@@ -1,15 +1,15 @@
 /**
  * OWASP Enterprise Security API (ESAPI)
- * 
+ *
  * This file is part of the Open Web Application Security Project (OWASP)
  * Enterprise Security API (ESAPI) project. For details, please see
  * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
  *
  * Copyright (c) 2007 - The OWASP Foundation
- * 
+ *
  * The ESAPI is published by OWASP under the BSD license. You should read and accept the
  * LICENSE before you use, modify, and/or redistribute this software.
- * 
+ *
  * @author Jeff Williams <a href="http://www.aspectsecurity.com">Aspect Security</a>
  * @created 2007
  */
@@ -18,7 +18,7 @@ package org.owasp.esapi.codecs;
 
 /**
  * Implementation of the Codec interface for backslash encoding in JavaScript.
- * 
+ *
  * @author Jeff Williams (jeff.williams .at. aspectsecurity.com) <a
  *         href="http://www.aspectsecurity.com">Aspect Security</a>
  * @since June 1, 2007
@@ -27,192 +27,194 @@ package org.owasp.esapi.codecs;
 public class JavaScriptCodec extends AbstractCharacterCodec {
 
 
-	/**
-	 * {@inheritDoc}
-	 * 
-	 * Returns backslash encoded numeric format. Does not use backslash character escapes
-	 * such as, \" or \' as these may cause parsing problems. For example, if a javascript
-	 * attribute, such as onmouseover, contains a \" that will close the entire attribute and
-	 * allow an attacker to inject another script attribute.
+    /**
+     * {@inheritDoc}
+     *
+     * Returns backslash encoded numeric format. Does not use backslash character escapes
+     * such as, \" or \' as these may cause parsing problems. For example, if a javascript
+     * attribute, such as onmouseover, contains a \" that will close the entire attribute and
+     * allow an attacker to inject another script attribute.
      *
      * @param immune
      */
-	public String encodeCharacter( char[] immune, Character c ) {
-
-		// check for immune characters
-		if ( containsCharacter(c, immune ) ) {
-			return ""+c;
-		}
-		
-		// check for alphanumeric characters
-		String hex = super.getHexForNonAlphanumeric(c);
-		if ( hex == null ) {
-			return ""+c;
-		}
-				
-		// Do not use these shortcuts as they can be used to break out of a context
-		// if ( ch == 0x00 ) return "\\0";
-		// if ( ch == 0x08 ) return "\\b";
-		// if ( ch == 0x09 ) return "\\t";
-		// if ( ch == 0x0a ) return "\\n";
-		// if ( ch == 0x0b ) return "\\v";
-		// if ( ch == 0x0c ) return "\\f";
-		// if ( ch == 0x0d ) return "\\r";
-		// if ( ch == 0x22 ) return "\\\"";
-		// if ( ch == 0x27 ) return "\\'";
-		// if ( ch == 0x5c ) return "\\\\";
-
-		// encode up to 256 with \\xHH
+    public String encodeCharacter( char[] immune, Character c ) {
+
+        // check for immune characters
+        if ( containsCharacter(c, immune ) ) {
+            return ""+c;
+        }
+
+        // check for alphanumeric characters
+        String hex = super.getHexForNonAlphanumeric(c);
+        if ( hex == null ) {
+            return ""+c;
+        }
+
+        // Do not use these shortcuts as they can be used to break out of a context
+        // if ( ch == 0x00 ) return "\\0";
+        // if ( ch == 0x08 ) return "\\b";
+        // if ( ch == 0x09 ) return "\\t";
+        // if ( ch == 0x0a ) return "\\n";
+        // if ( ch == 0x0b ) return "\\v";
+        // if ( ch == 0x0c ) return "\\f";
+        // if ( ch == 0x0d ) return "\\r";
+        // if ( ch == 0x22 ) return "\\\"";
+        // if ( ch == 0x27 ) return "\\'";
+        // if ( ch == 0x5c ) return "\\\\";
+
+        // encode up to 256 with \\xHH
         String temp = Integer.toHexString(c);
-		if ( c < 256 ) {
-	        String pad = "00".substring(temp.length() );
-	        return "\\x" + pad + temp.toUpperCase();
-		}
+        if ( c < 256 ) {
+            String pad = "00".substring(temp.length() );
+            return "\\x" + pad + temp.toUpperCase();
+        }
 
-		// otherwise encode with \\uHHHH
+        // otherwise encode with \\uHHHH
         String pad = "0000".substring(temp.length() );
         return "\\u" + pad + temp.toUpperCase();
-	}
-
-	
-	/**
-	 * {@inheritDoc}
-	 * 
-	 * Returns the decoded version of the character starting at index, or
-	 * null if no decoding is possible.
-	 * See http://www.planetpdf.com/codecuts/pdfs/tutorial/jsspec.pdf 
-	 * Formats all are legal both upper/lower case:
-	 *   \\a - special characters
-	 *   \\xHH
-	 *   \\uHHHH
-	 *   \\OOO (1, 2, or 3 digits)
-	 */
-	public Character decodeCharacter( PushbackSequence<Character> input ) {
-		input.mark();
-		Character first = input.next();
-		if ( first == null ) {
-			input.reset();
-			return null;
-		}
-		
-		// if this is not an encoded character, return null
-		if (first != '\\' ) {
-			input.reset();
-			return null;
-		}
-
-		Character second = input.next();
-		if ( second == null ) {
-			input.reset();
-			return null;
-		}
-		
-		// \0 collides with the octal decoder and is non-standard
-		// if ( second.charValue() == '0' ) {
-		//	return Character.valueOf( (char)0x00 );
-		if (second == 'b' ) {
-			return 0x08;
-		} else if (second == 't' ) {
-			return 0x09;
-		} else if (second == 'n' ) {
-			return 0x0a;
-		} else if (second == 'v' ) {
-			return 0x0b;
-		} else if (second == 'f' ) {
-			return 0x0c;
-		} else if (second == 'r' ) {
-			return 0x0d;
-		} else if (second == '\"' ) {
-			return 0x22;
-		} else if (second == '\'' ) {
-			return 0x27;
-		} else if (second == '\\' ) {
-			return 0x5c;
-			
-		// look for \\xXX format
-		} else if ( Character.toLowerCase( second.charValue() ) == 'x' ) {
-			// Search for exactly 2 hex digits following
-			StringBuilder sb = new StringBuilder();
-			for ( int i=0; i<2; i++ ) {
-				Character c = input.nextHex();
-				if ( c != null ) sb.append( c );
-				else {
-					input.reset();
-					return null;
-				}
-			}
-			try {
-				// parse the hex digit and create a character
-				int i = Integer.parseInt(sb.toString(), 16);
+    }
+
+
+    /**
+     * {@inheritDoc}
+     *
+     * Returns the decoded version of the character starting at index, or
+     * null if no decoding is possible.
+     * </p><p>
+     * Formats all are legal both upper/lower case:
+     * <pre>
+     *   \\a - special characters
+     *   \\xHH
+     *   \\uHHHH
+     *   \\OOO (1, 2, or 3 digits)
+     * </pre>
+     */
+    public Character decodeCharacter( PushbackSequence<Character> input ) {
+        input.mark();
+        Character first = input.next();
+        if ( first == null ) {
+            input.reset();
+            return null;
+        }
+
+        // if this is not an encoded character, return null
+        if (first != '\\' ) {
+            input.reset();
+            return null;
+        }
+
+        Character second = input.next();
+        if ( second == null ) {
+            input.reset();
+            return null;
+        }
+
+        // \0 collides with the octal decoder and is non-standard
+        // if ( second.charValue() == '0' ) {
+        //    return Character.valueOf( (char)0x00 );
+        if (second == 'b' ) {
+            return 0x08;
+        } else if (second == 't' ) {
+            return 0x09;
+        } else if (second == 'n' ) {
+            return 0x0a;
+        } else if (second == 'v' ) {
+            return 0x0b;
+        } else if (second == 'f' ) {
+            return 0x0c;
+        } else if (second == 'r' ) {
+            return 0x0d;
+        } else if (second == '\"' ) {
+            return 0x22;
+        } else if (second == '\'' ) {
+            return 0x27;
+        } else if (second == '\\' ) {
+            return 0x5c;
+
+        // look for \\xXX format
+        } else if ( Character.toLowerCase( second.charValue() ) == 'x' ) {
+            // Search for exactly 2 hex digits following
+            StringBuilder sb = new StringBuilder();
+            for ( int i=0; i<2; i++ ) {
+                Character c = input.nextHex();
+                if ( c != null ) sb.append( c );
+                else {
+                    input.reset();
+                    return null;
+                }
+            }
+            try {
+                // parse the hex digit and create a character
+                int i = Integer.parseInt(sb.toString(), 16);
                 if (Character.isValidCodePoint(i)) {
                     return (char) i;
                 }
-			} catch( NumberFormatException e ) {
-				// throw an exception for malformed entity?
-				input.reset();
-				return null;
-			}
-			
-		// look for \\uXXXX format
-		} else if ( Character.toLowerCase( second.charValue() ) == 'u') {
-			// Search for exactly 4 hex digits following
-			StringBuilder sb = new StringBuilder();
-			for ( int i=0; i<4; i++ ) {
-				Character c = input.nextHex();
-				if ( c != null ) sb.append( c );
-				else {
-					input.reset();
-					return null;
-				}
-			}
-			try {
-				// parse the hex string and create a character
-				int i = Integer.parseInt(sb.toString(), 16);
+            } catch( NumberFormatException e ) {
+                // throw an exception for malformed entity?
+                input.reset();
+                return null;
+            }
+
+        // look for \\uXXXX format
+        } else if ( Character.toLowerCase( second.charValue() ) == 'u') {
+            // Search for exactly 4 hex digits following
+            StringBuilder sb = new StringBuilder();
+            for ( int i=0; i<4; i++ ) {
+                Character c = input.nextHex();
+                if ( c != null ) sb.append( c );
+                else {
+                    input.reset();
+                    return null;
+                }
+            }
+            try {
+                // parse the hex string and create a character
+                int i = Integer.parseInt(sb.toString(), 16);
                 if (Character.isValidCodePoint(i)) {
                     return (char) i;
                 }
-			} catch( NumberFormatException e ) {
-				// throw an exception for malformed entity?
-				input.reset();
-				return null;
-			}
-			
-		// look for one, two, or three octal digits
-		} else if ( PushbackString.isOctalDigit(second) ) {
-			StringBuilder sb = new StringBuilder();
+            } catch( NumberFormatException e ) {
+                // throw an exception for malformed entity?
+                input.reset();
+                return null;
+            }
+
+        // look for one, two, or three octal digits
+        } else if ( PushbackString.isOctalDigit(second) ) {
+            StringBuilder sb = new StringBuilder();
             // get digit 1
             sb.append(second);
-            
+
             // get digit 2 if present
             Character c2 = input.next();
             if ( !PushbackString.isOctalDigit(c2) ) {
-            	input.pushback( c2 );
+                input.pushback( c2 );
             } else {
-            	sb.append( c2 );
-	            // get digit 3 if present
-	            Character c3 = input.next();
-	            if ( !PushbackString.isOctalDigit(c3) ) {
-	            	input.pushback( c3 );
-	            } else {
-	            	sb.append( c3 );
-	            }
+                sb.append( c2 );
+                // get digit 3 if present
+                Character c3 = input.next();
+                if ( !PushbackString.isOctalDigit(c3) ) {
+                    input.pushback( c3 );
+                } else {
+                    sb.append( c3 );
+                }
             }
-			try {
-				// parse the octal string and create a character
-				int i = Integer.parseInt(sb.toString(), 8);
+            try {
+                // parse the octal string and create a character
+                int i = Integer.parseInt(sb.toString(), 8);
                 if (Character.isValidCodePoint(i)) {
                     return (char) i;
                 }
-			} catch( NumberFormatException e ) {
-				// throw an exception for malformed entity?
-				input.reset();
-				return null;
-			}
-		}
-		
-		// ignore the backslash and return the character
-		input.reset();
-		return null;
-	}
-
-}
\ No newline at end of file
+            } catch( NumberFormatException e ) {
+                // throw an exception for malformed entity?
+                input.reset();
+                return null;
+            }
+        }
+
+        // ignore the backslash and return the character
+        input.reset();
+        return null;
+    }
+
+}
diff --git a/src/main/java/org/owasp/esapi/codecs/LegacyHTMLEntityCodec.java b/src/main/java/org/owasp/esapi/codecs/LegacyHTMLEntityCodec.java
index 31d6960..ce66ba2 100644
--- a/src/main/java/org/owasp/esapi/codecs/LegacyHTMLEntityCodec.java
+++ b/src/main/java/org/owasp/esapi/codecs/LegacyHTMLEntityCodec.java
@@ -1,15 +1,15 @@
 /**
  * OWASP Enterprise Security API (ESAPI)
- * 
+ *
  * This file is part of the Open Web Application Security Project (OWASP)
  * Enterprise Security API (ESAPI) project. For details, please see
  * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
  *
  * Copyright (c) 2007 - The OWASP Foundation
- * 
+ *
  * The ESAPI is published by OWASP under the BSD license. You should read and accept the
  * LICENSE before you use, modify, and/or redistribute this software.
- * 
+ *
  * @author Jeff Williams <a href="http://www.aspectsecurity.com">Aspect Security</a>
  * @created 2007
  */
@@ -20,14 +20,14 @@ import java.util.Collections;
 import java.util.Map;
 
 /**
- * 
+ *
  * This class is DEPRECATED.  It did not correctly handle encoding of non-BMP
  * unicode code points.  This class is provided solely for any fatal bugs
  * not accounted for in the new version and will be removed entirely in
- * a future release.  
- * 
+ * a future release.
+ *
  * Implementation of the Codec interface for HTML entity encoding.
- * 
+ *
  * @author Jeff Williams (jeff.williams .at. aspectsecurity.com) <a
  *         href="http://www.aspectsecurity.com">Aspect Security</a>
  * @since June 1, 2007
@@ -35,523 +35,523 @@ import java.util.Map;
  */
 @Deprecated
 public class LegacyHTMLEntityCodec extends AbstractCharacterCodec {
-	
-	private static final char REPLACEMENT_CHAR = '\ufffd';
-	private static final String REPLACEMENT_HEX = "fffd";
-	private static final String REPLACEMENT_STR = "" + REPLACEMENT_CHAR;
-	private static final Map<Character,String> characterToEntityMap = mkCharacterToEntityMap();
-	private static final Trie<Character> entityToCharacterTrie = mkEntityToCharacterTrie();
-
-	/**
-	 * {@inheritDoc}
-	 * 
+
+    private static final char REPLACEMENT_CHAR = '\ufffd';
+    private static final String REPLACEMENT_HEX = "fffd";
+    private static final String REPLACEMENT_STR = "" + REPLACEMENT_CHAR;
+    private static final Map<Character,String> characterToEntityMap = mkCharacterToEntityMap();
+    private static final Trie<Character> entityToCharacterTrie = mkEntityToCharacterTrie();
+
+    /**
+     * {@inheritDoc}
+     *
      * Encodes a Character for safe use in an HTML entity field.
      * @param immune
      */
-	public String encodeCharacter( char[] immune, Character c ) {
-
-		// check for immune characters
-		if ( containsCharacter(c, immune ) ) {
-			return ""+c;
-		}
-		
-		// check for alphanumeric characters
-		String hex = super.getHexForNonAlphanumeric(c);
-		if ( hex == null ) {
-			return ""+c;
-		}
-		
-		// check for illegal characters
-		if ( ( c <= 0x1f && c != '\t' && c != '\n' && c != '\r' ) || ( c >= 0x7f && c <= 0x9f ) )
-		{
-			hex = REPLACEMENT_HEX;	// Let's entity encode this instead of returning it
-			c = REPLACEMENT_CHAR;
-		}
-		
-		// check if there's a defined entity
-		String entityName = characterToEntityMap.get(c);
-		if (entityName != null) {
-			return "&" + entityName + ";";
-		}
-		
-		// return the hex entity as suggested in the spec
-		return "&#x" + hex + ";";
-	}
-	
-	/**
-	 * Returns the decoded version of the character starting at index, or
-	 * null if no decoding is possible.
-	 * 
-	 * Formats all are legal both with and without semi-colon, upper/lower case:
-	 *   &#dddd;
-	 *   &#xhhhh;
-	 *   &name;
-	 */
-	public Character decodeCharacter( PushbackString input ) {
-		input.mark();
-		Character first = input.next();
-		if ( first == null ) {
-			input.reset();
-			return null;
-		}
-		
-		// if this is not an encoded character, return null
-		if (first != '&' ) {
-			input.reset();
-			return null;
-		}
-		
-		// test for numeric encodings
-		Character second = input.next();
-		if ( second == null ) {
-			input.reset();
-			return null;
-		}
-		
-		if (second == '#' ) {
-			// handle numbers
-			Character c = getNumericEntity( input );
-			if ( c != null ) return c;
-		} else if ( Character.isLetter( second.charValue() ) ) {
-			// handle entities
-			input.pushback( second );
-			Character c = getNamedEntity( input );
-			if ( c != null ) return c;
-		}
-		input.reset();
-		return null;
-	}
-	
-	/**
-	 * getNumericEntry checks input to see if it is a numeric entity
-	 * 
-	 * @param input
-	 * 			The input to test for being a numeric entity
-	 *  
-	 * @return
-	 * 			null if input is null, the character of input after decoding
-	 */
-	private Character getNumericEntity( PushbackString input ) {
-		Character first = input.peek();
-		if ( first == null ) return null;
-
-		if (first == 'x' || first == 'X' ) {
-			input.next();
-			return parseHex( input );
-		}
-		return parseNumber( input );
-	}
-
-	/**
-	 * Parse a decimal number, such as those from JavaScript's String.fromCharCode(value)
-	 * 
-	 * @param input
-	 * 			decimal encoded string, such as 65
-	 * @return
-	 * 			character representation of this decimal value, e.g. A 
-	 * @throws NumberFormatException
-	 */
-	private Character parseNumber( PushbackString input ) {
-		StringBuilder sb = new StringBuilder();
-		while( input.hasNext() ) {
-			Character c = input.peek();
-			
-			// if character is a digit then add it on and keep going
-			if ( Character.isDigit( c.charValue() ) ) {
-				sb.append( c );
-				input.next();
-				
-			// if character is a semi-colon, eat it and quit
-			} else if (c == ';' ) {
-				input.next();
-				break;
-				
-			// otherwise just quit
-			} else {
-				break;
-			}
-		}
-		try {
-			int i = Integer.parseInt(sb.toString());
+    public String encodeCharacter( char[] immune, Character c ) {
+
+        // check for immune characters
+        if ( containsCharacter(c, immune ) ) {
+            return ""+c;
+        }
+
+        // check for alphanumeric characters
+        String hex = super.getHexForNonAlphanumeric(c);
+        if ( hex == null ) {
+            return ""+c;
+        }
+
+        // check for illegal characters
+        if ( ( c <= 0x1f && c != '\t' && c != '\n' && c != '\r' ) || ( c >= 0x7f && c <= 0x9f ) )
+        {
+            hex = REPLACEMENT_HEX;    // Let's entity encode this instead of returning it
+            c = REPLACEMENT_CHAR;
+        }
+
+        // check if there's a defined entity
+        String entityName = characterToEntityMap.get(c);
+        if (entityName != null) {
+            return "&" + entityName + ";";
+        }
+
+        // return the hex entity as suggested in the spec
+        return "&#x" + hex + ";";
+    }
+
+    /**
+     * Returns the decoded version of the character starting at index, or
+     * null if no decoding is possible.
+     *
+     * Formats all are legal both with and without semi-colon, upper/lower case:
+     *   &#dddd;
+     *   &#xhhhh;
+     *   &name;
+     */
+    public Character decodeCharacter( PushbackString input ) {
+        input.mark();
+        Character first = input.next();
+        if ( first == null ) {
+            input.reset();
+            return null;
+        }
+
+        // if this is not an encoded character, return null
+        if (first != '&' ) {
+            input.reset();
+            return null;
+        }
+
+        // test for numeric encodings
+        Character second = input.next();
+        if ( second == null ) {
+            input.reset();
+            return null;
+        }
+
+        if (second == '#' ) {
+            // handle numbers
+            Character c = getNumericEntity( input );
+            if ( c != null ) return c;
+        } else if ( Character.isLetter( second.charValue() ) ) {
+            // handle entities
+            input.pushback( second );
+            Character c = getNamedEntity( input );
+            if ( c != null ) return c;
+        }
+        input.reset();
+        return null;
+    }
+
+    /**
+     * getNumericEntry checks input to see if it is a numeric entity
+     *
+     * @param input
+     *             The input to test for being a numeric entity
+     *
+     * @return
+     *             null if input is null, the character of input after decoding
+     */
+    private Character getNumericEntity( PushbackString input ) {
+        Character first = input.peek();
+        if ( first == null ) return null;
+
+        if (first == 'x' || first == 'X' ) {
+            input.next();
+            return parseHex( input );
+        }
+        return parseNumber( input );
+    }
+
+    /**
+     * Parse a decimal number, such as those from JavaScript's String.fromCharCode(value)
+     *
+     * @param input
+     *             decimal encoded string, such as 65
+     * @return
+     *             character representation of this decimal value, e.g. A
+     * @throws NumberFormatException
+     */
+    private Character parseNumber( PushbackString input ) {
+        StringBuilder sb = new StringBuilder();
+        while( input.hasNext() ) {
+            Character c = input.peek();
+
+            // if character is a digit then add it on and keep going
+            if ( Character.isDigit( c.charValue() ) ) {
+                sb.append( c );
+                input.next();
+
+            // if character is a semi-colon, eat it and quit
+            } else if (c == ';' ) {
+                input.next();
+                break;
+
+            // otherwise just quit
+            } else {
+                break;
+            }
+        }
+        try {
+            int i = Integer.parseInt(sb.toString());
             if (Character.isValidCodePoint(i)) {
                 return (char) i;
             }
-		} catch( NumberFormatException e ) {
-			// throw an exception for malformed entity?
-		}
-			return null;
-		}
-	
-	/**
-	 * Parse a hex encoded entity
-	 * 
-	 * @param input
-	 * 			Hex encoded input (such as 437ae;)
-	 * @return
-	 * 			A single character from the string
-	 * @throws NumberFormatException
-	 */
-	private Character parseHex( PushbackString input ) {
-		StringBuilder sb = new StringBuilder();
-		while( input.hasNext() ) {
-			Character c = input.peek();
-			
-			// if character is a hex digit then add it on and keep going
-			if ( "0123456789ABCDEFabcdef".indexOf(c) != -1 ) {
-				sb.append( c );
-				input.next();
-				
-			// if character is a semi-colon, eat it and quit
-			} else if (c == ';' ) {
-				input.next();
-				break;
-				
-			// otherwise just quit
-			} else {
-				break;
-			}
-		}
-		try {
-			int i = Integer.parseInt(sb.toString(), 16);
+        } catch( NumberFormatException e ) {
+            // throw an exception for malformed entity?
+        }
+            return null;
+        }
+
+    /**
+     * Parse a hex encoded entity
+     *
+     * @param input
+     *             Hex encoded input (such as 437ae;)
+     * @return
+     *             A single character from the string
+     * @throws NumberFormatException
+     */
+    private Character parseHex( PushbackString input ) {
+        StringBuilder sb = new StringBuilder();
+        while( input.hasNext() ) {
+            Character c = input.peek();
+
+            // if character is a hex digit then add it on and keep going
+            if ( "0123456789ABCDEFabcdef".indexOf(c) != -1 ) {
+                sb.append( c );
+                input.next();
+
+            // if character is a semi-colon, eat it and quit
+            } else if (c == ';' ) {
+                input.next();
+                break;
+
+            // otherwise just quit
+            } else {
+                break;
+            }
+        }
+        try {
+            int i = Integer.parseInt(sb.toString(), 16);
             if (Character.isValidCodePoint(i)) {
                 return (char) i;
             }
-		} catch( NumberFormatException e ) {
-			// throw an exception for malformed entity?
-		}
-			return null;
-		}
-	
-	/**
-	 * 
-	 * Returns the decoded version of the character starting at index, or
-	 * null if no decoding is possible.
-	 * 
-	 * Formats all are legal both with and without semi-colon, upper/lower case:
-	 *   &aa;
-	 *   &aaa;
-	 *   &aaaa;
-	 *   &aaaaa;
-	 *   &aaaaaa;
-	 *   &aaaaaaa;
-	 *
-	 * @param input
-	 * 		A string containing a named entity like &quot;
-	 * @return
-	 * 		Returns the decoded version of the character starting at index, or null if no decoding is possible.
-	 */
-	private Character getNamedEntity( PushbackString input ) {
-		StringBuilder possible = new StringBuilder();
-		Map.Entry<CharSequence,Character> entry;
-		int len;
-		
-		// kludge around PushbackString....
-		len = Math.min(input.remainder().length(), entityToCharacterTrie.getMaxKeyLength());
-		for(int i=0;i<len;i++)
-			possible.append(input.next());
-
-		// look up the longest match
-		entry = entityToCharacterTrie.getLongestMatch(possible);
-		if(entry == null) {
-			// We are lowercasing & comparing the result because of this all the upper case named entities are getting converted lowercase named entities.
-			// check is there any exact match https://github.com/ESAPI/esapi-java-legacy/issues/302
-			String possibleString = possible.toString();
-			String possibleStringLowerCase = possibleString.toLowerCase();
-		        if(!possibleString.equals(possibleStringLowerCase)) {
-		           Map.Entry<CharSequence,Character> exactEntry = entityToCharacterTrie.getLongestMatch(possibleStringLowerCase);
-		           if(exactEntry != null) entry = exactEntry;
-		        }
-		        if(entry == null) return null; // no match, caller will reset input
-		}
-
-		// fixup input
-		input.reset();
-		input.next();	// read &
-		len = entry.getKey().length();	// what matched's length
-		for(int i=0;i<len;i++)
-			input.next();
-
-		// check for a trailing semicolen
-		if(input.peek(';'))
-			input.next();
-
-		return entry.getValue();
-	}
-
-	/**
-	 * Build a unmodifiable Map from entity Character to Name.
-	 * @return Unmodifiable map.
-	 */
-	private static synchronized Map<Character,String> mkCharacterToEntityMap()
-	{
-		Map<Character, String> map = new HashMap<Character,String>(252);
-
-		map.put((char)34,	"quot");	/* quotation mark */
-		map.put((char)38,	"amp");		/* ampersand */
-		map.put((char)60,	"lt");		/* less-than sign */
-		map.put((char)62,	"gt");		/* greater-than sign */
-		map.put((char)160,	"nbsp");	/* no-break space */
-		map.put((char)161,	"iexcl");	/* inverted exclamation mark */
-		map.put((char)162,	"cent");	/* cent sign */
-		map.put((char)163,	"pound");	/* pound sign */
-		map.put((char)164,	"curren");	/* currency sign */
-		map.put((char)165,	"yen");		/* yen sign */
-		map.put((char)166,	"brvbar");	/* broken bar */
-		map.put((char)167,	"sect");	/* section sign */
-		map.put((char)168,	"uml");		/* diaeresis */
-		map.put((char)169,	"copy");	/* copyright sign */
-		map.put((char)170,	"ordf");	/* feminine ordinal indicator */
-		map.put((char)171,	"laquo");	/* left-pointing double angle quotation mark */
-		map.put((char)172,	"not");		/* not sign */
-		map.put((char)173,	"shy");		/* soft hyphen */
-		map.put((char)174,	"reg");		/* registered sign */
-		map.put((char)175,	"macr");	/* macron */
-		map.put((char)176,	"deg");		/* degree sign */
-		map.put((char)177,	"plusmn");	/* plus-minus sign */
-		map.put((char)178,	"sup2");	/* superscript two */
-		map.put((char)179,	"sup3");	/* superscript three */
-		map.put((char)180,	"acute");	/* acute accent */
-		map.put((char)181,	"micro");	/* micro sign */
-		map.put((char)182,	"para");	/* pilcrow sign */
-		map.put((char)183,	"middot");	/* middle dot */
-		map.put((char)184,	"cedil");	/* cedilla */
-		map.put((char)185,	"sup1");	/* superscript one */
-		map.put((char)186,	"ordm");	/* masculine ordinal indicator */
-		map.put((char)187,	"raquo");	/* right-pointing double angle quotation mark */
-		map.put((char)188,	"frac14");	/* vulgar fraction one quarter */
-		map.put((char)189,	"frac12");	/* vulgar fraction one half */
-		map.put((char)190,	"frac34");	/* vulgar fraction three quarters */
-		map.put((char)191,	"iquest");	/* inverted question mark */
-		map.put((char)192,	"Agrave");	/* Latin capital letter a with grave */
-		map.put((char)193,	"Aacute");	/* Latin capital letter a with acute */
-		map.put((char)194,	"Acirc");	/* Latin capital letter a with circumflex */
-		map.put((char)195,	"Atilde");	/* Latin capital letter a with tilde */
-		map.put((char)196,	"Auml");	/* Latin capital letter a with diaeresis */
-		map.put((char)197,	"Aring");	/* Latin capital letter a with ring above */
-		map.put((char)198,	"AElig");	/* Latin capital letter ae */
-		map.put((char)199,	"Ccedil");	/* Latin capital letter c with cedilla */
-		map.put((char)200,	"Egrave");	/* Latin capital letter e with grave */
-		map.put((char)201,	"Eacute");	/* Latin capital letter e with acute */
-		map.put((char)202,	"Ecirc");	/* Latin capital letter e with circumflex */
-		map.put((char)203,	"Euml");	/* Latin capital letter e with diaeresis */
-		map.put((char)204,	"Igrave");	/* Latin capital letter i with grave */
-		map.put((char)205,	"Iacute");	/* Latin capital letter i with acute */
-		map.put((char)206,	"Icirc");	/* Latin capital letter i with circumflex */
-		map.put((char)207,	"Iuml");	/* Latin capital letter i with diaeresis */
-		map.put((char)208,	"ETH");		/* Latin capital letter eth */
-		map.put((char)209,	"Ntilde");	/* Latin capital letter n with tilde */
-		map.put((char)210,	"Ograve");	/* Latin capital letter o with grave */
-		map.put((char)211,	"Oacute");	/* Latin capital letter o with acute */
-		map.put((char)212,	"Ocirc");	/* Latin capital letter o with circumflex */
-		map.put((char)213,	"Otilde");	/* Latin capital letter o with tilde */
-		map.put((char)214,	"Ouml");	/* Latin capital letter o with diaeresis */
-		map.put((char)215,	"times");	/* multiplication sign */
-		map.put((char)216,	"Oslash");	/* Latin capital letter o with stroke */
-		map.put((char)217,	"Ugrave");	/* Latin capital letter u with grave */
-		map.put((char)218,	"Uacute");	/* Latin capital letter u with acute */
-		map.put((char)219,	"Ucirc");	/* Latin capital letter u with circumflex */
-		map.put((char)220,	"Uuml");	/* Latin capital letter u with diaeresis */
-		map.put((char)221,	"Yacute");	/* Latin capital letter y with acute */
-		map.put((char)222,	"THORN");	/* Latin capital letter thorn */
-		map.put((char)223,	"szlig");	/* Latin small letter sharp sXCOMMAX German Eszett */
-		map.put((char)224,	"agrave");	/* Latin small letter a with grave */
-		map.put((char)225,	"aacute");	/* Latin small letter a with acute */
-		map.put((char)226,	"acirc");	/* Latin small letter a with circumflex */
-		map.put((char)227,	"atilde");	/* Latin small letter a with tilde */
-		map.put((char)228,	"auml");	/* Latin small letter a with diaeresis */
-		map.put((char)229,	"aring");	/* Latin small letter a with ring above */
-		map.put((char)230,	"aelig");	/* Latin lowercase ligature ae */
-		map.put((char)231,	"ccedil");	/* Latin small letter c with cedilla */
-		map.put((char)232,	"egrave");	/* Latin small letter e with grave */
-		map.put((char)233,	"eacute");	/* Latin small letter e with acute */
-		map.put((char)234,	"ecirc");	/* Latin small letter e with circumflex */
-		map.put((char)235,	"euml");	/* Latin small letter e with diaeresis */
-		map.put((char)236,	"igrave");	/* Latin small letter i with grave */
-		map.put((char)237,	"iacute");	/* Latin small letter i with acute */
-		map.put((char)238,	"icirc");	/* Latin small letter i with circumflex */
-		map.put((char)239,	"iuml");	/* Latin small letter i with diaeresis */
-		map.put((char)240,	"eth");		/* Latin small letter eth */
-		map.put((char)241,	"ntilde");	/* Latin small letter n with tilde */
-		map.put((char)242,	"ograve");	/* Latin small letter o with grave */
-		map.put((char)243,	"oacute");	/* Latin small letter o with acute */
-		map.put((char)244,	"ocirc");	/* Latin small letter o with circumflex */
-		map.put((char)245,	"otilde");	/* Latin small letter o with tilde */
-		map.put((char)246,	"ouml");	/* Latin small letter o with diaeresis */
-		map.put((char)247,	"divide");	/* division sign */
-		map.put((char)248,	"oslash");	/* Latin small letter o with stroke */
-		map.put((char)249,	"ugrave");	/* Latin small letter u with grave */
-		map.put((char)250,	"uacute");	/* Latin small letter u with acute */
-		map.put((char)251,	"ucirc");	/* Latin small letter u with circumflex */
-		map.put((char)252,	"uuml");	/* Latin small letter u with diaeresis */
-		map.put((char)253,	"yacute");	/* Latin small letter y with acute */
-		map.put((char)254,	"thorn");	/* Latin small letter thorn */
-		map.put((char)255,	"yuml");	/* Latin small letter y with diaeresis */
-		map.put((char)338,	"OElig");	/* Latin capital ligature oe */
-		map.put((char)339,	"oelig");	/* Latin small ligature oe */
-		map.put((char)352,	"Scaron");	/* Latin capital letter s with caron */
-		map.put((char)353,	"scaron");	/* Latin small letter s with caron */
-		map.put((char)376,	"Yuml");	/* Latin capital letter y with diaeresis */
-		map.put((char)402,	"fnof");	/* Latin small letter f with hook */
-		map.put((char)710,	"circ");	/* modifier letter circumflex accent */
-		map.put((char)732,	"tilde");	/* small tilde */
-		map.put((char)913,	"Alpha");	/* Greek capital letter alpha */
-		map.put((char)914,	"Beta");	/* Greek capital letter beta */
-		map.put((char)915,	"Gamma");	/* Greek capital letter gamma */
-		map.put((char)916,	"Delta");	/* Greek capital letter delta */
-		map.put((char)917,	"Epsilon");	/* Greek capital letter epsilon */
-		map.put((char)918,	"Zeta");	/* Greek capital letter zeta */
-		map.put((char)919,	"Eta");		/* Greek capital letter eta */
-		map.put((char)920,	"Theta");	/* Greek capital letter theta */
-		map.put((char)921,	"Iota");	/* Greek capital letter iota */
-		map.put((char)922,	"Kappa");	/* Greek capital letter kappa */
-		map.put((char)923,	"Lambda");	/* Greek capital letter lambda */
-		map.put((char)924,	"Mu");		/* Greek capital letter mu */
-		map.put((char)925,	"Nu");		/* Greek capital letter nu */
-		map.put((char)926,	"Xi");		/* Greek capital letter xi */
-		map.put((char)927,	"Omicron");	/* Greek capital letter omicron */
-		map.put((char)928,	"Pi");		/* Greek capital letter pi */
-		map.put((char)929,	"Rho");		/* Greek capital letter rho */
-		map.put((char)931,	"Sigma");	/* Greek capital letter sigma */
-		map.put((char)932,	"Tau");		/* Greek capital letter tau */
-		map.put((char)933,	"Upsilon");	/* Greek capital letter upsilon */
-		map.put((char)934,	"Phi");		/* Greek capital letter phi */
-		map.put((char)935,	"Chi");		/* Greek capital letter chi */
-		map.put((char)936,	"Psi");		/* Greek capital letter psi */
-		map.put((char)937,	"Omega");	/* Greek capital letter omega */
-		map.put((char)945,	"alpha");	/* Greek small letter alpha */
-		map.put((char)946,	"beta");	/* Greek small letter beta */
-		map.put((char)947,	"gamma");	/* Greek small letter gamma */
-		map.put((char)948,	"delta");	/* Greek small letter delta */
-		map.put((char)949,	"epsilon");	/* Greek small letter epsilon */
-		map.put((char)950,	"zeta");	/* Greek small letter zeta */
-		map.put((char)951,	"eta");		/* Greek small letter eta */
-		map.put((char)952,	"theta");	/* Greek small letter theta */
-		map.put((char)953,	"iota");	/* Greek small letter iota */
-		map.put((char)954,	"kappa");	/* Greek small letter kappa */
-		map.put((char)955,	"lambda");	/* Greek small letter lambda */
-		map.put((char)956,	"mu");		/* Greek small letter mu */
-		map.put((char)957,	"nu");		/* Greek small letter nu */
-		map.put((char)958,	"xi");		/* Greek small letter xi */
-		map.put((char)959,	"omicron");	/* Greek small letter omicron */
-		map.put((char)960,	"pi");		/* Greek small letter pi */
-		map.put((char)961,	"rho");		/* Greek small letter rho */
-		map.put((char)962,	"sigmaf");	/* Greek small letter final sigma */
-		map.put((char)963,	"sigma");	/* Greek small letter sigma */
-		map.put((char)964,	"tau");		/* Greek small letter tau */
-		map.put((char)965,	"upsilon");	/* Greek small letter upsilon */
-		map.put((char)966,	"phi");		/* Greek small letter phi */
-		map.put((char)967,	"chi");		/* Greek small letter chi */
-		map.put((char)968,	"psi");		/* Greek small letter psi */
-		map.put((char)969,	"omega");	/* Greek small letter omega */
-		map.put((char)977,	"thetasym");	/* Greek theta symbol */
-		map.put((char)978,	"upsih");	/* Greek upsilon with hook symbol */
-		map.put((char)982,	"piv");		/* Greek pi symbol */
-		map.put((char)8194,	"ensp");	/* en space */
-		map.put((char)8195,	"emsp");	/* em space */
-		map.put((char)8201,	"thinsp");	/* thin space */
-		map.put((char)8204,	"zwnj");	/* zero width non-joiner */
-		map.put((char)8205,	"zwj");		/* zero width joiner */
-		map.put((char)8206,	"lrm");		/* left-to-right mark */
-		map.put((char)8207,	"rlm");		/* right-to-left mark */
-		map.put((char)8211,	"ndash");	/* en dash */
-		map.put((char)8212,	"mdash");	/* em dash */
-		map.put((char)8216,	"lsquo");	/* left single quotation mark */
-		map.put((char)8217,	"rsquo");	/* right single quotation mark */
-		map.put((char)8218,	"sbquo");	/* single low-9 quotation mark */
-		map.put((char)8220,	"ldquo");	/* left double quotation mark */
-		map.put((char)8221,	"rdquo");	/* right double quotation mark */
-		map.put((char)8222,	"bdquo");	/* double low-9 quotation mark */
-		map.put((char)8224,	"dagger");	/* dagger */
-		map.put((char)8225,	"Dagger");	/* double dagger */
-		map.put((char)8226,	"bull");	/* bullet */
-		map.put((char)8230,	"hellip");	/* horizontal ellipsis */
-		map.put((char)8240,	"permil");	/* per mille sign */
-		map.put((char)8242,	"prime");	/* prime */
-		map.put((char)8243,	"Prime");	/* double prime */
-		map.put((char)8249,	"lsaquo");	/* single left-pointing angle quotation mark */
-		map.put((char)8250,	"rsaquo");	/* single right-pointing angle quotation mark */
-		map.put((char)8254,	"oline");	/* overline */
-		map.put((char)8260,	"frasl");	/* fraction slash */
-		map.put((char)8364,	"euro");	/* euro sign */
-		map.put((char)8465,	"image");	/* black-letter capital i */
-		map.put((char)8472,	"weierp");	/* script capital pXCOMMAX Weierstrass p */
-		map.put((char)8476,	"real");	/* black-letter capital r */
-		map.put((char)8482,	"trade");	/* trademark sign */
-		map.put((char)8501,	"alefsym");	/* alef symbol */
-		map.put((char)8592,	"larr");	/* leftwards arrow */
-		map.put((char)8593,	"uarr");	/* upwards arrow */
-		map.put((char)8594,	"rarr");	/* rightwards arrow */
-		map.put((char)8595,	"darr");	/* downwards arrow */
-		map.put((char)8596,	"harr");	/* left right arrow */
-		map.put((char)8629,	"crarr");	/* downwards arrow with corner leftwards */
-		map.put((char)8656,	"lArr");	/* leftwards double arrow */
-		map.put((char)8657,	"uArr");	/* upwards double arrow */
-		map.put((char)8658,	"rArr");	/* rightwards double arrow */
-		map.put((char)8659,	"dArr");	/* downwards double arrow */
-		map.put((char)8660,	"hArr");	/* left right double arrow */
-		map.put((char)8704,	"forall");	/* for all */
-		map.put((char)8706,	"part");	/* partial differential */
-		map.put((char)8707,	"exist");	/* there exists */
-		map.put((char)8709,	"empty");	/* empty set */
-		map.put((char)8711,	"nabla");	/* nabla */
-		map.put((char)8712,	"isin");	/* element of */
-		map.put((char)8713,	"notin");	/* not an element of */
-		map.put((char)8715,	"ni");		/* contains as member */
-		map.put((char)8719,	"prod");	/* n-ary product */
-		map.put((char)8721,	"sum");		/* n-ary summation */
-		map.put((char)8722,	"minus");	/* minus sign */
-		map.put((char)8727,	"lowast");	/* asterisk operator */
-		map.put((char)8730,	"radic");	/* square root */
-		map.put((char)8733,	"prop");	/* proportional to */
-		map.put((char)8734,	"infin");	/* infinity */
-		map.put((char)8736,	"ang");		/* angle */
-		map.put((char)8743,	"and");		/* logical and */
-		map.put((char)8744,	"or");		/* logical or */
-		map.put((char)8745,	"cap");		/* intersection */
-		map.put((char)8746,	"cup");		/* union */
-		map.put((char)8747,	"int");		/* integral */
-		map.put((char)8756,	"there4");	/* therefore */
-		map.put((char)8764,	"sim");		/* tilde operator */
-		map.put((char)8773,	"cong");	/* congruent to */
-		map.put((char)8776,	"asymp");	/* almost equal to */
-		map.put((char)8800,	"ne");		/* not equal to */
-		map.put((char)8801,	"equiv");	/* identical toXCOMMAX equivalent to */
-		map.put((char)8804,	"le");		/* less-than or equal to */
-		map.put((char)8805,	"ge");		/* greater-than or equal to */
-		map.put((char)8834,	"sub");		/* subset of */
-		map.put((char)8835,	"sup");		/* superset of */
-		map.put((char)8836,	"nsub");	/* not a subset of */
-		map.put((char)8838,	"sube");	/* subset of or equal to */
-		map.put((char)8839,	"supe");	/* superset of or equal to */
-		map.put((char)8853,	"oplus");	/* circled plus */
-		map.put((char)8855,	"otimes");	/* circled times */
-		map.put((char)8869,	"perp");	/* up tack */
-		map.put((char)8901,	"sdot");	/* dot operator */
-		map.put((char)8968,	"lceil");	/* left ceiling */
-		map.put((char)8969,	"rceil");	/* right ceiling */
-		map.put((char)8970,	"lfloor");	/* left floor */
-		map.put((char)8971,	"rfloor");	/* right floor */
-		map.put((char)9001,	"lang");	/* left-pointing angle bracket */
-		map.put((char)9002,	"rang");	/* right-pointing angle bracket */
-		map.put((char)9674,	"loz");		/* lozenge */
-		map.put((char)9824,	"spades");	/* black spade suit */
-		map.put((char)9827,	"clubs");	/* black club suit */
-		map.put((char)9829,	"hearts");	/* black heart suit */
-		map.put((char)9830,	"diams");	/* black diamond suit */
-
-		return Collections.unmodifiableMap(map);
-	}
-
-	/**
-	 * Build a unmodifiable Trie from entitiy Name to Character
-	 * @return Unmodifiable trie.
-	 */
-	private static synchronized Trie<Character> mkEntityToCharacterTrie()
-	{
-		Trie<Character> trie = new HashTrie<Character>();
-
-		for(Map.Entry<Character,String> entry : characterToEntityMap.entrySet())
-			trie.put(entry.getValue(),entry.getKey());
-		return Trie.Util.unmodifiable(trie);
-	}
+        } catch( NumberFormatException e ) {
+            // throw an exception for malformed entity?
+        }
+            return null;
+        }
+
+    /**
+     *
+     * Returns the decoded version of the character starting at index, or
+     * null if no decoding is possible.
+     *
+     * Formats all are legal both with and without semi-colon, upper/lower case:
+     *   &aa;
+     *   &aaa;
+     *   &aaaa;
+     *   &aaaaa;
+     *   &aaaaaa;
+     *   &aaaaaaa;
+     *
+     * @param input
+     *         A string containing a named entity like &quot;
+     * @return
+     *         Returns the decoded version of the character starting at index, or null if no decoding is possible.
+     */
+    private Character getNamedEntity( PushbackString input ) {
+        StringBuilder possible = new StringBuilder();
+        Map.Entry<CharSequence,Character> entry;
+        int len;
+
+        // kludge around PushbackString....
+        len = Math.min(input.remainder().length(), entityToCharacterTrie.getMaxKeyLength());
+        for(int i=0;i<len;i++)
+            possible.append(input.next());
+
+        // look up the longest match
+        entry = entityToCharacterTrie.getLongestMatch(possible);
+        if(entry == null) {
+            // We are lowercasing & comparing the result because of this all the upper case named entities are getting converted lowercase named entities.
+            // check is there any exact match https://github.com/ESAPI/esapi-java-legacy/issues/302
+            String possibleString = possible.toString();
+            String possibleStringLowerCase = possibleString.toLowerCase();
+                if(!possibleString.equals(possibleStringLowerCase)) {
+                   Map.Entry<CharSequence,Character> exactEntry = entityToCharacterTrie.getLongestMatch(possibleStringLowerCase);
+                   if(exactEntry != null) entry = exactEntry;
+                }
+                if(entry == null) return null; // no match, caller will reset input
+        }
+
+        // fixup input
+        input.reset();
+        input.next();    // read &
+        len = entry.getKey().length();    // what matched's length
+        for(int i=0;i<len;i++)
+            input.next();
+
+        // check for a trailing semicolen
+        if(input.peek(';'))
+            input.next();
+
+        return entry.getValue();
+    }
+
+    /**
+     * Build a unmodifiable Map from entity Character to Name.
+     * @return Unmodifiable map.
+     */
+    private static synchronized Map<Character,String> mkCharacterToEntityMap()
+    {
+        Map<Character, String> map = new HashMap<Character,String>(252);
+
+        map.put((char)34,    "quot");    /* quotation mark */
+        map.put((char)38,    "amp");        /* ampersand */
+        map.put((char)60,    "lt");        /* less-than sign */
+        map.put((char)62,    "gt");        /* greater-than sign */
+        map.put((char)160,    "nbsp");    /* no-break space */
+        map.put((char)161,    "iexcl");    /* inverted exclamation mark */
+        map.put((char)162,    "cent");    /* cent sign */
+        map.put((char)163,    "pound");    /* pound sign */
+        map.put((char)164,    "curren");    /* currency sign */
+        map.put((char)165,    "yen");        /* yen sign */
+        map.put((char)166,    "brvbar");    /* broken bar */
+        map.put((char)167,    "sect");    /* section sign */
+        map.put((char)168,    "uml");        /* diaeresis */
+        map.put((char)169,    "copy");    /* copyright sign */
+        map.put((char)170,    "ordf");    /* feminine ordinal indicator */
+        map.put((char)171,    "laquo");    /* left-pointing double angle quotation mark */
+        map.put((char)172,    "not");        /* not sign */
+        map.put((char)173,    "shy");        /* soft hyphen */
+        map.put((char)174,    "reg");        /* registered sign */
+        map.put((char)175,    "macr");    /* macron */
+        map.put((char)176,    "deg");        /* degree sign */
+        map.put((char)177,    "plusmn");    /* plus-minus sign */
+        map.put((char)178,    "sup2");    /* superscript two */
+        map.put((char)179,    "sup3");    /* superscript three */
+        map.put((char)180,    "acute");    /* acute accent */
+        map.put((char)181,    "micro");    /* micro sign */
+        map.put((char)182,    "para");    /* pilcrow sign */
+        map.put((char)183,    "middot");    /* middle dot */
+        map.put((char)184,    "cedil");    /* cedilla */
+        map.put((char)185,    "sup1");    /* superscript one */
+        map.put((char)186,    "ordm");    /* masculine ordinal indicator */
+        map.put((char)187,    "raquo");    /* right-pointing double angle quotation mark */
+        map.put((char)188,    "frac14");    /* vulgar fraction one quarter */
+        map.put((char)189,    "frac12");    /* vulgar fraction one half */
+        map.put((char)190,    "frac34");    /* vulgar fraction three quarters */
+        map.put((char)191,    "iquest");    /* inverted question mark */
+        map.put((char)192,    "Agrave");    /* Latin capital letter a with grave */
+        map.put((char)193,    "Aacute");    /* Latin capital letter a with acute */
+        map.put((char)194,    "Acirc");    /* Latin capital letter a with circumflex */
+        map.put((char)195,    "Atilde");    /* Latin capital letter a with tilde */
+        map.put((char)196,    "Auml");    /* Latin capital letter a with diaeresis */
+        map.put((char)197,    "Aring");    /* Latin capital letter a with ring above */
+        map.put((char)198,    "AElig");    /* Latin capital letter ae */
+        map.put((char)199,    "Ccedil");    /* Latin capital letter c with cedilla */
+        map.put((char)200,    "Egrave");    /* Latin capital letter e with grave */
+        map.put((char)201,    "Eacute");    /* Latin capital letter e with acute */
+        map.put((char)202,    "Ecirc");    /* Latin capital letter e with circumflex */
+        map.put((char)203,    "Euml");    /* Latin capital letter e with diaeresis */
+        map.put((char)204,    "Igrave");    /* Latin capital letter i with grave */
+        map.put((char)205,    "Iacute");    /* Latin capital letter i with acute */
+        map.put((char)206,    "Icirc");    /* Latin capital letter i with circumflex */
+        map.put((char)207,    "Iuml");    /* Latin capital letter i with diaeresis */
+        map.put((char)208,    "ETH");        /* Latin capital letter eth */
+        map.put((char)209,    "Ntilde");    /* Latin capital letter n with tilde */
+        map.put((char)210,    "Ograve");    /* Latin capital letter o with grave */
+        map.put((char)211,    "Oacute");    /* Latin capital letter o with acute */
+        map.put((char)212,    "Ocirc");    /* Latin capital letter o with circumflex */
+        map.put((char)213,    "Otilde");    /* Latin capital letter o with tilde */
+        map.put((char)214,    "Ouml");    /* Latin capital letter o with diaeresis */
+        map.put((char)215,    "times");    /* multiplication sign */
+        map.put((char)216,    "Oslash");    /* Latin capital letter o with stroke */
+        map.put((char)217,    "Ugrave");    /* Latin capital letter u with grave */
+        map.put((char)218,    "Uacute");    /* Latin capital letter u with acute */
+        map.put((char)219,    "Ucirc");    /* Latin capital letter u with circumflex */
+        map.put((char)220,    "Uuml");    /* Latin capital letter u with diaeresis */
+        map.put((char)221,    "Yacute");    /* Latin capital letter y with acute */
+        map.put((char)222,    "THORN");    /* Latin capital letter thorn */
+        map.put((char)223,    "szlig");    /* Latin small letter sharp sXCOMMAX German Eszett */
+        map.put((char)224,    "agrave");    /* Latin small letter a with grave */
+        map.put((char)225,    "aacute");    /* Latin small letter a with acute */
+        map.put((char)226,    "acirc");    /* Latin small letter a with circumflex */
+        map.put((char)227,    "atilde");    /* Latin small letter a with tilde */
+        map.put((char)228,    "auml");    /* Latin small letter a with diaeresis */
+        map.put((char)229,    "aring");    /* Latin small letter a with ring above */
+        map.put((char)230,    "aelig");    /* Latin lowercase ligature ae */
+        map.put((char)231,    "ccedil");    /* Latin small letter c with cedilla */
+        map.put((char)232,    "egrave");    /* Latin small letter e with grave */
+        map.put((char)233,    "eacute");    /* Latin small letter e with acute */
+        map.put((char)234,    "ecirc");    /* Latin small letter e with circumflex */
+        map.put((char)235,    "euml");    /* Latin small letter e with diaeresis */
+        map.put((char)236,    "igrave");    /* Latin small letter i with grave */
+        map.put((char)237,    "iacute");    /* Latin small letter i with acute */
+        map.put((char)238,    "icirc");    /* Latin small letter i with circumflex */
+        map.put((char)239,    "iuml");    /* Latin small letter i with diaeresis */
+        map.put((char)240,    "eth");        /* Latin small letter eth */
+        map.put((char)241,    "ntilde");    /* Latin small letter n with tilde */
+        map.put((char)242,    "ograve");    /* Latin small letter o with grave */
+        map.put((char)243,    "oacute");    /* Latin small letter o with acute */
+        map.put((char)244,    "ocirc");    /* Latin small letter o with circumflex */
+        map.put((char)245,    "otilde");    /* Latin small letter o with tilde */
+        map.put((char)246,    "ouml");    /* Latin small letter o with diaeresis */
+        map.put((char)247,    "divide");    /* division sign */
+        map.put((char)248,    "oslash");    /* Latin small letter o with stroke */
+        map.put((char)249,    "ugrave");    /* Latin small letter u with grave */
+        map.put((char)250,    "uacute");    /* Latin small letter u with acute */
+        map.put((char)251,    "ucirc");    /* Latin small letter u with circumflex */
+        map.put((char)252,    "uuml");    /* Latin small letter u with diaeresis */
+        map.put((char)253,    "yacute");    /* Latin small letter y with acute */
+        map.put((char)254,    "thorn");    /* Latin small letter thorn */
+        map.put((char)255,    "yuml");    /* Latin small letter y with diaeresis */
+        map.put((char)338,    "OElig");    /* Latin capital ligature oe */
+        map.put((char)339,    "oelig");    /* Latin small ligature oe */
+        map.put((char)352,    "Scaron");    /* Latin capital letter s with caron */
+        map.put((char)353,    "scaron");    /* Latin small letter s with caron */
+        map.put((char)376,    "Yuml");    /* Latin capital letter y with diaeresis */
+        map.put((char)402,    "fnof");    /* Latin small letter f with hook */
+        map.put((char)710,    "circ");    /* modifier letter circumflex accent */
+        map.put((char)732,    "tilde");    /* small tilde */
+        map.put((char)913,    "Alpha");    /* Greek capital letter alpha */
+        map.put((char)914,    "Beta");    /* Greek capital letter beta */
+        map.put((char)915,    "Gamma");    /* Greek capital letter gamma */
+        map.put((char)916,    "Delta");    /* Greek capital letter delta */
+        map.put((char)917,    "Epsilon");    /* Greek capital letter epsilon */
+        map.put((char)918,    "Zeta");    /* Greek capital letter zeta */
+        map.put((char)919,    "Eta");        /* Greek capital letter eta */
+        map.put((char)920,    "Theta");    /* Greek capital letter theta */
+        map.put((char)921,    "Iota");    /* Greek capital letter iota */
+        map.put((char)922,    "Kappa");    /* Greek capital letter kappa */
+        map.put((char)923,    "Lambda");    /* Greek capital letter lambda */
+        map.put((char)924,    "Mu");        /* Greek capital letter mu */
+        map.put((char)925,    "Nu");        /* Greek capital letter nu */
+        map.put((char)926,    "Xi");        /* Greek capital letter xi */
+        map.put((char)927,    "Omicron");    /* Greek capital letter omicron */
+        map.put((char)928,    "Pi");        /* Greek capital letter pi */
+        map.put((char)929,    "Rho");        /* Greek capital letter rho */
+        map.put((char)931,    "Sigma");    /* Greek capital letter sigma */
+        map.put((char)932,    "Tau");        /* Greek capital letter tau */
+        map.put((char)933,    "Upsilon");    /* Greek capital letter upsilon */
+        map.put((char)934,    "Phi");        /* Greek capital letter phi */
+        map.put((char)935,    "Chi");        /* Greek capital letter chi */
+        map.put((char)936,    "Psi");        /* Greek capital letter psi */
+        map.put((char)937,    "Omega");    /* Greek capital letter omega */
+        map.put((char)945,    "alpha");    /* Greek small letter alpha */
+        map.put((char)946,    "beta");    /* Greek small letter beta */
+        map.put((char)947,    "gamma");    /* Greek small letter gamma */
+        map.put((char)948,    "delta");    /* Greek small letter delta */
+        map.put((char)949,    "epsilon");    /* Greek small letter epsilon */
+        map.put((char)950,    "zeta");    /* Greek small letter zeta */
+        map.put((char)951,    "eta");        /* Greek small letter eta */
+        map.put((char)952,    "theta");    /* Greek small letter theta */
+        map.put((char)953,    "iota");    /* Greek small letter iota */
+        map.put((char)954,    "kappa");    /* Greek small letter kappa */
+        map.put((char)955,    "lambda");    /* Greek small letter lambda */
+        map.put((char)956,    "mu");        /* Greek small letter mu */
+        map.put((char)957,    "nu");        /* Greek small letter nu */
+        map.put((char)958,    "xi");        /* Greek small letter xi */
+        map.put((char)959,    "omicron");    /* Greek small letter omicron */
+        map.put((char)960,    "pi");        /* Greek small letter pi */
+        map.put((char)961,    "rho");        /* Greek small letter rho */
+        map.put((char)962,    "sigmaf");    /* Greek small letter final sigma */
+        map.put((char)963,    "sigma");    /* Greek small letter sigma */
+        map.put((char)964,    "tau");        /* Greek small letter tau */
+        map.put((char)965,    "upsilon");    /* Greek small letter upsilon */
+        map.put((char)966,    "phi");        /* Greek small letter phi */
+        map.put((char)967,    "chi");        /* Greek small letter chi */
+        map.put((char)968,    "psi");        /* Greek small letter psi */
+        map.put((char)969,    "omega");    /* Greek small letter omega */
+        map.put((char)977,    "thetasym");    /* Greek theta symbol */
+        map.put((char)978,    "upsih");    /* Greek upsilon with hook symbol */
+        map.put((char)982,    "piv");        /* Greek pi symbol */
+        map.put((char)8194,    "ensp");    /* en space */
+        map.put((char)8195,    "emsp");    /* em space */
+        map.put((char)8201,    "thinsp");    /* thin space */
+        map.put((char)8204,    "zwnj");    /* zero width non-joiner */
+        map.put((char)8205,    "zwj");        /* zero width joiner */
+        map.put((char)8206,    "lrm");        /* left-to-right mark */
+        map.put((char)8207,    "rlm");        /* right-to-left mark */
+        map.put((char)8211,    "ndash");    /* en dash */
+        map.put((char)8212,    "mdash");    /* em dash */
+        map.put((char)8216,    "lsquo");    /* left single quotation mark */
+        map.put((char)8217,    "rsquo");    /* right single quotation mark */
+        map.put((char)8218,    "sbquo");    /* single low-9 quotation mark */
+        map.put((char)8220,    "ldquo");    /* left double quotation mark */
+        map.put((char)8221,    "rdquo");    /* right double quotation mark */
+        map.put((char)8222,    "bdquo");    /* double low-9 quotation mark */
+        map.put((char)8224,    "dagger");    /* dagger */
+        map.put((char)8225,    "Dagger");    /* double dagger */
+        map.put((char)8226,    "bull");    /* bullet */
+        map.put((char)8230,    "hellip");    /* horizontal ellipsis */
+        map.put((char)8240,    "permil");    /* per mille sign */
+        map.put((char)8242,    "prime");    /* prime */
+        map.put((char)8243,    "Prime");    /* double prime */
+        map.put((char)8249,    "lsaquo");    /* single left-pointing angle quotation mark */
+        map.put((char)8250,    "rsaquo");    /* single right-pointing angle quotation mark */
+        map.put((char)8254,    "oline");    /* overline */
+        map.put((char)8260,    "frasl");    /* fraction slash */
+        map.put((char)8364,    "euro");    /* euro sign */
+        map.put((char)8465,    "image");    /* black-letter capital i */
+        map.put((char)8472,    "weierp");    /* script capital pXCOMMAX Weierstrass p */
+        map.put((char)8476,    "real");    /* black-letter capital r */
+        map.put((char)8482,    "trade");    /* trademark sign */
+        map.put((char)8501,    "alefsym");    /* alef symbol */
+        map.put((char)8592,    "larr");    /* leftwards arrow */
+        map.put((char)8593,    "uarr");    /* upwards arrow */
+        map.put((char)8594,    "rarr");    /* rightwards arrow */
+        map.put((char)8595,    "darr");    /* downwards arrow */
+        map.put((char)8596,    "harr");    /* left right arrow */
+        map.put((char)8629,    "crarr");    /* downwards arrow with corner leftwards */
+        map.put((char)8656,    "lArr");    /* leftwards double arrow */
+        map.put((char)8657,    "uArr");    /* upwards double arrow */
+        map.put((char)8658,    "rArr");    /* rightwards double arrow */
+        map.put((char)8659,    "dArr");    /* downwards double arrow */
+        map.put((char)8660,    "hArr");    /* left right double arrow */
+        map.put((char)8704,    "forall");    /* for all */
+        map.put((char)8706,    "part");    /* partial differential */
+        map.put((char)8707,    "exist");    /* there exists */
+        map.put((char)8709,    "empty");    /* empty set */
+        map.put((char)8711,    "nabla");    /* nabla */
+        map.put((char)8712,    "isin");    /* element of */
+        map.put((char)8713,    "notin");    /* not an element of */
+        map.put((char)8715,    "ni");        /* contains as member */
+        map.put((char)8719,    "prod");    /* n-ary product */
+        map.put((char)8721,    "sum");        /* n-ary summation */
+        map.put((char)8722,    "minus");    /* minus sign */
+        map.put((char)8727,    "lowast");    /* asterisk operator */
+        map.put((char)8730,    "radic");    /* square root */
+        map.put((char)8733,    "prop");    /* proportional to */
+        map.put((char)8734,    "infin");    /* infinity */
+        map.put((char)8736,    "ang");        /* angle */
+        map.put((char)8743,    "and");        /* logical and */
+        map.put((char)8744,    "or");        /* logical or */
+        map.put((char)8745,    "cap");        /* intersection */
+        map.put((char)8746,    "cup");        /* union */
+        map.put((char)8747,    "int");        /* integral */
+        map.put((char)8756,    "there4");    /* therefore */
+        map.put((char)8764,    "sim");        /* tilde operator */
+        map.put((char)8773,    "cong");    /* congruent to */
+        map.put((char)8776,    "asymp");    /* almost equal to */
+        map.put((char)8800,    "ne");        /* not equal to */
+        map.put((char)8801,    "equiv");    /* identical toXCOMMAX equivalent to */
+        map.put((char)8804,    "le");        /* less-than or equal to */
+        map.put((char)8805,    "ge");        /* greater-than or equal to */
+        map.put((char)8834,    "sub");        /* subset of */
+        map.put((char)8835,    "sup");        /* superset of */
+        map.put((char)8836,    "nsub");    /* not a subset of */
+        map.put((char)8838,    "sube");    /* subset of or equal to */
+        map.put((char)8839,    "supe");    /* superset of or equal to */
+        map.put((char)8853,    "oplus");    /* circled plus */
+        map.put((char)8855,    "otimes");    /* circled times */
+        map.put((char)8869,    "perp");    /* up tack */
+        map.put((char)8901,    "sdot");    /* dot operator */
+        map.put((char)8968,    "lceil");    /* left ceiling */
+        map.put((char)8969,    "rceil");    /* right ceiling */
+        map.put((char)8970,    "lfloor");    /* left floor */
+        map.put((char)8971,    "rfloor");    /* right floor */
+        map.put((char)9001,    "lang");    /* left-pointing angle bracket */
+        map.put((char)9002,    "rang");    /* right-pointing angle bracket */
+        map.put((char)9674,    "loz");        /* lozenge */
+        map.put((char)9824,    "spades");    /* black spade suit */
+        map.put((char)9827,    "clubs");    /* black club suit */
+        map.put((char)9829,    "hearts");    /* black heart suit */
+        map.put((char)9830,    "diams");    /* black diamond suit */
+
+        return Collections.unmodifiableMap(map);
+    }
+
+    /**
+     * Build a unmodifiable Trie from entitiy Name to Character
+     * @return Unmodifiable trie.
+     */
+    private static synchronized Trie<Character> mkEntityToCharacterTrie()
+    {
+        Trie<Character> trie = new HashTrie<Character>();
+
+        for(Map.Entry<Character,String> entry : characterToEntityMap.entrySet())
+            trie.put(entry.getValue(),entry.getKey());
+        return Trie.Util.unmodifiable(trie);
+    }
 }
diff --git a/src/main/java/org/owasp/esapi/codecs/MySQLCodec.java b/src/main/java/org/owasp/esapi/codecs/MySQLCodec.java
index bdcf26a..193dfa2 100644
--- a/src/main/java/org/owasp/esapi/codecs/MySQLCodec.java
+++ b/src/main/java/org/owasp/esapi/codecs/MySQLCodec.java
@@ -1,15 +1,15 @@
 /**
  * OWASP Enterprise Security API (ESAPI)
- * 
+ *
  * This file is part of the Open Web Application Security Project (OWASP)
  * Enterprise Security API (ESAPI) project. For details, please see
  * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
  *
  * Copyright (c) 2007 - The OWASP Foundation
- * 
+ *
  * The ESAPI is published by OWASP under the BSD license. You should read and accept the
  * LICENSE before you use, modify, and/or redistribute this software.
- * 
+ *
  * @author Jeff Williams <a href="http://www.aspectsecurity.com">Aspect Security</a>
  * @created 2007
  */
@@ -27,7 +27,7 @@ package org.owasp.esapi.codecs;
  * Simply encode all ' (single tick) characters with '' (two single ticks)</li>
  * <br>
  * <li><b>Standard</b>
- * 
+ *
  * <pre>
  *   NUL (0x00) --> \0  [This is a zero, not the letter O]
  *   BS  (0x08) --> \b
@@ -39,20 +39,20 @@ package org.owasp.esapi.codecs;
  *   %   (0x25) --> \%
  *   '   (0x27) --> \'
  *   \   (0x5c) --> \\
- *   _   (0x5f) --> \_ 
+ *   _   (0x5f) --> \_
  *   <br>
  *   all other non-alphanumeric characters with ASCII values less than 256  --> \c
  *   where 'c' is the original non-alphanumeric character.
  * </pre>
- * 
+ *
  * </li>
- * 
+ *
  * </ul>
- * 
+ *
  * @author Jeff Williams (jeff.williams .at. aspectsecurity.com)
  *         <a href="http://www.aspectsecurity.com">Aspect Security</a>
  * @since June 1, 2007
- * 
+ *
  * <a href= "https://dev.mysql.com/doc/refman/8.0/en/string-literals.html">MySQL 8.0 String Literals</a>
  * <a href= "https://www.owasp.org/index.php/SQL_Injection_Prevention_Cheat_Sheet#MySQL_Escaping">OWASP
  *      SQL_Injection_Prevention_Cheat_Sheet#MySQL_Escaping</a>
@@ -85,31 +85,31 @@ public class MySQLCodec extends AbstractCharacterCodec {
 
     /** Target MySQL Server is running in Standard MySQL (Default) mode. */
     public static final int MYSQL_MODE = 0;
-    
+
     /**
      * Target MySQL Server is running in ANSI_QUOTES Mode
-     * 
+     *
      * @see <a href=
      *      "https://dev.mysql.com/doc/refman/8.0/en/sql-mode.html#sqlmode_ansi_quotes">
      *      https://dev.mysql.com/doc/refman/8.0/en/sql-mode.html#sqlmode_ansi_quotes</a>
      */
     public static final int ANSI_MODE = 1;
-	
-	//private int mode = 0;
+
+    //private int mode = 0;
     private Mode mode;
-	
-	/**
-	 * Instantiate the MySQL codec
-	 * 
-	 * @param mode
-	 * 			Mode has to be one of {MYSQL_MODE|ANSI_MODE} to allow correct encoding
+
+    /**
+     * Instantiate the MySQL codec
+     *
+     * @param mode
+     *             Mode has to be one of {MYSQL_MODE|ANSI_MODE} to allow correct encoding
      * @deprecated
      * @see #MySQLCodec(org.owasp.esapi.codecs.MySQLCodec.Mode)
-	 */
+     */
     @Deprecated
-	public MySQLCodec( int mode ) {
-		this.mode = Mode.findByKey(mode);
-	}
+    public MySQLCodec( int mode ) {
+        this.mode = Mode.findByKey(mode);
+    }
 
     /**
      * Instantiate the MySQL Codec with the given SQL {@link Mode}.
@@ -120,182 +120,182 @@ public class MySQLCodec extends AbstractCharacterCodec {
     }
 
 
-	/**
-	 * {@inheritDoc}
+    /**
+     * {@inheritDoc}
      */
-	public String encodeCharacter( char[] immune, Character c ) {
-		char ch = c.charValue();
-		
-		// check for immune characters
-		if ( containsCharacter( ch, immune ) ) {
-			return ""+ch;
-		}
-		
-		// check for alphanumeric characters
-		String hex = super.getHexForNonAlphanumeric( ch );
-		if ( hex == null ) {
-			return ""+ch;
-		}
-		
-		
-		switch( mode ) {
-			case ANSI: return encodeCharacterANSI( c );
-			case STANDARD: return encodeCharacterMySQL( c );
-			default: return null;
-		}
-	}
-	
-	/**
-	 * encodeCharacterANSI encodes for ANSI SQL. 
-	 * 
-	 * Apostrophe is encoded
+    public String encodeCharacter( char[] immune, Character c ) {
+        char ch = c.charValue();
+
+        // check for immune characters
+        if ( containsCharacter( ch, immune ) ) {
+            return ""+ch;
+        }
+
+        // check for alphanumeric characters
+        String hex = super.getHexForNonAlphanumeric( ch );
+        if ( hex == null ) {
+            return ""+ch;
+        }
+
+
+        switch( mode ) {
+            case ANSI: return encodeCharacterANSI( c );
+            case STANDARD: return encodeCharacterMySQL( c );
+            default: return null;
+        }
+    }
+
+    /**
+     * encodeCharacterANSI encodes for ANSI SQL.
+     *
+     * Apostrophe is encoded
      *
      * Bug ###: In ANSI Mode Strings can also be passed in using the quotation. In ANSI_QUOTES mode a quotation
      * is considered to be an identifier, thus cannot be used at all in a value and will be dropped completely.
-	 * 
-	 * @param c 
-	 * 			character to encode
-	 * @return
-	 * 			String encoded to standards of MySQL running in ANSI mode
-	 */
-	private String encodeCharacterANSI( Character c ) {
-		if ( c == '\'' )
-        	return "\'\'";
-     
+     *
+     * @param c
+     *             character to encode
+     * @return
+     *             String encoded to standards of MySQL running in ANSI mode
+     */
+    private String encodeCharacterANSI( Character c ) {
+        if ( c == '\'' )
+            return "\'\'";
+
         return ""+c;
-	}
+    }
 
-	/**
-	 * Encode a character suitable for MySQL
-	 * 
-	 * @param c
-	 * 			Character to encode
-	 * @return
-	 * 			Encoded Character
-	 */
-	private String encodeCharacterMySQL( Character c ) {
-		char ch = c.charValue();
-		if ( ch == 0x00 ) return "\\0";
-		if ( ch == 0x08 ) return "\\b";
-		if ( ch == 0x09 ) return "\\t";
-		if ( ch == 0x0a ) return "\\n";
-		if ( ch == 0x0d ) return "\\r";
-		if ( ch == 0x1a ) return "\\Z";
-		if ( ch == 0x22 ) return "\\\"";
-		if ( ch == 0x25 ) return "\\%";
-		if ( ch == 0x27 ) return "\\'";
-		if ( ch == 0x5c ) return "\\\\";
-		if ( ch == 0x5f ) return "\\_";
-	    return "\\" + c;
-	}
-	
-	/**
-	 * {@inheritDoc}
-	 * 
-	 * Returns the decoded version of the character starting at index, or
-	 * null if no decoding is possible.
-	 * 
-	 * Formats all are legal (case sensitive)
-	 *   In ANSI_MODE '' decodes to '
-	 *   In MYSQL_MODE \x decodes to x (or a small list of specials)
-	 */
-	public Character decodeCharacter( PushbackSequence<Character> input ) {
-		switch( mode ) {
-			case ANSI: return decodeCharacterANSI( input );
-			case STANDARD: return decodeCharacterMySQL( input );
-			default: return null;
-		}
-	}
+    /**
+     * Encode a character suitable for MySQL
+     *
+     * @param c
+     *             Character to encode
+     * @return
+     *             Encoded Character
+     */
+    private String encodeCharacterMySQL( Character c ) {
+        char ch = c.charValue();
+        if ( ch == 0x00 ) return "\\0";
+        if ( ch == 0x08 ) return "\\b";
+        if ( ch == 0x09 ) return "\\t";
+        if ( ch == 0x0a ) return "\\n";
+        if ( ch == 0x0d ) return "\\r";
+        if ( ch == 0x1a ) return "\\Z";
+        if ( ch == 0x22 ) return "\\\"";
+        if ( ch == 0x25 ) return "\\%";
+        if ( ch == 0x27 ) return "\\'";
+        if ( ch == 0x5c ) return "\\\\";
+        if ( ch == 0x5f ) return "\\_";
+        return "\\" + c;
+    }
 
-	/**
-	 * decodeCharacterANSI decodes the next character from ANSI SQL escaping
-	 *  
-	 * @param input
-	 * 			A PushBackString containing characters you'd like decoded
-	 * @return
-	 * 			A single character, decoded
-	 */
-	private Character decodeCharacterANSI( PushbackSequence<Character>  input ) {
-		input.mark();
-		Character first = input.next();
-		if ( first == null ) {
-			input.reset();
-			return null;
-		}
-		
-		// if this is not an encoded character, return null
-		if ( first.charValue() != '\'' ) {
-			input.reset();
-			return null;
-		}
+    /**
+     * {@inheritDoc}
+     *
+     * Returns the decoded version of the character starting at index, or
+     * null if no decoding is possible.
+     *
+     * Formats all are legal (case sensitive)
+     *   In ANSI_MODE '' decodes to '
+     *   In MYSQL_MODE \x decodes to x (or a small list of specials)
+     */
+    public Character decodeCharacter( PushbackSequence<Character> input ) {
+        switch( mode ) {
+            case ANSI: return decodeCharacterANSI( input );
+            case STANDARD: return decodeCharacterMySQL( input );
+            default: return null;
+        }
+    }
 
-		Character second = input.next();
-		if ( second == null ) {
-			input.reset();
-			return null;
-		}
-		
-		// if this is not an encoded character, return null
-		if ( second.charValue() != '\'' ) {
-			input.reset();
-			return null;
-		}
-		return( Character.valueOf( '\'' ) );
-	}
+    /**
+     * decodeCharacterANSI decodes the next character from ANSI SQL escaping
+     *
+     * @param input
+     *             A PushBackString containing characters you'd like decoded
+     * @return
+     *             A single character, decoded
+     */
+    private Character decodeCharacterANSI( PushbackSequence<Character>  input ) {
+        input.mark();
+        Character first = input.next();
+        if ( first == null ) {
+            input.reset();
+            return null;
+        }
 
-	/**
-	 * decodeCharacterMySQL decodes all the potential escaped characters that MySQL is prepared to escape
-	 * 
-	 * @param input
-	 * 			A string you'd like to be decoded
-	 * @return
-	 * 			A single character from that string, decoded.
-	 */
-	private Character decodeCharacterMySQL( PushbackSequence<Character> input ) {
-		input.mark();
-		Character first = input.next();
-		if ( first == null ) {
-			input.reset();
-			return null;
-		}
-		
-		// if this is not an encoded character, return null
-		if ( first.charValue() != '\\' ) {
-			input.reset();
-			return null;
-		}
+        // if this is not an encoded character, return null
+        if ( first.charValue() != '\'' ) {
+            input.reset();
+            return null;
+        }
 
-		Character second = input.next();
-		if ( second == null ) {
-			input.reset();
-			return null;
-		}
-		
-		if ( second.charValue() == '0' ) {
-			return Character.valueOf( (char)0x00 );
-		} else if ( second.charValue() == 'b' ) {
-			return Character.valueOf( (char)0x08 );
-		} else if ( second.charValue() == 't' ) {
-			return Character.valueOf( (char)0x09 );
-		} else if ( second.charValue() == 'n' ) {
-			return Character.valueOf( (char)0x0a );
-		} else if ( second.charValue() == 'r' ) {
-			return Character.valueOf( (char)0x0d );
-		} else if ( second.charValue() == 'Z' ) {
-			return Character.valueOf( (char)0x1a );
-		} else if ( second.charValue() == '\"' ) {
-			return Character.valueOf( (char)0x22 );
-		} else if ( second.charValue() == '%' ) {
-			return Character.valueOf( (char)0x25 );
-		} else if ( second.charValue() == '\'' ) {
-			return Character.valueOf( (char)0x27 );
-		} else if ( second.charValue() == '\\' ) {
-			return Character.valueOf( (char)0x5c );
-		} else if ( second.charValue() == '_' ) {
-			return Character.valueOf( (char)0x5f );
-		} else {
-			return second;
-		}
-	}
+        Character second = input.next();
+        if ( second == null ) {
+            input.reset();
+            return null;
+        }
+
+        // if this is not an encoded character, return null
+        if ( second.charValue() != '\'' ) {
+            input.reset();
+            return null;
+        }
+        return( Character.valueOf( '\'' ) );
+    }
+
+    /**
+     * decodeCharacterMySQL decodes all the potential escaped characters that MySQL is prepared to escape
+     *
+     * @param input
+     *             A string you'd like to be decoded
+     * @return
+     *             A single character from that string, decoded.
+     */
+    private Character decodeCharacterMySQL( PushbackSequence<Character> input ) {
+        input.mark();
+        Character first = input.next();
+        if ( first == null ) {
+            input.reset();
+            return null;
+        }
+
+        // if this is not an encoded character, return null
+        if ( first.charValue() != '\\' ) {
+            input.reset();
+            return null;
+        }
+
+        Character second = input.next();
+        if ( second == null ) {
+            input.reset();
+            return null;
+        }
+
+        if ( second.charValue() == '0' ) {
+            return Character.valueOf( (char)0x00 );
+        } else if ( second.charValue() == 'b' ) {
+            return Character.valueOf( (char)0x08 );
+        } else if ( second.charValue() == 't' ) {
+            return Character.valueOf( (char)0x09 );
+        } else if ( second.charValue() == 'n' ) {
+            return Character.valueOf( (char)0x0a );
+        } else if ( second.charValue() == 'r' ) {
+            return Character.valueOf( (char)0x0d );
+        } else if ( second.charValue() == 'Z' ) {
+            return Character.valueOf( (char)0x1a );
+        } else if ( second.charValue() == '\"' ) {
+            return Character.valueOf( (char)0x22 );
+        } else if ( second.charValue() == '%' ) {
+            return Character.valueOf( (char)0x25 );
+        } else if ( second.charValue() == '\'' ) {
+            return Character.valueOf( (char)0x27 );
+        } else if ( second.charValue() == '\\' ) {
+            return Character.valueOf( (char)0x5c );
+        } else if ( second.charValue() == '_' ) {
+            return Character.valueOf( (char)0x5f );
+        } else {
+            return second;
+        }
+    }
 
 }
diff --git a/src/main/java/org/owasp/esapi/codecs/OracleCodec.java b/src/main/java/org/owasp/esapi/codecs/OracleCodec.java
index 0021a86..eb91a07 100644
--- a/src/main/java/org/owasp/esapi/codecs/OracleCodec.java
+++ b/src/main/java/org/owasp/esapi/codecs/OracleCodec.java
@@ -20,11 +20,11 @@ package org.owasp.esapi.codecs;
 /**
  * Implementation of the Codec interface for Oracle strings. This function will only protect you from SQLi in the case of user data
  * bring placed within an Oracle quoted string such as:
- * 
+ *
  * select * from table where user_name='  USERDATA    ';
- * 
+ *
  * @see <a href="http://oraqa.com/2006/03/20/how-to-escape-single-quotes-in-strings/">how-to-escape-single-quotes-in-strings</a>
- * 
+ *
  * @author Jeff Williams (jeff.williams .at. aspectsecurity.com) <a href="http://www.aspectsecurity.com">Aspect Security</a>
  * @author Jim Manico (jim@manico.net) <a href="http://www.manico.net">Manico.net</a>
  * @since June 1, 2007
@@ -33,58 +33,58 @@ package org.owasp.esapi.codecs;
 public class OracleCodec extends AbstractCharacterCodec {
 
 
-	/**
-	 * {@inheritDoc}
-	 * 
-	 * Encodes ' to ''
+    /**
+     * {@inheritDoc}
      *
-	 * Encodes ' to ''
+     * Encodes ' to ''
+     *
+     * Encodes ' to ''
      *
      * @param immune
      */
-	public String encodeCharacter( char[] immune, Character c ) {
-		if ( c.charValue() == '\'' )
-        	return "\'\'";
+    public String encodeCharacter( char[] immune, Character c ) {
+        if ( c.charValue() == '\'' )
+            return "\'\'";
         return ""+c;
-	}
-	
+    }
+
 
 
-	/**
-	 * {@inheritDoc}
-	 *
-	 * Returns the decoded version of the character starting at index, or
-	 * null if no decoding is possible.
-	 *
-	 * Formats all are legal
-	 *   '' decodes to '
-	 */
-	public Character decodeCharacter( PushbackSequence<Character> input ) {
-		input.mark();
-		Character first = input.next();
-		if ( first == null ) {
-			input.reset();
-			return null;
-		}
+    /**
+     * {@inheritDoc}
+     *
+     * Returns the decoded version of the character starting at index, or
+     * null if no decoding is possible.
+     *
+     * Formats all are legal
+     *   '' decodes to '
+     */
+    public Character decodeCharacter( PushbackSequence<Character> input ) {
+        input.mark();
+        Character first = input.next();
+        if ( first == null ) {
+            input.reset();
+            return null;
+        }
+
+        // if this is not an encoded character, return null
+        if ( first.charValue() != '\'' ) {
+            input.reset();
+            return null;
+        }
 
-		// if this is not an encoded character, return null
-		if ( first.charValue() != '\'' ) {
-			input.reset();
-			return null;
-		}
+        Character second = input.next();
+        if ( second == null ) {
+            input.reset();
+            return null;
+        }
 
-		Character second = input.next();
-		if ( second == null ) {
-			input.reset();
-			return null;
-		}
-		
-		// if this is not an encoded character, return null
-		if ( second.charValue() != '\'' ) {
-			input.reset();
-			return null;
-		}
-		return( Character.valueOf( '\'' ) );
-	}
+        // if this is not an encoded character, return null
+        if ( second.charValue() != '\'' ) {
+            input.reset();
+            return null;
+        }
+        return( Character.valueOf( '\'' ) );
+    }
 
 }
\ No newline at end of file
diff --git a/src/main/java/org/owasp/esapi/codecs/PercentCodec.java b/src/main/java/org/owasp/esapi/codecs/PercentCodec.java
index ac9e9a5..5775055 100644
--- a/src/main/java/org/owasp/esapi/codecs/PercentCodec.java
+++ b/src/main/java/org/owasp/esapi/codecs/PercentCodec.java
@@ -1,15 +1,15 @@
 /**
  * OWASP Enterprise Security API (ESAPI)
- * 
+ *
  * This file is part of the Open Web Application Security Project (OWASP)
  * Enterprise Security API (ESAPI) project. For details, please see
  * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
  *
  * Copyright (c) 2007 - The OWASP Foundation
- * 
+ *
  * The ESAPI is published by OWASP under the BSD license. You should read and accept the
  * LICENSE before you use, modify, and/or redistribute this software.
- * 
+ *
  * @author Jeff Williams <a href="http://www.aspectsecurity.com">Aspect Security</a>
  * @created 2007
  */
@@ -22,7 +22,7 @@ import org.owasp.esapi.util.CollectionsUtil;
 
 /**
  * Implementation of the Codec interface for percent encoding (aka URL encoding).
- * 
+ *
  * @author Jeff Williams (jeff.williams .at. aspectsecurity.com) <a
  *         href="http://www.aspectsecurity.com">Aspect Security</a>
  * @since June 1, 2007
@@ -30,135 +30,135 @@ import org.owasp.esapi.util.CollectionsUtil;
  */
 public class PercentCodec extends AbstractCharacterCodec
 {
-	private static final String ALPHA_NUMERIC_STR = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
-	@SuppressWarnings("unused")
-	private static final String RFC3986_RESERVED_STR = ":/?#[]@!$&'()*+,;=";
-	private static final String RFC3986_NON_ALPHANUMERIC_UNRESERVED_STR = "-._~";
-		// rfc3986 2.3: For consistency, percent-encoded octets
-		// in the ranges of ALPHA (%41-%5A and %61-%7A), DIGIT
-		// (%30-%39), hyphen (%2D), period (%2E), underscore
-		// (%5F), or tilde (%7E) should not be created by URI
-		// producers
-	private static final boolean ENCODED_NON_ALPHA_NUMERIC_UNRESERVED = true;
-	private static final String UNENCODED_STR = ALPHA_NUMERIC_STR +
-		(ENCODED_NON_ALPHA_NUMERIC_UNRESERVED ? "" : RFC3986_NON_ALPHANUMERIC_UNRESERVED_STR);
-	private static final Set<Character> UNENCODED_SET = CollectionsUtil.strToUnmodifiableSet(UNENCODED_STR);
+    private static final String ALPHA_NUMERIC_STR = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
+    @SuppressWarnings("unused")
+    private static final String RFC3986_RESERVED_STR = ":/?#[]@!$&'()*+,;=";
+    private static final String RFC3986_NON_ALPHANUMERIC_UNRESERVED_STR = "-._~";
+        // rfc3986 2.3: For consistency, percent-encoded octets
+        // in the ranges of ALPHA (%41-%5A and %61-%7A), DIGIT
+        // (%30-%39), hyphen (%2D), period (%2E), underscore
+        // (%5F), or tilde (%7E) should not be created by URI
+        // producers
+    private static final boolean ENCODED_NON_ALPHA_NUMERIC_UNRESERVED = true;
+    private static final String UNENCODED_STR = ALPHA_NUMERIC_STR +
+        (ENCODED_NON_ALPHA_NUMERIC_UNRESERVED ? "" : RFC3986_NON_ALPHANUMERIC_UNRESERVED_STR);
+    private static final Set<Character> UNENCODED_SET = CollectionsUtil.strToUnmodifiableSet(UNENCODED_STR);
 
-	/**
-	 * Convinence method to encode a string into UTF-8. This
-	 * wraps the {@link UnsupportedEncodingException} that
-	 * {@link String#getBytes(String)} throws in a
-	 * {@link IllegalStateException} as UTF-8 support is required
-	 * by the Java spec and should never throw this exception.
-	 * @param str the string to encode
-	 * @return str encoded in UTF-8 as bytes.
-	 * @throws IllegalStateException wrapped {@link
-	 *	UnsupportedEncodingException} if
-	 *	{@link String.getBytes(String)} throws it.
-	 */
-	private static byte[] toUtf8Bytes(String str)
-	{
-		try
-		{
-			return str.getBytes("UTF-8");
-		}
-		catch(UnsupportedEncodingException e)
-		{
-			throw new IllegalStateException("The Java spec requires UTF-8 support.", e);
-		}
-	}
+    /**
+     * Convinence method to encode a string into UTF-8. This
+     * wraps the {@link UnsupportedEncodingException} that
+     * {@link String#getBytes(String)} throws in a
+     * {@link IllegalStateException} as UTF-8 support is required
+     * by the Java spec and should never throw this exception.
+     * @param str the string to encode
+     * @return str encoded in UTF-8 as bytes.
+     * @throws IllegalStateException wrapped {@link
+     *    UnsupportedEncodingException} if
+     *    {@link String.getBytes(String)} throws it.
+     */
+    private static byte[] toUtf8Bytes(String str)
+    {
+        try
+        {
+            return str.getBytes("UTF-8");
+        }
+        catch(UnsupportedEncodingException e)
+        {
+            throw new IllegalStateException("The Java spec requires UTF-8 support.", e);
+        }
+    }
 
-	/**
-	 * Append the two upper case hex characters for a byte.
-	 * @param sb The string buffer to append to.
-	 * @param b The byte to hexify
-	 * @return sb with the hex characters appended.
-	 */
-	// rfc3986 2.1: For consistency, URI producers 
-	// should use uppercase hexadecimal digits for all percent-
-	// encodings.
-	private static StringBuilder appendTwoUpperHex(StringBuilder sb, int b)
-	{
-		if(b < Byte.MIN_VALUE || b > Byte.MAX_VALUE)
-			throw new IllegalArgumentException("b is not a byte (was " + b + ')');
-		b &= 0xFF;
-		if(b<0x10)
-			sb.append('0');
-		return sb.append(Integer.toHexString(b).toUpperCase());
-	}
+    /**
+     * Append the two upper case hex characters for a byte.
+     * @param sb The string buffer to append to.
+     * @param b The byte to hexify
+     * @return sb with the hex characters appended.
+     */
+    // rfc3986 2.1: For consistency, URI producers
+    // should use uppercase hexadecimal digits for all percent-
+    // encodings.
+    private static StringBuilder appendTwoUpperHex(StringBuilder sb, int b)
+    {
+        if(b < Byte.MIN_VALUE || b > Byte.MAX_VALUE)
+            throw new IllegalArgumentException("b is not a byte (was " + b + ')');
+        b &= 0xFF;
+        if(b<0x10)
+            sb.append('0');
+        return sb.append(Integer.toHexString(b).toUpperCase());
+    }
 
-	/**
-	 * Encode a character for URLs
-	 * @param immune Additional characters not to encode. Note this could
+    /**
+     * Encode a character for URLs
+     * @param immune Additional characters not to encode. Note this could
      *               break URL encoding as referenced in RFC 3986. You should
      *               especially be wary of including '%' in this list of immune
      *               characters since it is used as the "escape" character for
      *               the hex encoding and including it may result in subsequent
      *               and/or dangerous results when decoding.
-	 * @param c character to encode
-	 * @return the encoded string representing c
-	 */
-	public String encodeCharacter( char[] immune, Character c )
-	{
-		String cStr = String.valueOf(c.charValue());
-		byte[] bytes;
-		StringBuilder sb;
+     * @param c character to encode
+     * @return the encoded string representing c
+     */
+    public String encodeCharacter( char[] immune, Character c )
+    {
+        String cStr = String.valueOf(c.charValue());
+        byte[] bytes;
+        StringBuilder sb;
 
         // check for user specified immune characters
         if ( immune != null && containsCharacter( c.charValue(), immune ) )
             return cStr;
 
         // check for standard characters (e.g., alphanumeric, etc.)
-		if(UNENCODED_SET.contains(c))
-			return cStr;
+        if(UNENCODED_SET.contains(c))
+            return cStr;
 
-		bytes = toUtf8Bytes(cStr);
-		sb = new StringBuilder(bytes.length * 3);
-		for(byte b : bytes)
-			appendTwoUpperHex(sb.append('%'), b);
-		return sb.toString();
-	}
+        bytes = toUtf8Bytes(cStr);
+        sb = new StringBuilder(bytes.length * 3);
+        for(byte b : bytes)
+            appendTwoUpperHex(sb.append('%'), b);
+        return sb.toString();
+    }
 
-	/**
-	 * {@inheritDoc}
-	 * 
-	 * Formats all are legal both upper/lower case:
-	 *   %hh;
-	 *   
-	 * @param input
-	 * 			encoded character using percent characters (such as URL encoding)
-	 */
-	public Character decodeCharacter( PushbackSequence<Character> input ) {
-		input.mark();
-		Character first = input.next();
-		if ( first == null ) {
-			input.reset();
-			return null;
-		}
+    /**
+     * {@inheritDoc}
+     *
+     * Formats all are legal both upper/lower case:
+     *   %hh;
+     *
+     * @param input
+     *             encoded character using percent characters (such as URL encoding)
+     */
+    public Character decodeCharacter( PushbackSequence<Character> input ) {
+        input.mark();
+        Character first = input.next();
+        if ( first == null ) {
+            input.reset();
+            return null;
+        }
 
-		// if this is not an encoded character, return null
-		if (first != '%' ) {
-			input.reset();
-			return null;
-		}
+        // if this is not an encoded character, return null
+        if (first != '%' ) {
+            input.reset();
+            return null;
+        }
 
-		// Search for exactly 2 hex digits following
-		StringBuilder sb = new StringBuilder();
-		for ( int i=0; i<2; i++ ) {
-			Character c = input.nextHex();
-			if ( c != null ) sb.append( c );
-		}
-		if ( sb.length() == 2 ) {
-			try {
-				// parse the hex digit and create a character
-				int i = Integer.parseInt(sb.toString(), 16);
-				if (Character.isValidCodePoint(i)) {
-					return (char) i;
-				}
-			} catch( NumberFormatException ignored ) { }
-		}
-		input.reset();
-		return null;
-	}
+        // Search for exactly 2 hex digits following
+        StringBuilder sb = new StringBuilder();
+        for ( int i=0; i<2; i++ ) {
+            Character c = input.nextHex();
+            if ( c != null ) sb.append( c );
+        }
+        if ( sb.length() == 2 ) {
+            try {
+                // parse the hex digit and create a character
+                int i = Integer.parseInt(sb.toString(), 16);
+                if (Character.isValidCodePoint(i)) {
+                    return (char) i;
+                }
+            } catch( NumberFormatException ignored ) { }
+        }
+        input.reset();
+        return null;
+    }
 
 }
diff --git a/src/main/java/org/owasp/esapi/codecs/PushBackSequenceImpl.java b/src/main/java/org/owasp/esapi/codecs/PushBackSequenceImpl.java
index adfa9e8..9f0c522 100644
--- a/src/main/java/org/owasp/esapi/codecs/PushBackSequenceImpl.java
+++ b/src/main/java/org/owasp/esapi/codecs/PushBackSequenceImpl.java
@@ -4,7 +4,7 @@ package org.owasp.esapi.codecs;
 /**
  * The pushback string is used by Codecs to allow them to push decoded characters back onto a string
  * for further decoding. This is necessary to detect double-encoding.
- * 
+ *
  * @author Jeff Williams (jeff.williams .at. aspectsecurity.com) <a
  *         href="http://www.aspectsecurity.com">Aspect Security</a>
  * @since June 1, 2007
@@ -16,121 +16,121 @@ public class PushBackSequenceImpl extends AbstractPushbackSequence<Integer>{
      * @param input
      */
     public PushBackSequenceImpl( String input ) {
-		super(input);
-	}
-	
+        super(input);
+    }
+
     /**
      *
      * @return The next value in this Sequence, as an Integer.
      */
     public Integer next() {
-		if ( pushback != null ) {
-			Integer save = pushback;
-			pushback = null;
-			return save;
-		}
-		if ( input == null ) return null;
-		if ( input.length() == 0 ) return null;
-		if ( index >= input.length() ) return null;
-		final Integer point = input.codePointAt(index);
-		index += Character.charCount(point);
-		return point;
-	}
-	
+        if ( pushback != null ) {
+            Integer save = pushback;
+            pushback = null;
+            return save;
+        }
+        if ( input == null ) return null;
+        if ( input.length() == 0 ) return null;
+        if ( index >= input.length() ) return null;
+        final Integer point = input.codePointAt(index);
+        index += Character.charCount(point);
+        return point;
+    }
+
     /**
     *
     * @return The next value in this Sequence, as an Integer if it is a hex digit. Null otherwise.
     */
    public Integer nextHex() {
-		Integer c = next();
-		if ( c == null ) return null;
-		if ( isHexDigit( c ) ) return c;
-		return null;
-	}
+        Integer c = next();
+        if ( c == null ) return null;
+        if ( isHexDigit( c ) ) return c;
+        return null;
+    }
 
    /**
    *
    * @return The next value in this Sequence, as an Integer if it is an octal digit. Null otherwise.
    */
   public Integer nextOctal() {
-		Integer c = next();
-		if ( c == null ) return null;
-		if ( isOctalDigit( c ) ) return c;
-		return null;
-	}
+        Integer c = next();
+        if ( c == null ) return null;
+        if ( isOctalDigit( c ) ) return c;
+        return null;
+    }
 
-	  /**
-	  * Returns true if the parameter character is a hexidecimal digit 0 through 9, a through f, or A through F.
-	  * @param c
-	  * @return true if it is a hexidecimal digit, false otherwise.
-	  */
-	 public static boolean isHexDigit( Integer c ) {
-		if ( c == null ) return false;
-		Integer ch = Integer.valueOf(c);
-		return (ch >= '0' && ch <= '9' ) || (ch >= 'a' && ch <= 'f' ) || (ch >= 'A' && ch <= 'F' );
-	}
+      /**
+      * Returns true if the parameter character is a hexidecimal digit 0 through 9, a through f, or A through F.
+      * @param c
+      * @return true if it is a hexidecimal digit, false otherwise.
+      */
+     public static boolean isHexDigit( Integer c ) {
+        if ( c == null ) return false;
+        Integer ch = Integer.valueOf(c);
+        return (ch >= '0' && ch <= '9' ) || (ch >= 'a' && ch <= 'f' ) || (ch >= 'A' && ch <= 'F' );
+    }
 
-	 /**
-	 * Returns true if the parameter character is an octal digit 0 through 7.
-	 * @param c
-	 * @return true if it is an octal digit, false otherwise.
-	 */
-	public static boolean isOctalDigit( Integer c ) {
-		if ( c == null ) return false;
-		Integer ch = Integer.valueOf(c); 
-		return ch >= '0' && ch <= '7';
-	}
+     /**
+     * Returns true if the parameter character is an octal digit 0 through 7.
+     * @param c
+     * @return true if it is an octal digit, false otherwise.
+     */
+    public static boolean isOctalDigit( Integer c ) {
+        if ( c == null ) return false;
+        Integer ch = Integer.valueOf(c);
+        return ch >= '0' && ch <= '7';
+    }
 
     /**
      * Return the next codePoint without affecting the current index.
      * @return the next codePoint
      */
     public Integer peek() {
-		if ( pushback != null ) return pushback;
-		if ( input == null ) return null;
-		if ( input.length() == 0 ) return null;
-		if ( index >= input.length() ) return null;		
-		return input.codePointAt(index);
-	}
-	
+        if ( pushback != null ) return pushback;
+        if ( input == null ) return null;
+        if ( input.length() == 0 ) return null;
+        if ( index >= input.length() ) return null;
+        return input.codePointAt(index);
+    }
+
     /**
      * Test to see if the next codePoint is a particular value without affecting the current index.
      * @param c
      * @return if the next value is equal to the supplied value.
      */
     public boolean peek( Integer c ) {
-		if ( pushback != null && pushback.intValue() == c ) return true;
-		if ( input == null ) return false;
-		if ( input.length() == 0 ) return false;
-		if ( index >= input.length() ) return false;		
-		return input.codePointAt(index) == c;
-	}	
-	
+        if ( pushback != null && pushback.intValue() == c ) return true;
+        if ( input == null ) return false;
+        if ( input.length() == 0 ) return false;
+        if ( index >= input.length() ) return false;
+        return input.codePointAt(index) == c;
+    }
+
     /**
      * {@inheritDoc}
      */
     public void mark() {
-		temp = pushback;
-		mark = index;
-	}
+        temp = pushback;
+        mark = index;
+    }
 
     /**
      * {@inheritDoc}
      */
     public void reset() {
-		pushback = temp;
-		index = mark;
-	}
-	
+        pushback = temp;
+        index = mark;
+    }
+
     /**
      * {@inheritDoc}
      */
     public String remainder() {
-		String output = input.substring( index );
-		if ( pushback != null ) {
-			output = pushback + output;
-		}
-		return output;
-	}
+        String output = input.substring( index );
+        if ( pushback != null ) {
+            output = pushback + output;
+        }
+        return output;
+    }
 
 }
diff --git a/src/main/java/org/owasp/esapi/codecs/PushbackSequence.java b/src/main/java/org/owasp/esapi/codecs/PushbackSequence.java
index e3aab4d..d2edcb6 100644
--- a/src/main/java/org/owasp/esapi/codecs/PushbackSequence.java
+++ b/src/main/java/org/owasp/esapi/codecs/PushbackSequence.java
@@ -1,89 +1,89 @@
 /**
  * OWASP Enterprise Security API (ESAPI)
- * 
+ *
  * This file is part of the Open Web Application Security Project (OWASP)
  * Enterprise Security API (ESAPI) project. For details, please see
  * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
  *
  * Copyright (c) 2017 - The OWASP Foundation
- * 
+ *
  * The ESAPI is published by OWASP under the BSD license. You should read and accept the
  * LICENSE before you use, modify, and/or redistribute this software.
- * 
+ *
  * @author Matt Seil (mseil .at. owasp.org)
  * @created 2017
- * 
+ *
  */
 package org.owasp.esapi.codecs;
 
 public interface PushbackSequence<T> {
 
-	/**
-	 *
-	 * @param c
-	 */
-	void pushback(T c);
+    /**
+     *
+     * @param c
+     */
+    void pushback(T c);
 
-	/**
-	 * Get the current index of the PushbackString. Typically used in error messages.
-	 * @return The current index of the PushbackSequence.
-	 */
-	int index();
+    /**
+     * Get the current index of the PushbackString. Typically used in error messages.
+     * @return The current index of the PushbackSequence.
+     */
+    int index();
 
-	/**
-	 * Determine if this sequence has another element.
-	 *
-	 * @return True if there is another element in this sequence. False otherwise.
-	 */
-	boolean hasNext();
+    /**
+     * Determine if this sequence has another element.
+     *
+     * @return True if there is another element in this sequence. False otherwise.
+     */
+    boolean hasNext();
 
-	/**
-	 * Return the next element in the Sequence and increment the current index.
-	 * @return The next element in the Sequence.
-	 */
-	T next();
+    /**
+     * Return the next element in the Sequence and increment the current index.
+     * @return The next element in the Sequence.
+     */
+    T next();
 
-	/**
-	 * Return the next element in the Sequence in Hex format and increment the current index.
-	 * @return The next element in the Sequence in Hex format (if that makes sense for this Sequence's type).
+    /**
+     * Return the next element in the Sequence in Hex format and increment the current index.
+     * @return The next element in the Sequence in Hex format (if that makes sense for this Sequence's type).
      */
-	T nextHex();
+    T nextHex();
 
-	/**
-	 * Return the next element in the Sequence in Octal format and increment the current index.
-	 * @return The next element in the Sequence in Octal format (if that makes sense for this Sequence's type).
-	 */
-	T nextOctal();
+    /**
+     * Return the next element in the Sequence in Octal format and increment the current index.
+     * @return The next element in the Sequence in Octal format (if that makes sense for this Sequence's type).
+     */
+    T nextOctal();
 
-	/**
-	 * Return the next element in the Sequence without affecting the current index.
-	 * @return the next element in the Sequence.
-	 */
-	T peek();
+    /**
+     * Return the next element in the Sequence without affecting the current index.
+     * @return the next element in the Sequence.
+     */
+    T peek();
 
-	/**
-	 * Test to see if the next element in the Sequence matches the supplied value without affecting the current index.
-	 * @param c The value to match against.
-	 * @return True if the next element matches the supplied value. False otherwise.
-	 */
-	boolean peek(T c);
+    /**
+     * Test to see if the next element in the Sequence matches the supplied value without affecting the current index.
+     * @param c The value to match against.
+     * @return True if the next element matches the supplied value. False otherwise.
+     */
+    boolean peek(T c);
 
-	/**
-	 * Mark the location of the current index.
-	 */
-	void mark();
+    /**
+     * Mark the location of the current index.
+     */
+    void mark();
 
-	/**
-	 * Set the index back to the last marked location.
-	 */
-	void reset();
+    /**
+     * Set the index back to the last marked location.
+     */
+    void reset();
 
-	/**
-	 * Not at all sure what this method is intended to do.  There 
-	 * is a line in HTMLEntityCodec that said calling this method 
-	 * is a "kludge around PushbackString..."
-	 * @return Return the remaining portion of the sequence, with any pushback appended to the front (if any).
-	 */
-	String remainder();
+    /**
+     * Not at all sure what this method is intended to do.  There
+     * is a line in HTMLEntityCodec that said calling this method
+     * is a "kludge around PushbackString..."
+     * @return Return the remaining portion of the sequence, with any pushback appended to the front (if any).
+     */
+    String remainder();
 
 }
\ No newline at end of file
diff --git a/src/main/java/org/owasp/esapi/codecs/PushbackString.java b/src/main/java/org/owasp/esapi/codecs/PushbackString.java
index fb133b5..b25cc1f 100644
--- a/src/main/java/org/owasp/esapi/codecs/PushbackString.java
+++ b/src/main/java/org/owasp/esapi/codecs/PushbackString.java
@@ -1,18 +1,18 @@
 /**
  * OWASP Enterprise Security API (ESAPI)
- * 
+ *
  * This file is part of the Open Web Application Security Project (OWASP)
  * Enterprise Security API (ESAPI) project. For details, please see
  * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
  *
  * Copyright (c) 2017 - The OWASP Foundation
- * 
+ *
  * The ESAPI is published by OWASP under the BSD license. You should read and accept the
  * LICENSE before you use, modify, and/or redistribute this software.
- * 
+ *
  * @author Matt Seil (mseil .at. owasp.org)
  * @updated 2017
- * 
+ *
  * @author Jeff Williams (jeff.williams .at. aspectsecurity.com) <a
  *         href="http://www.aspectsecurity.com">Aspect Security</a>
  * @created 2007
@@ -23,7 +23,7 @@ package org.owasp.esapi.codecs;
  * The pushback string is used by Codecs to allow them to push decoded
  * characters back onto a string for further decoding. This is necessary to
  * detect double-encoding.
- * 
+ *
  * @author Jeff Williams (jeff.williams .at. aspectsecurity.com)
  *         <a href="http://www.aspectsecurity.com">Aspect Security</a>
  * @since June 1, 2007
@@ -31,193 +31,193 @@ package org.owasp.esapi.codecs;
  */
 public class PushbackString extends AbstractPushbackSequence<Character> {
 
-	/**
+    /**
      * @param input Construct a PushbackString with the specified String.
-	 */
-	public PushbackString(String input) {
-		super(input);
-	}
+     */
+    public PushbackString(String input) {
+        super(input);
+    }
 
-	/*
-	 * (non-Javadoc)
-	 * 
-	 * @see org.owasp.esapi.codecs.PushbackSequence#index()
-	 */
-	public int index() {
-		return index;
-	}
+    /*
+     * (non-Javadoc)
+     *
+     * @see org.owasp.esapi.codecs.PushbackSequence#index()
+     */
+    public int index() {
+        return index;
+    }
 
-	/*
-	 * (non-Javadoc)
-	 * 
-	 * @see org.owasp.esapi.codecs.PushbackSequence#hasNext()
-	 */
-	public boolean hasNext() {
-		if (pushback != null){
-			return true;
-		}
-		if (input == null){
-			return false;
-		}
-		if (input.length() == 0){
-			return false;
-		}
-		if (index >= input.length()){
-			return false;
-		}
-		return true;
-	}
+    /*
+     * (non-Javadoc)
+     *
+     * @see org.owasp.esapi.codecs.PushbackSequence#hasNext()
+     */
+    public boolean hasNext() {
+        if (pushback != null){
+            return true;
+        }
+        if (input == null){
+            return false;
+        }
+        if (input.length() == 0){
+            return false;
+        }
+        if (index >= input.length()){
+            return false;
+        }
+        return true;
+    }
 
-	/*
-	 * (non-Javadoc)
-	 * 
-	 * @see org.owasp.esapi.codecs.PushbackSequence#next()
-	 */
-	public Character next() {
-		if (pushback != null) {
-			Character save = pushback;
-			pushback = null;
-			return save;
-		}
-		if (input == null){
-			return null;
-		}
-		if (input.length() == 0){
-			return null;
-		}
-		if (index >= input.length()){
-			return null;
-		}
-		return Character.valueOf(input.charAt(index++));
-	}
+    /*
+     * (non-Javadoc)
+     *
+     * @see org.owasp.esapi.codecs.PushbackSequence#next()
+     */
+    public Character next() {
+        if (pushback != null) {
+            Character save = pushback;
+            pushback = null;
+            return save;
+        }
+        if (input == null){
+            return null;
+        }
+        if (input.length() == 0){
+            return null;
+        }
+        if (index >= input.length()){
+            return null;
+        }
+        return Character.valueOf(input.charAt(index++));
+    }
 
-	/*
-	 * (non-Javadoc)
-	 * 
-	 * @see org.owasp.esapi.codecs.PushbackSequence#nextHex()
-	 */
-	public Character nextHex() {
-		Character c = next();
-		if (c == null){
-			return null;
-		}
-		if (isHexDigit(c)){
-			return c;
-		}
-		return null;
-	}
+    /*
+     * (non-Javadoc)
+     *
+     * @see org.owasp.esapi.codecs.PushbackSequence#nextHex()
+     */
+    public Character nextHex() {
+        Character c = next();
+        if (c == null){
+            return null;
+        }
+        if (isHexDigit(c)){
+            return c;
+        }
+        return null;
+    }
 
-	/*
-	 * (non-Javadoc)
-	 * 
-	 * @see org.owasp.esapi.codecs.PushbackSequence#nextOctal()
-	 */
-	public Character nextOctal() {
-		Character c = next();
-		if (c == null){
-			return null;
-		}
-		if (isOctalDigit(c)){
-			return c;
-		}
-		return null;
-	}
+    /*
+     * (non-Javadoc)
+     *
+     * @see org.owasp.esapi.codecs.PushbackSequence#nextOctal()
+     */
+    public Character nextOctal() {
+        Character c = next();
+        if (c == null){
+            return null;
+        }
+        if (isOctalDigit(c)){
+            return c;
+        }
+        return null;
+    }
 
-	/**
-	 * Returns true if the parameter character is a hexidecimal digit 0 through
-	 * 9, a through f, or A through F.
-	 * 
-	 * @param c
-	  * @return true if it is a hexidecimal digit, false otherwise.
-	 */
-	public static boolean isHexDigit(Character c) {
-		if (c == null){
-			return false;
-		}
-		char ch = c.charValue();
-		return (ch >= '0' && ch <= '9') || (ch >= 'a' && ch <= 'f') || (ch >= 'A' && ch <= 'F');
-	}
+    /**
+     * Returns true if the parameter character is a hexidecimal digit 0 through
+     * 9, a through f, or A through F.
+     *
+     * @param c
+      * @return true if it is a hexidecimal digit, false otherwise.
+     */
+    public static boolean isHexDigit(Character c) {
+        if (c == null){
+            return false;
+        }
+        char ch = c.charValue();
+        return (ch >= '0' && ch <= '9') || (ch >= 'a' && ch <= 'f') || (ch >= 'A' && ch <= 'F');
+    }
 
-	/**
-	 * Returns true if the parameter character is an octal digit 0 through 7.
-	 * 
-	 * @param c
-	  * @return true if it is an octal digit, false otherwise.
-	 */
-	public static boolean isOctalDigit(Character c) {
-		if (c == null){
-			return false;
-		}
-		char ch = c.charValue();
-		return ch >= '0' && ch <= '7';
-	}
+    /**
+     * Returns true if the parameter character is an octal digit 0 through 7.
+     *
+     * @param c
+      * @return true if it is an octal digit, false otherwise.
+     */
+    public static boolean isOctalDigit(Character c) {
+        if (c == null){
+            return false;
+        }
+        char ch = c.charValue();
+        return ch >= '0' && ch <= '7';
+    }
 
-	/*
-	 * (non-Javadoc)
-	 * 
-	 * @see org.owasp.esapi.codecs.PushbackSequence#peek()
-	 */
-	public Character peek() {
-		if (pushback != null){
-			return pushback;
-		}
-		if (input == null){
-			return null;
-		}
-		if (input.length() == 0){
-			return null;
-		}
-		if (index >= input.length()){
-			return null;
-		}
-		return Character.valueOf(input.charAt(index));
-	}
+    /*
+     * (non-Javadoc)
+     *
+     * @see org.owasp.esapi.codecs.PushbackSequence#peek()
+     */
+    public Character peek() {
+        if (pushback != null){
+            return pushback;
+        }
+        if (input == null){
+            return null;
+        }
+        if (input.length() == 0){
+            return null;
+        }
+        if (index >= input.length()){
+            return null;
+        }
+        return Character.valueOf(input.charAt(index));
+    }
 
-	/*
-	 * (non-Javadoc)
-	 * 
-	 * @see org.owasp.esapi.codecs.PushbackSequence#peek(char)
-	 */
-	public boolean peek(Character c) {
-		if (pushback != null && pushback.charValue() == c){
-			return true;
-		}
-		if (input == null){
-			return false;
-		}
-		if (input.length() == 0){
-			return false;
-		}
-		if (index >= input.length()){
-			return false;
-		}
-		return input.charAt(index) == c;
-	}
+    /*
+     * (non-Javadoc)
+     *
+     * @see org.owasp.esapi.codecs.PushbackSequence#peek(char)
+     */
+    public boolean peek(Character c) {
+        if (pushback != null && pushback.charValue() == c){
+            return true;
+        }
+        if (input == null){
+            return false;
+        }
+        if (input.length() == 0){
+            return false;
+        }
+        if (index >= input.length()){
+            return false;
+        }
+        return input.charAt(index) == c;
+    }
 
-	/**
-	 * {@inheritDoc}
-	 */
-	public void mark() {
-		temp = pushback;
-		mark = index;
-	}
+    /**
+     * {@inheritDoc}
+     */
+    public void mark() {
+        temp = pushback;
+        mark = index;
+    }
 
-	/**
-	 * {@inheritDoc}
-	 */
-	public void reset() {
-		pushback = temp;
-		index = mark;
-	}
+    /**
+     * {@inheritDoc}
+     */
+    public void reset() {
+        pushback = temp;
+        index = mark;
+    }
 
-	/**
-	 * {@inheritDoc}
-	 */
-	public String remainder() {
-		String output = input.substring(index);
-		if (pushback != null) {
-			output = pushback + output;
-		}
-		return output;
-	}
+    /**
+     * {@inheritDoc}
+     */
+    public String remainder() {
+        String output = input.substring(index);
+        if (pushback != null) {
+            output = pushback + output;
+        }
+        return output;
+    }
 }
\ No newline at end of file
diff --git a/src/main/java/org/owasp/esapi/codecs/Trie.java b/src/main/java/org/owasp/esapi/codecs/Trie.java
index da11268..fbb8c99 100644
--- a/src/main/java/org/owasp/esapi/codecs/Trie.java
+++ b/src/main/java/org/owasp/esapi/codecs/Trie.java
@@ -9,164 +9,164 @@ import java.util.Set;
 
 public interface Trie<T> extends Map<CharSequence,T>
 {
-	public Map.Entry<CharSequence,T> getLongestMatch(CharSequence key);
-	public Map.Entry<CharSequence,T> getLongestMatch(PushbackReader keyIn) throws IOException;
-	public int getMaxKeyLength();
-
-	static class TrieProxy<T> implements Trie<T>
-	{
-		private Trie<T> wrapped;
-
-		TrieProxy(Trie<T> toWrap)
-		{
-			wrapped = toWrap;
-		}
-
-		protected Trie<T> getWrapped()
-		{
-			return wrapped;
-		}
-
-		public Map.Entry<CharSequence,T> getLongestMatch(CharSequence key)
-		{
-			return wrapped.getLongestMatch(key);
-		}
-
-		public Map.Entry<CharSequence,T> getLongestMatch(PushbackReader keyIn) throws IOException
-		{
-			return wrapped.getLongestMatch(keyIn);
-		}
-
-		public int getMaxKeyLength()
-		{
-			return wrapped.getMaxKeyLength();
-		}
-
-		/* java.util.Map: */
-
-    		public int size()
-		{
-			return wrapped.size();
-		}
-
-    		public boolean isEmpty()
-		{
-			return wrapped.isEmpty();
-		}
-
-    		public boolean containsKey(Object key)
-		{
-			return wrapped.containsKey(key);
-		}
-
-    		public boolean containsValue(Object val)
-		{
-			return wrapped.containsValue(val);
-		}
-
-    		public T get(Object key)
-		{
-			return wrapped.get(key);
-		}
-
-    		public T put(CharSequence key, T value)
-		{
-			return wrapped.put(key, value);
-		}
-
-    		public T remove(Object key)
-		{
-			return wrapped.remove(key);
-		}
-
-    		public void putAll(Map<? extends CharSequence,? extends T> t)
-		{
-			wrapped.putAll(t);
-		}
-
-    		public void clear()
-		{
-			wrapped.clear();
-		}
-
-    		public Set<CharSequence> keySet()
-		{
-			return wrapped.keySet();
-		}
-
-    		public Collection<T> values()
-		{
-			return wrapped.values();
-		}
-
-    		public Set<Map.Entry<CharSequence,T>> entrySet()
-		{
-			return wrapped.entrySet();
-		}
-
-    		public boolean equals(Object other)
-		{
-			return wrapped.equals(other);
-		}
-
-    		public int hashCode()
-		{
-			return wrapped.hashCode();
-		}
-	}
-
-	static class Unmodifiable<T> extends TrieProxy<T>
-	{
-		Unmodifiable(Trie<T> toWrap)
-		{
-			super(toWrap);
-		}
-
-    		public T put(CharSequence key, T value)
-		{
-			throw new UnsupportedOperationException("Unmodifiable Trie");
-		}
-
-    		public T remove(CharSequence key)
-		{
-			throw new UnsupportedOperationException("Unmodifiable Trie");
-		}
-
-    		public void putAll(Map<? extends CharSequence,? extends T> t)
-		{
-			throw new UnsupportedOperationException("Unmodifiable Trie");
-		}
-
-    		public void clear()
-		{
-			throw new UnsupportedOperationException("Unmodifiable Trie");
-		}
-
-    		public Set<CharSequence> keySet()
-		{
-			return Collections.unmodifiableSet(super.keySet());
-		}
-
-    		public Collection<T> values()
-		{
-			return Collections.unmodifiableCollection(super.values());
-		}
-
-    		public Set<Map.Entry<CharSequence,T>> entrySet()
-		{
-			return Collections.unmodifiableSet(super.entrySet());
-		}
-	}
-
-	public static class Util
-	{
-		private Util()
-		{
-		}
-
-		static <T> Trie<T> unmodifiable(Trie<T> toWrap)
-		{
-			return new Unmodifiable<T>(toWrap);
-		}
-	}
+    public Map.Entry<CharSequence,T> getLongestMatch(CharSequence key);
+    public Map.Entry<CharSequence,T> getLongestMatch(PushbackReader keyIn) throws IOException;
+    public int getMaxKeyLength();
+
+    static class TrieProxy<T> implements Trie<T>
+    {
+        private Trie<T> wrapped;
+
+        TrieProxy(Trie<T> toWrap)
+        {
+            wrapped = toWrap;
+        }
+
+        protected Trie<T> getWrapped()
+        {
+            return wrapped;
+        }
+
+        public Map.Entry<CharSequence,T> getLongestMatch(CharSequence key)
+        {
+            return wrapped.getLongestMatch(key);
+        }
+
+        public Map.Entry<CharSequence,T> getLongestMatch(PushbackReader keyIn) throws IOException
+        {
+            return wrapped.getLongestMatch(keyIn);
+        }
+
+        public int getMaxKeyLength()
+        {
+            return wrapped.getMaxKeyLength();
+        }
+
+        /* java.util.Map: */
+
+            public int size()
+        {
+            return wrapped.size();
+        }
+
+            public boolean isEmpty()
+        {
+            return wrapped.isEmpty();
+        }
+
+            public boolean containsKey(Object key)
+        {
+            return wrapped.containsKey(key);
+        }
+
+            public boolean containsValue(Object val)
+        {
+            return wrapped.containsValue(val);
+        }
+
+            public T get(Object key)
+        {
+            return wrapped.get(key);
+        }
+
+            public T put(CharSequence key, T value)
+        {
+            return wrapped.put(key, value);
+        }
+
+            public T remove(Object key)
+        {
+            return wrapped.remove(key);
+        }
+
+            public void putAll(Map<? extends CharSequence,? extends T> t)
+        {
+            wrapped.putAll(t);
+        }
+
+            public void clear()
+        {
+            wrapped.clear();
+        }
+
+            public Set<CharSequence> keySet()
+        {
+            return wrapped.keySet();
+        }
+
+            public Collection<T> values()
+        {
+            return wrapped.values();
+        }
+
+            public Set<Map.Entry<CharSequence,T>> entrySet()
+        {
+            return wrapped.entrySet();
+        }
+
+            public boolean equals(Object other)
+        {
+            return wrapped.equals(other);
+        }
+
+            public int hashCode()
+        {
+            return wrapped.hashCode();
+        }
+    }
+
+    static class Unmodifiable<T> extends TrieProxy<T>
+    {
+        Unmodifiable(Trie<T> toWrap)
+        {
+            super(toWrap);
+        }
+
+            public T put(CharSequence key, T value)
+        {
+            throw new UnsupportedOperationException("Unmodifiable Trie");
+        }
+
+            public T remove(CharSequence key)
+        {
+            throw new UnsupportedOperationException("Unmodifiable Trie");
+        }
+
+            public void putAll(Map<? extends CharSequence,? extends T> t)
+        {
+            throw new UnsupportedOperationException("Unmodifiable Trie");
+        }
+
+            public void clear()
+        {
+            throw new UnsupportedOperationException("Unmodifiable Trie");
+        }
+
+            public Set<CharSequence> keySet()
+        {
+            return Collections.unmodifiableSet(super.keySet());
+        }
+
+            public Collection<T> values()
+        {
+            return Collections.unmodifiableCollection(super.values());
+        }
+
+            public Set<Map.Entry<CharSequence,T>> entrySet()
+        {
+            return Collections.unmodifiableSet(super.entrySet());
+        }
+    }
+
+    public static class Util
+    {
+        private Util()
+        {
+        }
+
+        static <T> Trie<T> unmodifiable(Trie<T> toWrap)
+        {
+            return new Unmodifiable<T>(toWrap);
+        }
+    }
 }
diff --git a/src/main/java/org/owasp/esapi/codecs/UnixCodec.java b/src/main/java/org/owasp/esapi/codecs/UnixCodec.java
index faeebad..aa513b9 100644
--- a/src/main/java/org/owasp/esapi/codecs/UnixCodec.java
+++ b/src/main/java/org/owasp/esapi/codecs/UnixCodec.java
@@ -1,15 +1,15 @@
 /**
  * OWASP Enterprise Security API (ESAPI)
- * 
+ *
  * This file is part of the Open Web Application Security Project (OWASP)
  * Enterprise Security API (ESAPI) project. For details, please see
  * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
  *
  * Copyright (c) 2007 - The OWASP Foundation
- * 
+ *
  * The ESAPI is published by OWASP under the BSD license. You should read and accept the
  * LICENSE before you use, modify, and/or redistribute this software.
- * 
+ *
  * @author Jeff Williams <a href="http://www.aspectsecurity.com">Aspect Security</a>
  * @created 2007
  */
@@ -17,8 +17,8 @@ package org.owasp.esapi.codecs;
 
 
 /**
- * Implementation of the Codec interface for '\' encoding from Unix command shell.
- * 
+ * Implementation of the {@code Codec} interface for '\' encoding from Unix command shell (bash lineage, not csh lineage).
+ *
  * @author Jeff Williams (jeff.williams .at. aspectsecurity.com) <a
  *         href="http://www.aspectsecurity.com">Aspect Security</a>
  * @since June 1, 2007
@@ -26,57 +26,61 @@ package org.owasp.esapi.codecs;
  */
 public class UnixCodec extends AbstractCharacterCodec {
 
-	/**
-	 * {@inheritDoc}
-	 * 
-	 * Returns backslash-encoded character
+    /**
+     * {@inheritDoc}
      *
-     * @param immune
+     * @return the backslash-encoded character
+     *
+     * @param immune Array of characters that should not be encoded. Use with caution! All
+     *               alphanumeric characters are "immune" by default so you needn't
+     *               include them.
      */
-	public String encodeCharacter( char[] immune, Character c ) {
-		char ch = c.charValue();
-		
-		// check for immune characters
-		if ( containsCharacter( ch, immune ) ) {
-			return ""+ch;
-		}
-		
-		// check for alphanumeric characters
-		String hex = super.getHexForNonAlphanumeric( ch );
-		if ( hex == null ) {
-			return ""+ch;
-		}
-		
+    public String encodeCharacter( char[] immune, Character c ) {
+        char ch = c.charValue();
+
+        // check for immune characters
+        if ( containsCharacter( ch, immune ) ) {
+            return ""+ch;
+        }
+
+        // check for alphanumeric characters
+        String hex = super.getHexForNonAlphanumeric( ch );
+        if ( hex == null ) {
+            return ""+ch;
+        }
+
         return "\\" + c;
-	}
-	
-	
-	/**
-	 * {@inheritDoc}
-	 * 
-	 * Returns the decoded version of the character starting at index, or
-	 * null if no decoding is possible.
-	 * <p>
-	 * Formats all are legal both upper/lower case:
-	 *   \x - all special characters
-	 *   
-	 */
-	public Character decodeCharacter( PushbackSequence<Character> input ) {
-		input.mark();
-		Character first = input.next();
-		if ( first == null ) {
-			input.reset();
-			return null;
-		}
-		
-		// if this is not an encoded character, return null
-		if ( first.charValue() != '\\' ) {
-			input.reset();
-			return null;
-		}
+    }
+
+
+    /**
+     * {@inheritDoc}
+     *
+     * <p>
+     * Formats all are legal both upper/lower case:
+     * <pre>
+     *   \x - all special characters
+     * </pre>
+     *
+     * @return the decoded version of the character starting at index, or
+     * null if no decoding is possible.
+     */
+    public Character decodeCharacter( PushbackSequence<Character> input ) {
+        input.mark();
+        Character first = input.next();
+        if ( first == null ) {
+            input.reset();
+            return null;
+        }
+
+        // if this is not an encoded character, return null
+        if ( first.charValue() != '\\' ) {
+            input.reset();
+            return null;
+        }
 
-		Character second = input.next();
-		return second;
-	}
+        Character second = input.next();
+        return second;
+    }
 
-}
\ No newline at end of file
+}
diff --git a/src/main/java/org/owasp/esapi/codecs/VBScriptCodec.java b/src/main/java/org/owasp/esapi/codecs/VBScriptCodec.java
index 122e90a..5f768ec 100644
--- a/src/main/java/org/owasp/esapi/codecs/VBScriptCodec.java
+++ b/src/main/java/org/owasp/esapi/codecs/VBScriptCodec.java
@@ -1,15 +1,15 @@
 /**
  * OWASP Enterprise Security API (ESAPI)
- * 
+ *
  * This file is part of the Open Web Application Security Project (OWASP)
  * Enterprise Security API (ESAPI) project. For details, please see
  * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
  *
  * Copyright (c) 2007 - The OWASP Foundation
- * 
+ *
  * The ESAPI is published by OWASP under the BSD license. You should read and accept the
  * LICENSE before you use, modify, and/or redistribute this software.
- * 
+ *
  * @author Jeff Williams <a href="http://www.aspectsecurity.com">Aspect Security</a>
  * @created 2007
  */
@@ -20,7 +20,7 @@ import org.owasp.esapi.EncoderConstants;
 
 /**
  * Implementation of the Codec interface for 'quote' encoding from VBScript.
- * 
+ *
  * @author Jeff Williams (jeff.williams .at. aspectsecurity.com) <a
  *         href="http://www.aspectsecurity.com">Aspect Security</a>
  * @since June 1, 2007
@@ -28,90 +28,90 @@ import org.owasp.esapi.EncoderConstants;
  */
 public class VBScriptCodec extends AbstractCharacterCodec {
 
-	/**
-	 * Encode a String so that it can be safely used in a specific context.
-	 * 
+    /**
+     * Encode a String so that it can be safely used in a specific context.
+     *
      * @param immune
      * @param input
-	 * 		the String to encode
-	 * @return the encoded String
-	 */
+     *         the String to encode
+     * @return the encoded String
+     */
     public String encode(char[] immune, String input) {
-    	StringBuilder sb = new StringBuilder();
-		boolean encoding = false;
-		boolean inquotes = false;
-		for ( int i=0; i<input.length(); i++ ) {
-			char c = input.charAt(i);
-			
-			// handle normal characters and surround them with quotes
-			if (containsCharacter(c, EncoderConstants.CHAR_ALPHANUMERICS) || containsCharacter(c, immune)) {
-				if ( encoding && i > 0 ) sb.append( "&" );
-				if ( !inquotes && i > 0 ) sb.append( "\"" );
-				sb.append( c );
-				inquotes = true;
-				encoding = false;
-				
-			// handle characters that need encoding
-			} else {
-				if ( inquotes && i < input.length() ) sb.append( "\"" );
-				if ( i > 0 ) sb.append( "&" );
-				sb.append( encodeCharacter( immune, Character.valueOf( c ) ) );
-				inquotes = false;
-				encoding = true;
-			}
-		}
-		return sb.toString();
+        StringBuilder sb = new StringBuilder();
+        boolean encoding = false;
+        boolean inquotes = false;
+        for ( int i=0; i<input.length(); i++ ) {
+            char c = input.charAt(i);
+
+            // handle normal characters and surround them with quotes
+            if (containsCharacter(c, EncoderConstants.CHAR_ALPHANUMERICS) || containsCharacter(c, immune)) {
+                if ( encoding && i > 0 ) sb.append( "&" );
+                if ( !inquotes && i > 0 ) sb.append( "\"" );
+                sb.append( c );
+                inquotes = true;
+                encoding = false;
+
+            // handle characters that need encoding
+            } else {
+                if ( inquotes && i < input.length() ) sb.append( "\"" );
+                if ( i > 0 ) sb.append( "&" );
+                sb.append( encodeCharacter( immune, Character.valueOf( c ) ) );
+                inquotes = false;
+                encoding = true;
+            }
+        }
+        return sb.toString();
     }
 
 
-	/**
-	 * Returns quote-encoded character
+    /**
+     * Returns quote-encoded character
      *
      * @param immune
      */
-	public String encodeCharacter( char[] immune, Character c ) {
-		char ch = c.charValue();
-		
-		// check for immune characters
-		if ( containsCharacter( ch, immune ) ) {
-			return ""+ch;
-		}
-		
-		// check for alphanumeric characters
-		String hex = super.getHexForNonAlphanumeric( ch );
-		if ( hex == null ) {
-			return ""+ch;
-		}
-		
+    public String encodeCharacter( char[] immune, Character c ) {
+        char ch = c.charValue();
+
+        // check for immune characters
+        if ( containsCharacter( ch, immune ) ) {
+            return ""+ch;
+        }
+
+        // check for alphanumeric characters
+        String hex = super.getHexForNonAlphanumeric( ch );
+        if ( hex == null ) {
+            return ""+ch;
+        }
+
         return "chrw(" + (int)c.charValue() + ")";
-	}
-	
-	
-	
-	/**
-	 * Returns the decoded version of the character starting at index, or
-	 * null if no decoding is possible.
-	 * 
-	 * Formats all are legal both upper/lower case:
-	 *   "x - all special characters
-	 *   " + chr(x) + "  - not supported yet
-	 */
-	public Character decodeCharacter( PushbackSequence<Character> input ) {
-		input.mark();
-		Character first = input.next();
-		if ( first == null ) {
-			input.reset();
-			return null;
-		}
-		
-		// if this is not an encoded character, return null
-		if ( first.charValue() != '\"' ) {
-			input.reset();
-			return null;
-		}
-
-		Character second = input.next();
-		return second;
-	}
+    }
+
+
+
+    /**
+     * Returns the decoded version of the character starting at index, or
+     * null if no decoding is possible.
+     *
+     * Formats all are legal both upper/lower case:
+     *   "x - all special characters
+     *   " + chr(x) + "  - not supported yet
+     */
+    public Character decodeCharacter( PushbackSequence<Character> input ) {
+        input.mark();
+        Character first = input.next();
+        if ( first == null ) {
+            input.reset();
+            return null;
+        }
+
+        // if this is not an encoded character, return null
+        if ( first.charValue() != '\"' ) {
+            input.reset();
+            return null;
+        }
+
+        Character second = input.next();
+        return second;
+    }
 
 }
\ No newline at end of file
diff --git a/src/main/java/org/owasp/esapi/codecs/WindowsCodec.java b/src/main/java/org/owasp/esapi/codecs/WindowsCodec.java
index be22640..d3338b1 100644
--- a/src/main/java/org/owasp/esapi/codecs/WindowsCodec.java
+++ b/src/main/java/org/owasp/esapi/codecs/WindowsCodec.java
@@ -1,15 +1,15 @@
 /**
  * OWASP Enterprise Security API (ESAPI)
- * 
+ *
  * This file is part of the Open Web Application Security Project (OWASP)
  * Enterprise Security API (ESAPI) project. For details, please see
  * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
  *
  * Copyright (c) 2007 - The OWASP Foundation
- * 
+ *
  * The ESAPI is published by OWASP under the BSD license. You should read and accept the
  * LICENSE before you use, modify, and/or redistribute this software.
- * 
+ *
  * @author Jeff Williams <a href="http://www.aspectsecurity.com">Aspect Security</a>
  * @created 2007
  */
@@ -18,7 +18,7 @@ package org.owasp.esapi.codecs;
 
 /**
  * Implementation of the Codec interface for '^' encoding from Windows command shell.
- * 
+ *
  * @author Jeff Williams (jeff.williams .at. aspectsecurity.com) <a
  *         href="http://www.aspectsecurity.com">Aspect Security</a>
  * @since June 1, 2007
@@ -26,57 +26,57 @@ package org.owasp.esapi.codecs;
  */
 public class WindowsCodec extends AbstractCharacterCodec {
 
-	
-	/**
-	 * {@inheritDoc}
-	 * 
-	 * Returns Windows shell encoded character (which is ^)
+
+    /**
+     * {@inheritDoc}
+     *
+     * Returns Windows shell encoded character (which is ^)
      *
      * @param immune
      */
-	public String encodeCharacter( char[] immune, Character c ) {
-		char ch = c.charValue();
-		
-		// check for immune characters
-		if ( containsCharacter( ch, immune ) ) {
-			return ""+ch;
-		}
-		
-		// check for alphanumeric characters
-		String hex = super.getHexForNonAlphanumeric( ch );
-		if ( hex == null ) {
-			return ""+ch;
-		}
-		
+    public String encodeCharacter( char[] immune, Character c ) {
+        char ch = c.charValue();
+
+        // check for immune characters
+        if ( containsCharacter( ch, immune ) ) {
+            return ""+ch;
+        }
+
+        // check for alphanumeric characters
+        String hex = super.getHexForNonAlphanumeric( ch );
+        if ( hex == null ) {
+            return ""+ch;
+        }
+
         return "^" + c;
-	}
-	
+    }
+
+
+    /**
+     * {@inheritDoc}
+     *
+     * Returns the decoded version of the character starting at index, or
+     * null if no decoding is possible.
+     * <p>
+     * Formats all are legal both upper/lower case:
+     *   ^x - all special characters
+     */
+    public Character decodeCharacter( PushbackSequence<Character> input ) {
+        input.mark();
+        Character first = input.next();
+        if ( first == null ) {
+            input.reset();
+            return null;
+        }
 
-	/**
-	 * {@inheritDoc}
-	 * 
-	 * Returns the decoded version of the character starting at index, or
-	 * null if no decoding is possible.
-	 * <p>
-	 * Formats all are legal both upper/lower case:
-	 *   ^x - all special characters
-	 */
-	public Character decodeCharacter( PushbackSequence<Character> input ) {
-		input.mark();
-		Character first = input.next();
-		if ( first == null ) {
-			input.reset();
-			return null;
-		}
-		
-		// if this is not an encoded character, return null
-		if ( first.charValue() != '^' ) {
-			input.reset();
-			return null;
-		}
+        // if this is not an encoded character, return null
+        if ( first.charValue() != '^' ) {
+            input.reset();
+            return null;
+        }
 
-		Character second = input.next();
-		return second;
-	}
+        Character second = input.next();
+        return second;
+    }
 
 }
\ No newline at end of file
diff --git a/src/main/java/org/owasp/esapi/codecs/XMLEntityCodec.java b/src/main/java/org/owasp/esapi/codecs/XMLEntityCodec.java
index 418f4c5..c287343 100644
--- a/src/main/java/org/owasp/esapi/codecs/XMLEntityCodec.java
+++ b/src/main/java/org/owasp/esapi/codecs/XMLEntityCodec.java
@@ -1,15 +1,15 @@
 /**
  * OWASP Enterprise Security API (ESAPI)
- * 
+ *
  * This file is part of the Open Web Application Security Project (OWASP)
  * Enterprise Security API (ESAPI) project. For details, please see
  * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
  *
  * Copyright (c) 2009 - The OWASP Foundation
- * 
+ *
  * The ESAPI is published by OWASP under the BSD license. You should read and accept the
  * LICENSE before you use, modify, and/or redistribute this software.
- * 
+ *
  */
 package org.owasp.esapi.codecs;
 
@@ -23,11 +23,11 @@ import org.owasp.esapi.util.CollectionsUtil;
  * This differes from HTML entity encoding in that only the following
  * named entities are predefined:
  * <ul>
- * 	<li>lt</li>
- * 	<li>gt</li>
- * 	<li>amp</li>
- * 	<li>apos</li>
- * 	<li>quot</li>
+ *     <li>lt</li>
+ *     <li>gt</li>
+ *     <li>amp</li>
+ *     <li>apos</li>
+ *     <li>quot</li>
  * </ul>
  * However, the XML Specification 1.0 states in section 4.6 "Predefined
  * Entities" that these should still be declared for interoperability
@@ -43,256 +43,256 @@ import org.owasp.esapi.util.CollectionsUtil;
  */
 public class XMLEntityCodec extends AbstractCharacterCodec
 {
-	private static final String ALPHA_NUMERIC_STR = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
-	private static final String UNENCODED_STR = ALPHA_NUMERIC_STR + " \t";
-	private static final Set<Character> UNENCODED_SET = CollectionsUtil.strToUnmodifiableSet(UNENCODED_STR);
-	private static final HashTrie<Character> entityToCharacterMap;
+    private static final String ALPHA_NUMERIC_STR = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
+    private static final String UNENCODED_STR = ALPHA_NUMERIC_STR + " \t";
+    private static final Set<Character> UNENCODED_SET = CollectionsUtil.strToUnmodifiableSet(UNENCODED_STR);
+    private static final HashTrie<Character> entityToCharacterMap;
 
-	static
-	{	// populate entitites
-		entityToCharacterMap = new HashTrie<Character>();
-		entityToCharacterMap.put("lt", '<');
-		entityToCharacterMap.put("gt", '>');
-		entityToCharacterMap.put("amp", '&');
-		entityToCharacterMap.put("apos", '\'');
-		entityToCharacterMap.put("quot", '"');
-	}
+    static
+    {    // populate entitites
+        entityToCharacterMap = new HashTrie<Character>();
+        entityToCharacterMap.put("lt", '<');
+        entityToCharacterMap.put("gt", '>');
+        entityToCharacterMap.put("amp", '&');
+        entityToCharacterMap.put("apos", '\'');
+        entityToCharacterMap.put("quot", '"');
+    }
 
-	/**
-	 * {@inheritDoc}
-	 * 
-	 * Encodes a Character using XML entities as necessary.
-	 *
-	 * @param immune characters that should not be encoded as entities
-	 */
-	public String encodeCharacter(char[] immune, Character c)
-	{
-		// check for immune characters
-		if(containsCharacter(c, immune))
-			return c.toString();
+    /**
+     * {@inheritDoc}
+     *
+     * Encodes a Character using XML entities as necessary.
+     *
+     * @param immune characters that should not be encoded as entities
+     */
+    public String encodeCharacter(char[] immune, Character c)
+    {
+        // check for immune characters
+        if(containsCharacter(c, immune))
+            return c.toString();
 
-		// check for unencoded characters
-		if(UNENCODED_SET.contains(c))
-			return c.toString();
+        // check for unencoded characters
+        if(UNENCODED_SET.contains(c))
+            return c.toString();
 
-		return "&#x" + Integer.toHexString(c.charValue()) + ";";
-	}
+        return "&#x" + Integer.toHexString(c.charValue()) + ";";
+    }
 
-	/**
-	 * {@inheritDoc}
-	 * 
-	 * Returns the decoded version of the character starting at index, or
-	 * null if no decoding is possible.
-	 * 
-	 * Legal formats:
-	 * <ul>
-	 * 	<li>&amp;#dddd;</li>
-	 * 	<li>&amp;#xhhhh;</li>
-	 * 	<li>&amp;name;</li>
-	 * </ul>
-	 */
-	public Character decodeCharacter(PushbackSequence<Character> input)
-	{
-		Character ret = null;
-		Character first;
-		Character second;
+    /**
+     * {@inheritDoc}
+     *
+     * Returns the decoded version of the character starting at index, or
+     * null if no decoding is possible.
+     *
+     * Legal formats:
+     * <ul>
+     *     <li>&amp;#dddd;</li>
+     *     <li>&amp;#xhhhh;</li>
+     *     <li>&amp;name;</li>
+     * </ul>
+     */
+    public Character decodeCharacter(PushbackSequence<Character> input)
+    {
+        Character ret = null;
+        Character first;
+        Character second;
 
-		input.mark();
-		try
-		{
-			first = input.next();
-			if(first == null)
-				return null;
+        input.mark();
+        try
+        {
+            first = input.next();
+            if(first == null)
+                return null;
 
-			// if this is not an encoded character, return null
-			if(first != '&')
-				return null;
+            // if this is not an encoded character, return null
+            if(first != '&')
+                return null;
 
-			// test for numeric encodings
-			second = input.next();
-			if(second==null)
-				return null;
+            // test for numeric encodings
+            second = input.next();
+            if(second==null)
+                return null;
 
-			if(second=='#')
-			{	// handle numbers
-				ret = getNumericEntity(input);
-			}
-			else if(Character.isLetter(second.charValue()))
-			{	// handle entities
-				input.pushback(second);
-				ret = getNamedEntity(input);
-			}
-		}
-		finally
-		{
-			if(ret == null)
-				input.reset();
-		}
-		return ret;
-	}
+            if(second=='#')
+            {    // handle numbers
+                ret = getNumericEntity(input);
+            }
+            else if(Character.isLetter(second.charValue()))
+            {    // handle entities
+                input.pushback(second);
+                ret = getNamedEntity(input);
+            }
+        }
+        finally
+        {
+            if(ret == null)
+                input.reset();
+        }
+        return ret;
+    }
 
-	/**
-	 * Converts the rest of a numeric entity to a character.
-	 * @param input The input to read from. It is assumed that input
-	 * 	is positioned at the character after the &amp;#
-	 * @return The character decoded or null on failure.
-	 */
-	private static Character getNumericEntity(PushbackSequence<Character> input)
-	{
-		Character first = input.peek();
+    /**
+     * Converts the rest of a numeric entity to a character.
+     * @param input The input to read from. It is assumed that input
+     *     is positioned at the character after the &amp;#
+     * @return The character decoded or null on failure.
+     */
+    private static Character getNumericEntity(PushbackSequence<Character> input)
+    {
+        Character first = input.peek();
 
-		if(first == null)
-			return null;
+        if(first == null)
+            return null;
 
-		if(first=='x'||first=='X')
-		{
-			input.next();	// nuke X
-			return parseHex(input);
-		}
-		return parseNumber(input);
-	}
+        if(first=='x'||first=='X')
+        {
+            input.next();    // nuke X
+            return parseHex(input);
+        }
+        return parseNumber(input);
+    }
 
-	/**
-	 * Convert a integer code point to a Character.
-	 * @param i the integer
-	 * @return i as a Character or null if i is a invalid code point
-	 * 	or outside of the Java char range.
-	 */
-	private static Character int2char(int i)
-	{
-		if(!Character.isValidCodePoint(i))
-			return null;
-		if(!(Character.MIN_VALUE <= i && i <= Character.MAX_VALUE))
-			return null;	// we can't 0x010000-0x100000 currently
-		return (char)i;
-	}
+    /**
+     * Convert a integer code point to a Character.
+     * @param i the integer
+     * @return i as a Character or null if i is a invalid code point
+     *     or outside of the Java char range.
+     */
+    private static Character int2char(int i)
+    {
+        if(!Character.isValidCodePoint(i))
+            return null;
+        if(!(Character.MIN_VALUE <= i && i <= Character.MAX_VALUE))
+            return null;    // we can't 0x010000-0x100000 currently
+        return (char)i;
+    }
 
-	/**
-	 * Converts the rest of a decimal numeric entity to a character.
-	 * @param input The input to read from. It is assumed that input
-	 * 	is positioned at the character after the &amp;# and that
-	 *	the next char is not a 'x' or 'X'.
-	 * @return The character decoded or null on failutre.
-	 */
-	private static Character parseNumber(PushbackSequence<Character> input)
-	{
-		StringBuilder sb = new StringBuilder();
-		Character c;
-		while((c=input.next())!=null)
-		{
-			// end of entity?
-			if(c==';')
-				break;
+    /**
+     * Converts the rest of a decimal numeric entity to a character.
+     * @param input The input to read from. It is assumed that input
+     *     is positioned at the character after the &amp;# and that
+     *    the next char is not a 'x' or 'X'.
+     * @return The character decoded or null on failutre.
+     */
+    private static Character parseNumber(PushbackSequence<Character> input)
+    {
+        StringBuilder sb = new StringBuilder();
+        Character c;
+        while((c=input.next())!=null)
+        {
+            // end of entity?
+            if(c==';')
+                break;
 
-			// check for digit
-			if(!Character.isDigit(c.charValue()))
-				return null;
-			sb.append(c);
-		}
-		if(c==null)
-			return null;	// not ';' termintated
-		if(sb.length()<=0)	// no digits
-			return null;
-		try
-		{
-			return int2char(Integer.parseInt(sb.toString()));
-		}
-		catch(NumberFormatException e)
-		{
-			return null;
-		}
-	}
+            // check for digit
+            if(!Character.isDigit(c.charValue()))
+                return null;
+            sb.append(c);
+        }
+        if(c==null)
+            return null;    // not ';' termintated
+        if(sb.length()<=0)    // no digits
+            return null;
+        try
+        {
+            return int2char(Integer.parseInt(sb.toString()));
+        }
+        catch(NumberFormatException e)
+        {
+            return null;
+        }
+    }
 
-	/**
-	 * Converts the rest of a hexidecimal numeric entity to a character.
-	 * @param input The input to read from. It is assumed that input
-	 * 	is positioned at the character after the &amp;#[xX]
-	 * @return The character decoded or null on failutre.
-	 */
-	private static Character parseHex(PushbackSequence<Character> input)
-	{
-		Character c;
-		StringBuilder sb = new StringBuilder();
-		input_loop: while((c=input.next())!=null)
-		{
-			switch(c.charValue())
-			{
-				case 'a':
-				case 'b':
-				case 'c':
-				case 'd':
-				case 'e':
-				case 'f':
-				case 'A':
-				case 'B':
-				case 'C':
-				case 'D':
-				case 'E':
-				case '0':
-				case '1':
-				case '2':
-				case '3':
-				case '4':
-				case '5':
-				case '6':
-				case '7':
-				case '8':
-				case '9':
-					sb.append(c);
-					break;
-				case ';':
-					break input_loop;
-				default:
-					return null;
-			}
-		}
-		if(c==null)
-			return null;	// not ';' termintated
-		if(sb.length()<=0)	// no digits
-			return null;
-		try
-		{
-			return int2char(Integer.parseInt(sb.toString(),16));
-		}
-		catch(NumberFormatException e)
-		{
-			return null;
-		}
-	}
+    /**
+     * Converts the rest of a hexidecimal numeric entity to a character.
+     * @param input The input to read from. It is assumed that input
+     *     is positioned at the character after the &amp;#[xX]
+     * @return The character decoded or null on failutre.
+     */
+    private static Character parseHex(PushbackSequence<Character> input)
+    {
+        Character c;
+        StringBuilder sb = new StringBuilder();
+        input_loop: while((c=input.next())!=null)
+        {
+            switch(c.charValue())
+            {
+                case 'a':
+                case 'b':
+                case 'c':
+                case 'd':
+                case 'e':
+                case 'f':
+                case 'A':
+                case 'B':
+                case 'C':
+                case 'D':
+                case 'E':
+                case '0':
+                case '1':
+                case '2':
+                case '3':
+                case '4':
+                case '5':
+                case '6':
+                case '7':
+                case '8':
+                case '9':
+                    sb.append(c);
+                    break;
+                case ';':
+                    break input_loop;
+                default:
+                    return null;
+            }
+        }
+        if(c==null)
+            return null;    // not ';' termintated
+        if(sb.length()<=0)    // no digits
+            return null;
+        try
+        {
+            return int2char(Integer.parseInt(sb.toString(),16));
+        }
+        catch(NumberFormatException e)
+        {
+            return null;
+        }
+    }
 
-	/**
-	 * 
-	 * Converts the rest of a named entity to a character.
-	 * null if no decoding is possible.
-	 * @param input The input to read from. It is assumed that input
-	 * 	is positioned at the character after the &amp;.
-	 * @return The character decoded or null on failutre.
-	 */
-	private Character getNamedEntity(PushbackSequence<Character> input)
-	{
-		StringBuilder possible = new StringBuilder();
-		Map.Entry<CharSequence,Character> entry;
-		int len;
+    /**
+     *
+     * Converts the rest of a named entity to a character.
+     * null if no decoding is possible.
+     * @param input The input to read from. It is assumed that input
+     *     is positioned at the character after the &amp;.
+     * @return The character decoded or null on failutre.
+     */
+    private Character getNamedEntity(PushbackSequence<Character> input)
+    {
+        StringBuilder possible = new StringBuilder();
+        Map.Entry<CharSequence,Character> entry;
+        int len;
 
-		// kludge around PushbackString....
-		len = Math.min(input.remainder().length(), entityToCharacterMap.getMaxKeyLength()+1);
-		for(int i=0;i<len;i++)
-			possible.append(Character.toLowerCase(input.next()));
+        // kludge around PushbackString....
+        len = Math.min(input.remainder().length(), entityToCharacterMap.getMaxKeyLength()+1);
+        for(int i=0;i<len;i++)
+            possible.append(Character.toLowerCase(input.next()));
 
-		// look up the longest match
-		entry = entityToCharacterMap.getLongestMatch(possible);
-		if(entry == null)
-			return null;	// no match, caller will reset input
-		len = entry.getKey().length();	// what matched's length
-		if(possible.length() <= len || possible.charAt(len)!=';')
-			return null;	// not semicolon
+        // look up the longest match
+        entry = entityToCharacterMap.getLongestMatch(possible);
+        if(entry == null)
+            return null;    // no match, caller will reset input
+        len = entry.getKey().length();    // what matched's length
+        if(possible.length() <= len || possible.charAt(len)!=';')
+            return null;    // not semicolon
 
-		// fixup input
-		input.reset();
-		input.next();	// read &
-		for(int i=0;i<len;i++)
-			input.next();
-		input.next();	// read semicolen
-		return entry.getValue();
-	}
+        // fixup input
+        input.reset();
+        input.next();    // read &
+        for(int i=0;i<len;i++)
+            input.next();
+        input.next();    // read semicolen
+        return entry.getValue();
+    }
 }
diff --git a/src/main/java/org/owasp/esapi/codecs/package.html b/src/main/java/org/owasp/esapi/codecs/package.html
index 0951a73..0726d78 100644
--- a/src/main/java/org/owasp/esapi/codecs/package.html
+++ b/src/main/java/org/owasp/esapi/codecs/package.html
@@ -10,7 +10,7 @@ both canonicalization and output encoding. By using the codecs to decode (canoni
 before validation, many attacks can be detected and handled.  By using the codecs to encode
 untrusted data before sending it to an interpreter, a wide variety of 'injection' attacks can
 be stopped. However,
-this package does not currently address issues related to converting between byte-streams and 
+this package does not currently address issues related to converting between byte-streams and
 internal character representations, such as overlong UTF-8 issues. Those are left to the platform.
 The codecs cover protocol encodings such as HTML entity encoding and percent encoding, but also
 common product escaping schemes, such as Unix, Windows, MySQL, and Oracle.
diff --git a/src/main/java/org/owasp/esapi/codecs/ref/EncodingPatternPreservation.java b/src/main/java/org/owasp/esapi/codecs/ref/EncodingPatternPreservation.java
index 4829985..3094854 100644
--- a/src/main/java/org/owasp/esapi/codecs/ref/EncodingPatternPreservation.java
+++ b/src/main/java/org/owasp/esapi/codecs/ref/EncodingPatternPreservation.java
@@ -12,100 +12,100 @@ import java.util.regex.Pattern;
  *
  */
 public class EncodingPatternPreservation {
-	/** Default replacement marker. */
-	private static final String REPLACEMENT_MARKER = EncodingPatternPreservation.class.getSimpleName();
-	/** Pattern that is used to identify which content should be replaced. */
-	private final Pattern noEncodeContent;
-	/** The Marker used to replace found Pattern references. */
-	private String replacementMarker = REPLACEMENT_MARKER;
+    /** Default replacement marker. */
+    private static final String REPLACEMENT_MARKER = EncodingPatternPreservation.class.getSimpleName();
+    /** Pattern that is used to identify which content should be replaced. */
+    private final Pattern noEncodeContent;
+    /** The Marker used to replace found Pattern references. */
+    private String replacementMarker = REPLACEMENT_MARKER;
 
-	/**
-	 * The ordered-list of elements that were replaced in the last call to
-	 * {@link #captureAndReplaceMatches(String)}, and that will be used to replace
-	 * the {@link #replacementMarker} on the next call to
-	 * {@link #restoreOriginalContent(String)}
-	 */
-	private final List<String> replacedContentList = new ArrayList<>();
+    /**
+     * The ordered-list of elements that were replaced in the last call to
+     * {@link #captureAndReplaceMatches(String)}, and that will be used to replace
+     * the {@link #replacementMarker} on the next call to
+     * {@link #restoreOriginalContent(String)}
+     */
+    private final List<String> replacedContentList = new ArrayList<>();
 
-	/**
-	 * Constructor.
-	 * 
-	 * @param pattern Pattern identifying content being replaced.
-	 */
-	public EncodingPatternPreservation(Pattern pattern) {
-		noEncodeContent = pattern;
-	}
+    /**
+     * Constructor.
+     *
+     * @param pattern Pattern identifying content being replaced.
+     */
+    public EncodingPatternPreservation(Pattern pattern) {
+        noEncodeContent = pattern;
+    }
 
-	/**
-	 * Replaces each matching instance of this instance's Pattern with an
-	 * identifiable replacement marker. <br>
-	 * 
-	 * <br>
-	 * After the encoding process is complete, use
-	 * {@link #restoreOriginalContent(String)} to re-insert the original data.
-	 * 
-	 * @param input String to adjust
-	 * @return The adjusted String
-	 */
-	public String captureAndReplaceMatches(String input) {
-		if (!replacedContentList.isEmpty()) {
-			// This may seem odd, but this will prevent programmer error that would result
-			// in being unable to restore a previously tokenized String.
-			String message = "Previously captured state is still present in instance. Call PatternContentPreservation.reset() to clear out preserved state and to reuse the reference.";
-			throw new IllegalStateException(message);
-		}
-		String inputCpy = input;
-		Matcher matcher = noEncodeContent.matcher(input);
+    /**
+     * Replaces each matching instance of this instance's Pattern with an
+     * identifiable replacement marker. <br>
+     *
+     * <br>
+     * After the encoding process is complete, use
+     * {@link #restoreOriginalContent(String)} to re-insert the original data.
+     *
+     * @param input String to adjust
+     * @return The adjusted String
+     */
+    public String captureAndReplaceMatches(String input) {
+        if (!replacedContentList.isEmpty()) {
+            // This may seem odd, but this will prevent programmer error that would result
+            // in being unable to restore a previously tokenized String.
+            String message = "Previously captured state is still present in instance. Call PatternContentPreservation.reset() to clear out preserved state and to reuse the reference.";
+            throw new IllegalStateException(message);
+        }
+        String inputCpy = input;
+        Matcher matcher = noEncodeContent.matcher(input);
 
-		while (matcher.find()) {
-			String replaceContent = matcher.group(0);
-			if (replaceContent != null) {
-				replacedContentList.add(replaceContent);
-				inputCpy = inputCpy.replaceFirst(noEncodeContent.pattern(), replacementMarker);
-			}			
-		}
+        while (matcher.find()) {
+            String replaceContent = matcher.group(0);
+            if (replaceContent != null) {
+                replacedContentList.add(replaceContent);
+                inputCpy = inputCpy.replaceFirst(noEncodeContent.pattern(), replacementMarker);
+            }
+        }
 
-		return inputCpy;
-	}
+        return inputCpy;
+    }
 
-	/**
-	 * Replaces each instance of the {@link #replacementMarker} with the original
-	 * content, as captured by {@link #captureAndReplaceMatches(String)}
-	 * 
-	 * @param input String to restore.
-	 * @return String reference with all values replaced.
-	 */
-	public String restoreOriginalContent(String input) {
-		String result = input;
-		while (replacedContentList.size() > 0) {
-			String origValue = replacedContentList.remove(0);
-			result = result.replaceFirst(replacementMarker, origValue);
-		}
+    /**
+     * Replaces each instance of the {@link #replacementMarker} with the original
+     * content, as captured by {@link #captureAndReplaceMatches(String)}
+     *
+     * @param input String to restore.
+     * @return String reference with all values replaced.
+     */
+    public String restoreOriginalContent(String input) {
+        String result = input;
+        while (replacedContentList.size() > 0) {
+            String origValue = replacedContentList.remove(0);
+            result = result.replaceFirst(replacementMarker, origValue);
+        }
 
-		return result;
+        return result;
 
-	}
+    }
 
-	/**
-	 * Allows the marker used as a replacement to be altered.
-	 * 
-	 * @param marker String replacment to use for regex matches.
-	 */
-	public void setReplacementMarker(String marker) {
-		if (!replacedContentList.isEmpty()) {
-			// This may seem odd, but this will prevent programmer error that would result
-			// in being unable to restore a previously tokenized String.
-			String message = "Previously captured state is still present in instance. Call PatternContentPreservation.reset() to clear out preserved state and to alter the marker.";
-			throw new IllegalStateException(message);
-		}
-		this.replacementMarker = marker;
-	}
+    /**
+     * Allows the marker used as a replacement to be altered.
+     *
+     * @param marker String replacment to use for regex matches.
+     */
+    public void setReplacementMarker(String marker) {
+        if (!replacedContentList.isEmpty()) {
+            // This may seem odd, but this will prevent programmer error that would result
+            // in being unable to restore a previously tokenized String.
+            String message = "Previously captured state is still present in instance. Call PatternContentPreservation.reset() to clear out preserved state and to alter the marker.";
+            throw new IllegalStateException(message);
+        }
+        this.replacementMarker = marker;
+    }
 
-	/**
-	 * Clears any stored replacement values out of the instance.
-	 */
-	public void reset() {
-		replacedContentList.clear();
-	}
+    /**
+     * Clears any stored replacement values out of the instance.
+     */
+    public void reset() {
+        replacedContentList.clear();
+    }
 
 }
diff --git a/src/main/java/org/owasp/esapi/configuration/EsapiPropertyLoaderFactory.java b/src/main/java/org/owasp/esapi/configuration/EsapiPropertyLoaderFactory.java
index 4f814e0..d6a1dff 100644
--- a/src/main/java/org/owasp/esapi/configuration/EsapiPropertyLoaderFactory.java
+++ b/src/main/java/org/owasp/esapi/configuration/EsapiPropertyLoaderFactory.java
@@ -51,9 +51,9 @@ public class EsapiPropertyLoaderFactory {
         if (PROPERTIES.getTypeName().equalsIgnoreCase(fileExtension)) {
             return new StandardEsapiPropertyLoader(cfgPath, cfg.getPriority());
         } else {
-            throw new ConfigurationException("Configuration storage type [" + fileExtension + "] is not " +
-                    "supported");
+            throw new ConfigurationException("The extension of given configuration path [ " + cfgPath + " ] is not supported." +
+                    "Only .xml or .properties file extensions are supported.");
         }
     }
-    
+
 }
diff --git a/src/main/java/org/owasp/esapi/configuration/StandardEsapiPropertyLoader.java b/src/main/java/org/owasp/esapi/configuration/StandardEsapiPropertyLoader.java
index 565235a..fe50e02 100644
--- a/src/main/java/org/owasp/esapi/configuration/StandardEsapiPropertyLoader.java
+++ b/src/main/java/org/owasp/esapi/configuration/StandardEsapiPropertyLoader.java
@@ -83,7 +83,7 @@ public class StandardEsapiPropertyLoader extends AbstractPrioritizedPropertyLoad
     }
 
     /**
-     * Methods loads configuration from .properties file. 
+     * Methods loads configuration from .properties file.
      * @param file
      */
     protected void loadPropertiesFromFile(File file) {
diff --git a/src/main/java/org/owasp/esapi/configuration/XmlEsapiPropertyLoader.java b/src/main/java/org/owasp/esapi/configuration/XmlEsapiPropertyLoader.java
index a801397..3b3dc8e 100644
--- a/src/main/java/org/owasp/esapi/configuration/XmlEsapiPropertyLoader.java
+++ b/src/main/java/org/owasp/esapi/configuration/XmlEsapiPropertyLoader.java
@@ -99,7 +99,7 @@ public class XmlEsapiPropertyLoader extends AbstractPrioritizedPropertyLoader {
     }
 
     /**
-     * Methods loads configuration from .xml file. 
+     * Methods loads configuration from .xml file.
      * @param file
      * @throws ConfigurationException if there is a problem loading the specified configuration file.
      */
@@ -133,9 +133,9 @@ public class XmlEsapiPropertyLoader extends AbstractPrioritizedPropertyLoader {
     private void validateAgainstXSD(InputStream xml) throws IOException, SAXException {
         try ( InputStream xsd = getClass().getResourceAsStream("/ESAPI-properties.xsd"); ) {
             SchemaFactory factory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
-	        Schema schema = factory.newSchema(new StreamSource(xsd));
-	        Validator validator = schema.newValidator();
-	        validator.validate(new StreamSource(xml));
+            Schema schema = factory.newSchema(new StreamSource(xsd));
+            Validator validator = schema.newValidator();
+            validator.validate(new StreamSource(xml));
         }
     }
 
diff --git a/src/main/java/org/owasp/esapi/configuration/consts/EsapiConfiguration.java b/src/main/java/org/owasp/esapi/configuration/consts/EsapiConfiguration.java
index 7428123..e5e3305 100644
--- a/src/main/java/org/owasp/esapi/configuration/consts/EsapiConfiguration.java
+++ b/src/main/java/org/owasp/esapi/configuration/consts/EsapiConfiguration.java
@@ -1,7 +1,7 @@
 package org.owasp.esapi.configuration.consts;
 
 /**
- * Enum used for initialization of esapi configuration files. 
+ * Enum used for initialization of esapi configuration files.
  *
  * @since 2.2
  */
@@ -11,7 +11,7 @@ public enum EsapiConfiguration {
     DEVTEAM_ESAPI_CFG("org.owasp.esapi.devteam", 2);
 
     /**
-     * Key of system property pointing to path esapi to configuration file. 
+     * Key of system property pointing to path esapi to configuration file.
      */
     String configName;
 
diff --git a/src/main/java/org/owasp/esapi/crypto/CipherSpec.java b/src/main/java/org/owasp/esapi/crypto/CipherSpec.java
index d0c2917..10b89b4 100644
--- a/src/main/java/org/owasp/esapi/crypto/CipherSpec.java
+++ b/src/main/java/org/owasp/esapi/crypto/CipherSpec.java
@@ -1,6 +1,6 @@
 /*
  * OWASP Enterprise Security API (ESAPI)
- * 
+ *
  * This file is part of the Open Web Application Security Project (OWASP)
  * Enterprise Security API (ESAPI) project. For details, please see
  * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
@@ -33,312 +33,312 @@ import org.owasp.esapi.util.NullSafe;
  * by application developers, but rather only by those either extending ESAPI
  * or in the ESAPI reference implementation. Use <i>directly</i> by application
  * code is not recommended or supported.
- * 
+ *
  * @author kevin.w.wall@gmail.com
  * @since 2.0
  */
 public final class CipherSpec implements Serializable {
 
-	private static final long serialVersionUID = 20090822;	// version, in YYYYMMDD format
-	
-	private String  cipher_xform_   = ESAPI.securityConfiguration().getCipherTransformation();
-	private int     keySize_        = ESAPI.securityConfiguration().getEncryptionKeyLength(); // In bits
-	private int     blockSize_      = 16;   // In bytes! I.e., 128 bits!!!
-	private byte[]  iv_             = null;
+    private static final long serialVersionUID = 20090822;    // version, in YYYYMMDD format
+
+    private String  cipher_xform_   = ESAPI.securityConfiguration().getCipherTransformation();
+    private int     keySize_        = ESAPI.securityConfiguration().getEncryptionKeyLength(); // In bits
+    private int     blockSize_      = 16;   // In bytes! I.e., 128 bits!!!
+    private byte[]  iv_             = null;
+
+    private boolean blockSizeExplicitlySet = false;    // Used for check in setIV().
 
-	private boolean blockSizeExplicitlySet = false;	// Used for check in setIV().
-	
-	// Cipher transformation component. Format is ALG/MODE/PADDING
+    // Cipher transformation component. Format is ALG/MODE/PADDING
     private enum CipherTransformationComponent { ALG, MODE, PADDING }
 
-	/**
-	 * CTOR that explicitly sets everything.
-	 * @param cipherXform	The cipher transformation
-	 * @param keySize		The key size (in bits).
-	 * @param blockSize		The block size (in bytes).
-	 * @param iv			The initialization vector. Null if not applicable.
-	 */
-	public CipherSpec(String cipherXform, int keySize, int blockSize, final byte[] iv) {
-		setCipherTransformation(cipherXform);
-		setKeySize(keySize);
-		setBlockSize(blockSize);
-		setIV(iv);
-	}
-	
-	/**
-	 * CTOR that sets everything but IV.
-	 * @param cipherXform	The cipher transformation
-	 * @param keySize		The key size (in bits).
-	 * @param blockSize		The block size (in bytes).
-	 */
-	public CipherSpec(String cipherXform, int keySize, int blockSize) {
-		// Note: Do NOT use
-		//			this(cipherXform, keySize, blockSize, null);
-		// because of checks in setIV().
-		//
-		setCipherTransformation(cipherXform);
-		setKeySize(keySize);
-		setBlockSize(blockSize);
-	}
-	
-	/** CTOR that sets everything but block size and IV. */
-	public CipherSpec(String cipherXform, int keySize) {
-		setCipherTransformation(cipherXform);
-		setKeySize(keySize);
-	}
-	
-	/** CTOR that sets everything except block size. */
-	public CipherSpec(String cipherXform, int keySize, final byte[] iv) {
-		setCipherTransformation(cipherXform);
-		setKeySize(keySize);
-		setIV(iv);
-	}
-
-	/** CTOR that sets everything except for the cipher key size and possibly
-	 *  the IV. (IV may not be applicable--e.g., with ECB--or may not have
-	 *  been specified yet.
-	 */
-	public CipherSpec(final Cipher cipher) {
-		setCipherTransformation(cipher.getAlgorithm(), true);
-		setBlockSize(cipher.getBlockSize());
-		if ( cipher.getIV() != null ) {
-			setIV(cipher.getIV());
-		}
-	}
-	
-	/** CTOR that sets everything. */
-	public CipherSpec(final Cipher cipher, int keySize) {
-		this(cipher);
-		setKeySize(keySize);
-	}
-	
-	/* CTOR that sets only the IV and uses defaults for everything else. */
-	public CipherSpec(final byte[] iv) {
-		setIV(iv);
-	}
-	
-	/**
-	 * Default CTOR. Creates a cipher specification for 128-bit cipher
-	 * transformation of "AES/CBC/PKCS5Padding" and a {@code null} IV.
-	 */
-	public CipherSpec() {
-		// All defaults
-	}
-
-	/**
-	 * Set the cipher transformation for this {@code CipherSpec}.
-	 * @param cipherXform	The cipher transformation string; e.g., "DESede/CBC/PKCS5Padding".
-	 * @return	This current {@code CipherSpec} object.
-	 */
-	public CipherSpec setCipherTransformation(String cipherXform) {
-		setCipherTransformation(cipherXform, false);
-		return this;
-	}
-
-	/**
-	 * Set the cipher transformation for this {@code CipherSpec}. This is only
-	 * used by the CTOR {@code CipherSpec(Cipher)} and {@code CipherSpec(Cipher, int)}.
-	 * @param cipherXform	The cipher transformation string; e.g.,
-	 * 						"DESede/CBC/PKCS5Padding". May not be null or empty.
-	 * @param fromCipher If true, the cipher transformation was set via
-	 * 					 {@code Cipher.getAlgorithm()} which may only return the
-	 * 					 actual algorithm. In that case we check and if all 3 parts
-	 * 					 were not specified, then we specify the parts that were
-	 * 					 based on "ECB" as the default cipher mode and "NoPadding"
-	 * 					 as the default padding scheme.
-	 * @return	This current {@code CipherSpec} object.
-	 */
-	private CipherSpec setCipherTransformation(String cipherXform, boolean fromCipher) {
-		if ( ! StringUtilities.notNullOrEmpty(cipherXform, true) ) {	// Yes, really want '!' here.
-			throw new IllegalArgumentException("Cipher transformation may not be null or empty string (after trimming whitespace).");
-		}
-		int parts = cipherXform.split("/").length;
+    /**
+     * CTOR that explicitly sets everything.
+     * @param cipherXform    The cipher transformation
+     * @param keySize        The key size (in bits).
+     * @param blockSize        The block size (in bytes).
+     * @param iv            The initialization vector. Null if not applicable.
+     */
+    public CipherSpec(String cipherXform, int keySize, int blockSize, final byte[] iv) {
+        setCipherTransformation(cipherXform);
+        setKeySize(keySize);
+        setBlockSize(blockSize);
+        setIV(iv);
+    }
+
+    /**
+     * CTOR that sets everything but IV.
+     * @param cipherXform    The cipher transformation
+     * @param keySize        The key size (in bits).
+     * @param blockSize        The block size (in bytes).
+     */
+    public CipherSpec(String cipherXform, int keySize, int blockSize) {
+        // Note: Do NOT use
+        //            this(cipherXform, keySize, blockSize, null);
+        // because of checks in setIV().
+        //
+        setCipherTransformation(cipherXform);
+        setKeySize(keySize);
+        setBlockSize(blockSize);
+    }
+
+    /** CTOR that sets everything but block size and IV. */
+    public CipherSpec(String cipherXform, int keySize) {
+        setCipherTransformation(cipherXform);
+        setKeySize(keySize);
+    }
+
+    /** CTOR that sets everything except block size. */
+    public CipherSpec(String cipherXform, int keySize, final byte[] iv) {
+        setCipherTransformation(cipherXform);
+        setKeySize(keySize);
+        setIV(iv);
+    }
+
+    /** CTOR that sets everything except for the cipher key size and possibly
+     *  the IV. (IV may not be applicable--e.g., with ECB--or may not have
+     *  been specified yet.
+     */
+    public CipherSpec(final Cipher cipher) {
+        setCipherTransformation(cipher.getAlgorithm(), true);
+        setBlockSize(cipher.getBlockSize());
+        if ( cipher.getIV() != null ) {
+            setIV(cipher.getIV());
+        }
+    }
+
+    /** CTOR that sets everything. */
+    public CipherSpec(final Cipher cipher, int keySize) {
+        this(cipher);
+        setKeySize(keySize);
+    }
+
+    /* CTOR that sets only the IV and uses defaults for everything else. */
+    public CipherSpec(final byte[] iv) {
+        setIV(iv);
+    }
+
+    /**
+     * Default CTOR. Creates a cipher specification for 128-bit cipher
+     * transformation of "AES/CBC/PKCS5Padding" and a {@code null} IV.
+     */
+    public CipherSpec() {
+        // All defaults
+    }
+
+    /**
+     * Set the cipher transformation for this {@code CipherSpec}.
+     * @param cipherXform    The cipher transformation string; e.g., "DESede/CBC/PKCS5Padding".
+     * @return    This current {@code CipherSpec} object.
+     */
+    public CipherSpec setCipherTransformation(String cipherXform) {
+        setCipherTransformation(cipherXform, false);
+        return this;
+    }
+
+    /**
+     * Set the cipher transformation for this {@code CipherSpec}. This is only
+     * used by the CTOR {@code CipherSpec(Cipher)} and {@code CipherSpec(Cipher, int)}.
+     * @param cipherXform    The cipher transformation string; e.g.,
+     *                         "DESede/CBC/PKCS5Padding". May not be null or empty.
+     * @param fromCipher If true, the cipher transformation was set via
+     *                      {@code Cipher.getAlgorithm()} which may only return the
+     *                      actual algorithm. In that case we check and if all 3 parts
+     *                      were not specified, then we specify the parts that were
+     *                      based on "ECB" as the default cipher mode and "NoPadding"
+     *                      as the default padding scheme.
+     * @return    This current {@code CipherSpec} object.
+     */
+    private CipherSpec setCipherTransformation(String cipherXform, boolean fromCipher) {
+        if ( ! StringUtilities.notNullOrEmpty(cipherXform, true) ) {    // Yes, really want '!' here.
+            throw new IllegalArgumentException("Cipher transformation may not be null or empty string (after trimming whitespace).");
+        }
+        int parts = cipherXform.split("/").length;
 
             // Assertion should be okay here as these conditions are checked
             // elsewhere and this method is private.
-		assert ( !fromCipher ? (parts == 3) : true ) :
-			"Malformed cipherXform (" + cipherXform + "); must have form: \"alg/mode/paddingscheme\"";
-		if ( fromCipher && (parts != 3)  ) {
-				// Indicates cipherXform was set based on Cipher.getAlgorithm()
-				// and thus may not be a *complete* cipher transformation.
-			if ( parts == 1 ) {
-				// Only algorithm was given.
-				cipherXform += "/ECB/NoPadding";
-			} else if ( parts == 2 ) {
-				// Only algorithm and mode was given.
-				cipherXform += "/NoPadding";
-			} else if ( parts == 3 ) {
+        assert ( !fromCipher ? (parts == 3) : true ) :
+            "Malformed cipherXform (" + cipherXform + "); must have form: \"alg/mode/paddingscheme\"";
+        if ( fromCipher && (parts != 3)  ) {
+                // Indicates cipherXform was set based on Cipher.getAlgorithm()
+                // and thus may not be a *complete* cipher transformation.
+            if ( parts == 1 ) {
+                // Only algorithm was given.
+                cipherXform += "/ECB/NoPadding";
+            } else if ( parts == 2 ) {
+                // Only algorithm and mode was given.
+                cipherXform += "/NoPadding";
+            } else if ( parts == 3 ) {
                         // All three parts provided. Do nothing. Could happen if not compiled with
                         // assertions enabled, but there are explicit checks elsewhere.
-				;	// Do nothing - shown only for completeness.
-			} else {
-				// Should never happen unless Cipher implementation is totally screwed up.
-				throw new IllegalArgumentException("Cipher transformation '" +
-								cipherXform + "' must have form \"alg/mode/paddingscheme\"");
-			}
-		} else if ( !fromCipher && parts != 3 ) {
-			throw new IllegalArgumentException("Malformed cipherXform (" + cipherXform +
-											   "); must have form: \"alg/mode/paddingscheme\"");
-		}
+                ;    // Do nothing - shown only for completeness.
+            } else {
+                // Should never happen unless Cipher implementation is totally screwed up.
+                throw new IllegalArgumentException("Cipher transformation '" +
+                                cipherXform + "' must have form \"alg/mode/paddingscheme\"");
+            }
+        } else if ( !fromCipher && parts != 3 ) {
+            throw new IllegalArgumentException("Malformed cipherXform (" + cipherXform +
+                                               "); must have form: \"alg/mode/paddingscheme\"");
+        }
             // Assertion should also be okay here as these conditions are checked
             // elsewhere and this method is private.
-		assert cipherXform.split("/").length == 3 : "Implementation error setCipherTransformation()";
-		this.cipher_xform_ = cipherXform;
-		return this;
-	}
-	
-	/**
-	 * Get the cipher transformation.
-	 * @return	The cipher transformation {@code String}.
-	 */
-	public String getCipherTransformation() {
-		return cipher_xform_;
-	}
-
-	/**
-	 * Set the key size for this {@code CipherSpec}.
-	 * @param keySize	The key size, in bits. Must be positive integer.
-	 * @return	This current {@code CipherSpec} object.
-	 */
-	public CipherSpec setKeySize(int keySize) {
-		if ( keySize <= 0 ) {
-			throw new IllegalArgumentException("keySize must be > 0; keySize=" + keySize);
-		}
-		this.keySize_ = keySize;
-		return this;
-	}
-
-	/**
-	 * Retrieve the key size, in bits.
-	 * @return	The key size, in bits, is returned.
-	 */
-	public int getKeySize() {
-		return keySize_;
-	}
-
-	/**
-	 * Set the block size for this {@code CipherSpec}.
-	 * @param blockSize	The block size, in bytes. Must be positive integer appropriate
-	 * 					for the specified cipher algorithm.
-	 * @return	This current {@code CipherSpec} object.
-	 */
-	public CipherSpec setBlockSize(int blockSize) {
-		if ( blockSize <= 0 ) {
-			throw new IllegalArgumentException("blockSize must be > 0; blockSize=" + blockSize);
-		}
-		this.blockSize_ = blockSize;
-		blockSizeExplicitlySet = true;
-		return this;
-	}
-
-	/**
-	 * Retrieve the block size, in bytes.
-	 * @return	The block size, in bytes, is returned.
-	 */
-	public int getBlockSize() {
-		return blockSize_;
-	}
-
-	/**
-	 * Retrieve the cipher algorithm.
-	 * @return	The cipher algorithm.
-	 */
-	public String getCipherAlgorithm() {
-		return getFromCipherXform(CipherTransformationComponent.ALG);
-	}
-	
-	/**
-	 * Retrieve the cipher mode.
-	 * @return	The cipher mode.
-	 */
-	public String getCipherMode() {
-		return getFromCipherXform(CipherTransformationComponent.MODE);
-	}
-	
-	/**
-	 * Retrieve the cipher padding scheme.
-	 * @return	The padding scheme is returned.
-	 */
-	public String getPaddingScheme() {
-		return getFromCipherXform(CipherTransformationComponent.PADDING);
-	}
-	
-	/**
-	 * Retrieve the initialization vector (IV).
-	 * @return	The IV as a byte array.
-	 */
-	public byte[] getIV() {
-		return iv_;
-	}
-	
-	/**
-	 * Set the initialization vector (IV).
-	 * @param iv	The byte array to set as the IV. A copy of the IV is saved.
-	 * 				This parameter is ignored if the cipher mode does not
-	 * 				require an IV.
-	 * @return		This current {@code CipherSpec} object.
-	 */
-	public CipherSpec setIV(final byte[] iv) {
-		if ( ! ( requiresIV() && (iv != null && iv.length != 0) ) ) {
-			throw new IllegalArgumentException("Required IV cannot be null or 0 length.");
-		}
-		
-		// Don't store a reference, but make a copy! When an IV is provided, it generally should
-		// be the same length as the block size of the cipher.
-		if ( iv != null ) {	// Allow null IV for ECB mode.
-			  // TODO: FIXME: As per email from Jeff Walton to Kevin Wall dated 12/03/2013,
-			  //			  this is not always true. E.g., for CCM, the IV length is supposed
-			  //			  to be 7, 8, 9, 10, 11, 12, or 13 octets because of
-			  //			  it's formatting function.
+        assert cipherXform.split("/").length == 3 : "Implementation error setCipherTransformation()";
+        this.cipher_xform_ = cipherXform;
+        return this;
+    }
+
+    /**
+     * Get the cipher transformation.
+     * @return    The cipher transformation {@code String}.
+     */
+    public String getCipherTransformation() {
+        return cipher_xform_;
+    }
+
+    /**
+     * Set the key size for this {@code CipherSpec}.
+     * @param keySize    The key size, in bits. Must be positive integer.
+     * @return    This current {@code CipherSpec} object.
+     */
+    public CipherSpec setKeySize(int keySize) {
+        if ( keySize <= 0 ) {
+            throw new IllegalArgumentException("keySize must be > 0; keySize=" + keySize);
+        }
+        this.keySize_ = keySize;
+        return this;
+    }
+
+    /**
+     * Retrieve the key size, in bits.
+     * @return    The key size, in bits, is returned.
+     */
+    public int getKeySize() {
+        return keySize_;
+    }
+
+    /**
+     * Set the block size for this {@code CipherSpec}.
+     * @param blockSize    The block size, in bytes. Must be positive integer appropriate
+     *                     for the specified cipher algorithm.
+     * @return    This current {@code CipherSpec} object.
+     */
+    public CipherSpec setBlockSize(int blockSize) {
+        if ( blockSize <= 0 ) {
+            throw new IllegalArgumentException("blockSize must be > 0; blockSize=" + blockSize);
+        }
+        this.blockSize_ = blockSize;
+        blockSizeExplicitlySet = true;
+        return this;
+    }
+
+    /**
+     * Retrieve the block size, in bytes.
+     * @return    The block size, in bytes, is returned.
+     */
+    public int getBlockSize() {
+        return blockSize_;
+    }
+
+    /**
+     * Retrieve the cipher algorithm.
+     * @return    The cipher algorithm.
+     */
+    public String getCipherAlgorithm() {
+        return getFromCipherXform(CipherTransformationComponent.ALG);
+    }
+
+    /**
+     * Retrieve the cipher mode.
+     * @return    The cipher mode.
+     */
+    public String getCipherMode() {
+        return getFromCipherXform(CipherTransformationComponent.MODE);
+    }
+
+    /**
+     * Retrieve the cipher padding scheme.
+     * @return    The padding scheme is returned.
+     */
+    public String getPaddingScheme() {
+        return getFromCipherXform(CipherTransformationComponent.PADDING);
+    }
+
+    /**
+     * Retrieve the initialization vector (IV).
+     * @return    The IV as a byte array.
+     */
+    public byte[] getIV() {
+        return iv_;
+    }
+
+    /**
+     * Set the initialization vector (IV).
+     * @param iv    The byte array to set as the IV. A copy of the IV is saved.
+     *                 This parameter is ignored if the cipher mode does not
+     *                 require an IV.
+     * @return        This current {@code CipherSpec} object.
+     */
+    public CipherSpec setIV(final byte[] iv) {
+        if ( ! ( requiresIV() && (iv != null && iv.length != 0) ) ) {
+            throw new IllegalArgumentException("Required IV cannot be null or 0 length.");
+        }
+
+        // Don't store a reference, but make a copy! When an IV is provided, it generally should
+        // be the same length as the block size of the cipher.
+        if ( iv != null ) {    // Allow null IV for ECB mode.
+              // TODO: FIXME: As per email from Jeff Walton to Kevin Wall dated 12/03/2013,
+              //              this is not always true. E.g., for CCM, the IV length is supposed
+              //              to be 7, 8, 9, 10, 11, 12, or 13 octets because of
+              //              it's formatting function.
 /***
-			if ( iv.length != this.getBlockSize() && blockSizeExplicitlySet ) {
-				throw new IllegalArgumentException("IV must be same length as cipher block size (" +
-													this.getBlockSize() + " bytes)");
-			}
+            if ( iv.length != this.getBlockSize() && blockSizeExplicitlySet ) {
+                throw new IllegalArgumentException("IV must be same length as cipher block size (" +
+                                                    this.getBlockSize() + " bytes)");
+            }
 ***/
-			iv_ = new byte[ iv.length ];
-			CryptoHelper.copyByteArray(iv, iv_);
-		}
-		return this;
-	}
-
-	/**
-	 * Return true if the cipher mode requires an IV.
-	 * @return True if the cipher mode requires an IV, otherwise false.
-	 * */
-	public boolean requiresIV() {
-		
-		String cm = getCipherMode();
-		
-		// Add any other cipher modes supported by JCE but not requiring IV.
-		// ECB is the only one I'm aware of that doesn't. Mode is not case
-		// sensitive.
-		if ( "ECB".equalsIgnoreCase(cm) ) {
-			return false;
-		}
-		return true;
-	}
-	
-	/**
-	 * Override {@code Object.toString()} to provide something more useful.
-	 * @return A meaningful string describing this object.
-	 */
-	@Override
-	public String toString() {
-		StringBuilder sb = new StringBuilder("CipherSpec: ");
-		sb.append( getCipherTransformation() ).append("; keysize= ").append( getKeySize() );
-		sb.append(" bits; blocksize= ").append( getBlockSize() ).append(" bytes");
-		byte[] iv = getIV();
-		String ivLen = null;
-		if ( iv != null ) {
-			ivLen = "" + iv.length;	// Convert length to a string
-		} else {
-			ivLen = "[No IV present (not set or not required)]";
-		}
-		sb.append("; IV length = ").append( ivLen ).append(" bytes.");
-		return sb.toString();
-	}
-	
+            iv_ = new byte[ iv.length ];
+            CryptoHelper.copyByteArray(iv, iv_);
+        }
+        return this;
+    }
+
+    /**
+     * Return true if the cipher mode requires an IV.
+     * @return True if the cipher mode requires an IV, otherwise false.
+     * */
+    public boolean requiresIV() {
+
+        String cm = getCipherMode();
+
+        // Add any other cipher modes supported by JCE but not requiring IV.
+        // ECB is the only one I'm aware of that doesn't. Mode is not case
+        // sensitive.
+        if ( "ECB".equalsIgnoreCase(cm) ) {
+            return false;
+        }
+        return true;
+    }
+
+    /**
+     * Override {@code Object.toString()} to provide something more useful.
+     * @return A meaningful string describing this object.
+     */
+    @Override
+    public String toString() {
+        StringBuilder sb = new StringBuilder("CipherSpec: ");
+        sb.append( getCipherTransformation() ).append("; keysize= ").append( getKeySize() );
+        sb.append(" bits; blocksize= ").append( getBlockSize() ).append(" bytes");
+        byte[] iv = getIV();
+        String ivLen = null;
+        if ( iv != null ) {
+            ivLen = "" + iv.length;    // Convert length to a string
+        } else {
+            ivLen = "[No IV present (not set or not required)]";
+        }
+        sb.append("; IV length = ").append( ivLen ).append(" bytes.");
+        return sb.toString();
+    }
+
     /**
      * {@inheritDoc}
      */
@@ -399,19 +399,19 @@ public final class CipherSpec implements Serializable {
      */
     protected boolean canEqual(Object other) {
         return (other instanceof CipherSpec);
-    }	
-	
-	/**
-	 * Split the current cipher transformation and return the requested part. 
-	 * @param component The component of the cipher transformation to return.
-	 * @return The cipher algorithm, cipher mode, or padding, as requested.
-	 */
-	private String getFromCipherXform(CipherTransformationComponent component) {
+    }
+
+    /**
+     * Split the current cipher transformation and return the requested part.
+     * @param component The component of the cipher transformation to return.
+     * @return The cipher algorithm, cipher mode, or padding, as requested.
+     */
+    private String getFromCipherXform(CipherTransformationComponent component) {
         int part = component.ordinal();
-		String[] parts = getCipherTransformation().split("/");
+        String[] parts = getCipherTransformation().split("/");
             // Assertion should also be okay here as these conditions are checked
             // elsewhere and this method is private.
-		assert parts.length == 3 : "Invalid cipher transformation: " + getCipherTransformation();	
-		return parts[part];
-	}
+        assert parts.length == 3 : "Invalid cipher transformation: " + getCipherTransformation();
+        return parts[part];
+    }
 }
diff --git a/src/main/java/org/owasp/esapi/crypto/CipherText.java b/src/main/java/org/owasp/esapi/crypto/CipherText.java
index a23aaed..e0b549d 100644
--- a/src/main/java/org/owasp/esapi/crypto/CipherText.java
+++ b/src/main/java/org/owasp/esapi/crypto/CipherText.java
@@ -1,6 +1,6 @@
 /*
  * OWASP Enterprise Security API (ESAPI)
- * 
+ *
  * This file is part of the Open Web Application Security Project (OWASP)
  * Enterprise Security API (ESAPI) project. For details, please see
  * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
@@ -71,9 +71,9 @@ public final class CipherText implements Serializable {
     public  static final int cipherTextVersion = 20130830; // Format: YYYYMMDD, max is 99991231.
         // Required by Serializable classes.
     private static final long serialVersionUID = cipherTextVersion; // Format: YYYYMMDD
-    
+
     private static final Logger logger = ESAPI.getLogger("CipherText");
-    
+
     private CipherSpec cipherSpec_           = null;
     private byte[]     raw_ciphertext_       = null;
     private byte[]     separate_mac_         = null;
@@ -94,7 +94,7 @@ public final class CipherText implements Serializable {
                    CipherTextFlags.PADDING,    CipherTextFlags.KEYSIZE,
                    CipherTextFlags.BLOCKSIZE,  CipherTextFlags.CIPHERTEXT,
                    CipherTextFlags.INITVECTOR);
-    
+
     // These are all the pieces we collect when passed a CipherSpec object.
     private final EnumSet<CipherTextFlags> fromCipherSpec =
         EnumSet.of(CipherTextFlags.ALGNAME,    CipherTextFlags.CIPHERMODE,
@@ -103,7 +103,7 @@ public final class CipherText implements Serializable {
 
     // How much we've collected so far. We start out with having collected nothing.
     private EnumSet<CipherTextFlags> progress = EnumSet.noneOf(CipherTextFlags.class);
-    
+
     // Check if versions of KeyDerivationFunction, CipherText, and
     // CipherTextSerializer are all the same.
     {
@@ -118,7 +118,7 @@ public final class CipherText implements Serializable {
     }
 
     ///////////////////////////  C O N S T R U C T O R S  /////////////////////////
-    
+
     /**
      * Default CTOR. Takes all the defaults from the ESAPI.properties, or
      * default values from initial values from this class (when appropriate)
@@ -128,12 +128,12 @@ public final class CipherText implements Serializable {
         cipherSpec_ = new CipherSpec(); // Uses default for everything but IV.
         received(fromCipherSpec);
     }
-    
+
     /**
      * Construct from a {@code CipherSpec} object. Still needs to have
      * {@link #setCiphertext(byte[])} or {@link #setIVandCiphertext(byte[], byte[])}
      * called to be usable.
-     * 
+     *
      * @param cipherSpec The cipher specification to use.
      */
     public CipherText(final CipherSpec cipherSpec) {
@@ -143,10 +143,10 @@ public final class CipherText implements Serializable {
             received(CipherTextFlags.INITVECTOR);
         }
     }
-    
+
     /**
      * Construct from a {@code CipherSpec} object and the raw ciphertext.
-     * 
+     *
      * @param cipherSpec The cipher specification to use.
      * @param cipherText The raw ciphertext bytes to use.
      * @throws EncryptionException  Thrown if {@code cipherText} is null or
@@ -162,7 +162,7 @@ public final class CipherText implements Serializable {
             received(CipherTextFlags.INITVECTOR);
         }
     }
-    
+
     /** Create a {@code CipherText} object from what is supposed to be a
      *  portable serialized byte array, given in network byte order, that
      *  represents a valid, previously serialized {@code CipherText} object
@@ -194,39 +194,39 @@ public final class CipherText implements Serializable {
      * The cipher transformation name is usually sufficient to be passed to
      * {@link javax.crypto.Cipher#getInstance(String)} to create a
      * <code>Cipher</code> object to decrypt the ciphertext.
-     * 
+     *
      * @return The cipher transformation name used to encrypt the plaintext
      *         resulting in this ciphertext.
      */
     public String getCipherTransformation() {
         return cipherSpec_.getCipherTransformation();
     }
-    
+
     /**
      * Obtain the name of the cipher algorithm used for encrypting the
      * plaintext.
-     * 
+     *
      * @return The name as the cryptographic algorithm used to perform the
      *         encryption resulting in this ciphertext.
      */
     public String getCipherAlgorithm() {
         return cipherSpec_.getCipherAlgorithm();
     }
-    
+
     /**
      * Retrieve the key size used with the cipher algorithm that was used to
      * encrypt data to produce this ciphertext.
-     * 
+     *
      * @return The key size in bits. We work in bits because that's the crypto way!
      */
     public int getKeySize() {
         return cipherSpec_.getKeySize();
     }
-    
+
     /**
      * Retrieve the block size (in bytes!) of the cipher used for encryption.
      * (Note: If an IV is used, this will also be the IV length.)
-     * 
+     *
      * @return The block size in bytes. (Bits, bytes! It's confusing I know. Blame
      *                                  the cryptographers; we've just following
      *                                  convention.)
@@ -234,10 +234,10 @@ public final class CipherText implements Serializable {
     public int getBlockSize() {
         return cipherSpec_.getBlockSize();
     }
-    
+
     /**
      * Get the name of the cipher mode used to encrypt some plaintext.
-     * 
+     *
      * @return The name of the cipher mode used to encrypt the plaintext
      *         resulting in this ciphertext. E.g., "CBC" for "cipher block
      *         chaining", "ECB" for "electronic code book", etc.
@@ -245,10 +245,10 @@ public final class CipherText implements Serializable {
     public String getCipherMode() {
         return cipherSpec_.getCipherMode();
     }
-    
+
     /**
      * Get the name of the padding scheme used to encrypt some plaintext.
-     * 
+     *
      * @return The name of the padding scheme used to encrypt the plaintext
      *         resulting in this ciphertext. Example: "PKCS5Padding". If no
      *         padding was used "None" is returned.
@@ -256,11 +256,11 @@ public final class CipherText implements Serializable {
     public String getPaddingScheme() {
         return cipherSpec_.getPaddingScheme();
     }
-    
+
     /**
      * Return the initialization vector (IV) used to encrypt the plaintext
      * if applicable.
-     *  
+     *
      * @return  The IV is returned if the cipher mode used to encrypt the
      *          plaintext was not "ECB". ECB mode does not use an IV so in
      *          that case, <code>null</code> is returned.
@@ -273,8 +273,8 @@ public final class CipherText implements Serializable {
             return null;
         }
     }
-    
-    /** 
+
+    /**
      * Return true if the cipher mode used requires an IV. Usually this will
      * be true unless ECB mode (which should be avoided whenever possible) is
      * used.
@@ -282,11 +282,11 @@ public final class CipherText implements Serializable {
     public boolean requiresIV() {
         return cipherSpec_.requiresIV();
     }
-    
+
     /**
      * Get the raw ciphertext byte array resulting from encrypting some
      * plaintext.
-     * 
+     *
      * @return A copy of the raw ciphertext as a byte array.
      */
     public byte[] getRawCipherText() {
@@ -299,11 +299,11 @@ public final class CipherText implements Serializable {
             return null;
         }
     }
-    
+
     /**
      * Get number of bytes in raw ciphertext. Zero is returned if ciphertext has not
      * yet been stored.
-     * 
+     *
      * @return The number of bytes of raw ciphertext; 0 if no raw ciphertext has been stored.
      */
     public int getRawCipherTextByteLength() {
@@ -330,7 +330,7 @@ public final class CipherText implements Serializable {
     public String getBase64EncodedRawCipherText() {
         return ESAPI.encoder().encodeForBase64(getRawCipherText(),false);
     }
-    
+
     /**
      * Return the ciphertext as a base64-encoded <code>String</code>. If an
      * IV was used, the IV if first prepended to the raw ciphertext before
@@ -382,7 +382,7 @@ public final class CipherText implements Serializable {
      * implementation of {@code Encryptor} always computes it and includes it.
      * The recipient of the ciphertext can then choose whether or not to validate
      * it.
-     * 
+     *
      * @param authKey The secret key that is used for proving authenticity of
      *              the IV and ciphertext. This key should be derived from
      *              the {@code SecretKey} passed to the
@@ -424,7 +424,7 @@ public final class CipherText implements Serializable {
         }
         // If 'result' is null, we already logged this in computeMAC().
     }
-    
+
     /**
      * Same as {@link #computeAndStoreMAC(SecretKey)} but this is only used by
      * {@code CipherTextSerializeer}. (Has package level access.)
@@ -437,14 +437,14 @@ public final class CipherText implements Serializable {
             assert macComputed() : "MAC failed to compute correctly!";
         }
     }
-    
+
     /**
      * Validate the message authentication code (MAC) associated with the ciphertext.
      * This is mostly meant to ensure that an attacker has not replaced the IV
      * or raw ciphertext with something arbitrary. Note however that it will
      * <i>not</i> detect the case where an attacker simply substitutes one
      * valid ciphertext with another ciphertext.
-     * 
+     *
      * @param authKey The secret key that is used for proving authenticity of
      *              the IV and ciphertext. This key should be derived from
      *              the {@code SecretKey} passed to the
@@ -490,14 +490,14 @@ public final class CipherText implements Serializable {
             return false;    // Deprecated decrypt() method removed, so now return false.
         }
     }
-    
+
     /**
      * Return this {@code CipherText} object as a portable (i.e., network byte
      * ordered) serialized byte array. Note this is <b>not</b> the same as
      * returning a serialized object using Java serialization. Instead this
      * is a representation that all ESAPI implementations will use to pass
      * ciphertext between different programming language implementations.
-     * 
+     *
      * @return A network byte-ordered serialized representation of this object.
      * @throws EncryptionException
      */    // DISCUSS: This method name sucks too. Suggestions???
@@ -509,7 +509,7 @@ public final class CipherText implements Serializable {
                          "all mandatory information has been collected";
             throw new EncryptionException("Can't serialize incomplete ciphertext info", msg);
         }
-        
+
         // If we are supposed to be using a (separate) MAC, also make sure
         // that it has been computed/stored.
         boolean requiresMAC = ESAPI.securityConfiguration().useMACforCipherText();
@@ -522,11 +522,11 @@ public final class CipherText implements Serializable {
             throw new EncryptionException("Can't serialize ciphertext info: Data integrity issue.",
                                           msg);
         }
-        
+
         // OK, everything ready, so give it a shot.
         return new CipherTextSerializer(this).asSerializedByteArray();
     }
-    
+
     ///// Setters /////
     /**
      * Set the raw ciphertext.
@@ -555,7 +555,7 @@ public final class CipherText implements Serializable {
             throw new EncryptionException("MAC already set; cannot store new raw ciphertext", logMsg);
         }
     }
-    
+
     /**
      * Set the IV and raw ciphertext.
      * @param iv            The initialization vector.
@@ -599,7 +599,7 @@ public final class CipherText implements Serializable {
             throw new EncryptionException("Validation of decryption failed.", logMsg);
         }
     }
-    
+
     public int getKDFVersion() {
         return kdfVersion_;
     }
@@ -608,7 +608,7 @@ public final class CipherText implements Serializable {
         CryptoHelper.isValidKDFVersion(vers, false, true);
         kdfVersion_ = vers;
     }
-    
+
     public KeyDerivationFunction.PRF_ALGORITHMS getKDF_PRF() {
         return KeyDerivationFunction.convertIntToPRF(kdfPrfSelection_);
     }
@@ -616,19 +616,19 @@ public final class CipherText implements Serializable {
     int kdfPRFAsInt() {
         return kdfPrfSelection_;
     }
-    
+
     public void setKDF_PRF(int prfSelection) {
         if ( prfSelection < 0 || prfSelection > 15 ) {
             throw new IllegalArgumentException("kdfPrf == " + prfSelection + " must be between 0 and 15, inclusive.");
         }
         kdfPrfSelection_ = prfSelection;
     }
-    
+
     /** Get stored time stamp representing when data was encrypted. */
     public long getEncryptionTimestamp() {
         return encryption_timestamp_;
     }
-    
+
     /**
      * Set the encryption timestamp to the current system time as determined by
      * {@code System.currentTimeMillis()}, but only if it has not been previously
@@ -647,12 +647,12 @@ public final class CipherText implements Serializable {
         }
         encryption_timestamp_ = System.currentTimeMillis();
     }
- 
+
     /**
      * Set the encryption timestamp to the time stamp specified by the parameter.
      * </p><p>
      * This method is intended for use only by {@code CipherTextSerializer}.
-     * 
+     *
      * @param timestamp The time in milliseconds since epoch time (midnight,
      *                  January 1, 1970 GMT).
      */ // Package level access. ESAPI jar should be sealed and signed.
@@ -666,7 +666,7 @@ public final class CipherText implements Serializable {
         }
         encryption_timestamp_ = timestamp;
     }
-    
+
     /** Return the separately calculated Message Authentication Code (MAC) that
      * is computed via the {@code computeAndStoreMAC(SecretKey authKey)} method.
      * @return The copy of the computed MAC, or {@code null} if one is not used.
@@ -677,9 +677,9 @@ public final class CipherText implements Serializable {
         }
         byte[] copy = new byte[ separate_mac_.length ];
         System.arraycopy(separate_mac_, 0, copy, 0, separate_mac_.length);
-        return copy;   
+        return copy;
     }
-    
+
     /**
      * More useful {@code toString()} method.
      */
@@ -782,7 +782,7 @@ public final class CipherText implements Serializable {
     }
 
     ////////////////////////////////////  P R I V A T E  /////////////////////////////////////////
-    
+
     /**
      * Compute a MAC, but do not store it. May set the nonce value as a
      * side-effect.  The MAC is calculated as:
@@ -798,10 +798,10 @@ public final class CipherText implements Serializable {
      * proved in 1996 [see http://pssic.free.fr/Extra%20Reading/SEC+/SEC+/hmac-cb.pdf] that
      * HMAC security doesn’t require that the underlying hash function be collision resistant,
      * but only that it acts as a pseudo-random function, which SHA1 satisfies.
-     * @param authKey    The {@Code SecretKey} used with the computed HMAC-SHA1
+     * @param authKey    The {@code SecretKey} used with the computed HMAC-SHA1
      * to ensure authenticity.
      * @return The value for the MAC.
-     */ 
+     */
     private byte[] computeMAC(SecretKey authKey) {
         // These assertions are okay and leaving them as assertions rather than
         // changing the to conditional statements that throw should be all right
@@ -840,7 +840,7 @@ public final class CipherText implements Serializable {
             return null;
         }
     }
-    
+
     /**
      * Return true if the MAC has already been computed (i.e., not null).
      */
@@ -859,7 +859,7 @@ public final class CipherText implements Serializable {
             EnumSet<CipherTextFlags> initVector = EnumSet.of(CipherTextFlags.INITVECTOR);
             ctFlags = EnumSet.complementOf(initVector);
         }
-        boolean result = progress.containsAll(ctFlags);  
+        boolean result = progress.containsAll(ctFlags);
         return result;
     }
 
@@ -878,7 +878,7 @@ public final class CipherText implements Serializable {
     private void received(CipherTextFlags flag) {
         progress.add(flag);
     }
-    
+
     /**
      * Add all the flags from the specified set to that we've collected so far.
      * @param ctSet A {@code EnumSet<CipherTextFlags>} containing all the flags
diff --git a/src/main/java/org/owasp/esapi/crypto/CipherTextSerializer.java b/src/main/java/org/owasp/esapi/crypto/CipherTextSerializer.java
index 547068c..c5daa7d 100644
--- a/src/main/java/org/owasp/esapi/crypto/CipherTextSerializer.java
+++ b/src/main/java/org/owasp/esapi/crypto/CipherTextSerializer.java
@@ -27,7 +27,7 @@ import org.owasp.esapi.errors.EncryptionException;
  * supports. (Perhaps wishful thinking that other ESAPI implementations such as
  * ESAPI for .NET, ESAPI for C, ESAPI for C++, etc. will all support a single, common
  * serialization technique so they could exchange encrypted data.)
- * 
+ *
  * @author kevin.w.wall@gmail.com
  * @since 2.0
  *
@@ -44,9 +44,9 @@ public class CipherTextSerializer {
     private static final long serialVersionUID = cipherTextSerializerVersion;
 
     private static final Logger logger = ESAPI.getLogger("CipherTextSerializer");
-    
+
     private CipherText cipherText_ = null;
-    
+
     // Check if versions of KeyDerivationFunction, CipherText, and
     // CipherTextSerializer are all the same.
     {
@@ -59,14 +59,14 @@ public class CipherTextSerializer {
             throw new ExceptionInInitializerError("Versions of CipherTextSerializer and KeyDerivationFunction are not compatible.");
         }
     }
-    
+
     public CipherTextSerializer(CipherText cipherTextObj) {
         if ( cipherTextObj == null ) {
             throw new IllegalArgumentException("CipherText object must not be null.");
         }
         cipherText_ = cipherTextObj;
     }
-    
+
     /**
      * Given byte array in network byte order (i.e., big-endian order), convert
      * it so that a {@code CipherText} can be constructed from it.
@@ -116,7 +116,7 @@ public class CipherTextSerializer {
             throw new IllegalArgumentException("MAC length too large. Max is " + Short.MAX_VALUE + " bytes");
         }
         short macLen = (short) mac.length;
-        
+
         byte[] serializedObj = computeSerialization(kdfInfo,
                                                     timestamp,
                                                     cipherXform,
@@ -129,10 +129,10 @@ public class CipherTextSerializer {
                                                     macLen,
                                                     mac
                                                    );
-        
+
         return serializedObj;
     }
-    
+
     /**
      * Return the actual {@code CipherText} object.
      * @return The {@code CipherText} object that we are serializing.
@@ -143,7 +143,7 @@ public class CipherTextSerializer {
         }
         return cipherText_;
     }
-      
+
     /**
      * Take all the individual elements that make of the serialized ciphertext
      * format and put them in order and return them as a byte array.
@@ -204,7 +204,7 @@ public class CipherTextSerializer {
         if ( macLen > 0 ) baos.write(mac, 0, mac.length);
         return baos.toByteArray();
     }
-    
+
     // All strings are written as UTF-8 encoded byte streams with the
     // length prepended before it as a short. The prepended length is
     // more for the benefit of languages like C so they can pre-allocate
@@ -230,7 +230,7 @@ public class CipherTextSerializer {
                            "converting string to UTF8 encoding. Results suspect. Corrupt rt.jar????");
         }
     }
-    
+
     private String readString(ByteArrayInputStream bais, short sz)
         throws NullPointerException, IOException
     {
@@ -242,7 +242,7 @@ public class CipherTextSerializer {
         }
         return new String(bytes, "UTF8");
     }
-    
+
     private void writeShort(ByteArrayOutputStream baos, short s) {
         byte[] shortAsByteArray = ByteConversionUtil.fromShort(s);
         if ( shortAsByteArray.length != 2 ) {
@@ -250,7 +250,7 @@ public class CipherTextSerializer {
         }
         baos.write(shortAsByteArray, 0, 2);
     }
-    
+
     private short readShort(ByteArrayInputStream bais)
         throws NullPointerException, IndexOutOfBoundsException
     {
@@ -261,12 +261,12 @@ public class CipherTextSerializer {
         }
         return ByteConversionUtil.toShort(shortAsByteArray);
     }
-    
+
     private void writeInt(ByteArrayOutputStream baos, int i) {
         byte[] intAsByteArray = ByteConversionUtil.fromInt(i);
         baos.write(intAsByteArray, 0, 4);
     }
-    
+
     private int readInt(ByteArrayInputStream bais)
         throws NullPointerException, IndexOutOfBoundsException
     {
@@ -277,7 +277,7 @@ public class CipherTextSerializer {
         }
         return ByteConversionUtil.toInt(intAsByteArray);
     }
-    
+
     private void writeLong(ByteArrayOutputStream baos, long l) {
         byte[] longAsByteArray = ByteConversionUtil.fromLong(l);
         if ( longAsByteArray.length != 8 ) {
@@ -285,7 +285,7 @@ public class CipherTextSerializer {
         }
         baos.write(longAsByteArray, 0, 8);
     }
-    
+
     private long readLong(ByteArrayInputStream bais)
         throws NullPointerException, IndexOutOfBoundsException
     {
@@ -296,7 +296,7 @@ public class CipherTextSerializer {
         }
         return ByteConversionUtil.toLong(longAsByteArray);
     }
-    
+
     /** Convert the serialized ciphertext byte array to a {@code CipherText}
      * object.
      * @param cipherTextSerializedBytes    The serialized ciphertext as a byte array.
@@ -337,11 +337,11 @@ public class CipherTextSerializer {
                 throw new EncryptionException("Version info from serialized ciphertext not in valid range.",
                              "Likely tampering with KDF version on serialized ciphertext." + logMsg);
             }
-            
+
             debug("convertToCipherText: kdfPrf = " + kdfPrf + ", kdfVers = " + kdfVers);
             if ( ! versionIsCompatible( kdfVers) ) {
                 throw new EncryptionException("This version of ESAPI is not compatible with the version of ESAPI that encrypted your data.",
-                        "KDF version " + kdfVers + " from serialized ciphertext not compatibile with current KDF version of " + 
+                        "KDF version " + kdfVers + " from serialized ciphertext not compatibile with current KDF version of " +
                         KeyDerivationFunction.kdfVersion);
             }
             long timestamp = readLong(bais);
@@ -424,12 +424,12 @@ public class CipherTextSerializer {
      *  the serialized ciphertext. In particular, we assume that if we have a
      *  newer version of KDF than we can support it as we assume that we have
      *  built in backward compatibility.
-     *  
+     *
      *  At this point (ESAPI 2.1.0, KDF version 20130830), all we need to check
      *  if the version is either the current version or the previous version as
      *  both versions work the same. This checking may get more complicated in
      *  the future.
-     *  
+     *
      *  @param readKdfVers    The version information extracted from the serialized
      *                      ciphertext.
      */
@@ -437,7 +437,7 @@ public class CipherTextSerializer {
         if ( readKdfVers <= 0 ) {
             throw new IllegalArgumentException("Extracted KDF version is <= 0. Must be integer >= 1.");
         }
-        
+
         switch ( readKdfVers ) {
         case KeyDerivationFunction.originalVersion:        // First version
             return true;
diff --git a/src/main/java/org/owasp/esapi/crypto/CryptoDiscoverer.java b/src/main/java/org/owasp/esapi/crypto/CryptoDiscoverer.java
index e42c8cf..53ab1c7 100644
--- a/src/main/java/org/owasp/esapi/crypto/CryptoDiscoverer.java
+++ b/src/main/java/org/owasp/esapi/crypto/CryptoDiscoverer.java
@@ -22,8 +22,8 @@ import java.util.List;
 import java.util.regex.Pattern;
 
 public class CryptoDiscoverer {
-	private static String EOL = System.getProperty("line.separator", "\n");
-	
+    private static String EOL = System.getProperty("line.separator", "\n");
+
     public static void main(String... args) {
         String provider = ".*";
         String algorithm = ".*";
@@ -69,7 +69,7 @@ public class CryptoDiscoverer {
     private static void usage() {
         System.out.println("CryptoDiscoverer - Discover or Query for available Crypto Providers and Algorithms");
         System.out.println(EOL + "\t--help\t\t\t\t\tShows this message" + EOL +
-        		"\t--provider <regex>\t\tSearch for particular Provider" + EOL +
+                "\t--provider <regex>\t\tSearch for particular Provider" + EOL +
                 "\t--algorithm <regex>\t\tSearch for a particular Algorithm" + EOL + EOL);
     }
 }
diff --git a/src/main/java/org/owasp/esapi/crypto/CryptoHelper.java b/src/main/java/org/owasp/esapi/crypto/CryptoHelper.java
index 31f276a..922fbf3 100644
--- a/src/main/java/org/owasp/esapi/crypto/CryptoHelper.java
+++ b/src/main/java/org/owasp/esapi/crypto/CryptoHelper.java
@@ -1,6 +1,6 @@
 /*
  * OWASP Enterprise Security API (ESAPI)
- * 
+ *
  * This file is part of the Open Web Application Security Project (OWASP)
  * Enterprise Security API (ESAPI) project. For details, please see
  * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
@@ -31,173 +31,173 @@ import org.owasp.esapi.errors.EncryptionException;
  * All the cryptographic operations use the default cryptographic properties;
  * e.g., default cipher transformation, default key size, default IV type (where
  * applicable), etc.
- * 
+ *
  * @author kevin.w.wall@gmail.com
  * @since 2.0
  */
 public class CryptoHelper {
-	
-	private static final Logger logger = ESAPI.getLogger("CryptoHelper");
 
-	// TODO: Also consider supplying implementation of RFC 2898 / PKCS#5 PBKDF2
-	//		 in this file as well??? Maybe save for ESAPI 2.1 or 3.0.
-	/**
-	 * Generate a random secret key appropriate to the specified cipher algorithm
-	 * and key size.
-	 * @param alg	The cipher algorithm or cipher transformation. (If the latter is
-	 * 				passed, the cipher algorithm is determined from it.) Cannot be
-	 * 				null or empty.
-	 * @param keySize	The key size, in bits.
-	 * @return	A random {@code SecretKey} is returned.
-	 * @throws EncryptionException Thrown if cannot create secret key conforming to
-	 * 				requested algorithm with requested size. Typically this is caused by
-	 * 				specifying an unavailable algorithm or invalid key size.
-	 */
-	public static SecretKey generateSecretKey(String alg, int keySize)
-		throws EncryptionException
-	{
-		if ( alg == null || alg.equals("") ) {
-			throw new IllegalArgumentException("Algorithm must not be null or empty."); // Avoid later possibly ambiguous NPE.
-		}
-		if ( keySize <= 0 ) {
-			throw new IllegalArgumentException("Key size must be positive.");	// Usually should be an even multiple of 8, but not strictly required by alg.
-		}
-		// Don't use CipherSpec here to get algorithm as this may cause assertion
-		// to fail (when enabled) if only algorithm name is passed to us.
-		String[] cipherSpec = alg.split("/");
-		String cipherAlg = cipherSpec[0];
-		try {
-		    // Special case for things like PBEWithMD5AndDES or PBEWithSHA1AndDESede.
-		    // In such cases, the key generator should only request an instance of "PBE".
-		    if ( cipherAlg.toUpperCase().startsWith("PBEWITH") ) {
-		        cipherAlg = "PBE";
-		    }
-			KeyGenerator kgen =
-				KeyGenerator.getInstance( cipherAlg );
-			kgen.init(keySize);
-			return kgen.generateKey();
-		} catch (NoSuchAlgorithmException e) {
-			throw new EncryptionException("Failed to generate random secret key",
-					"Invalid algorithm. Failed to generate secret key for " + alg + " with size of " + keySize + " bits.", e);
-		} catch (InvalidParameterException e) {
-			throw new EncryptionException("Failed to generate random secret key - invalid key size specified.",
-					"Invalid key size. Failed to generate secret key for " + alg + " with size of " + keySize + " bits.", e);
-		}
-	}
+    private static final Logger logger = ESAPI.getLogger("CryptoHelper");
 
-	/**
-	 * The method is ESAPI's Key Derivation Function (KDF) that computes a
-	 * derived key from the {@code keyDerivationKey} for either
-	 * encryption / decryption or for authentication.
-	 * <p>
-	 * <b>CAUTION:</b> If this algorithm for computing derived keys from the
-	 * key derivation key is <i>ever</i> changed, we risk breaking backward compatibility of being
-	 * able to decrypt data previously encrypted with earlier / different versions
-	 * of this method. Therefore, do not change this unless you are 100% certain that
-	 * what you are doing will NOT change either of the derived keys for
-	 * ANY "key derivation key" AT ALL!!!
-	 * <p>
-	 * <b>NOTE:</b> This method is generally not intended to be called separately.
-	 * It is used by ESAPI's reference crypto implementation class {@code JavaEncryptor}
-	 * and might be useful for someone implementing their own replacement class, but
-	 * generally it is not something that is useful to application client code.
-	 * 
-	 * @param keyDerivationKey  A key used as an input to a key derivation function
-	 *                          to derive other keys. This is the key that generally
-	 *                          is created using some key generation mechanism such as
-	 *                          {@link #generateSecretKey(String, int)}. The
-	 *                          "input" key from which the other keys are derived.
-	 * 							The derived key will have the same algorithm type
-	 * 							as this key.
-	 * @param keySize		The cipher's key size (in bits) for the {@code keyDerivationKey}.
-	 * 						Must have a minimum size of 56 bits and be an integral multiple of 8-bits.
-	 * 						<b>Note:</b> The derived key will have the same size as this.
-	 * @param purpose		The purpose for the derived key. Must be either the
-	 * 						string "encryption" or "authenticity". Use "encryption" for
+    // TODO: Also consider supplying implementation of RFC 2898 / PKCS#5 PBKDF2
+    //         in this file as well??? Maybe save for ESAPI 2.1 or 3.0.
+    /**
+     * Generate a random secret key appropriate to the specified cipher algorithm
+     * and key size.
+     * @param alg    The cipher algorithm or cipher transformation. (If the latter is
+     *                 passed, the cipher algorithm is determined from it.) Cannot be
+     *                 null or empty.
+     * @param keySize    The key size, in bits.
+     * @return    A random {@code SecretKey} is returned.
+     * @throws EncryptionException Thrown if cannot create secret key conforming to
+     *                 requested algorithm with requested size. Typically this is caused by
+     *                 specifying an unavailable algorithm or invalid key size.
+     */
+    public static SecretKey generateSecretKey(String alg, int keySize)
+        throws EncryptionException
+    {
+        if ( alg == null || alg.equals("") ) {
+            throw new IllegalArgumentException("Algorithm must not be null or empty."); // Avoid later possibly ambiguous NPE.
+        }
+        if ( keySize <= 0 ) {
+            throw new IllegalArgumentException("Key size must be positive.");    // Usually should be an even multiple of 8, but not strictly required by alg.
+        }
+        // Don't use CipherSpec here to get algorithm as this may cause assertion
+        // to fail (when enabled) if only algorithm name is passed to us.
+        String[] cipherSpec = alg.split("/");
+        String cipherAlg = cipherSpec[0];
+        try {
+            // Special case for things like PBEWithMD5AndDES or PBEWithSHA1AndDESede.
+            // In such cases, the key generator should only request an instance of "PBE".
+            if ( cipherAlg.toUpperCase().startsWith("PBEWITH") ) {
+                cipherAlg = "PBE";
+            }
+            KeyGenerator kgen =
+                KeyGenerator.getInstance( cipherAlg );
+            kgen.init(keySize);
+            return kgen.generateKey();
+        } catch (NoSuchAlgorithmException e) {
+            throw new EncryptionException("Failed to generate random secret key",
+                    "Invalid algorithm. Failed to generate secret key for " + alg + " with size of " + keySize + " bits.", e);
+        } catch (InvalidParameterException e) {
+            throw new EncryptionException("Failed to generate random secret key - invalid key size specified.",
+                    "Invalid key size. Failed to generate secret key for " + alg + " with size of " + keySize + " bits.", e);
+        }
+    }
+
+    /**
+     * The method is ESAPI's Key Derivation Function (KDF) that computes a
+     * derived key from the {@code keyDerivationKey} for either
+     * encryption / decryption or for authentication.
+     * <p>
+     * <b>CAUTION:</b> If this algorithm for computing derived keys from the
+     * key derivation key is <i>ever</i> changed, we risk breaking backward compatibility of being
+     * able to decrypt data previously encrypted with earlier / different versions
+     * of this method. Therefore, do not change this unless you are 100% certain that
+     * what you are doing will NOT change either of the derived keys for
+     * ANY "key derivation key" AT ALL!!!
+     * <p>
+     * <b>NOTE:</b> This method is generally not intended to be called separately.
+     * It is used by ESAPI's reference crypto implementation class {@code JavaEncryptor}
+     * and might be useful for someone implementing their own replacement class, but
+     * generally it is not something that is useful to application client code.
+     *
+     * @param keyDerivationKey  A key used as an input to a key derivation function
+     *                          to derive other keys. This is the key that generally
+     *                          is created using some key generation mechanism such as
+     *                          {@link #generateSecretKey(String, int)}. The
+     *                          "input" key from which the other keys are derived.
+     *                             The derived key will have the same algorithm type
+     *                             as this key.
+     * @param keySize        The cipher's key size (in bits) for the {@code keyDerivationKey}.
+     *                         Must have a minimum size of 56 bits and be an integral multiple of 8-bits.
+     *                         <b>Note:</b> The derived key will have the same size as this.
+     * @param purpose        The purpose for the derived key. Must be either the
+     *                         string "encryption" or "authenticity". Use "encryption" for
      *                      creating a derived key to use for confidentiality, and "authenticity"
      *                      for a derived key to use with a MAC to ensure message authenticity.
-	 * @return				The derived {@code SecretKey} to be used according
-	 * 						to the specified purpose. Note that this serves the same purpose
-	 * 						as "label" in section 5.1 of NIST SP 800-108.
-	 * @throws NoSuchAlgorithmException		The {@code keyDerivationKey} has an unsupported
-	 * 						encryption algorithm or no current JCE provider supports
-	 * 						"HmacSHA1".
-	 * @throws EncryptionException		If "UTF-8" is not supported as an encoding, then
-	 * 						this is thrown with the original {@code UnsupportedEncodingException}
-	 * 						as the cause. (NOTE: This should never happen as "UTF-8" is supposed to
-	 * 						be a common encoding supported by all Java implementations. Support
-	 * 					    for it is usually in rt.jar.) This exception is also thrown if the
-     * 					    requested {@code keySize} parameter exceeds the length of the number of
-     * 					    bytes provded in the {@code keyDerivationKey} parameter.
-	 * @throws InvalidKeyException 	Likely indicates a coding error. Should not happen.
-	 * @throws EncryptionException  Throw for some precondition violations.
-	 * @deprecated Use same method in {@code KeyDerivationFunction} instead. This method will be <b>removed</b> as of
-	 * 			   ESAPI release 2.3 so if you are using this, please CHANGE YOUR CODE. Note that the replacement
-     * 			   is not a static method, so create your own wrapper if you wish, but this will soon disappear.
-	 */
+     * @return                The derived {@code SecretKey} to be used according
+     *                         to the specified purpose. Note that this serves the same purpose
+     *                         as "label" in section 5.1 of NIST SP 800-108.
+     * @throws NoSuchAlgorithmException        The {@code keyDerivationKey} has an unsupported
+     *                         encryption algorithm or no current JCE provider supports
+     *                         "HmacSHA1".
+     * @throws EncryptionException        If "UTF-8" is not supported as an encoding, then
+     *                         this is thrown with the original {@code UnsupportedEncodingException}
+     *                         as the cause. (NOTE: This should never happen as "UTF-8" is supposed to
+     *                         be a common encoding supported by all Java implementations. Support
+     *                         for it is usually in rt.jar.) This exception is also thrown if the
+     *                         requested {@code keySize} parameter exceeds the length of the number of
+     *                         bytes provded in the {@code keyDerivationKey} parameter.
+     * @throws InvalidKeyException     Likely indicates a coding error. Should not happen.
+     * @throws EncryptionException  Throw for some precondition violations.
+     * @deprecated Use same method in {@code KeyDerivationFunction} instead. This method will be <b>removed</b> as of
+     *                ESAPI release 2.3 so if you are using this, please CHANGE YOUR CODE. Note that the replacement
+     *                is not a static method, so create your own wrapper if you wish, but this will soon disappear.
+     */
     @Deprecated
-	public static SecretKey computeDerivedKey(SecretKey keyDerivationKey, int keySize, String purpose)
-			throws NoSuchAlgorithmException, InvalidKeyException, EncryptionException
-	{
+    public static SecretKey computeDerivedKey(SecretKey keyDerivationKey, int keySize, String purpose)
+            throws NoSuchAlgorithmException, InvalidKeyException, EncryptionException
+    {
         // Fingers cross; maybe this will help.
         logger.warning(Logger.SECURITY_AUDIT,
                 "Your code is using the deprecated CryptoHelper.computeDerivedKey() method which will be removed next release");
 
-		if ( keyDerivationKey == null ) {
+        if ( keyDerivationKey == null ) {
             throw new IllegalArgumentException("Key derivation key cannot be null.");
         }
-			// We would choose a larger minimum key size, but we want to be
-			// able to accept DES for legacy encryption needs.
-		if ( keySize < 56 ) {
+            // We would choose a larger minimum key size, but we want to be
+            // able to accept DES for legacy encryption needs.
+        if ( keySize < 56 ) {
             throw new IllegalArgumentException("Key has size of " + keySize + ", which is less than minimum of 56-bits.");
         }
-		if ( (keySize % 8) != 0 ) {
+        if ( (keySize % 8) != 0 ) {
             throw new IllegalArgumentException("Key size (" + keySize + ") must be a even multiple of 8-bits.");
         }
-		if ( purpose == null ) {
+        if ( purpose == null ) {
             throw new IllegalArgumentException("'purpose' may not be null.");
         }
-		if ( ! ( purpose.equals("encryption") || purpose.equals("authenticity") ) ) {
-			throw new IllegalArgumentException("Purpose must be \"encryption\" or \"authenticity\".");
+        if ( ! ( purpose.equals("encryption") || purpose.equals("authenticity") ) ) {
+            throw new IllegalArgumentException("Purpose must be \"encryption\" or \"authenticity\".");
         }
 
-		// DISCUSS: Should we use HmacSHA1 (what we were using) or the HMAC defined by
-		//			Encryptor.KDF.PRF instead? Either way, this is not compatible with
-		//			previous ESAPI versions. JavaEncryptor doesn't use this any longer.
+        // DISCUSS: Should we use HmacSHA1 (what we were using) or the HMAC defined by
+        //            Encryptor.KDF.PRF instead? Either way, this is not compatible with
+        //            previous ESAPI versions. JavaEncryptor doesn't use this any longer.
         // ANSWER:  This is deprecated and will be removed in 2.3.0.0, so it really matter
         //          that much. However, Since the property Encryptor.KDF.PRF is (and has
         //          been) "HMacSHA256". changing this could unintentionally break code.
-		KeyDerivationFunction kdf = new KeyDerivationFunction(
-											KeyDerivationFunction.PRF_ALGORITHMS.HmacSHA1);
-		return kdf.computeDerivedKey(keyDerivationKey, keySize, purpose);
-	}
+        KeyDerivationFunction kdf = new KeyDerivationFunction(
+                                            KeyDerivationFunction.PRF_ALGORITHMS.HmacSHA1);
+        return kdf.computeDerivedKey(keyDerivationKey, keySize, purpose);
+    }
 
-	/**
-	 * Return true if specified cipher mode is one of those specified in the
-	 * {@code ESAPI.properties} file that supports both confidentiality
-	 * <b>and</b> authenticity (i.e., a "combined cipher mode" as NIST refers
-	 * to it).
-	 * @param cipherMode The specified cipher mode to be used for the encryption
-	 *                   or decryption operation.
-	 * @return true if the specified cipher mode is in the comma-separated list
-	 *         of cipher modes supporting both confidentiality and authenticity;
-	 *         otherwise false.
-	 * @see org.owasp.esapi.SecurityConfiguration#getCombinedCipherModes()
-	 */
-	public static boolean isCombinedCipherMode(String cipherMode)
-	{
-	    if ( cipherMode == null ) {
+    /**
+     * Return true if specified cipher mode is one of those specified in the
+     * {@code ESAPI.properties} file that supports both confidentiality
+     * <b>and</b> authenticity (i.e., a "combined cipher mode" as NIST refers
+     * to it).
+     * @param cipherMode The specified cipher mode to be used for the encryption
+     *                   or decryption operation.
+     * @return true if the specified cipher mode is in the comma-separated list
+     *         of cipher modes supporting both confidentiality and authenticity;
+     *         otherwise false.
+     * @see org.owasp.esapi.SecurityConfiguration#getCombinedCipherModes()
+     */
+    public static boolean isCombinedCipherMode(String cipherMode)
+    {
+        if ( cipherMode == null ) {
             throw new IllegalArgumentException("Cipher mode may not be null");
         }
-	    if ( cipherMode.equals("") ) {
+        if ( cipherMode.equals("") ) {
             throw new IllegalArgumentException("Cipher mode may not be empty string");
         }
-	    List<String> combinedCipherModes =
-	        ESAPI.securityConfiguration().getCombinedCipherModes();
-	    return combinedCipherModes.contains( cipherMode );
-	}
+        List<String> combinedCipherModes =
+            ESAPI.securityConfiguration().getCombinedCipherModes();
+        return combinedCipherModes.contains( cipherMode );
+    }
 
-	/**
+    /**
      * Return true if specified cipher mode is one that may be used for
      * encryption / decryption operations via {@link org.owasp.esapi.Encryptor}.
      * @param cipherMode The specified cipher mode to be used for the encryption
@@ -209,16 +209,16 @@ public class CryptoHelper {
      * @see org.owasp.esapi.SecurityConfiguration#getCombinedCipherModes()
      * @see org.owasp.esapi.SecurityConfiguration#getAdditionalAllowedCipherModes()
      */
-	public static boolean isAllowedCipherMode(String cipherMode)
-	{
-	    if ( isCombinedCipherMode(cipherMode) ) {
-	        return true;
-	    }
-	    List<String> extraCipherModes =
-	        ESAPI.securityConfiguration().getAdditionalAllowedCipherModes();
-	    return extraCipherModes.contains( cipherMode );
-	}
-	
+    public static boolean isAllowedCipherMode(String cipherMode)
+    {
+        if ( isCombinedCipherMode(cipherMode) ) {
+            return true;
+        }
+        List<String> extraCipherModes =
+            ESAPI.securityConfiguration().getAdditionalAllowedCipherModes();
+        return extraCipherModes.contains( cipherMode );
+    }
+
     /**
      * Check to see if a Message Authentication Code (MAC) is required
      * for a given {@code CipherText} object and the current ESAPI.property
@@ -247,7 +247,7 @@ public class CryptoHelper {
         // additional computing time.
         return ( !preferredCipherMode && wantsMAC );
     }
-	
+
     /**
      * If a Message Authentication Code (MAC) is required for the specified
      * {@code CipherText} object, then attempt to validate the MAC that
@@ -257,7 +257,7 @@ public class CryptoHelper {
      * @param sk    The {@code SecretKey} used to derived a key to check
      *              the authenticity via the MAC.
      * @param ct    The {@code CipherText} that we are checking for a
-     *              valid MAC. 
+     *              valid MAC.
      *
      * @return  True is returned if a MAC is required and it is valid as
      *          verified using a key derived from the specified
@@ -268,7 +268,7 @@ public class CryptoHelper {
     {
         if ( CryptoHelper.isMACRequired( ct ) ) {
             try {
-		        KeyDerivationFunction kdf = new KeyDerivationFunction( ct.getKDF_PRF() );
+                KeyDerivationFunction kdf = new KeyDerivationFunction( ct.getKDF_PRF() );
                 SecretKey authKey = kdf.computeDerivedKey(sk, ct.getKeySize(), "authenticity");
                 boolean validMAC = ct.validateMAC( authKey );
                 return validMAC;
@@ -282,35 +282,35 @@ public class CryptoHelper {
         }
         return true;
     }
-    
-	/**
-	 * Overwrite a byte array with a specified byte. This is frequently done
-	 * to a plaintext byte array so the sensitive data is not lying around
-	 * exposed in memory.
-	 * @param bytes	The byte array to be overwritten.
-	 * @param x The byte array {@code bytes} is overwritten with this byte.
-	 */
-	public static void overwrite(byte[] bytes, byte x)
-	{
-		Arrays.fill(bytes, x);
-	}
-	
-	/**
-	 * Overwrite a byte array with the byte containing '*'. That is, call
-	 * <pre>
-	 * 		overwrite(bytes, (byte)'*');
-	 * </pre>
-	 * @param bytes The byte array to be overwritten.
-	 */
-	public static void overwrite(byte[] bytes)
-	{
-		overwrite(bytes, (byte)'*');
-	}
-	
-	// These provide for a bit more type safety when copying bytes around.
-	/**
-	 * Same as {@code System.arraycopy(src, 0, dest, 0, length)}.
-	 * 
+
+    /**
+     * Overwrite a byte array with a specified byte. This is frequently done
+     * to a plaintext byte array so the sensitive data is not lying around
+     * exposed in memory.
+     * @param bytes    The byte array to be overwritten.
+     * @param x The byte array {@code bytes} is overwritten with this byte.
+     */
+    public static void overwrite(byte[] bytes, byte x)
+    {
+        Arrays.fill(bytes, x);
+    }
+
+    /**
+     * Overwrite a byte array with the byte containing '*'. That is, call
+     * <pre>
+     *         overwrite(bytes, (byte)'*');
+     * </pre>
+     * @param bytes The byte array to be overwritten.
+     */
+    public static void overwrite(byte[] bytes)
+    {
+        overwrite(bytes, (byte)'*');
+    }
+
+    // These provide for a bit more type safety when copying bytes around.
+    /**
+     * Same as {@code System.arraycopy(src, 0, dest, 0, length)}.
+     *
      * @param      src      the source array.
      * @param      dest     the destination array.
      * @param      length   the number of array elements to be copied.
@@ -318,40 +318,40 @@ public class CryptoHelper {
      *               access of data outside array bounds.
      * @exception  NullPointerException if either <code>src</code> or
      *               <code>dest</code> is <code>null</code>.
-	 */
-	public static void copyByteArray(final byte[] src, byte[] dest, int length)
-	{
-		System.arraycopy(src, 0, dest, 0, length);
-	}
-	
-	/**
-	 * Same as {@code copyByteArray(src, dest, src.length)}.
+     */
+    public static void copyByteArray(final byte[] src, byte[] dest, int length)
+    {
+        System.arraycopy(src, 0, dest, 0, length);
+    }
+
+    /**
+     * Same as {@code copyByteArray(src, dest, src.length)}.
      * @param      src      the source array.
      * @param      dest     the destination array.
      * @exception  IndexOutOfBoundsException  if copying would cause
      *               access of data outside array bounds.
      * @exception  NullPointerException if either <code>src</code> or
      *               <code>dest</code> is <code>null</code>.
-	 */
-	public static void copyByteArray(final byte[] src, byte[] dest)
-	{
-		copyByteArray(src, dest, src.length);
-	}
-	
-	/**
-	 * A "safe" array comparison that is not vulnerable to side-channel
-	 * "timing attacks". All comparisons of non-null, equal length bytes should
-	 * take same amount of time. We use this for cryptographic comparisons.
-	 * 
-	 * @param b1   A byte array to compare.
-	 * @param b2   A second byte array to compare.
-	 * @return     {@code true} if both byte arrays are null or if both byte
-	 *             arrays are identical or have the same value; otherwise
-	 *             {@code false} is returned.
+     */
+    public static void copyByteArray(final byte[] src, byte[] dest)
+    {
+        copyByteArray(src, dest, src.length);
+    }
+
+    /**
+     * A "safe" array comparison that is not vulnerable to side-channel
+     * "timing attacks". All comparisons of non-null, equal length bytes should
+     * take same amount of time. We use this for cryptographic comparisons.
+     *
+     * @param b1   A byte array to compare.
+     * @param b2   A second byte array to compare.
+     * @return     {@code true} if both byte arrays are null or if both byte
+     *             arrays are identical or have the same value; otherwise
+     *             {@code false} is returned.
      * @deprecated  Use java.security.MessageDigest#isEqual(byte[], byte[]) instead.
-	 */
+     */
     @Deprecated
-	public static boolean arrayCompare(byte[] b1, byte[] b2) {
+    public static boolean arrayCompare(byte[] b1, byte[] b2) {
         // Note: See GitHub issue #246 and #554.
         // If we make Java 8 the minimal ESAPI baseline before we remove this
         // method, we can at least remove these next 6 lines. (Issue 554.)
@@ -362,53 +362,53 @@ public class CryptoHelper {
             return false;    // Prevent NPE; compatibility with Java 8 and later.
         }
         return java.security.MessageDigest.isEqual(b1, b2);
-	}
-  
-	/**
-	 * Is this particular KDF version number one that is sane? For that, we
-	 * just make sure it is inbounds of the valid range which is:
-	 * <pre>
-	 *     [20110203, 99991231]
-	 * </pre>
-	 * @param kdfVers	KDF version # that we are checking. Generally this is
-	 * 				extracted from the serialized {@code CipherText}.
-	 * @param restrictToCurrent	If this is set, we do an additional check
-	 *				to see if the KDF version is a later version than the
-	 *				one that this current ESAPI version supports.
-	 * @param throwIfError	Instead of returning {@code false} in the case of
-	 * 				an error, throw an {@code IllegalArgumentException}
-	 * @return	True if in range, false otherwise (except if {@code throwIfError}
-	 * 			is true.}
-	 */
-	public static boolean isValidKDFVersion(int kdfVers, boolean restrictToCurrent,
-											boolean throwIfError)
-				throws IllegalArgumentException
-	{
-		boolean ret = true;
-		
-		if ( kdfVers < KeyDerivationFunction.originalVersion || kdfVers > 99991231 ) {
-			ret = false;
-		} else if ( restrictToCurrent ) {
-			ret = ( kdfVers <= KeyDerivationFunction.kdfVersion );
-		}
-		if ( ret ) {
-			return ret;				// True
-		} else {					// False, so throw or not.
-			logger.warning(Logger.SECURITY_FAILURE, "Possible data tampering. Encountered invalid KDF version #. " +
-						   ( throwIfError ? "Throwing IllegalArgumentException" : "" ));
-			if ( throwIfError ) {	
-				throw new IllegalArgumentException("Version (" + kdfVers + ") invalid. " +
-					"Must be date in format of YYYYMMDD between " + KeyDerivationFunction.originalVersion + "and 99991231.");
-			}
-		}
-		return false;
-	}
-	
+    }
+
+    /**
+     * Is this particular KDF version number one that is sane? For that, we
+     * just make sure it is inbounds of the valid range which is:
+     * <pre>
+     *     [20110203, 99991231]
+     * </pre>
+     * @param kdfVers    KDF version # that we are checking. Generally this is
+     *                 extracted from the serialized {@code CipherText}.
+     * @param restrictToCurrent    If this is set, we do an additional check
+     *                to see if the KDF version is a later version than the
+     *                one that this current ESAPI version supports.
+     * @param throwIfError    Instead of returning {@code false} in the case of
+     *                 an error, throw an {@code IllegalArgumentException}
+     * @return    True if in range, false otherwise (except if {@code throwIfError}
+     *             is true.}
+     */
+    public static boolean isValidKDFVersion(int kdfVers, boolean restrictToCurrent,
+                                            boolean throwIfError)
+                throws IllegalArgumentException
+    {
+        boolean ret = true;
+
+        if ( kdfVers < KeyDerivationFunction.originalVersion || kdfVers > 99991231 ) {
+            ret = false;
+        } else if ( restrictToCurrent ) {
+            ret = ( kdfVers <= KeyDerivationFunction.kdfVersion );
+        }
+        if ( ret ) {
+            return ret;                // True
+        } else {                    // False, so throw or not.
+            logger.warning(Logger.SECURITY_FAILURE, "Possible data tampering. Encountered invalid KDF version #. " +
+                           ( throwIfError ? "Throwing IllegalArgumentException" : "" ));
+            if ( throwIfError ) {
+                throw new IllegalArgumentException("Version (" + kdfVers + ") invalid. " +
+                    "Must be date in format of YYYYMMDD between " + KeyDerivationFunction.originalVersion + "and 99991231.");
+            }
+        }
+        return false;
+    }
+
     /**
      * Prevent public, no-argument CTOR from being auto-generated. Public CTOR
      * is not needed as all methods are static.
      */
     private CryptoHelper() {
-    	;	// Prevent default CTOR from being auto-created.
+        ;    // Prevent default CTOR from being auto-created.
     }
 }
diff --git a/src/main/java/org/owasp/esapi/crypto/CryptoToken.java b/src/main/java/org/owasp/esapi/crypto/CryptoToken.java
index b8dc983..c12ee10 100644
--- a/src/main/java/org/owasp/esapi/crypto/CryptoToken.java
+++ b/src/main/java/org/owasp/esapi/crypto/CryptoToken.java
@@ -1,15 +1,15 @@
 /**
  * OWASP Enterprise Security API (ESAPI)
- * 
+ *
  * This file is part of the Open Web Application Security Project (OWASP)
  * Enterprise Security API (ESAPI) project. For details, please see
  * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
  *
  * Copyright &copy; 2010 - The OWASP Foundation
- * 
+ *
  * The ESAPI is published by OWASP under the BSD license. You should read and
  * accept the LICENSE before you use, modify, and/or redistribute this software.
- * 
+ *
  * @created 2010
  */
 package org.owasp.esapi.crypto;
@@ -79,7 +79,7 @@ import org.owasp.esapi.errors.ValidationException;
  * is, the value is not checked, so beware! When rendering these values, output
  * encoding may be required to prevent XSS. Use ESAPI's {@code Encoder} for that.
  * <p>
- * This entire semicolon-separated string is then encrypted via one of the 
+ * This entire semicolon-separated string is then encrypted via one of the
  * {@code Encryptor.encrypt()} methods and then base64-encoded, serialized
  * IV + ciphertext + MAC representation as determined by
  * {@code CipherTextasPortableSerializedByteArray()} is used as the
@@ -100,17 +100,17 @@ import org.owasp.esapi.errors.ValidationException;
 public class CryptoToken {
     /** Represents an anonymous user. */
     public static final String ANONYMOUS_USER = "<anonymous>";
-    
+
     // Default expiration time
     private static final long DEFAULT_EXP_TIME = 5 * 60 * 1000;  // 5 min == 300 milliseconds
     private static final String DELIM = ";";                     // field delimiter
     private static final char DELIM_CHAR = ';';                  // field delim as a char
     private static final char QUOTE_CHAR = '\\';                 // char used to quote delimiters, '=' and itself.
-    
+
         // OPEN ISSUE: Should we make these 2 regex's properties in ESAPI.properties???
     private static final String ATTR_NAME_REGEX = "[A-Za-z0-9_.-]+"; // One or more alphanumeric, underscore, periods, or hyphens.
     private static final String USERNAME_REGEX = "[a-z][a-z0-9_.@-]*";
-    
+
     private static Logger logger = ESAPI.getLogger("CryptoToken");
 
     private String username = ANONYMOUS_USER;        // Default user name if not set. Always lower case.
@@ -121,10 +121,10 @@ public class CryptoToken {
     private transient SecretKey secretKey = null;
     private Pattern attrNameRegex = Pattern.compile(ATTR_NAME_REGEX);
     private Pattern userNameRegex = Pattern.compile(USERNAME_REGEX);
-    
+
     /**
      * Create a cryptographic token using default secret key from the
-     * <b>ESAPI.properties</b> property <b>Encryptor.MasterKey</b>. 
+     * <b>ESAPI.properties</b> property <b>Encryptor.MasterKey</b>.
      */
     public CryptoToken() {
         secretKey = getDefaultSecretKey(
@@ -137,7 +137,7 @@ public class CryptoToken {
     // Create using specified SecretKey
     /**
      * Create a cryptographic token using specified {@code SecretKey}.
-     * 
+     *
      * @param skey  The specified {@code SecretKey} to use to encrypt the token.
      */
     public CryptoToken(SecretKey skey) {
@@ -149,7 +149,7 @@ public class CryptoToken {
         expirationTime = now + DEFAULT_EXP_TIME;
     }
 
-    /** 
+    /**
      * Create using previously encrypted token encrypted with default secret
      * key from <b>ESAPI.properties</b>.
      * @param token A previously encrypted token returned by one of the
@@ -180,10 +180,10 @@ public class CryptoToken {
         }
     }
 
-    /** 
+    /**
      * Create cryptographic token using previously encrypted token that was
      * encrypted with specified secret key.
-     * 
+     *
      * @param token A previously encrypted token returned by one of the
      *              {@code getToken()} or {@code updateToken()} methods.
      * @throws EncryptionException  Thrown if they are any problems while decrypting
@@ -227,7 +227,7 @@ public class CryptoToken {
     public String getUserAccountName() {
         return ( (username != null) ? username : ANONYMOUS_USER );
     }
-    
+
     /**
      * Set the user account name associated with this cryptographic token
      * object. The user account name is converted to lower case.
@@ -243,10 +243,10 @@ public class CryptoToken {
         if ( userAccountName == null ) {
             throw new IllegalArgumentException("User account name may not be null.");
         }
-        
+
         // Converting to lower case first allows a simpler regex.
         String userAcct = userAccountName.toLowerCase();
-        
+
         // Check to make sure that attribute name is valid as per our regex.
         Matcher userNameChecker = userNameRegex.matcher(userAcct);
         if ( userNameChecker.matches() ) {
@@ -265,7 +265,7 @@ public class CryptoToken {
     public boolean isExpired() {
         return System.currentTimeMillis() > expirationTime;
     }
-    
+
     /**
      * Set expiration time to expire in 'interval' seconds (NOT milliseconds).
      * @param intervalSecs  Number of seconds in the future from current date/time
@@ -274,7 +274,7 @@ public class CryptoToken {
     public void setExpiration(int intervalSecs) throws IllegalArgumentException
     {
         int intervalMillis = intervalSecs * 1000;   // Need to convert secs to millisec.
-        
+
         // Don't want to use assertion here, because if they are disabled,
         // this would result in setting the expiration time prior to the
         // current time, hence it would already be expired.
@@ -288,7 +288,7 @@ public class CryptoToken {
         preAdd(now, intervalMillis);
         expirationTime = now + intervalMillis;
     }
-    
+
     /**
      * Set expiration time for a specific date/time.
      * @param expirationDate    The date/time at which the token will fail. Must
@@ -304,10 +304,10 @@ public class CryptoToken {
         long expTime = expirationDate.getTime();
         if ( expTime <= curTime ) {
             throw new IllegalArgumentException("Expiration date must be after current date/time.");
-        }        
+        }
         expirationTime = expTime;
     }
-    
+
     /**
      * Return the expiration time in milliseconds since epoch time (midnight,
      * January 1, 1970 UTC).
@@ -320,7 +320,7 @@ public class CryptoToken {
         assert expirationTime > 0L : "Programming error: Expiration time <= 0";
         return expirationTime;
     }
-    
+
     /**
      * Return the expiration time as a {@code Date}.
      * @return The {@code Date} object representing the expiration time.
@@ -344,7 +344,7 @@ public class CryptoToken {
         }
         if ( value == null ) {
             throw new ValidationException("Null attribute VALUE encountered for attr name " + name,
-                                          "Attribute VALUE may not be null; attr name: " + name);            
+                                          "Attribute VALUE may not be null; attr name: " + name);
         }
         // NOTE: OTOH, it *is* VALID if the _value_ is empty! Null values cause too much trouble
         // to make it worth the effort of getting it to work consistently.
@@ -359,12 +359,12 @@ public class CryptoToken {
                                           ATTR_NAME_REGEX);
         }
     }
-    
+
     /**
      * Add the specified collection of attributes to the current attributes.
      * If there are duplicate attributes specified, they will replace any
      * existing ones.
-     * 
+     *
      * @param attrs Name/value pairs of attributes to add or replace the existing
      *              attributes. Map must be non-null, but may be empty.
      * @throws ValidationException Thrown if one of the keys in the specified
@@ -387,7 +387,7 @@ public class CryptoToken {
         }
         return;
     }
-    
+
     /**
      * Retrieve the attribute with the specified name.
      * @param name  The attribute name.
@@ -397,13 +397,13 @@ public class CryptoToken {
     public String getAttribute(String name) {
         return attributes.get(name);
     }
-    
+
     /**
      * Retrieve a {@code Map} that is a clone of all the attributes. A <i>copy</i>
      * is returned so that the attributes in {@code CrytpToken} are unaffected
      * by alterations made the returned {@code Map}. (Otherwise, multi-threaded code
      * could get trick.
-     * 
+     *
      * @return  A {@code Map} of all the attributes.
      * @see #getAttribute(String)
      */
@@ -412,7 +412,7 @@ public class CryptoToken {
         // Unfortunately, this requires a cast, which requires us to supress warnings.
         return (Map<String, String>) attributes.clone();
     }
-    
+
     /**
      * Removes all the attributes (if any) associated with this token. Note
      * that this does not clear / reset the user account name or expiration time.
@@ -440,7 +440,7 @@ public class CryptoToken {
      *      SecretKey aliceSecretKey = ...  // Shared with Alice
      *      SecretKey bobSecretKey = ...;   // Shared with Carol
      *      CryptoToken cryptoToken = new CryptoToken(aliceSecretKey, tokenFromAlice);
-     *      
+     *
      *      // Re-encrypt for Carol using my (Bob's) key...
      *      String tokenForCarol = cryptoToken.getToken(bobSecretKey);
      *      // send tokenForCarol to Carol ...
@@ -466,12 +466,12 @@ public class CryptoToken {
     public String getToken(SecretKey skey) throws EncryptionException {
         return createEncryptedToken(skey);
     }
-    
+
     /**
      * Update the (current) expiration time by adding the specified number of
      * seconds to it and then re-encrypting with the current {@code SecretKey}
      * that was used to construct this object.
-     * 
+     *
      * @param additionalSecs    The additional number of seconds to add to the
      *                          current expiration time. This number must be
      *                          &gt;= 0 or otherwise an {@code IllegalArgumentException}
@@ -493,7 +493,7 @@ public class CryptoToken {
         if ( additionalSecs < 0) {
             throw new IllegalArgumentException("additionalSecs argument must be >= 0.");
         }
-        
+
         // Avoid integer overflow. This could happen if one first calls
         // setExpiration(Date) with a date far into the future. We want
         // to avoid overflows as they might lead to security vulnerabilities.
@@ -503,14 +503,14 @@ public class CryptoToken {
             //       'long'. Could convert to Date first, and use
             //       setExpiration(Date) but that hardly seems worth the trouble.
         expirationTime = curExpTime + (additionalSecs * 1000);
-        
+
         if ( isExpired() ) {
             // Too bad there is no ProcrastinationException ;-)
             expirationTime = curExpTime;    // Restore the original value (which still may
                                             // be expired.
             throw new ValidationException("Token timed out.",
                     "Cryptographic token not increased to sufficient value to prevent timeout.");
-            
+
         }
             // Don't change anything else (user acct name, attributes, skey, etc.)
         return getToken();
@@ -519,14 +519,14 @@ public class CryptoToken {
     /**
      * Return the new encrypted token as a base64-encoded string, encrypted with
      * the specified {@code SecretKey} with which this object was constructed.
-     * 
+     *
      * @return The newly encrypted token.
      * @see #getToken(SecretKey)
      */
     public String getToken() throws EncryptionException {
         return createEncryptedToken(secretKey);
     }
-   
+
     // Create the actual encrypted token based on the specified SecretKey.
     // This method will ensure that the decrypted token always ends with an
     // unquoted delimiter.
@@ -537,7 +537,7 @@ public class CryptoToken {
         //          If so, then updateToken() should also be revisited.
         sb.append( getExpiration() ).append( DELIM );
         sb.append( getQuotedAttributes() );
-        
+
         Encryptor encryptor = ESAPI.encryptor();
         CipherText ct = encryptor.encrypt(skey, new PlainText( sb.toString() ) );
         String b64 =
@@ -545,7 +545,7 @@ public class CryptoToken {
                                             false);
         return b64;
     }
-    
+
     // Return a string of all the attributes, properly quoted. This is used in
     // creating the encrypted token. Note that this method ensures that the
     // quoted attribute string always ends with an (quoted) delimiter.
@@ -563,7 +563,7 @@ public class CryptoToken {
         }
         return sb.toString();
     }
-    
+
     // Do NOT define a toString() method as there may be sensitive
     // information contained in the attribute names. If we absolutely
     // need this, then only return the username and expiration time, and
@@ -572,8 +572,8 @@ public class CryptoToken {
     /*
      * public String toString() { return null; }
      */
-    
-    
+
+
     // Quote any special characters in value.
     private static String quoteAttributeValue(String value) {
         if ( value == null ) {
@@ -592,7 +592,7 @@ public class CryptoToken {
         }
         return sb.toString();
     }
-    
+
     // Parse the possibly quoted value and return the unquoted value.
     private static String parseQuotedValue(String quotedValue) {
         StringBuilder sb = new StringBuilder();
@@ -608,7 +608,7 @@ public class CryptoToken {
         }
         return sb.toString();
     }
-    
+
     /*
      * Decrypt the encrypted token and parse it into the individual components.
      * The string should always end with a semicolon (;) even when there are
@@ -682,9 +682,9 @@ public class CryptoToken {
                 fields.add( record );
                 fieldNo++;
                 prevPos = curPos;
-            } 
+            }
         }
-        
+
         Object[] objArray = fields.toArray();
         if ( fieldNo != objArray.length ) {
             String exm = "Programming error???: Mismatch of delimited field count.";
@@ -698,7 +698,7 @@ public class CryptoToken {
         username = ((String)(objArray[0])).toLowerCase();
         String expTime = (String)objArray[1];
         expirationTime = Long.parseLong(expTime);
-        
+
         for( int i = 2; i < objArray.length; i++ ) {
             String nvpair = (String)objArray[i];
             int equalsAt = nvpair.indexOf("=");
@@ -726,7 +726,7 @@ public class CryptoToken {
         }
         return;
     }
-    
+
     private SecretKey getDefaultSecretKey(String encryptAlgorithm) {
         if ( encryptAlgorithm == null ) {
             throw new IllegalArgumentException("Encryption algorithm cannot be null");
@@ -745,7 +745,7 @@ public class CryptoToken {
         // decryption.
         return new SecretKeySpec(skey, encryptAlgorithm );
     }
-    
+
     // Check precondition to see if addition of two operands will result in
     // arithmetic overflow. Note that the operands are of two different
     // integral types. I.e., check to see if:
diff --git a/src/main/java/org/owasp/esapi/crypto/KeyDerivationFunction.java b/src/main/java/org/owasp/esapi/crypto/KeyDerivationFunction.java
index 7535eec..02f925b 100644
--- a/src/main/java/org/owasp/esapi/crypto/KeyDerivationFunction.java
+++ b/src/main/java/org/owasp/esapi/crypto/KeyDerivationFunction.java
@@ -1,6 +1,6 @@
 /*
  * OWASP Enterprise Security API (ESAPI)
- * 
+ *
  * This file is part of the Open Web Application Security Project (OWASP)
  * Enterprise Security API (ESAPI) project. For details, please see
  * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
@@ -21,7 +21,7 @@ import org.owasp.esapi.ESAPI;
 import org.owasp.esapi.Logger;
 import org.owasp.esapi.errors.ConfigurationException;
 import org.owasp.esapi.errors.EncryptionException;
-import org.owasp.esapi.reference.DefaultSecurityConfiguration;
+import static org.owasp.esapi.PropNames.KDF_PRF_ALG;
 import org.owasp.esapi.util.ByteConversionUtil;
 
 /**
@@ -41,67 +41,67 @@ import org.owasp.esapi.util.ByteConversionUtil;
  * @since 2.0
  */
 public class KeyDerivationFunction {
-	/**
-	 * Used to support backward compatibility. {@code kdfVersion} is used as the
-	 * version for the serialized encrypted ciphertext on all the "encrypt"
-	 * operations. This static field should be the same as
-	 * {@link CipherText#cipherTextVersion} and
-	 * {@link CipherTextSerializer#cipherTextSerializerVersion} to make sure
-	 * that these classes are all kept in-sync in order to support backward
-	 * compatibility of previously encrypted data.
-	 * <pre>
-	 * Previous versions:	20110203 - Original version (ESAPI releases 2.0 & 2.0.1)
-	 *					    20130830 - Fix to issue #306 (release 2.1.0)
-	 * </pre>
-	 * @see CipherTextSerializer#asSerializedByteArray()
-	 * @see CipherText#asPortableSerializedByteArray()
-	 * @see CipherText#fromPortableSerializedBytes(byte[])
-	 */
-	public  static final int  originalVersion  = 20110203;	 // First version. Do not change. EVER!
-	public  static final int  kdfVersion       = 20130830;   // Current version. Format: YYYYMMDD, max is 99991231.
-	private static final long serialVersionUID = kdfVersion; // Format: YYYYMMDD
-	
+    /**
+     * Used to support backward compatibility. {@code kdfVersion} is used as the
+     * version for the serialized encrypted ciphertext on all the "encrypt"
+     * operations. This static field should be the same as
+     * {@link CipherText#cipherTextVersion} and
+     * {@link CipherTextSerializer#cipherTextSerializerVersion} to make sure
+     * that these classes are all kept in-sync in order to support backward
+     * compatibility of previously encrypted data.
+     * <pre>
+     * Previous versions:    20110203 - Original version (ESAPI releases 2.0 & 2.0.1)
+     *                        20130830 - Fix to issue #306 (release 2.1.0)
+     * </pre>
+     * @see CipherTextSerializer#asSerializedByteArray()
+     * @see CipherText#asPortableSerializedByteArray()
+     * @see CipherText#fromPortableSerializedBytes(byte[])
+     */
+    public  static final int  originalVersion  = 20110203;     // First version. Do not change. EVER!
+    public  static final int  kdfVersion       = 20130830;   // Current version. Format: YYYYMMDD, max is 99991231.
+    private static final long serialVersionUID = kdfVersion; // Format: YYYYMMDD
+
     // Pseudo-random function algorithms suitable for NIST KDF in counter mode.
-	// Note that HmacMD5 is intentionally omitted here!!!
+    // Note that HmacMD5 is intentionally omitted here!!!
     public enum PRF_ALGORITHMS {
-    		// SHA-1, 160-bits
+            // SHA-1, 160-bits
         HmacSHA1(0, 160, "HmacSHA1"),
-        	// SHA-2 candidates, 256-, 384-, and 512-bits
+            // SHA-2 candidates, 256-, 384-, and 512-bits
         HmacSHA256(1, 256, "HmacSHA256"),
         HmacSHA384(2, 384, "HmacSHA384"),
         HmacSHA512(3, 512, "HmacSHA512");
-        	// Reserved for SHA-3 winner, 224-, 256-, 384-, and 512-bits
-        	// Names not yet known. Will use standard JCE alg names here.
-        	//
-        	// E.g., might be something like
-        	//		HmacSHA3_224(4, 224, "HmacSHA3-224"),
-        	//		HmacSHA3_256(5, 256, "HmacSHA3-256"),
-        	//		HmacSHA3_384(6, 384, "HmacSHA3-385"),
-        	//		HmacSHA3_512(7, 512, "HmacSHA3-512");
+            // Reserved for SHA-3 winner, 224-, 256-, 384-, and 512-bits
+            // Names not yet known. Will use standard JCE alg names here.
+            //
+            // E.g., might be something like
+            //        HmacSHA3_224(4, 224, "HmacSHA3-224"),
+            //        HmacSHA3_256(5, 256, "HmacSHA3-256"),
+            //        HmacSHA3_384(6, 384, "HmacSHA3-385"),
+            //        HmacSHA3_512(7, 512, "HmacSHA3-512");
         // Reserved for future use -- values 8 through 15
         //  Most likely these might be some other strong contenders that
         //  were are based on HMACs from the NIST SHA-3 finalists.
-        
-        private final byte value;	// Value stored in serialized encrypted data to represent PRF
+
+        private final byte value;    // Value stored in serialized encrypted data to represent PRF
         private final short bits;
         private final String algName;
-        
+
         PRF_ALGORITHMS(int value, int bits, String algName) {
-        	this.value = (byte) value;
-        	this.bits  = (short) bits;
-        	this.algName = algName;
+            this.value = (byte) value;
+            this.bits  = (short) bits;
+            this.algName = algName;
         }
-        
+
         public byte getValue() { return value; }
         public short getBits() { return bits; }
         public String getAlgName() { return algName; }
     }
 
-	private static final Logger logger = ESAPI.getLogger("KeyDerivationFunction");
+    private static final Logger logger = ESAPI.getLogger("KeyDerivationFunction");
 
-	private String prfAlg_ = null;
-	private int version_ = kdfVersion;
-	private String context_ = "";
+    private String prfAlg_ = null;
+    private int version_ = kdfVersion;
+    private String context_ = "";
 
     // Check if versions of KeyDerivationFunction, CipherText, and
     // CipherTextSerializer are all the same.
@@ -115,196 +115,195 @@ public class KeyDerivationFunction {
             throw new ExceptionInInitializerError("Versions of CipherTextSerializer and KeyDerivationFunction are not compatible.");
         }
     }
-    
-	/**
-	 * Construct a {@code KeyDerivationFunction}.
-	 * @param prfAlg	Specifies a supported algorithm.
-	 */
-	public KeyDerivationFunction(KeyDerivationFunction.PRF_ALGORITHMS prfAlg) {
-		this.prfAlg_ = prfAlg.getAlgName();
-	}
-
-	/**
-	 * Construct a {@code KeyDerivationFunction} based on the
-	 * <b>ESAPI.property</b> property, {@code Encryptor.KDF.PRF}.
-	 */
-	public KeyDerivationFunction() {			
-		String prfName = ESAPI.securityConfiguration().getKDFPseudoRandomFunction();
-		if ( ! KeyDerivationFunction.isValidPRF(prfName) ) {
-    		throw new ConfigurationException("Algorithm name " + prfName +
-    							" not a valid algorithm name for property " +
-    							DefaultSecurityConfiguration.KDF_PRF_ALG);
-		}
-		prfAlg_ = prfName;
-	}
-
-	/**
-	 * Return the name of the algorithm for the Pseudo Random Function (PRF)
-	 * that is being used.
-	 * @return	The PRF algorithm name.
-	 */
-	public String getPRFAlgName() {
-		return prfAlg_;		
-	}
-	
-	/**
-	 * Package level method for use by {@code CipherText} class to get default
-	 * 
-	 */
-	static int getDefaultPRFSelection() {
-		String prfName = ESAPI.securityConfiguration().getKDFPseudoRandomFunction();
-		for (PRF_ALGORITHMS prf : PRF_ALGORITHMS.values()) {
-			if ( prf.getAlgName().equals(prfName) ) {
-				return prf.getValue();
-			}
-		}
-		throw new ConfigurationException("Algorithm name " + prfName +
-				" not a valid algorithm name for property " +
-				DefaultSecurityConfiguration.KDF_PRF_ALG);
-	}
-	
-	/**
-	 * Set version so backward compatibility can be supported. Used to set the
-	 * version to some previous version so that previously encrypted data can
-	 * be decrypted.
-	 * @param version	Date as a integer, in format of YYYYMMDD. Maximum
-	 * 					version date is 99991231 (December 31, 9999).
-	 * @throws	IllegalArgumentException	If {@code version} is not within
-	 * 					the valid range of [20110203, 99991231].
-	 */
-	public void setVersion(int version) throws IllegalArgumentException {
-		CryptoHelper.isValidKDFVersion(version, false, true);
-		this.version_ = version;
-	}
-
-	/**
-	 * Return the version used for backward compatibility.
-	 * @return	The KDF version #, in format YYYYMMDD, used for supporting
-	 * 			backward compatibility.
-	 */
-	public int getVersion() {
-		return version_;
-	}
-	
-	
-	// TODO: IMPORTANT NOTE: In a future release (hopefully starting in 2.3),
-	// we will be using the 'context' to mix in some additional things. At a
-	// minimum, we will be using the KDF version (version_) so that downgrade version
-	// attacks are not possible. Other candidates are the cipher xform and
-	// the timestamp.
-	/**
-	 * Set the 'context' as specified by NIST Special Publication 800-108. NIST
-	 * defines 'context' as "A binary string containing the information related
-	 * to the derived keying material. It may include identities of parties who
-	 * are deriving and/or using the derived keying material and, optionally, a 
-	 * once known by the parties who derive the keys." NIST SP 800-108 seems to
-	 * imply that while 'context' is recommended, that it is optional. In section
-	 * 7.6 of NIST 800-108, NIST uses "SHOULD" rather than "MUST":
-	 * <blockquote>
-	 * "Derived keying material should be bound to all relying
-	 * entities and other information to identify the derived
-	 * keying material. This is called context binding.
-	 * In particular, the identity (or identifier, as the term
-	 * is defined in [NIST SP 800-56A , sic] and [NIST SP
-	 * 800-56B , sic]) of each entity that will access (meaning
-	 * derive, hold, use, and/or distribute) any segment of
-	 * the keying material should be included in the Context
-	 * string input to the KDF, provided that this information
-	 * is known by each entity who derives the keying material."
-	 * </blockquote>
-	 * The ISO/IEC's KDF2 uses a similar construction for their KDF and there
-	 * 'context' data is not specified at all. Therefore, ESAPI 2.0's
-	 * reference implementation, {@code JavaEncryptor}, chooses not to use
-	 * 'context' at all.
-	 * 
-	 * @param context	Optional binary string containing information related to
-	 * 					the derived keying material. By default (if this method
-	 * 					is never called), the empty string is used. May have any
-	 * 					value but {@code null}.
-	 */
-	public void setContext(String context) {
-		if ( context == null ) {
-			throw new IllegalArgumentException("Context may not be null.");
-		}
-		context_ = context;
-	}
-	
-	/**
-	 * Return the optional 'context' that typically contains information
-	 * related to the keying material, such as the identities of the message
-	 * sender and recipient.
-	 * @see #setContext(String)
-	 * @return The 'context' is returned.
-	 */
-	public String getContext() {
-		return context_;
-	}
-
-	/**
-	 * The method is ESAPI's Key Derivation Function (KDF) that computes a
-	 * derived key from the {@code keyDerivationKey} for either
-	 * encryption / decryption or for authentication.
-	 * <p>
-	 * <b>CAUTION:</b> If this algorithm for computing derived keys from the
-	 * key derivation key is <i>ever</i> changed, we risk breaking backward compatibility of being
-	 * able to decrypt data previously encrypted with earlier / different versions
-	 * of this method. Therefore, do not change this unless you are 100% certain that
-	 * what you are doing will NOT change either of the derived keys for
-	 * ANY "key derivation key" AT ALL!!!
-	 * <p>
-	 * <b>NOTE:</b> This method is generally not intended to be called separately.
-	 * It is used by ESAPI's reference crypto implementation class {@code JavaEncryptor}
-	 * and might be useful for someone implementing their own replacement class, but
-	 * generally it is not something that is useful to application client code.
-	 * 
-	 * @param keyDerivationKey  A key used as an input to a key derivation function
-	 *                          to derive other keys. This is the key that generally
-	 *                          is created using some key generation mechanism such as
-	 *                          {@link CryptoHelper#generateSecretKey(String, int)}. The
-	 *                          "input" key from which the other keys are derived.
-	 * 							The derived key will have the same algorithm type
-	 * 							as this key. This KDK cannot be null.
-	 * @param keySize		The cipher's key size (in bits) for the {@code keyDerivationKey}.
-	 * 						Must have a minimum size of 56 bits and be an integral multiple of 8-bits.
-	 * 						<b>Note:</b> The derived key will have the same size as this.
-	 * @param purpose		The purpose for the derived key. <b>IMPORTANT:</b> For the ESAPI reference implementation,
-	 * 						{@code JavaEncryptor}, this <i>must</i> be either the string "encryption" or
-	 * 						"authenticity", where "encryption" is used for creating a derived key to use
-	 * 						for confidentiality, and "authenticity" is used for creating a derived key to
-	 * 						use with a MAC to ensure message authenticity. However, since parameter serves
-	 * 						the same purpose as the "Label" in section 5.1 of NIST SP 800-108, it really can
-	 * 						be set to anything other than {@code null} or an empty string when called outside
-	 * 						of ESAPI's {@code JavaEncryptor} reference implementation (but you must consistent).
-	 * @return				The derived {@code SecretKey} to be used according
-	 * 						to the specified purpose. 
-	 * @throws NoSuchAlgorithmException		The {@code keyDerivationKey} has an unsupported
-	 * 						encryption algorithm or no current JCE provider supports requested
-     * 						Hmac algorithrm used for the PRF for key generation.
-	 * @throws EncryptionException		If "UTF-8" is not supported as an encoding, then
-	 * 						this is thrown with the original {@code UnsupportedEncodingException}
-	 * 						as the cause. (NOTE: This should never happen as "UTF-8" is supposed to
-	 * 						be a common encoding supported by all Java implementations. Support
-	 * 					    for it is usually in rt.jar.) This exception is also thrown if the
-     * 					    requested {@code keySize} parameter exceeds the length of the number of
-     * 					    bytes provded in the {@code keyDerivationKey} parameter.
-	 * @throws InvalidKeyException 	Likely indicates a coding error. Should not happen.
-	 * @throws EncryptionException  Throw for some precondition violations.
-	 */
-	public SecretKey computeDerivedKey(SecretKey keyDerivationKey, int keySize, String purpose)
-			throws NoSuchAlgorithmException, InvalidKeyException, EncryptionException
-	{
-		// Acknowledgments: David Wagner first suggested this approach, I (Kevin Wall)
-		//				    stumbled upon NIST SP 800-108 and used it as a basis to
-		//				    extend it. Later it was changed that conforms more closely
-		//					to section 5.1 of NIST SP 800-108 based on feedback from
-		//					Jeffrey Walton.
-		//
-
-		// These checks used to be assertions prior to ESAPI 2.1.0.1
-		if ( keyDerivationKey == null ) {
-			throw new IllegalArgumentException("Key derivation key cannot be null.");
-		}
-			// We would choose a larger minimum key size, but we want to allow
+
+    /**
+     * Construct a {@code KeyDerivationFunction}.
+     * @param prfAlg    Specifies a supported algorithm.
+     */
+    public KeyDerivationFunction(KeyDerivationFunction.PRF_ALGORITHMS prfAlg) {
+        this.prfAlg_ = prfAlg.getAlgName();
+    }
+
+    /**
+     * Construct a {@code KeyDerivationFunction} based on the
+     * <b>ESAPI.property</b> property, {@code Encryptor.KDF.PRF}.
+     */
+    public KeyDerivationFunction() {
+        String prfName = ESAPI.securityConfiguration().getKDFPseudoRandomFunction();
+        if ( ! KeyDerivationFunction.isValidPRF(prfName) ) {
+            throw new ConfigurationException("Algorithm name " + prfName +
+                                " not a valid algorithm name for property " +
+                                KDF_PRF_ALG);
+        }
+        prfAlg_ = prfName;
+    }
+
+    /**
+     * Return the name of the algorithm for the Pseudo Random Function (PRF)
+     * that is being used.
+     * @return    The PRF algorithm name.
+     */
+    public String getPRFAlgName() {
+        return prfAlg_;
+    }
+
+    /**
+     * Package level method for use by {@code CipherText} class to get default
+     *
+     */
+    static int getDefaultPRFSelection() {
+        String prfName = ESAPI.securityConfiguration().getKDFPseudoRandomFunction();
+        for (PRF_ALGORITHMS prf : PRF_ALGORITHMS.values()) {
+            if ( prf.getAlgName().equals(prfName) ) {
+                return prf.getValue();
+            }
+        }
+        throw new ConfigurationException("Algorithm name " + prfName +
+                " not a valid algorithm name for property " + KDF_PRF_ALG);
+    }
+
+    /**
+     * Set version so backward compatibility can be supported. Used to set the
+     * version to some previous version so that previously encrypted data can
+     * be decrypted.
+     * @param version    Date as a integer, in format of YYYYMMDD. Maximum
+     *                     version date is 99991231 (December 31, 9999).
+     * @throws    IllegalArgumentException    If {@code version} is not within
+     *                     the valid range of [20110203, 99991231].
+     */
+    public void setVersion(int version) throws IllegalArgumentException {
+        CryptoHelper.isValidKDFVersion(version, false, true);
+        this.version_ = version;
+    }
+
+    /**
+     * Return the version used for backward compatibility.
+     * @return    The KDF version #, in format YYYYMMDD, used for supporting
+     *             backward compatibility.
+     */
+    public int getVersion() {
+        return version_;
+    }
+
+
+    // TODO: IMPORTANT NOTE: In a future release (hopefully starting in 2.3),
+    // we will be using the 'context' to mix in some additional things. At a
+    // minimum, we will be using the KDF version (version_) so that downgrade version
+    // attacks are not possible. Other candidates are the cipher xform and
+    // the timestamp.
+    /**
+     * Set the 'context' as specified by NIST Special Publication 800-108. NIST
+     * defines 'context' as "A binary string containing the information related
+     * to the derived keying material. It may include identities of parties who
+     * are deriving and/or using the derived keying material and, optionally, a
+     * once known by the parties who derive the keys." NIST SP 800-108 seems to
+     * imply that while 'context' is recommended, that it is optional. In section
+     * 7.6 of NIST 800-108, NIST uses "SHOULD" rather than "MUST":
+     * <blockquote>
+     * "Derived keying material should be bound to all relying
+     * entities and other information to identify the derived
+     * keying material. This is called context binding.
+     * In particular, the identity (or identifier, as the term
+     * is defined in [NIST SP 800-56A , sic] and [NIST SP
+     * 800-56B , sic]) of each entity that will access (meaning
+     * derive, hold, use, and/or distribute) any segment of
+     * the keying material should be included in the Context
+     * string input to the KDF, provided that this information
+     * is known by each entity who derives the keying material."
+     * </blockquote>
+     * The ISO/IEC's KDF2 uses a similar construction for their KDF and there
+     * 'context' data is not specified at all. Therefore, ESAPI 2.0's
+     * reference implementation, {@code JavaEncryptor}, chooses not to use
+     * 'context' at all.
+     *
+     * @param context    Optional binary string containing information related to
+     *                     the derived keying material. By default (if this method
+     *                     is never called), the empty string is used. May have any
+     *                     value but {@code null}.
+     */
+    public void setContext(String context) {
+        if ( context == null ) {
+            throw new IllegalArgumentException("Context may not be null.");
+        }
+        context_ = context;
+    }
+
+    /**
+     * Return the optional 'context' that typically contains information
+     * related to the keying material, such as the identities of the message
+     * sender and recipient.
+     * @see #setContext(String)
+     * @return The 'context' is returned.
+     */
+    public String getContext() {
+        return context_;
+    }
+
+    /**
+     * The method is ESAPI's Key Derivation Function (KDF) that computes a
+     * derived key from the {@code keyDerivationKey} for either
+     * encryption / decryption or for authentication.
+     * <p>
+     * <b>CAUTION:</b> If this algorithm for computing derived keys from the
+     * key derivation key is <i>ever</i> changed, we risk breaking backward compatibility of being
+     * able to decrypt data previously encrypted with earlier / different versions
+     * of this method. Therefore, do not change this unless you are 100% certain that
+     * what you are doing will NOT change either of the derived keys for
+     * ANY "key derivation key" AT ALL!!!
+     * <p>
+     * <b>NOTE:</b> This method is generally not intended to be called separately.
+     * It is used by ESAPI's reference crypto implementation class {@code JavaEncryptor}
+     * and might be useful for someone implementing their own replacement class, but
+     * generally it is not something that is useful to application client code.
+     *
+     * @param keyDerivationKey  A key used as an input to a key derivation function
+     *                          to derive other keys. This is the key that generally
+     *                          is created using some key generation mechanism such as
+     *                          {@link CryptoHelper#generateSecretKey(String, int)}. The
+     *                          "input" key from which the other keys are derived.
+     *                             The derived key will have the same algorithm type
+     *                             as this key. This KDK cannot be null.
+     * @param keySize        The cipher's key size (in bits) for the {@code keyDerivationKey}.
+     *                         Must have a minimum size of 56 bits and be an integral multiple of 8-bits.
+     *                         <b>Note:</b> The derived key will have the same size as this.
+     * @param purpose        The purpose for the derived key. <b>IMPORTANT:</b> For the ESAPI reference implementation,
+     *                         {@code JavaEncryptor}, this <i>must</i> be either the string "encryption" or
+     *                         "authenticity", where "encryption" is used for creating a derived key to use
+     *                         for confidentiality, and "authenticity" is used for creating a derived key to
+     *                         use with a MAC to ensure message authenticity. However, since parameter serves
+     *                         the same purpose as the "Label" in section 5.1 of NIST SP 800-108, it really can
+     *                         be set to anything other than {@code null} or an empty string when called outside
+     *                         of ESAPI's {@code JavaEncryptor} reference implementation (but you must consistent).
+     * @return                The derived {@code SecretKey} to be used according
+     *                         to the specified purpose.
+     * @throws NoSuchAlgorithmException        The {@code keyDerivationKey} has an unsupported
+     *                         encryption algorithm or no current JCE provider supports requested
+     *                         Hmac algorithrm used for the PRF for key generation.
+     * @throws EncryptionException        If "UTF-8" is not supported as an encoding, then
+     *                         this is thrown with the original {@code UnsupportedEncodingException}
+     *                         as the cause. (NOTE: This should never happen as "UTF-8" is supposed to
+     *                         be a common encoding supported by all Java implementations. Support
+     *                         for it is usually in rt.jar.) This exception is also thrown if the
+     *                         requested {@code keySize} parameter exceeds the length of the number of
+     *                         bytes provded in the {@code keyDerivationKey} parameter.
+     * @throws InvalidKeyException     Likely indicates a coding error. Should not happen.
+     * @throws EncryptionException  Throw for some precondition violations.
+     */
+    public SecretKey computeDerivedKey(SecretKey keyDerivationKey, int keySize, String purpose)
+            throws NoSuchAlgorithmException, InvalidKeyException, EncryptionException
+    {
+        // Acknowledgments: David Wagner first suggested this approach, I (Kevin Wall)
+        //                    stumbled upon NIST SP 800-108 and used it as a basis to
+        //                    extend it. Later it was changed that conforms more closely
+        //                    to section 5.1 of NIST SP 800-108 based on feedback from
+        //                    Jeffrey Walton.
+        //
+
+        // These checks used to be assertions prior to ESAPI 2.1.0.1
+        if ( keyDerivationKey == null ) {
+            throw new IllegalArgumentException("Key derivation key cannot be null.");
+        }
+            // We would choose a larger minimum key size, but we want to allow
             // this KDF to be able to accept DES for legacy encryption needs. (Note that
             // elsewhere there are checks that disallow *encryption* for key size
             // less than Encryptor.EncryptionKeyLength bits, so if they want
@@ -312,17 +311,17 @@ public class KeyDerivationFunction {
             // be 56 bits. But I can't think of any valid symmetric encryption
             // algorithm whose key size is less than 56 bits that we would ever
             // want to allow.
-		if ( keySize < 56 ) {
-			throw new IllegalArgumentException("Key has size of " + keySize +
-											   ", which is less than minimum of 56-bits.");
-		}
-		if ( (keySize % 8) != 0 ) {
-			throw new IllegalArgumentException("Key size (" + keySize +
-											   ") must be a even multiple of 8-bits.");
-		}
-		if ( purpose == null || "".equals(purpose) ) {
-			throw new IllegalArgumentException("Purpose may not be null or empty.");
-		}
+        if ( keySize < 56 ) {
+            throw new IllegalArgumentException("Key has size of " + keySize +
+                                               ", which is less than minimum of 56-bits.");
+        }
+        if ( (keySize % 8) != 0 ) {
+            throw new IllegalArgumentException("Key size (" + keySize +
+                                               ") must be a even multiple of 8-bits.");
+        }
+        if ( purpose == null || "".equals(purpose) ) {
+            throw new IllegalArgumentException("Purpose may not be null or empty.");
+        }
 
         //
         // No longer, since we no longer wish to restrict this to use only by JavaEncryptor, so
@@ -346,54 +345,54 @@ public class KeyDerivationFunction {
                             providedKeyLen + " bits) to generate key of requested size of " + keySize + " bits.");
         }
 
-		keySize = calcKeySize( keySize );	// Safely convert from bits to a whole # of bytes.
-		byte[] derivedKey = new byte[ keySize ];
-		byte[] label;				    	// Same purpose as NIST SP 800-108's "label" in section 5.1.
-		byte[] context;						// See setContext() for details.
-		try {
-			label = purpose.getBytes("UTF-8");
-			context = context_.getBytes("UTF-8");
-		} catch (UnsupportedEncodingException e) {
-			throw new EncryptionException("Encryption failure (internal encoding error: UTF-8)",
-					 "UTF-8 encoding is NOT supported as a standard byte encoding: " + e.getMessage(), e);
-		}
-		
-			// Note that keyDerivationKey is going to be some SecretKey like an AES or
-			// DESede key, but not an HmacSHA1 key. That means it is not likely
-			// going to be 20 bytes but something different. Experiments show
-			// that doesn't really matter though as the SecretKeySpec CTOR on
-			// the following line still returns the appropriate sized key for
-			// HmacSHA1. So, if keyDerivationKey was originally (say) a 56-bit
+        keySize = calcKeySize( keySize );    // Safely convert from bits to a whole # of bytes.
+        byte[] derivedKey = new byte[ keySize ];
+        byte[] label;                        // Same purpose as NIST SP 800-108's "label" in section 5.1.
+        byte[] context;                        // See setContext() for details.
+        try {
+            label = purpose.getBytes("UTF-8");
+            context = context_.getBytes("UTF-8");
+        } catch (UnsupportedEncodingException e) {
+            throw new EncryptionException("Encryption failure (internal encoding error: UTF-8)",
+                     "UTF-8 encoding is NOT supported as a standard byte encoding: " + e.getMessage(), e);
+        }
+
+            // Note that keyDerivationKey is going to be some SecretKey like an AES or
+            // DESede key, but not an HmacSHA1 key. That means it is not likely
+            // going to be 20 bytes but something different. Experiments show
+            // that doesn't really matter though as the SecretKeySpec CTOR on
+            // the following line still returns the appropriate sized key for
+            // HmacSHA1. So, if keyDerivationKey was originally (say) a 56-bit
             // DES key, then there is apparently some key-stretching going on here
             // under the hood to create 'sk' so that it is 20 bytes. I cannot vouch
             // for how secure this key-stretching is. Worse, it might not be specified
             // as to *how* it is done and left to each JCE provider.
-      	SecretKey sk = new SecretKeySpec(keyDerivationKey.getEncoded(), prfAlg_ );
-		Mac mac = null;
-
-		try {
-    		mac = Mac.getInstance( prfAlg_ );
-			mac.init(sk);
-		} catch( InvalidKeyException ex ) {
-			logger.error(Logger.SECURITY_FAILURE,
-					"Created " + prfAlg_ + " Mac but SecretKey sk has alg " +
-					sk.getAlgorithm(), ex);
-			throw ex;
-		}
-		
-		// Repeatedly call of PRF Hmac until we've collected enough bits
-		// for the derived key. The first time through, we calculate the HmacSHA1
-		// on the "purpose" string, but subsequent calculations are performed
-		// on the previous result.
-		int ctr = 1;		// Iteration counter for NIST 800-108
-		int totalCopied = 0;
-		int destPos = 0;
-		int len = 0;
-		byte[] tmpKey = null;	// Do not declare inside do-while loop!!!
-		do {
-			//
-			// This is to make our KDF more along the line of NIST's.
-			// NIST's Special Publication 800-108 performs the following in
+          SecretKey sk = new SecretKeySpec(keyDerivationKey.getEncoded(), prfAlg_ );
+        Mac mac = null;
+
+        try {
+            mac = Mac.getInstance( prfAlg_ );
+            mac.init(sk);
+        } catch( InvalidKeyException ex ) {
+            logger.error(Logger.SECURITY_FAILURE,
+                    "Created " + prfAlg_ + " Mac but SecretKey sk has alg " +
+                    sk.getAlgorithm(), ex);
+            throw ex;
+        }
+
+        // Repeatedly call of PRF Hmac until we've collected enough bits
+        // for the derived key. The first time through, we calculate the HmacSHA1
+        // on the "purpose" string, but subsequent calculations are performed
+        // on the previous result.
+        int ctr = 1;        // Iteration counter for NIST 800-108
+        int totalCopied = 0;
+        int destPos = 0;
+        int len = 0;
+        byte[] tmpKey = null;    // Do not declare inside do-while loop!!!
+        do {
+            //
+            // This is to make our KDF more along the line of NIST's.
+            // NIST's Special Publication 800-108 performs the following in
             // the iterative loop of Section 5.1:
             //       n := number of blocks required to fulfill request
             //       for i = 1 to n, do
@@ -409,36 +408,36 @@ public class KeyDerivationFunction {
             // document (Section 7.6) implies that Context is to be an
             // optional field (based on NIST's use of the word SHOULD
             // rather than MUST)
-            // 
-			mac.update( ByteConversionUtil.fromInt( ctr++ ) );
-			mac.update(label);
-			mac.update((byte) '\0');
-			mac.update(context); // This is problematic for us. See Jeff Walton's
-								  // analysis of ESAPI 2.0's KDF for details.
-								  // Maybe for 2.1, we'll see; 2.0 too close to GA.
-			
-	            // According to the Javadoc for Mac.doFinal(byte[]),
-	            // "A call to this method resets this Mac object to the state it was
-	            // in when previously initialized via a call to init(Key) or
-	            // init(Key, AlgorithmParameterSpec). That is, the object is reset
-	            // and available to generate another MAC from the same key, if
-	            // desired, via new calls to update and doFinal." Therefore, we do
-	            // not do an explicit reset().
-			tmpKey = mac.doFinal( ByteConversionUtil.fromInt( keySize ) );
-			
-			if ( tmpKey.length >= keySize ) {
-				len = keySize;
-			} else {
-				len = Math.min(tmpKey.length, keySize - totalCopied);
-			}
-			System.arraycopy(tmpKey, 0, derivedKey, destPos, len);
-			label = tmpKey;
-			totalCopied += tmpKey.length;
-			destPos += len;
-		} while( totalCopied < keySize );
-		
-		// Don't leave remnants of the partial key in memory. (Note: we could
-		// not do this if tmpKey were declared in the do-while loop.
+            //
+            mac.update( ByteConversionUtil.fromInt( ctr++ ) );
+            mac.update(label);
+            mac.update((byte) '\0');
+            mac.update(context); // This is problematic for us. See Jeff Walton's
+                                  // analysis of ESAPI 2.0's KDF for details.
+                                  // Maybe for 2.1, we'll see; 2.0 too close to GA.
+
+                // According to the Javadoc for Mac.doFinal(byte[]),
+                // "A call to this method resets this Mac object to the state it was
+                // in when previously initialized via a call to init(Key) or
+                // init(Key, AlgorithmParameterSpec). That is, the object is reset
+                // and available to generate another MAC from the same key, if
+                // desired, via new calls to update and doFinal." Therefore, we do
+                // not do an explicit reset().
+            tmpKey = mac.doFinal( ByteConversionUtil.fromInt( keySize ) );
+
+            if ( tmpKey.length >= keySize ) {
+                len = keySize;
+            } else {
+                len = Math.min(tmpKey.length, keySize - totalCopied);
+            }
+            System.arraycopy(tmpKey, 0, derivedKey, destPos, len);
+            label = tmpKey;
+            totalCopied += tmpKey.length;
+            destPos += len;
+        } while( totalCopied < keySize );
+
+        // Don't leave remnants of the partial key in memory. (Note: we could
+        // not do this if tmpKey were declared in the do-while loop.
         // Of course, in reality, trying to stomp these bits out is probably not
         // realistic because the JIT is likely toing to be smart enough to
         // optimze this loop away. We probably could try to outsmart it, by
@@ -448,48 +447,48 @@ public class KeyDerivationFunction {
         // to a serious limitation in Java and many other languages that one
         // cannot arbitrarily disable the optimizer either at compile time or
         // run time because of security reasons. Sigh. At least we've tried.
-		for ( int i = 0; i < tmpKey.length; i++ ) {
-			tmpKey[i] = '\0';
-		}
-		tmpKey = null;	// Make it immediately eligible for GC.
-		
+        for ( int i = 0; i < tmpKey.length; i++ ) {
+            tmpKey[i] = '\0';
+        }
+        tmpKey = null;    // Make it immediately eligible for GC.
+
         // Convert it back into a SecretKey of the appropriate type.
-		return new SecretKeySpec(derivedKey, keyDerivationKey.getAlgorithm());
-	}
-
-	/**
-	 * Check if specified algorithm name is a valid PRF that can be used.
-	 * @param prfAlgName	Name of the PRF algorithm; e.g., "HmacSHA1", "HmacSHA384", etc.
-	 * @return	True if {@code prfAlgName} is supported, otherwise false.
-	 */
-	public static boolean isValidPRF(String prfAlgName) {
-		for (PRF_ALGORITHMS prf : PRF_ALGORITHMS.values()) {
-			if ( prf.getAlgName().equals(prfAlgName) ) {
-				return true;
-			}
-		}
-		return false;
-	}
-
-	public static PRF_ALGORITHMS convertNameToPRF(String prfAlgName) {
-		for (PRF_ALGORITHMS prf : PRF_ALGORITHMS.values()) {
-			if ( prf.getAlgName().equals(prfAlgName) ) {
-				return prf;
-			}
-		}
-		throw new IllegalArgumentException("Algorithm name " + prfAlgName +
-				" not a valid PRF algorithm name for the ESAPI KDF.");
-	}
-	
-	public static PRF_ALGORITHMS convertIntToPRF(int selection) {
-		for (PRF_ALGORITHMS prf : PRF_ALGORITHMS.values()) {
-			if ( prf.getValue() == selection ) {
-				return prf;
-			}
-		}
-		throw new IllegalArgumentException("No KDF PRF algorithm found for value name " + selection);		
-	}
-	
+        return new SecretKeySpec(derivedKey, keyDerivationKey.getAlgorithm());
+    }
+
+    /**
+     * Check if specified algorithm name is a valid PRF that can be used.
+     * @param prfAlgName    Name of the PRF algorithm; e.g., "HmacSHA1", "HmacSHA384", etc.
+     * @return    True if {@code prfAlgName} is supported, otherwise false.
+     */
+    public static boolean isValidPRF(String prfAlgName) {
+        for (PRF_ALGORITHMS prf : PRF_ALGORITHMS.values()) {
+            if ( prf.getAlgName().equals(prfAlgName) ) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    public static PRF_ALGORITHMS convertNameToPRF(String prfAlgName) {
+        for (PRF_ALGORITHMS prf : PRF_ALGORITHMS.values()) {
+            if ( prf.getAlgName().equals(prfAlgName) ) {
+                return prf;
+            }
+        }
+        throw new IllegalArgumentException("Algorithm name " + prfAlgName +
+                " not a valid PRF algorithm name for the ESAPI KDF.");
+    }
+
+    public static PRF_ALGORITHMS convertIntToPRF(int selection) {
+        for (PRF_ALGORITHMS prf : PRF_ALGORITHMS.values()) {
+            if ( prf.getValue() == selection ) {
+                return prf;
+            }
+        }
+        throw new IllegalArgumentException("No KDF PRF algorithm found for value name " + selection);
+    }
+
     /**
      * Calculate the size of a key. The key size is given in bits, but we
      * can only allocate them by octets (i.e., bytes), so make sure we
@@ -522,11 +521,11 @@ public class KeyDerivationFunction {
      *
      * @param args  Required, but not used.
      */
-	public static final void main(String args[]) {
-		System.out.println("Supported pseudo-random functions for KDF (version: " + kdfVersion + ")");
-		System.out.println("Enum Name\tAlgorithm\t# bits");
-		for (PRF_ALGORITHMS prf : PRF_ALGORITHMS.values()) {
-		    System.out.println(prf + "\t" + prf.getAlgName() + "\t" + prf.getBits());
-		}
-	}
+    public static final void main(String args[]) {
+        System.out.println("Supported pseudo-random functions for KDF (version: " + kdfVersion + ")");
+        System.out.println("Enum Name\tAlgorithm\t# bits");
+        for (PRF_ALGORITHMS prf : PRF_ALGORITHMS.values()) {
+            System.out.println(prf + "\t" + prf.getAlgName() + "\t" + prf.getBits());
+        }
+    }
 }
diff --git a/src/main/java/org/owasp/esapi/crypto/PlainText.java b/src/main/java/org/owasp/esapi/crypto/PlainText.java
index d70dd98..60fda89 100644
--- a/src/main/java/org/owasp/esapi/crypto/PlainText.java
+++ b/src/main/java/org/owasp/esapi/crypto/PlainText.java
@@ -29,74 +29,74 @@ import org.owasp.esapi.Logger;
  */
 public final class PlainText implements Serializable {
 
-	private static final long serialVersionUID = 20090921;
-	private static Logger logger = ESAPI.getLogger("PlainText");
-	
-	private byte[] rawBytes = null;
-	
-	/**
-	 * Construct a {@code PlainText} object from a {@code String}.
-	 * @param str	The {@code String} that is converted to a UTF-8 encoded
-	 * 				byte array to create the {@code PlainText} object.
-	 * @throws IllegalArgumentException	If {@code str} argument is null.
-	 */
-	public PlainText(String str) {
-		try {
-		    if ( str == null ) {
-		    	throw new IllegalArgumentException("String for plaintext may not be null!");
-		    }
-			rawBytes = str.getBytes("UTF-8");
-		} catch (UnsupportedEncodingException e) {
-			// Should never happen.
-			logger.error(Logger.EVENT_FAILURE, "PlainText(String) CTOR failed: Can't find UTF-8 byte-encoding!", e);
-			throw new RuntimeException("Can't find UTF-8 byte-encoding!", e);
-		}
-	}
-
-	/**
-	 * Construct a {@code PlainText} object from a {@code byte} array.
-	 * @param b	The {@code byte} array used to create the {@code PlainText}
-	 * 			object.
-	 */
-	public PlainText(byte[] b) {
-		// Must allow 0 length arrays though, to represent empty strings.
-		if ( b == null ) {
+    private static final long serialVersionUID = 20090921;
+    private static Logger logger = ESAPI.getLogger("PlainText");
+
+    private byte[] rawBytes = null;
+
+    /**
+     * Construct a {@code PlainText} object from a {@code String}.
+     * @param str    The {@code String} that is converted to a UTF-8 encoded
+     *                 byte array to create the {@code PlainText} object.
+     * @throws IllegalArgumentException    If {@code str} argument is null.
+     */
+    public PlainText(String str) {
+        try {
+            if ( str == null ) {
+                throw new IllegalArgumentException("String for plaintext may not be null!");
+            }
+            rawBytes = str.getBytes("UTF-8");
+        } catch (UnsupportedEncodingException e) {
+            // Should never happen.
+            logger.error(Logger.EVENT_FAILURE, "PlainText(String) CTOR failed: Can't find UTF-8 byte-encoding!", e);
+            throw new RuntimeException("Can't find UTF-8 byte-encoding!", e);
+        }
+    }
+
+    /**
+     * Construct a {@code PlainText} object from a {@code byte} array.
+     * @param b    The {@code byte} array used to create the {@code PlainText}
+     *             object.
+     */
+    public PlainText(byte[] b) {
+        // Must allow 0 length arrays though, to represent empty strings.
+        if ( b == null ) {
             throw new IllegalArgumentException("Byte array representing plaintext cannot be null.");
         }
 
         // Make copy so mutable byte array b can't change PlainText.
-		rawBytes = new byte[ b.length ];
-		System.arraycopy(b, 0, rawBytes, 0, b.length);
-	}
-	
-	/**
-	 * Convert the {@code PlainText} object to a UTF-8 encoded {@code String}.
-	 * @return	A {@code String} representing the {@code PlainText} object.
-	 */
-	public String toString() {
-		try {
-			return new String(rawBytes, "UTF-8");
-		} catch (UnsupportedEncodingException e) {
-			// Should never happen.
-			logger.error(Logger.EVENT_FAILURE, "PlainText.toString() failed: Can't find UTF-8 byte-encoding!", e);
-			throw new RuntimeException("Can't find UTF-8 byte-encoding!", e);
-		}
-	}
-	
-	/**
-	 * Convert the {@code PlainText} object to a byte array.
-	 * @return	A byte array representing the {@code PlainText} object.
-	 */
-	public byte[] asBytes() {
-	    byte[] bytes = new byte[ rawBytes.length ];
-	    System.arraycopy(rawBytes, 0, bytes, 0, rawBytes.length);
-		return bytes;
-	}
-	
-	/**
-	 * {@inheritDoc}
-	 */
-	@Override public boolean equals(Object anObject) {
+        rawBytes = new byte[ b.length ];
+        System.arraycopy(b, 0, rawBytes, 0, b.length);
+    }
+
+    /**
+     * Convert the {@code PlainText} object to a UTF-8 encoded {@code String}.
+     * @return    A {@code String} representing the {@code PlainText} object.
+     */
+    public String toString() {
+        try {
+            return new String(rawBytes, "UTF-8");
+        } catch (UnsupportedEncodingException e) {
+            // Should never happen.
+            logger.error(Logger.EVENT_FAILURE, "PlainText.toString() failed: Can't find UTF-8 byte-encoding!", e);
+            throw new RuntimeException("Can't find UTF-8 byte-encoding!", e);
+        }
+    }
+
+    /**
+     * Convert the {@code PlainText} object to a byte array.
+     * @return    A byte array representing the {@code PlainText} object.
+     */
+    public byte[] asBytes() {
+        byte[] bytes = new byte[ rawBytes.length ];
+        System.arraycopy(rawBytes, 0, bytes, 0, rawBytes.length);
+        return bytes;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override public boolean equals(Object anObject) {
 
         if ( this == anObject ) return true;
         if ( anObject == null ) return false;
@@ -108,42 +108,42 @@ public final class PlainText implements Serializable {
                   );
         }
         return result;
-	}
-	
-	/**
-	 * Same as {@code this.toString().hashCode()}.
-	 * @return	{@code this.toString().hashCode()}.
-	 */
-	@Override public int hashCode() {
-		return this.toString().hashCode();
-	}
-	
-	/**
-	 * Return the length of the UTF-8 encoded byte array representing this
-	 * object. Note that if this object was constructed with the constructor
-	 * {@code PlainText(String str)}, then this length might not necessarily
-	 * agree with {@code str.length()}.
-	 * 
-	 * @return	The length of the UTF-8 encoded byte array representing this
-	 * 			object.
-	 */
-	public int length() {
-		return rawBytes.length;
-	}
-	
-	// DISCUSS: Should we set 'rawBytes' to null??? Won't make it eligible for
-	//			GC unless this PlainText object is set to null which can't do
-	//			from here. If we set it to null, most methods will cause
-	//			NullPointerException to be thrown. Also will have to change a
-	//			lot of JUnit tests.
-	/**
-	 * First overwrite the bytes of plaintext with the character '*'.
-	 */
-	public void overwrite() {
-		CryptoHelper.overwrite( rawBytes );
-		// rawBytes = null;					// See above comment re: discussion.
-	}
-	
+    }
+
+    /**
+     * Same as {@code this.toString().hashCode()}.
+     * @return    {@code this.toString().hashCode()}.
+     */
+    @Override public int hashCode() {
+        return this.toString().hashCode();
+    }
+
+    /**
+     * Return the length of the UTF-8 encoded byte array representing this
+     * object. Note that if this object was constructed with the constructor
+     * {@code PlainText(String str)}, then this length might not necessarily
+     * agree with {@code str.length()}.
+     *
+     * @return    The length of the UTF-8 encoded byte array representing this
+     *             object.
+     */
+    public int length() {
+        return rawBytes.length;
+    }
+
+    // DISCUSS: Should we set 'rawBytes' to null??? Won't make it eligible for
+    //            GC unless this PlainText object is set to null which can't do
+    //            from here. If we set it to null, most methods will cause
+    //            NullPointerException to be thrown. Also will have to change a
+    //            lot of JUnit tests.
+    /**
+     * First overwrite the bytes of plaintext with the character '*'.
+     */
+    public void overwrite() {
+        CryptoHelper.overwrite( rawBytes );
+        // rawBytes = null;                    // See above comment re: discussion.
+    }
+
     /**
      * Needed for correct definition of equals for general classes.
      * (Technically not needed for 'final' classes though like this class
diff --git a/src/main/java/org/owasp/esapi/crypto/SecurityProviderLoader.java b/src/main/java/org/owasp/esapi/crypto/SecurityProviderLoader.java
index 6639f13..a5cbd70 100644
--- a/src/main/java/org/owasp/esapi/crypto/SecurityProviderLoader.java
+++ b/src/main/java/org/owasp/esapi/crypto/SecurityProviderLoader.java
@@ -8,7 +8,7 @@ import java.util.Hashtable;
 import org.owasp.esapi.ESAPI;
 import org.owasp.esapi.Logger;
 
-/** 
+/**
  * This class provides a generic static method that loads a
  * {@code java.security.Provider} either by some generic name
  * (i.e., {@code Provider.getName()}) or by a fully-qualified class name.
@@ -43,14 +43,14 @@ public class SecurityProviderLoader  {
             // with Sun-based JREs. As of JDK 1.3 and later, it is part of the
             // standard JRE install.
         jceProviders.put("SunJCE", "com.sun.crypto.provider.SunJCE");
-        
+
             // IBMJCE is default for WebSphere and is used by IBM JDKs. They
             // also have IBMJCEFIPS, but not sure if this is *always* provided
             // with WebSphere or just an add-on, hence not including it. IBMJCEFIPS
-        	// is a FIPS 140-2 compliant JCE provider from IBM.
+            // is a FIPS 140-2 compliant JCE provider from IBM.
         jceProviders.put("IBMJCE", "com.ibm.crypto.provider.IBMJCE");
         // jceProviders.put("IBMJCEFIPS", "com.ibm.crypto.fips.provider.IBMJCEFIPS");
-        
+
             // GnuCrypto is JCE provider for GNU Compiler for Java (GCJ)
         jceProviders.put("GnuCrypto", "gnu.crypto.jce.GnuCrypto");
 
@@ -79,9 +79,9 @@ public class SecurityProviderLoader  {
         jceProviders.put("ABA", "au.net.aba.crypto.provider.ABAProvider");
     }
 
-    /** 
+    /**
      * This methods adds a provider to the {@code SecurityManager}
-     * either by some generic name or by the class name. 
+     * either by some generic name or by the class name.
      * </p><p>
      * The following generic JCE provider names are built-in:
      * <ul>
@@ -209,13 +209,13 @@ public class SecurityProviderLoader  {
                     // compliant JCE provider at the first position and it was
                     // already loaded at position 3, then this is not FIPS 140-2
                     // compliant. Therefore, we make it a warning and a failure.
-                	// Also log separately using 'always' in case warnings suppressed
-                	// as per NSA suggestion.
+                    // Also log separately using 'always' in case warnings suppressed
+                    // as per NSA suggestion.
                     logger.warning(Logger.SECURITY_FAILURE, msg);
                     logger.always(Logger.SECURITY_FAILURE, "(audit) " + msg);
                 }
             } else {
-            	// As per NSA suggestion.
+                // As per NSA suggestion.
                 logger.always(Logger.SECURITY_AUDIT,
                         "Successfully loaded preferred JCE provider " +
                         algProvider + " at position " + pos);
@@ -223,12 +223,12 @@ public class SecurityProviderLoader  {
             return ret;
         } catch(SecurityException ex) {
             // CHECKME: Log security event here too? This is a RuntimeException.
-        	// It would only be thrown if a SecurityManager is installed that
-        	// prohibits Security.addProvider() or Security.insertProviderAt()
-        	// by the current user of this thread. Will log it here. Can always
-        	// be ignored.
-        	logger.always(Logger.SECURITY_FAILURE, "Failed to load preferred JCE provider " +
-        				  algProvider + " at position " + pos, ex);
+            // It would only be thrown if a SecurityManager is installed that
+            // prohibits Security.addProvider() or Security.insertProviderAt()
+            // by the current user of this thread. Will log it here. Can always
+            // be ignored.
+            logger.always(Logger.SECURITY_FAILURE, "Failed to load preferred JCE provider " +
+                          algProvider + " at position " + pos, ex);
             throw ex;
         } catch(Exception ex) {
             // Possibilities include: ClassNotFoundException,
@@ -236,8 +236,8 @@ public class SecurityProviderLoader  {
             //
             // Log an error & re-throw original message as NoSuchProviderException,
             // since that what it probably really implied here. This probably a configuration
-        	// error (e.g., classpath problem, etc.) so we use EVENT_FAILURE rather than
-        	// SECURITY_FAILURE here.
+            // error (e.g., classpath problem, etc.) so we use EVENT_FAILURE rather than
+            // SECURITY_FAILURE here.
             logger.error(Logger.EVENT_FAILURE, "Failed to insert failed crypto " +
                     " provider " + algProvider + " at position " + pos, ex);
             throw new NoSuchProviderException("Failed to insert crypto " +
@@ -245,7 +245,7 @@ public class SecurityProviderLoader  {
                                        "; exception msg: " + ex.toString());
         }
     }
-    
+
     /**
      * Load the preferred JCE provider for ESAPI based on the <b>ESAPI.properties</b>
      * property {@code Encryptor.PreferredJCEProvider}. If this property is null
@@ -272,7 +272,7 @@ public class SecurityProviderLoader  {
         try {
             // If unset or set to empty string, then don't try to change it.
             if ( prefJCEProvider == null || prefJCEProvider.trim().length() == 0) {
-            		// Always log, per NSA suggestion.
+                    // Always log, per NSA suggestion.
                 logger.always(Logger.SECURITY_AUDIT, "No Encryptor.PreferredJCEProvider specified.");
                 return -1;  // Unchanged; it is, whatever it is.
             } else {
@@ -280,8 +280,8 @@ public class SecurityProviderLoader  {
             }
         } catch (NoSuchProviderException ex) {
             // Will already have logged with exception msg.
-        	String msg = "failed to load *preferred* " + "JCE crypto provider, " + prefJCEProvider;
-        	logger.always(Logger.SECURITY_AUDIT, msg);	// Per NSA suggestion.
+            String msg = "failed to load *preferred* " + "JCE crypto provider, " + prefJCEProvider;
+            logger.always(Logger.SECURITY_AUDIT, msg);    // Per NSA suggestion.
             logger.error(Logger.SECURITY_FAILURE, msg);
             throw ex;
         }
diff --git a/src/main/java/org/owasp/esapi/errors/AccessControlException.java b/src/main/java/org/owasp/esapi/errors/AccessControlException.java
index 96eaf80..fbc537f 100644
--- a/src/main/java/org/owasp/esapi/errors/AccessControlException.java
+++ b/src/main/java/org/owasp/esapi/errors/AccessControlException.java
@@ -1,15 +1,15 @@
 /**
  * OWASP Enterprise Security API (ESAPI)
- * 
+ *
  * This file is part of the Open Web Application Security Project (OWASP)
  * Enterprise Security API (ESAPI) project. For details, please see
  * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
  *
  * Copyright (c) 2007 - The OWASP Foundation
- * 
+ *
  * The ESAPI is published by OWASP under the BSD license. You should read and accept the
  * LICENSE before you use, modify, and/or redistribute this software.
- * 
+ *
  * @author Jeff Williams <a href="http://www.aspectsecurity.com">Aspect Security</a>
  * @created 2007
  */
@@ -18,40 +18,40 @@ package org.owasp.esapi.errors;
 /**
  * An AccessControlException should be thrown when a user attempts to access a
  * resource that they are not authorized for.
- * 
+ *
  * @author Jeff Williams (jeff.williams@aspectsecurity.com)
  */
 public class AccessControlException extends EnterpriseSecurityException {
 
-	/** The Constant serialVersionUID. */
-	private static final long serialVersionUID = 1L;
+    /** The Constant serialVersionUID. */
+    private static final long serialVersionUID = 1L;
 
-	/**
-	 * Instantiates a new access control exception.
-	 */
-	protected AccessControlException() {
-		// hidden
-	}
+    /**
+     * Instantiates a new access control exception.
+     */
+    protected AccessControlException() {
+        // hidden
+    }
 
-	/**
-	 * Creates a new instance of {@code AccessControlException}.
+    /**
+     * Creates a new instance of {@code AccessControlException}.
      *
      * @param userMessage
      * @param logMessage
      */
-	public AccessControlException(String userMessage, String logMessage) {
-		super(userMessage, logMessage);
-	}
+    public AccessControlException(String userMessage, String logMessage) {
+        super(userMessage, logMessage);
+    }
 
-	/**
-	 * Instantiates a new access control exception.
-	 * 
-	 * @param userMessage the message displayed to the user
-	 * @param logMessage the message logged
-	 * @param cause the root cause
-	 */
-	public AccessControlException(String userMessage, String logMessage, Throwable cause) {
-		super(userMessage, logMessage, cause);
-	}
+    /**
+     * Instantiates a new access control exception.
+     *
+     * @param userMessage the message displayed to the user
+     * @param logMessage the message logged
+     * @param cause the root cause
+     */
+    public AccessControlException(String userMessage, String logMessage, Throwable cause) {
+        super(userMessage, logMessage, cause);
+    }
 
 }
diff --git a/src/main/java/org/owasp/esapi/errors/AuthenticationAccountsException.java b/src/main/java/org/owasp/esapi/errors/AuthenticationAccountsException.java
index c81ff84..a08b02c 100644
--- a/src/main/java/org/owasp/esapi/errors/AuthenticationAccountsException.java
+++ b/src/main/java/org/owasp/esapi/errors/AuthenticationAccountsException.java
@@ -1,15 +1,15 @@
 /**
  * OWASP Enterprise Security API (ESAPI)
- * 
+ *
  * This file is part of the Open Web Application Security Project (OWASP)
  * Enterprise Security API (ESAPI) project. For details, please see
  * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
  *
  * Copyright (c) 2007 - The OWASP Foundation
- * 
+ *
  * The ESAPI is published by OWASP under the BSD license. You should read and accept the
  * LICENSE before you use, modify, and/or redistribute this software.
- * 
+ *
  * @author Jeff Williams <a href="http://www.aspectsecurity.com">Aspect Security</a>
  * @created 2007
  */
@@ -19,41 +19,41 @@ package org.owasp.esapi.errors;
  * An AuthenticationException should be thrown when anything goes wrong during
  * login or logout. They are also appropriate for any problems related to
  * identity management.
- * 
+ *
  * @author Jeff Williams (jeff.williams@aspectsecurity.com)
  */
 public class AuthenticationAccountsException extends AuthenticationException {
 
-	/** The Constant serialVersionUID. */
-	private static final long serialVersionUID = 1L;
+    /** The Constant serialVersionUID. */
+    private static final long serialVersionUID = 1L;
 
-	/**
-	 * Instantiates a new authentication exception.
-	 */
-	protected AuthenticationAccountsException() {
-		// hidden
-	}
+    /**
+     * Instantiates a new authentication exception.
+     */
+    protected AuthenticationAccountsException() {
+        // hidden
+    }
 
-	/**
-	 * Creates a new instance of {@code AuthenticationAccountsException}.
-	 * 
-	 * @param userMessage the message displayed to the user
-	 * @param logMessage the message logged     
-	 *       
-	 */
-	public AuthenticationAccountsException(String userMessage, String logMessage) {
-		super(userMessage, logMessage);
-	}
+    /**
+     * Creates a new instance of {@code AuthenticationAccountsException}.
+     *
+     * @param userMessage the message displayed to the user
+     * @param logMessage the message logged
+     *
+     */
+    public AuthenticationAccountsException(String userMessage, String logMessage) {
+        super(userMessage, logMessage);
+    }
 
-	/**
-	 * Instantiates a new authentication exception.
-	 * 
-	 * @param userMessage the message displayed to the user
-	 * @param logMessage the message logged
-	 * @param cause the root cause
-	 */
-	public AuthenticationAccountsException(String userMessage, String logMessage, Throwable cause) {
-		super(userMessage, logMessage, cause);
-	}
+    /**
+     * Instantiates a new authentication exception.
+     *
+     * @param userMessage the message displayed to the user
+     * @param logMessage the message logged
+     * @param cause the root cause
+     */
+    public AuthenticationAccountsException(String userMessage, String logMessage, Throwable cause) {
+        super(userMessage, logMessage, cause);
+    }
 
 }
diff --git a/src/main/java/org/owasp/esapi/errors/AuthenticationCredentialsException.java b/src/main/java/org/owasp/esapi/errors/AuthenticationCredentialsException.java
index e481877..ad3d8df 100644
--- a/src/main/java/org/owasp/esapi/errors/AuthenticationCredentialsException.java
+++ b/src/main/java/org/owasp/esapi/errors/AuthenticationCredentialsException.java
@@ -1,15 +1,15 @@
 /**
  * OWASP Enterprise Security API (ESAPI)
- * 
+ *
  * This file is part of the Open Web Application Security Project (OWASP)
  * Enterprise Security API (ESAPI) project. For details, please see
  * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
  *
  * Copyright (c) 2007 - The OWASP Foundation
- * 
+ *
  * The ESAPI is published by OWASP under the BSD license. You should read and accept the
  * LICENSE before you use, modify, and/or redistribute this software.
- * 
+ *
  * @author Jeff Williams <a href="http://www.aspectsecurity.com">Aspect Security</a>
  * @created 2007
  */
@@ -19,40 +19,40 @@ package org.owasp.esapi.errors;
  * An AuthenticationException should be thrown when anything goes wrong during
  * login or logout. They are also appropriate for any problems related to
  * identity management.
- * 
+ *
  * @author Jeff Williams (jeff.williams@aspectsecurity.com)
  */
 public class AuthenticationCredentialsException extends AuthenticationException {
 
-	/** The Constant serialVersionUID. */
-	private static final long serialVersionUID = 1L;
+    /** The Constant serialVersionUID. */
+    private static final long serialVersionUID = 1L;
 
-	/**
-	 * Instantiates a new authentication exception.
-	 */
-	protected AuthenticationCredentialsException() {
-		// hidden
-	}
+    /**
+     * Instantiates a new authentication exception.
+     */
+    protected AuthenticationCredentialsException() {
+        // hidden
+    }
 
-	/**
-	 * Creates a new instance of {@code AuthenticationCredentialsException}.
-	 * 
-	 * @param userMessage the message displayed to the user
-	 * @param logMessage the message logged
-	 */
-	public AuthenticationCredentialsException(String userMessage, String logMessage) {
-		super(userMessage, logMessage);
-	}
+    /**
+     * Creates a new instance of {@code AuthenticationCredentialsException}.
+     *
+     * @param userMessage the message displayed to the user
+     * @param logMessage the message logged
+     */
+    public AuthenticationCredentialsException(String userMessage, String logMessage) {
+        super(userMessage, logMessage);
+    }
 
-	/**
-	 * Instantiates a new authentication exception.
-	 * 
-	 * @param userMessage the message displayed to the user
-	 * @param logMessage the message logged
-	 * @param cause the root cause
-	 */
-	public AuthenticationCredentialsException(String userMessage, String logMessage, Throwable cause) {
-		super(userMessage, logMessage, cause);
-	}
+    /**
+     * Instantiates a new authentication exception.
+     *
+     * @param userMessage the message displayed to the user
+     * @param logMessage the message logged
+     * @param cause the root cause
+     */
+    public AuthenticationCredentialsException(String userMessage, String logMessage, Throwable cause) {
+        super(userMessage, logMessage, cause);
+    }
 
 }
diff --git a/src/main/java/org/owasp/esapi/errors/AuthenticationException.java b/src/main/java/org/owasp/esapi/errors/AuthenticationException.java
index c8198f5..55abbc3 100644
--- a/src/main/java/org/owasp/esapi/errors/AuthenticationException.java
+++ b/src/main/java/org/owasp/esapi/errors/AuthenticationException.java
@@ -1,15 +1,15 @@
 /**
  * OWASP Enterprise Security API (ESAPI)
- * 
+ *
  * This file is part of the Open Web Application Security Project (OWASP)
  * Enterprise Security API (ESAPI) project. For details, please see
  * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
  *
  * Copyright (c) 2007 - The OWASP Foundation
- * 
+ *
  * The ESAPI is published by OWASP under the BSD license. You should read and accept the
  * LICENSE before you use, modify, and/or redistribute this software.
- * 
+ *
  * @author Jeff Williams <a href="http://www.aspectsecurity.com">Aspect Security</a>
  * @created 2007
  */
@@ -19,24 +19,24 @@ package org.owasp.esapi.errors;
  * An AuthenticationException should be thrown when anything goes wrong during
  * login or logout. They are also appropriate for any problems related to
  * identity management.
- * 
+ *
  * @author Jeff Williams (jeff.williams@aspectsecurity.com)
  */
 public class AuthenticationException extends EnterpriseSecurityException {
 
-	/** The Constant serialVersionUID. */
-	private static final long serialVersionUID = 1L;
+    /** The Constant serialVersionUID. */
+    private static final long serialVersionUID = 1L;
 
-	/**
-	 * Instantiates a new authentication exception.
-	 */
-	protected AuthenticationException() {
-		// hidden
-	}
+    /**
+     * Instantiates a new authentication exception.
+     */
+    protected AuthenticationException() {
+        // hidden
+    }
 
     /**
      * Creates a new instance of {@code AuthenticationException}.
-     * 
+     *
      * @param userMessage the message displayed to the user
      * @param logMessage the message logged
      */
@@ -46,7 +46,7 @@ public class AuthenticationException extends EnterpriseSecurityException {
 
     /**
      * Instantiates a new authentication exception.
-     * 
+     *
      * @param userMessage the message displayed to the user
      * @param logMessage the message logged
      * @param cause the root cause
diff --git a/src/main/java/org/owasp/esapi/errors/AuthenticationHostException.java b/src/main/java/org/owasp/esapi/errors/AuthenticationHostException.java
index 1deac4b..4010d79 100644
--- a/src/main/java/org/owasp/esapi/errors/AuthenticationHostException.java
+++ b/src/main/java/org/owasp/esapi/errors/AuthenticationHostException.java
@@ -1,15 +1,15 @@
 /**
  * OWASP Enterprise Security API (ESAPI)
- * 
+ *
  * This file is part of the Open Web Application Security Project (OWASP)
  * Enterprise Security API (ESAPI) project. For details, please see
  * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
  *
  * Copyright (c) 2007 - The OWASP Foundation
- * 
+ *
  * The ESAPI is published by OWASP under the BSD license. You should read and accept the
  * LICENSE before you use, modify, and/or redistribute this software.
- * 
+ *
  * @author Jeff Williams <a href="http://www.aspectsecurity.com">Aspect Security</a>
  * @created 2007
  */
@@ -18,40 +18,40 @@ package org.owasp.esapi.errors;
 /**
  * An AuthenticationHostException should be thrown when there is a problem with
  * the host involved with authentication, particularly if the host changes unexpectedly.
- * 
+ *
  * @author Jeff Williams (jeff.williams@aspectsecurity.com)
  */
 public class AuthenticationHostException extends AuthenticationException {
 
-	/** The Constant serialVersionUID. */
-	private static final long serialVersionUID = 1L;
+    /** The Constant serialVersionUID. */
+    private static final long serialVersionUID = 1L;
 
-	/**
-	 * Instantiates a new authentication exception.
-	 */
-	protected AuthenticationHostException() {
-		// hidden
-	}
+    /**
+     * Instantiates a new authentication exception.
+     */
+    protected AuthenticationHostException() {
+        // hidden
+    }
 
-	/**
-	 * Creates a new instance of AuthenticationHostException.
-	 * 
-	 * @param userMessage the message displayed to the user
-	 * @param logMessage the message logged
-	 */
-	public AuthenticationHostException(String userMessage, String logMessage) {
-		super(userMessage, logMessage);
-	}
+    /**
+     * Creates a new instance of AuthenticationHostException.
+     *
+     * @param userMessage the message displayed to the user
+     * @param logMessage the message logged
+     */
+    public AuthenticationHostException(String userMessage, String logMessage) {
+        super(userMessage, logMessage);
+    }
 
-	/**
-	 * Instantiates a new authentication exception.
-	 * 
-	 * @param userMessage the message displayed to the user
-	 * @param logMessage the message logged
-	 * @param cause the cause
-	 */
-	public AuthenticationHostException(String userMessage, String logMessage, Throwable cause) {
-		super(userMessage, logMessage, cause);
-	}
+    /**
+     * Instantiates a new authentication exception.
+     *
+     * @param userMessage the message displayed to the user
+     * @param logMessage the message logged
+     * @param cause the cause
+     */
+    public AuthenticationHostException(String userMessage, String logMessage, Throwable cause) {
+        super(userMessage, logMessage, cause);
+    }
 
 }
diff --git a/src/main/java/org/owasp/esapi/errors/AuthenticationLoginException.java b/src/main/java/org/owasp/esapi/errors/AuthenticationLoginException.java
index d389591..0f7a3d8 100644
--- a/src/main/java/org/owasp/esapi/errors/AuthenticationLoginException.java
+++ b/src/main/java/org/owasp/esapi/errors/AuthenticationLoginException.java
@@ -1,15 +1,15 @@
 /**
  * OWASP Enterprise Security API (ESAPI)
- * 
+ *
  * This file is part of the Open Web Application Security Project (OWASP)
  * Enterprise Security API (ESAPI) project. For details, please see
  * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
  *
  * Copyright (c) 2007 - The OWASP Foundation
- * 
+ *
  * The ESAPI is published by OWASP under the BSD license. You should read and accept the
  * LICENSE before you use, modify, and/or redistribute this software.
- * 
+ *
  * @author Jeff Williams <a href="http://www.aspectsecurity.com">Aspect Security</a>
  * @created 2007
  */
@@ -19,40 +19,40 @@ package org.owasp.esapi.errors;
  * An AuthenticationException should be thrown when anything goes wrong during
  * login or logout. They are also appropriate for any problems related to
  * identity management.
- * 
+ *
  * @author Jeff Williams (jeff.williams@aspectsecurity.com)
  */
 public class AuthenticationLoginException extends AuthenticationException {
 
-	/** The Constant serialVersionUID. */
-	private static final long serialVersionUID = 1L;
+    /** The Constant serialVersionUID. */
+    private static final long serialVersionUID = 1L;
 
-	/**
-	 * Instantiates a new authentication exception.
-	 */
-	protected AuthenticationLoginException() {
-		// hidden
-	}
+    /**
+     * Instantiates a new authentication exception.
+     */
+    protected AuthenticationLoginException() {
+        // hidden
+    }
 
-	/**
-	 * Creates a new instance of EnterpriseSecurityException.
-	 * 
-	 * @param userMessage the message displayed to the user
-	 * @param logMessage the message logged
-	 */
-	public AuthenticationLoginException(String userMessage, String logMessage) {
-		super(userMessage, logMessage);
-	}
+    /**
+     * Creates a new instance of EnterpriseSecurityException.
+     *
+     * @param userMessage the message displayed to the user
+     * @param logMessage the message logged
+     */
+    public AuthenticationLoginException(String userMessage, String logMessage) {
+        super(userMessage, logMessage);
+    }
 
-	/**
-	 * Instantiates a new authentication exception.
-	 * 
-	 * @param userMessage the message displayed to the user
-	 * @param logMessage the message logged
-	 * @param cause the cause
-	 */
-	public AuthenticationLoginException(String userMessage, String logMessage, Throwable cause) {
-		super(userMessage, logMessage, cause);
-	}
+    /**
+     * Instantiates a new authentication exception.
+     *
+     * @param userMessage the message displayed to the user
+     * @param logMessage the message logged
+     * @param cause the cause
+     */
+    public AuthenticationLoginException(String userMessage, String logMessage, Throwable cause) {
+        super(userMessage, logMessage, cause);
+    }
 
 }
diff --git a/src/main/java/org/owasp/esapi/errors/AvailabilityException.java b/src/main/java/org/owasp/esapi/errors/AvailabilityException.java
index 3ec04b6..9809915 100644
--- a/src/main/java/org/owasp/esapi/errors/AvailabilityException.java
+++ b/src/main/java/org/owasp/esapi/errors/AvailabilityException.java
@@ -1,15 +1,15 @@
 /**
  * OWASP Enterprise Security API (ESAPI)
- * 
+ *
  * This file is part of the Open Web Application Security Project (OWASP)
  * Enterprise Security API (ESAPI) project. For details, please see
  * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
  *
  * Copyright (c) 2007 - The OWASP Foundation
- * 
+ *
  * The ESAPI is published by OWASP under the BSD license. You should read and accept the
  * LICENSE before you use, modify, and/or redistribute this software.
- * 
+ *
  * @author Jeff Williams <a href="http://www.aspectsecurity.com">Aspect Security</a>
  * @created 2007
  */
@@ -19,24 +19,24 @@ package org.owasp.esapi.errors;
  * An AvailabilityException should be thrown when the availability of a limited
  * resource is in jeopardy. For example, if a database connection pool runs out
  * of connections, an availability exception should be thrown.
- * 
+ *
  * @author Jeff Williams (jeff.williams@aspectsecurity.com)
  */
 public class AvailabilityException extends EnterpriseSecurityException {
 
-	/** The Constant serialVersionUID. */
-	private static final long serialVersionUID = 1L;
+    /** The Constant serialVersionUID. */
+    private static final long serialVersionUID = 1L;
 
-	/**
-	 * Instantiates a new availability exception.
-	 */
-	protected AvailabilityException() {
-		// hidden
-	}
+    /**
+     * Instantiates a new availability exception.
+     */
+    protected AvailabilityException() {
+        // hidden
+    }
 
     /**
      * Creates a new instance of AvailabilityException.
-     * 
+     *
      * @param userMessage the message displayed to the user
      * @param logMessage the message logged
      */
@@ -46,7 +46,7 @@ public class AvailabilityException extends EnterpriseSecurityException {
 
     /**
      * Instantiates a new AvailabilityException.
-     * 
+     *
      * @param userMessage the message displayed to the user
      * @param logMessage the message logged
      * @param cause the cause
diff --git a/src/main/java/org/owasp/esapi/errors/CertificateException.java b/src/main/java/org/owasp/esapi/errors/CertificateException.java
index 2f84b2c..561d411 100644
--- a/src/main/java/org/owasp/esapi/errors/CertificateException.java
+++ b/src/main/java/org/owasp/esapi/errors/CertificateException.java
@@ -1,15 +1,15 @@
 /**
  * OWASP Enterprise Security API (ESAPI)
- * 
+ *
  * This file is part of the Open Web Application Security Project (OWASP)
  * Enterprise Security API (ESAPI) project. For details, please see
  * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
  *
  * Copyright (c) 2007 - The OWASP Foundation
- * 
+ *
  * The ESAPI is published by OWASP under the BSD license. You should read and accept the
  * LICENSE before you use, modify, and/or redistribute this software.
- * 
+ *
  * @author Jeff Williams <a href="http://www.aspectsecurity.com">Aspect Security</a>
  * @created 2007
  */
@@ -18,24 +18,24 @@ package org.owasp.esapi.errors;
 /**
  * A CertificateException should be thrown for any problems that arise during
  * processing of digital certificates.
- * 
+ *
  * @author Jeff Williams (jeff.williams@aspectsecurity.com)
  */
 public class CertificateException extends EnterpriseSecurityException {
 
-	/** The Constant serialVersionUID. */
-	private static final long serialVersionUID = 1L;
+    /** The Constant serialVersionUID. */
+    private static final long serialVersionUID = 1L;
 
-	/**
-	 * Instantiates a new certificate exception.
-	 */
-	protected CertificateException() {
-		// hidden
-	}
+    /**
+     * Instantiates a new certificate exception.
+     */
+    protected CertificateException() {
+        // hidden
+    }
 
     /**
      * Creates a new instance of CertificateException.
-     * 
+     *
      * @param userMessage the message displayed to the user
      * @param logMessage the message logged
      */
@@ -45,7 +45,7 @@ public class CertificateException extends EnterpriseSecurityException {
 
     /**
      * Instantiates a new CertificateException.
-     * 
+     *
      * @param userMessage the message displayed to the user
      * @param logMessage the message logged
      * @param cause the cause
diff --git a/src/main/java/org/owasp/esapi/errors/ConfigurationException.java b/src/main/java/org/owasp/esapi/errors/ConfigurationException.java
index 4e6a381..17d6a6b 100644
--- a/src/main/java/org/owasp/esapi/errors/ConfigurationException.java
+++ b/src/main/java/org/owasp/esapi/errors/ConfigurationException.java
@@ -14,21 +14,21 @@ package org.owasp.esapi.errors;
  */
 public class ConfigurationException extends RuntimeException {
 
-	protected static final long serialVersionUID = 1L;
+    protected static final long serialVersionUID = 1L;
 
-	public ConfigurationException(Exception e) {
-		super(e);
-	}
+    public ConfigurationException(Exception e) {
+        super(e);
+    }
 
-	public ConfigurationException(String s) {
-		super(s);
-	}
-	
-	public ConfigurationException(String s, Throwable cause) {
-		super(s, cause);
-	}
-	
-	public ConfigurationException(Throwable cause) {
-		super(cause);
-	}
+    public ConfigurationException(String s) {
+        super(s);
+    }
+
+    public ConfigurationException(String s, Throwable cause) {
+        super(s, cause);
+    }
+
+    public ConfigurationException(Throwable cause) {
+        super(cause);
+    }
 }
diff --git a/src/main/java/org/owasp/esapi/errors/EncodingException.java b/src/main/java/org/owasp/esapi/errors/EncodingException.java
index f2b2694..cee3abf 100644
--- a/src/main/java/org/owasp/esapi/errors/EncodingException.java
+++ b/src/main/java/org/owasp/esapi/errors/EncodingException.java
@@ -1,15 +1,15 @@
 /**
  * OWASP Enterprise Security API (ESAPI)
- * 
+ *
  * This file is part of the Open Web Application Security Project (OWASP)
  * Enterprise Security API (ESAPI) project. For details, please see
  * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
  *
  * Copyright (c) 2007 - The OWASP Foundation
- * 
+ *
  * The ESAPI is published by OWASP under the BSD license. You should read and accept the
  * LICENSE before you use, modify, and/or redistribute this software.
- * 
+ *
  * @author Jeff Williams <a href="http://www.aspectsecurity.com">Aspect Security</a>
  * @created 2007
  */
@@ -18,28 +18,28 @@ package org.owasp.esapi.errors;
 /**
  * An EncodingException should be thrown for any problems that occur when
  * encoding or decoding data.
- * 
+ *
  * @author Jeff Williams (jeff.williams@aspectsecurity.com)
  */
 public class EncodingException extends EnterpriseSecurityException {
 
-	/** The Constant serialVersionUID. */
-	private static final long serialVersionUID = 1L;
+    /** The Constant serialVersionUID. */
+    private static final long serialVersionUID = 1L;
 
-	/**
-	 * Instantiates a new service exception.
-	 */
-	protected EncodingException() {
-		// hidden
-	}
+    /**
+     * Instantiates a new service exception.
+     */
+    protected EncodingException() {
+        // hidden
+    }
 
        /**
      * Creates a new instance of EncodingException.
-     * 
+     *
      * @param userMessage
      *            the message displayed to the user
      * @param logMessage
-	 * 			  the message logged
+     *               the message logged
      */
     public EncodingException(String userMessage, String logMessage) {
         super(userMessage, logMessage);
@@ -47,11 +47,11 @@ public class EncodingException extends EnterpriseSecurityException {
 
     /**
      * Instantiates a new EncodingException.
-     * 
+     *
      * @param userMessage
      *            the message displayed to the user
      * @param logMessage
-	 * 			  the message logged
+     *               the message logged
      * @param cause
      *            the cause
      */
diff --git a/src/main/java/org/owasp/esapi/errors/EncryptionException.java b/src/main/java/org/owasp/esapi/errors/EncryptionException.java
index 163a1d2..895d34e 100644
--- a/src/main/java/org/owasp/esapi/errors/EncryptionException.java
+++ b/src/main/java/org/owasp/esapi/errors/EncryptionException.java
@@ -1,15 +1,15 @@
 /**
  * OWASP Enterprise Security API (ESAPI)
- * 
+ *
  * This file is part of the Open Web Application Security Project (OWASP)
  * Enterprise Security API (ESAPI) project. For details, please see
  * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
  *
  * Copyright (c) 2007 - The OWASP Foundation
- * 
+ *
  * The ESAPI is published by OWASP under the BSD license. You should read and accept the
  * LICENSE before you use, modify, and/or redistribute this software.
- * 
+ *
  * @author Jeff Williams <a href="http://www.aspectsecurity.com">Aspect Security</a>
  * @created 2007
  */
@@ -18,28 +18,28 @@ package org.owasp.esapi.errors;
 /**
  * An EncryptionException should be thrown for any problems related to
  * encryption, hashing, or digital signatures.
- * 
+ *
  * @author Jeff Williams (jeff.williams@aspectsecurity.com)
  */
 public class EncryptionException extends EnterpriseSecurityException {
 
-	/** The Constant serialVersionUID. */
-	private static final long serialVersionUID = 1L;
+    /** The Constant serialVersionUID. */
+    private static final long serialVersionUID = 1L;
 
-	/**
-	 * Instantiates a new EncryptionException.
-	 */
-	protected EncryptionException() {
-		// hidden
-	}
+    /**
+     * Instantiates a new EncryptionException.
+     */
+    protected EncryptionException() {
+        // hidden
+    }
 
     /**
      * Creates a new instance of EncryptionException.
-     * 
+     *
      * @param userMessage
      *            the message displayed to the user
      * @param logMessage
-	 * 			  the message logged
+     *               the message logged
      */
     public EncryptionException(String userMessage, String logMessage) {
         super(userMessage, logMessage);
@@ -47,11 +47,11 @@ public class EncryptionException extends EnterpriseSecurityException {
 
     /**
      * Instantiates a new EncryptionException.
-     * 
+     *
      * @param userMessage
      *            the message displayed to the user
      * @param logMessage
-	 * 			  the message logged
+     *               the message logged
      * @param cause
      *            the cause
      */
diff --git a/src/main/java/org/owasp/esapi/errors/EncryptionRuntimeException.java b/src/main/java/org/owasp/esapi/errors/EncryptionRuntimeException.java
index 466ef5c..cdc4843 100644
--- a/src/main/java/org/owasp/esapi/errors/EncryptionRuntimeException.java
+++ b/src/main/java/org/owasp/esapi/errors/EncryptionRuntimeException.java
@@ -1,12 +1,12 @@
 /**
  * OWASP Enterprise Security API (ESAPI)
- * 
+ *
  * This file is part of the Open Web Application Security Project (OWASP)
  * Enterprise Security API (ESAPI) project. For details, please see
  * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
  *
  * Copyright (c) 2010 - The OWASP Foundation
- * 
+ *
  * The ESAPI is published by OWASP under the BSD license. You should read and accept the
  * LICENSE before you use, modify, and/or redistribute this software.
  *
@@ -18,30 +18,30 @@ package org.owasp.esapi.errors;
 /**
  * An EncryptionRuntimeException should be thrown for any problems related to
  * encryption, hashing, or digital signatures.
- * 
+ *
  * @author August Detlefsen (augustd at codemagi dot com)
  *         <a href="http://www.codemagi.com">CodeMagi, Inc.</a>
  * @since October 8, 2010
  */
 public class EncryptionRuntimeException extends EnterpriseSecurityRuntimeException {
 
-	/** The Constant serialVersionUID. */
-	private static final long serialVersionUID = 1L;
+    /** The Constant serialVersionUID. */
+    private static final long serialVersionUID = 1L;
 
-	/**
-	 * Instantiates a new EncryptionException.
-	 */
-	protected EncryptionRuntimeException() {
-		// hidden
-	}
+    /**
+     * Instantiates a new EncryptionException.
+     */
+    protected EncryptionRuntimeException() {
+        // hidden
+    }
 
     /**
      * Creates a new instance of EncryptionException.
-     * 
+     *
      * @param userMessage
      *            the message displayed to the user
      * @param logMessage
-	 * 			  the message logged
+     *               the message logged
      */
     public EncryptionRuntimeException(String userMessage, String logMessage) {
         super(userMessage, logMessage);
@@ -49,11 +49,11 @@ public class EncryptionRuntimeException extends EnterpriseSecurityRuntimeExcepti
 
     /**
      * Instantiates a new EncryptionException.
-     * 
+     *
      * @param userMessage
      *            the message displayed to the user
      * @param logMessage
-	 * 			  the message logged
+     *               the message logged
      * @param cause
      *            the cause
      */
diff --git a/src/main/java/org/owasp/esapi/errors/EnterpriseSecurityException.java b/src/main/java/org/owasp/esapi/errors/EnterpriseSecurityException.java
index da03ef2..6b150bb 100644
--- a/src/main/java/org/owasp/esapi/errors/EnterpriseSecurityException.java
+++ b/src/main/java/org/owasp/esapi/errors/EnterpriseSecurityException.java
@@ -1,15 +1,15 @@
 /**
  * OWASP Enterprise Security API (ESAPI)
- * 
+ *
  * This file is part of the Open Web Application Security Project (OWASP)
  * Enterprise Security API (ESAPI) project. For details, please see
  * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
  *
  * Copyright (c) 2007 - The OWASP Foundation
- * 
+ *
  * The ESAPI is published by OWASP under the BSD license. You should read and accept the
  * LICENSE before you use, modify, and/or redistribute this software.
- * 
+ *
  * @author Jeff Williams <a href="http://www.aspectsecurity.com">Aspect Security</a>
  * @created 2007
  */
@@ -18,12 +18,7 @@ package org.owasp.esapi.errors;
 import org.owasp.esapi.ESAPI;
 import org.owasp.esapi.Logger;
 
-// At some point, all these property names will be moved to a new class named
-//      org.owasp.esapi.PropNames
-// but until then, while this is an ugly kludge, we are importing it via a
-// reference implementation class until we have a chance to clean it up.
-// (Note: kwwall's Bitbucket code already has that class.)
-import static org.owasp.esapi.reference.DefaultSecurityConfiguration.DISABLE_INTRUSION_DETECTION;
+import static org.owasp.esapi.PropNames.DISABLE_INTRUSION_DETECTION;
 
 
 /**
@@ -95,47 +90,47 @@ public class EnterpriseSecurityException extends Exception {
      * It should be noted that messages that are intended to be displayed to the user should be safe for display. In
      * other words, don't pass in unsanitized data here. Also could hold true for the logging message depending on the
      * context of the exception.
-     * 
-     * @param userMessage 
-     * 			  the message displayed to the user
+     *
+     * @param userMessage
+     *               the message displayed to the user
      * @param logMessage
-	 * 			  the message logged
+     *               the message logged
      */
     public EnterpriseSecurityException(String userMessage, String logMessage) {
-    	super(userMessage);
+        super(userMessage);
         this.logMessage = logMessage;
         if (!ESAPI.securityConfiguration().getBooleanProp( DISABLE_INTRUSION_DETECTION )) {
-        	ESAPI.intrusionDetector().addException(this);
+            ESAPI.intrusionDetector().addException(this);
         }
     }
 
     /**
      * Creates a new instance of EnterpriseSecurityException that includes a root cause Throwable.
-     * 
+     *
      * It should be noted that messages that are intended to be displayed to the user should be safe for display. In
      * other words, don't pass in unsanitized data here. Also could hold true for the logging message depending on the
      * context of the exception.
      *
      * @param userMessage
-     * 			  the message displayed to the user
+     *               the message displayed to the user
      * @param logMessage
-	 * 			  the message logged
+     *               the message logged
      * @param cause the cause
      */
     public EnterpriseSecurityException(String userMessage, String logMessage, Throwable cause) {
         super(userMessage, cause);
         this.logMessage = logMessage;
         if (!ESAPI.securityConfiguration().getBooleanProp( DISABLE_INTRUSION_DETECTION )) {
-        	ESAPI.intrusionDetector().addException(this);
+            ESAPI.intrusionDetector().addException(this);
         }
     }
-    
+
     /**
      * Returns message meant for display to users
      *
      * Note that if you are unsure of what set this message, it would probably
      * be a good idea to encode this message before displaying it to the end user.
-     * 
+     *
      * @return a String containing a message that is safe to display to users
      */
     public String getUserMessage() {
@@ -146,7 +141,7 @@ public class EnterpriseSecurityException extends Exception {
      * Returns a message that is safe to display in logs, but may contain
      * sensitive information and therefore probably should not be displayed to
      * users.
-     * 
+     *
      * @return a String containing a message that is safe to display in logs,
      * but probably not to users as it may contain sensitive information.
      */
diff --git a/src/main/java/org/owasp/esapi/errors/EnterpriseSecurityRuntimeException.java b/src/main/java/org/owasp/esapi/errors/EnterpriseSecurityRuntimeException.java
index 6dab2a5..3b511c3 100644
--- a/src/main/java/org/owasp/esapi/errors/EnterpriseSecurityRuntimeException.java
+++ b/src/main/java/org/owasp/esapi/errors/EnterpriseSecurityRuntimeException.java
@@ -1,12 +1,12 @@
 /**
  * OWASP Enterprise Security API (ESAPI)
- * 
+ *
  * This file is part of the Open Web Application Security Project (OWASP)
  * Enterprise Security API (ESAPI) project. For details, please see
  * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
  *
  * Copyright (c) 2010 - The OWASP Foundation
- * 
+ *
  * The ESAPI is published by OWASP under the BSD license. You should read and accept the
  * LICENSE before you use, modify, and/or redistribute this software.
  *
@@ -32,7 +32,7 @@ import org.owasp.esapi.Logger;
  * used extensively throughout ESAPI implementations and the result is a fairly complete set of security log records.
  * ALL EnterpriseSecurityRuntimeExceptions are also sent to the IntrusionDetector for use in detecting anomalous patterns of
  * application usage.
- * 
+ *
  * @author August Detlefsen (augustd at codemagi dot com)
  *         <a href="http://www.codemagi.com">CodeMagi, Inc.</a>
  * @since October 8, 2010
@@ -91,47 +91,47 @@ public class EnterpriseSecurityRuntimeException extends java.lang.RuntimeExcepti
      * It should be noted that messages that are intended to be displayed to the user should be safe for display. In
      * other words, don't pass in unsanitized data here. Also could hold true for the logging message depending on the
      * context of the exception.
-     * 
-     * @param userMessage 
-     * 			  the message displayed to the user
+     *
+     * @param userMessage
+     *               the message displayed to the user
      * @param logMessage
-	 * 			  the message logged
+     *               the message logged
      */
     public EnterpriseSecurityRuntimeException(String userMessage, String logMessage) {
-    	super(userMessage);
+        super(userMessage);
         this.logMessage = logMessage;
         if (!ESAPI.securityConfiguration().getDisableIntrusionDetection()) {
-        	ESAPI.intrusionDetector().addException(this);
+            ESAPI.intrusionDetector().addException(this);
         }
     }
 
     /**
      * Creates a new instance of EnterpriseSecurityException that includes a root cause Throwable.
-     * 
+     *
      * It should be noted that messages that are intended to be displayed to the user should be safe for display. In
      * other words, don't pass in unsanitized data here. Also could hold true for the logging message depending on the
      * context of the exception.
      *
      * @param userMessage
-     * 			  the message displayed to the user
+     *               the message displayed to the user
      * @param logMessage
-	 * 			  the message logged
+     *               the message logged
      * @param cause the cause
      */
     public EnterpriseSecurityRuntimeException(String userMessage, String logMessage, Throwable cause) {
         super(userMessage, cause);
         this.logMessage = logMessage;
         if (!ESAPI.securityConfiguration().getDisableIntrusionDetection()) {
-        	ESAPI.intrusionDetector().addException(this);
+            ESAPI.intrusionDetector().addException(this);
         }
     }
-    
+
     /**
      * Returns message meant for display to users
      *
      * Note that if you are unsure of what set this message, it would probably
      * be a good idea to encode this message before displaying it to the end user.
-     * 
+     *
      * @return a String containing a message that is safe to display to users
      */
     public String getUserMessage() {
@@ -142,7 +142,7 @@ public class EnterpriseSecurityRuntimeException extends java.lang.RuntimeExcepti
      * Returns a message that is safe to display in logs, but may contain
      * sensitive information and therefore probably should not be displayed to
      * users.
-     * 
+     *
      * @return a String containing a message that is safe to display in logs,
      * but probably not to users as it may contain sensitive information.
      */
diff --git a/src/main/java/org/owasp/esapi/errors/ExecutorException.java b/src/main/java/org/owasp/esapi/errors/ExecutorException.java
index a27c74f..9adda92 100644
--- a/src/main/java/org/owasp/esapi/errors/ExecutorException.java
+++ b/src/main/java/org/owasp/esapi/errors/ExecutorException.java
@@ -1,15 +1,15 @@
 /**
  * OWASP Enterprise Security API (ESAPI)
- * 
+ *
  * This file is part of the Open Web Application Security Project (OWASP)
  * Enterprise Security API (ESAPI) project. For details, please see
  * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
  *
  * Copyright (c) 2007 - The OWASP Foundation
- * 
+ *
  * The ESAPI is published by OWASP under the BSD license. You should read and accept the
  * LICENSE before you use, modify, and/or redistribute this software.
- * 
+ *
  * @author Jeff Williams <a href="http://www.aspectsecurity.com">Aspect Security</a>
  * @created 2007
  */
@@ -18,28 +18,28 @@ package org.owasp.esapi.errors;
 /**
  * An ExecutorException should be thrown for any problems that arise during the
  * execution of a system executable.
- * 
+ *
  * @author Jeff Williams (jeff.williams@aspectsecurity.com)
  */
 public class ExecutorException extends EnterpriseSecurityException {
 
-	/** The Constant serialVersionUID. */
-	private static final long serialVersionUID = 1L;
+    /** The Constant serialVersionUID. */
+    private static final long serialVersionUID = 1L;
 
-	/**
-	 * Instantiates a new ExecutorException.
-	 */
-	protected ExecutorException() {
-		// hidden
-	}
+    /**
+     * Instantiates a new ExecutorException.
+     */
+    protected ExecutorException() {
+        // hidden
+    }
 
     /**
      * Creates a new instance of ExecutorException.
-     * 
+     *
      * @param userMessage
      *            the message to display to users
      * @param logMessage
-	 * 			  the message logged
+     *               the message logged
      */
     public ExecutorException(String userMessage, String logMessage) {
         super(userMessage, logMessage);
@@ -47,11 +47,11 @@ public class ExecutorException extends EnterpriseSecurityException {
 
     /**
      * Instantiates a new ExecutorException.
-     * 
+     *
      * @param userMessage
      *            the message to display to users
      * @param logMessage
-	 * 			  the message logged
+     *               the message logged
      * @param cause
      *            the cause
      */
diff --git a/src/main/java/org/owasp/esapi/errors/IntegrityException.java b/src/main/java/org/owasp/esapi/errors/IntegrityException.java
index 59d97a1..92a546a 100644
--- a/src/main/java/org/owasp/esapi/errors/IntegrityException.java
+++ b/src/main/java/org/owasp/esapi/errors/IntegrityException.java
@@ -1,15 +1,15 @@
 /**
  * OWASP Enterprise Security API (ESAPI)
- * 
+ *
  * This file is part of the Open Web Application Security Project (OWASP)
  * Enterprise Security API (ESAPI) project. For details, please see
  * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
  *
  * Copyright (c) 2007 - The OWASP Foundation
- * 
+ *
  * The ESAPI is published by OWASP under the BSD license. You should read and accept the
  * LICENSE before you use, modify, and/or redistribute this software.
- * 
+ *
  * @author Jeff Williams <a href="http://www.aspectsecurity.com">Aspect Security</a>
  * @created 2007
  */
@@ -19,28 +19,28 @@ package org.owasp.esapi.errors;
  * An IntegrityException should be thrown when a problem with the integrity of data
  * has been detected. For example, if a financial account cannot be reconciled after
  * a transaction has been performed, an integrity exception should be thrown.
- * 
+ *
  * @author Jeff Williams (jeff.williams@aspectsecurity.com)
  */
 public class IntegrityException extends EnterpriseSecurityException {
 
-	/** The Constant serialVersionUID. */
-	private static final long serialVersionUID = 1L;
+    /** The Constant serialVersionUID. */
+    private static final long serialVersionUID = 1L;
 
-	/**
-	 * Instantiates a new availability exception.
-	 */
-	protected IntegrityException() {
-		// hidden
-	}
+    /**
+     * Instantiates a new availability exception.
+     */
+    protected IntegrityException() {
+        // hidden
+    }
 
     /**
      * Creates a new instance of IntegrityException.
-     * 
+     *
      * @param userMessage
      *            the message to display to users
      * @param logMessage
-	 * 			  the message logged
+     *               the message logged
      */
     public IntegrityException(String userMessage, String logMessage) {
         super(userMessage, logMessage);
@@ -48,11 +48,11 @@ public class IntegrityException extends EnterpriseSecurityException {
 
     /**
      * Instantiates a new IntegrityException.
-     * 
+     *
      * @param userMessage
      *            the message to display to users
      * @param logMessage
-	 * 			  the message logged
+     *               the message logged
      * @param cause
      *            the cause
      */
diff --git a/src/main/java/org/owasp/esapi/errors/IntrusionException.java b/src/main/java/org/owasp/esapi/errors/IntrusionException.java
index b5253ea..72261d9 100644
--- a/src/main/java/org/owasp/esapi/errors/IntrusionException.java
+++ b/src/main/java/org/owasp/esapi/errors/IntrusionException.java
@@ -1,15 +1,15 @@
 /**
  * OWASP Enterprise Security API (ESAPI)
- * 
+ *
  * This file is part of the Open Web Application Security Project (OWASP)
  * Enterprise Security API (ESAPI) project. For details, please see
  * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
  *
  * Copyright (c) 2007 - The OWASP Foundation
- * 
+ *
  * The ESAPI is published by OWASP under the BSD license. You should read and accept the
  * LICENSE before you use, modify, and/or redistribute this software.
- * 
+ *
  * @author Jeff Williams <a href="http://www.aspectsecurity.com">Aspect Security</a>
  * @created 2007
  */
@@ -25,7 +25,7 @@ import org.owasp.esapi.Logger;
  * <P>
  * Unlike other exceptions in the ESAPI, the IntrusionException is a RuntimeException so that it can be thrown from
  * anywhere and will not require a lot of special exception handling.
- * 
+ *
  * @author Jeff Williams (jeff.williams@aspectsecurity.com)
  */
 public class IntrusionException extends EnterpriseSecurityRuntimeException {
@@ -43,11 +43,11 @@ public class IntrusionException extends EnterpriseSecurityRuntimeException {
 
     /**
      * Creates a new instance of IntrusionException.
-     * 
+     *
      * @param userMessage
      *            the message to display to users
      * @param logMessage
-	 * 			  the message logged
+     *               the message logged
      */
     public IntrusionException(String userMessage, String logMessage) {
         super(userMessage);
@@ -57,13 +57,13 @@ public class IntrusionException extends EnterpriseSecurityRuntimeException {
 
     /**
      * Instantiates a new intrusion exception.
-     * 
+     *
      * @param userMessage
      *            the message to display to users
      * @param logMessage
-	 * 			  the message logged
-     * @param cause 
-     *			  the cause
+     *               the message logged
+     * @param cause
+     *              the cause
      */
     public IntrusionException(String userMessage, String logMessage, Throwable cause) {
         super(userMessage, cause);
@@ -73,7 +73,7 @@ public class IntrusionException extends EnterpriseSecurityRuntimeException {
 
     /**
      * Returns a String containing a message that is safe to display to users
-     * 
+     *
      * @return a String containing a message that is safe to display to users
      */
     public String getUserMessage() {
@@ -82,7 +82,7 @@ public class IntrusionException extends EnterpriseSecurityRuntimeException {
 
     /**
      * Returns a String that is safe to display in logs, but probably not to users
-     * 
+     *
      * @return a String containing a message that is safe to display in logs, but probably not to users
      */
     public String getLogMessage() {
diff --git a/src/main/java/org/owasp/esapi/errors/ValidationAvailabilityException.java b/src/main/java/org/owasp/esapi/errors/ValidationAvailabilityException.java
index 4e4a1d4..5274da5 100644
--- a/src/main/java/org/owasp/esapi/errors/ValidationAvailabilityException.java
+++ b/src/main/java/org/owasp/esapi/errors/ValidationAvailabilityException.java
@@ -1,15 +1,15 @@
 /**
  * OWASP Enterprise Security API (ESAPI)
- * 
+ *
  * This file is part of the Open Web Application Security Project (OWASP)
  * Enterprise Security API (ESAPI) project. For details, please see
  * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
  *
  * Copyright (c) 2007 - The OWASP Foundation
- * 
+ *
  * The ESAPI is published by OWASP under the BSD license. You should read and accept the
  * LICENSE before you use, modify, and/or redistribute this software.
- * 
+ *
  * @author Jeff Williams <a href="http://www.aspectsecurity.com">Aspect Security</a>
  * @created 2007
  */
@@ -20,38 +20,38 @@ package org.owasp.esapi.errors;
  */
 public class ValidationAvailabilityException extends ValidationException {
 
-	/** The Constant serialVersionUID. */
-	private static final long serialVersionUID = 1L;
+    /** The Constant serialVersionUID. */
+    private static final long serialVersionUID = 1L;
 
-	/**
-	 * Instantiates a new validation exception.
-	 */
-	protected ValidationAvailabilityException() {
-		// hidden
-	}
+    /**
+     * Instantiates a new validation exception.
+     */
+    protected ValidationAvailabilityException() {
+        // hidden
+    }
 
     /**
      * Create a new ValidationException
      * @param userMessage
      *            the message to display to users
      * @param logMessage
-	 * 			  the message logged
+     *               the message logged
      */
-	public ValidationAvailabilityException(String userMessage, String logMessage) {
-		super(userMessage, logMessage);
-	}
+    public ValidationAvailabilityException(String userMessage, String logMessage) {
+        super(userMessage, logMessage);
+    }
 
     /**
      * Create a new ValidationException
      * @param userMessage
      *            the message to display to users
      * @param logMessage
-	 * 			  the message logged
+     *               the message logged
      * @param cause
-     * 			  the cause
-     */			  
-	public ValidationAvailabilityException(String userMessage, String logMessage, Throwable cause) {
-		super(userMessage, logMessage, cause);
-	}
+     *               the cause
+     */
+    public ValidationAvailabilityException(String userMessage, String logMessage, Throwable cause) {
+        super(userMessage, logMessage, cause);
+    }
 
 }
diff --git a/src/main/java/org/owasp/esapi/errors/ValidationException.java b/src/main/java/org/owasp/esapi/errors/ValidationException.java
index a33562f..c185574 100644
--- a/src/main/java/org/owasp/esapi/errors/ValidationException.java
+++ b/src/main/java/org/owasp/esapi/errors/ValidationException.java
@@ -1,15 +1,15 @@
 /**
  * OWASP Enterprise Security API (ESAPI)
- * 
+ *
  * This file is part of the Open Web Application Security Project (OWASP)
  * Enterprise Security API (ESAPI) project. For details, please see
  * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
  *
  * Copyright (c) 2007 - The OWASP Foundation
- * 
+ *
  * The ESAPI is published by OWASP under the BSD license. You should read and accept the
  * LICENSE before you use, modify, and/or redistribute this software.
- * 
+ *
  * @author Jeff Williams <a href="http://www.aspectsecurity.com">Aspect Security</a>
  * @created 2007
  */
@@ -19,30 +19,30 @@ package org.owasp.esapi.errors;
  * A ValidationException should be thrown to indicate that the data provided by
  * the user or from some other external source does not match the validation
  * rules that have been specified for that data.
- * 
+ *
  * @author Jeff Williams (jeff.williams@aspectsecurity.com)
  */
 public class ValidationException extends EnterpriseSecurityException {
 
     protected static final long serialVersionUID = 1L;
 
-	/** The UI reference that caused this ValidationException */
-	private String context;
+    /** The UI reference that caused this ValidationException */
+    private String context;
 
-	/**
-	 * Instantiates a new validation exception.
-	 */
-	protected ValidationException() {
-		// hidden
-	}
+    /**
+     * Instantiates a new validation exception.
+     */
+    protected ValidationException() {
+        // hidden
+    }
 
     /**
      * Creates a new instance of ValidationException.
-     * 
+     *
      * @param userMessage
      *            the message to display to users
      * @param logMessage
-	 * 			  the message logged
+     *               the message logged
      */
     public ValidationException(String userMessage, String logMessage) {
         super(userMessage, logMessage);
@@ -50,25 +50,25 @@ public class ValidationException extends EnterpriseSecurityException {
 
     /**
      * Instantiates a new ValidationException.
-     * 
+     *
      * @param userMessage
      *            the message to display to users
      * @param logMessage
-	 * 			  the message logged
+     *               the message logged
      * @param cause
      *            the cause
      */
     public ValidationException(String userMessage, String logMessage, Throwable cause) {
         super(userMessage, logMessage, cause);
     }
-    
+
     /**
      * Creates a new instance of ValidationException.
-     * 
+     *
      * @param userMessage
      *            the message to display to users
      * @param logMessage
-	 * 			  the message logged
+     *               the message logged
      * @param context
      *            the source that caused this exception
      */
@@ -76,14 +76,14 @@ public class ValidationException extends EnterpriseSecurityException {
         super(userMessage, logMessage);
         setContext(context);
     }
-    
+
     /**
      * Instantiates a new ValidationException.
-     * 
+     *
      * @param userMessage
      *            the message to display to users
      * @param logMessage
-	 * 			  the message logged
+     *               the message logged
      * @param cause
      *            the cause
      * @param context
@@ -91,25 +91,25 @@ public class ValidationException extends EnterpriseSecurityException {
      */
     public ValidationException(String userMessage, String logMessage, Throwable cause, String context) {
         super(userMessage, logMessage, cause);
-    	setContext(context);
+        setContext(context);
+    }
+
+    /**
+     * Returns the UI reference that caused this ValidationException
+     *
+     * @return context, the source that caused the exception, stored as a string
+     */
+    public String getContext() {
+        return context;
     }
-    
-	/**
-	 * Returns the UI reference that caused this ValidationException
-	 *  
-	 * @return context, the source that caused the exception, stored as a string
-	 */
-	public String getContext() {
-		return context;
-	}
 
-	/**
-	 * Set's the UI reference that caused this ValidationException
-	 *  
-	 * @param context
-	 * 			the context to set, passed as a String
-	 */
-	public void setContext(String context) {
-		this.context = context;
-	}
+    /**
+     * Set's the UI reference that caused this ValidationException
+     *
+     * @param context
+     *             the context to set, passed as a String
+     */
+    public void setContext(String context) {
+        this.context = context;
+    }
 }
diff --git a/src/main/java/org/owasp/esapi/errors/ValidationUploadException.java b/src/main/java/org/owasp/esapi/errors/ValidationUploadException.java
index 4a04de2..825f154 100644
--- a/src/main/java/org/owasp/esapi/errors/ValidationUploadException.java
+++ b/src/main/java/org/owasp/esapi/errors/ValidationUploadException.java
@@ -1,15 +1,15 @@
 /**
  * OWASP Enterprise Security API (ESAPI)
- * 
+ *
  * This file is part of the Open Web Application Security Project (OWASP)
  * Enterprise Security API (ESAPI) project. For details, please see
  * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
  *
  * Copyright (c) 2007 - The OWASP Foundation
- * 
+ *
  * The ESAPI is published by OWASP under the BSD license. You should read and accept the
  * LICENSE before you use, modify, and/or redistribute this software.
- * 
+ *
  * @author Jeff Williams <a href="http://www.aspectsecurity.com">Aspect Security</a>
  * @created 2007
  */
@@ -20,40 +20,40 @@ package org.owasp.esapi.errors;
  */
 public class ValidationUploadException extends ValidationException {
 
-	/** The Constant serialVersionUID. */
-	private static final long serialVersionUID = 1L;
+    /** The Constant serialVersionUID. */
+    private static final long serialVersionUID = 1L;
 
-	/**
-	 * Instantiates a new validation exception.
-	 */
-	protected ValidationUploadException() {
-		// hidden
-	}
+    /**
+     * Instantiates a new validation exception.
+     */
+    protected ValidationUploadException() {
+        // hidden
+    }
 
     /**
      * Create a new ValidationException
-     * 
+     *
      * @param userMessage
      *            the message to display to users
      * @param logMessage
-	 * 			  the message logged
+     *               the message logged
      */
-	public ValidationUploadException(String userMessage, String logMessage) {
-		super(userMessage, logMessage);
-	}
+    public ValidationUploadException(String userMessage, String logMessage) {
+        super(userMessage, logMessage);
+    }
 
     /**
      * Create a new ValidationException
-     * 
+     *
      * @param userMessage
      *            the message to display to users
      * @param logMessage
-	 * 			  the message logged
+     *               the message logged
      * @param cause
-     * 			  the cause
+     *               the cause
      */
-	public ValidationUploadException(String userMessage, String logMessage, Throwable cause) {
-		super(userMessage, logMessage, cause);
-	}
+    public ValidationUploadException(String userMessage, String logMessage, Throwable cause) {
+        super(userMessage, logMessage, cause);
+    }
 
 }
diff --git a/src/main/java/org/owasp/esapi/filters/ClickjackFilter.java b/src/main/java/org/owasp/esapi/filters/ClickjackFilter.java
index c57b836..e10a4e1 100644
--- a/src/main/java/org/owasp/esapi/filters/ClickjackFilter.java
+++ b/src/main/java/org/owasp/esapi/filters/ClickjackFilter.java
@@ -1,15 +1,15 @@
 /**
  * OWASP Enterprise Security API (ESAPI)
- * 
+ *
  * This file is part of the Open Web Application Security Project (OWASP)
  * Enterprise Security API (ESAPI) project. For details, please see
  * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
  *
  * Copyright (c) 2007 - The OWASP Foundation
- * 
+ *
  * The ESAPI is published by OWASP under the BSD license. You should read and accept the
  * LICENSE before you use, modify, and/or redistribute this software.
- * 
+ *
  * @author     Jeff Williams <a href="http://www.aspectsecurity.com">Aspect Security</a>
  * @created    February 6, 2009
  */
@@ -26,83 +26,89 @@ import javax.servlet.ServletResponse;
 import javax.servlet.http.HttpServletResponse;
 
 /**
- * The {@code ClickjackFilter} is discussed at
- * @link http://www.owasp.org/index.php/ClickjackFilter_for_Java_EE
+ * The {@code ClickjackFilter} is configured as follows:
  * <pre>
- *     <filter>
- *            <filter-name>ClickjackFilterDeny</filter-name>
- *            <filter-class>org.owasp.filters.ClickjackFilter</filter-class>
- *            <init-param>
- *                <param-name>mode</param-name>
- *                 <param-value>DENY</param-value>
- *             </init-param>
- *         </filter>
- *         
- *         <filter>
- *             <filter-name>ClickjackFilterSameOrigin</filter-name>
- *             <filter-class>org.owasp.filters.ClickjackFilter</filter-class>
- *             <init-param>
- *                 <param-name>mode</param-name>
- *                 <param-value>SAMEORIGIN</param-value>
- *             </init-param>
- *         </filter>
- *        
- *        <!--  use the Deny version to prevent anyone, including yourself, from framing the page -->
- *        <filter-mapping> 
- *            <filter-name>ClickjackFilterDeny</filter-name>
- *            <url-pattern>/*</url-pattern>
- *        </filter-mapping>
- *         
- *         <!-- use the SameOrigin version to allow your application to frame, but nobody else
- *         <filter-mapping> 
- *            <filter-name>ClickjackFilterSameOrigin</filter-name>
- *             <url-pattern>/*</url-pattern>
- *         </filter-mapping>
+ *
+ *     &lt;filter&gt;
+ *            &lt;filter-name&gt;ClickjackFilterDeny&lt;/filter-name&gt;
+ *            &lt;filter-class&gt;org.owasp.filters.ClickjackFilter&lt;/filter-class&gt;
+ *            &lt;init-param&gt;
+ *                &lt;param-name&gt;mode&lt;/param-name&gt;
+ *                 &lt;param-value&gt;DENY&lt;/param-value&gt;
+ *             &lt;/init-param&gt;
+ *         &lt;/filter&gt;
+ *
+ *         &lt;filter&gt;
+ *             &lt;filter-name&gt;ClickjackFilterSameOrigin&lt;/filter-name&gt;
+ *             &lt;filter-class&gt;org.owasp.filters.ClickjackFilter&lt;/filter-class&gt;
+ *             &lt;init-param&gt;
+ *                 &lt;param-name&gt;mode&lt;/param-name&gt;
+ *                 &lt;param-value&gt;SAMEORIGIN&lt;/param-value&gt;
+ *             &lt;/init-param&gt;
+ *         &lt;/filter&gt;
+ *
+ *        &lt;!--  use the Deny version to prevent anyone, including yourself, from framing the page --&gt;
+ *        &lt;filter-mapping&gt;
+ *            &lt;filter-name&gt;ClickjackFilterDeny&lt;/filter-name&gt;
+ *            &lt;url-pattern&gt;/*&lt;/url-pattern&gt;
+ *        &lt;/filter-mapping&gt;
+ *
+ *         &lt;!-- use the SameOrigin version to allow your application to frame, but nobody else
+ *         &lt;filter-mapping&gt;
+ *            &lt;filter-name&gt;ClickjackFilterSameOrigin&lt;/filter-name&gt;
+ *             &lt;url-pattern&gt;/*&lt;/url-pattern&gt;
+ *         &lt;/filter-mapping&gt;
  * </pre>
+ *
+ * @see <a href="https://web.archive.org/web/20131020084831/https://www.owasp.org/index.php/ClickjackFilter_for_Java_EE">
+ *          OWASP - Clickjacking Filter for JavaEE</a>
+ * @see <a href="https://owasp.org/www-community/attacks/Clickjacking">OWASP - Clickjacking Attack</a>
+ * @see <a href="https://cheatsheetseries.owasp.org/cheatsheets/Clickjacking_Defense_Cheat_Sheet.html">
+ *          OWASP - Clickjacking Defense Cheat Sheet</a>
  */
-public class ClickjackFilter implements Filter 
+public class ClickjackFilter implements Filter
 {
 
-	private String mode = "DENY";
+    private String mode = "DENY";
 
-	/**
-	 * Initialize "mode" parameter from web.xml. Valid values are "DENY" and "SAMEORIGIN". 
-	 * If you leave this parameter out, the default is to use the DENY mode.
-	 * 
-	 * @param filterConfig A filter configuration object used by a servlet container
-	 *                     to pass information to a filter during initialization. 
-	 */
-	public void init(FilterConfig filterConfig) {
-		String configMode = filterConfig.getInitParameter("mode");
-		if ( configMode != null && ( configMode.equals( "DENY" ) || configMode.equals( "SAMEORIGIN" ) ) ) {
-			mode = configMode;
-		}
-	}
-	
-	/**
-	 * Add X-FRAME-OPTIONS response header to tell IE8 (and any other browsers who
-	 * decide to implement) not to display this content in a frame. For details, please
-	 * refer to
-	 * @link http://blogs.msdn.com/sdl/archive/2009/02/05/clickjacking-defense-in-ie8.aspx
-	 * 
-	 * @param request The request object.
-	 * @param response The response object.
-	 * @param chain Refers to the {@code FilterChain} object to pass control to the
-	 *              next {@code Filter}.
-	 * @throws IOException
-	 * @throws ServletException
-	 */
-	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException
-	{
+    /**
+     * Initialize "mode" parameter from web.xml. Valid values are "DENY" and "SAMEORIGIN".
+     * If you leave this parameter out, the default is to use the DENY mode.
+     *
+     * @param filterConfig A filter configuration object used by a servlet container
+     *                     to pass information to a filter during initialization.
+     */
+    public void init(FilterConfig filterConfig) {
+        String configMode = filterConfig.getInitParameter("mode");
+        if ( configMode != null && ( configMode.equals( "DENY" ) || configMode.equals( "SAMEORIGIN" ) ) ) {
+            mode = configMode;
+        }
+    }
+
+    /**
+     * Add X-FRAME-OPTIONS response header to tell IE8 (and any other browsers who
+     * decide to implement) not to display this content in a frame. For details, please
+     * refer to
+     * @link http://blogs.msdn.com/sdl/archive/2009/02/05/clickjacking-defense-in-ie8.aspx
+     *
+     * @param request The request object.
+     * @param response The response object.
+     * @param chain Refers to the {@code FilterChain} object to pass control to the
+     *              next {@code Filter}.
+     * @throws IOException
+     * @throws ServletException
+     */
+    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException
+    {
         HttpServletResponse res = (HttpServletResponse)response;
         res.addHeader("X-FRAME-OPTIONS", mode );
         chain.doFilter(request, response);
-	}
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void destroy() {
+    }
 
-	/**
-	 * {@inheritDoc}
-	 */
-	public void destroy() {
-	}
-	
 }
diff --git a/src/main/java/org/owasp/esapi/filters/ESAPIFilter.java b/src/main/java/org/owasp/esapi/filters/ESAPIFilter.java
index 3477439..be0417b 100644
--- a/src/main/java/org/owasp/esapi/filters/ESAPIFilter.java
+++ b/src/main/java/org/owasp/esapi/filters/ESAPIFilter.java
@@ -1,15 +1,15 @@
 /**
  * OWASP Enterprise Security API (ESAPI)
- * 
+ *
  * This file is part of the Open Web Application Security Project (OWASP)
  * Enterprise Security API (ESAPI) project. For details, please see
  * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
  *
  * Copyright (c) 2007 - The OWASP Foundation
- * 
+ *
  * The ESAPI is published by OWASP under the BSD license. You should read and accept the
  * LICENSE before you use, modify, and/or redistribute this software.
- * 
+ *
  * @author Jeff Williams <a href="http://www.aspectsecurity.com">Aspect Security</a>
  * @created 2007
  */
@@ -37,18 +37,18 @@ import org.owasp.esapi.errors.AuthenticationException;
  */
 public class ESAPIFilter implements Filter {
 
-	private final Logger logger = ESAPI.getLogger("ESAPIFilter");
+    private final Logger logger = ESAPI.getLogger("ESAPIFilter");
 
-	private static final String[] obfuscate = { "password" };
+    private static final String[] obfuscate = { "password" };
 
-	private String loginPage                     = "WEB-INF/login.jsp";
+    private String loginPage                     = "WEB-INF/login.jsp";
     private String publicUnauthorizedLandingPage = "WEB-INF/index.jsp";
 
-	/**
-	 * Called by the web container to indicate to a filter that it is being
-	 * placed into service. The servlet container calls the init method exactly
-	 * once after instantiating the filter. The init method must complete
-	 * successfully before the filter is asked to do any filtering work.
+    /**
+     * Called by the web container to indicate to a filter that it is being
+     * placed into service. The servlet container calls the init method exactly
+     * once after instantiating the filter. The init method must complete
+     * successfully before the filter is asked to do any filtering work.
      * <p>
      * Init parameters in web.xml for this filter:
      * <ul>
@@ -59,104 +59,104 @@ public class ESAPIFilter implements Filter {
      * Default is "WEB-INF/index.jsp".</li>
      * </ul>
      * </p>
-	 * 
-	 * @param filterConfig
-	 *            configuration object
-	 */
-	public void init(FilterConfig filterConfig) {
-		String path = filterConfig.getInitParameter("resourceDirectory");
-		if ( path != null ) {
-			ESAPI.securityConfiguration().setResourceDirectory( path );
-		}
-		String paramLoginPage = filterConfig.getInitParameter("loginPage");
-		if ( paramLoginPage != null ) {
-			loginPage = paramLoginPage;
-		}
+     *
+     * @param filterConfig
+     *            configuration object
+     */
+    public void init(FilterConfig filterConfig) {
+        String path = filterConfig.getInitParameter("resourceDirectory");
+        if ( path != null ) {
+            ESAPI.securityConfiguration().setResourceDirectory( path );
+        }
+        String paramLoginPage = filterConfig.getInitParameter("loginPage");
+        if ( paramLoginPage != null ) {
+            loginPage = paramLoginPage;
+        }
         String paramUnauthorizedPage = filterConfig.getInitParameter("publicUnauthorizedLandingPage");
         if ( paramUnauthorizedPage != null ) {
             publicUnauthorizedLandingPage = paramUnauthorizedPage;
         }
-	}
-
-	/**
-	 * The doFilter method of the Filter is called by the container each time a
-	 * request/response pair is passed through the chain due to a client request
-	 * for a resource at the end of the chain. The FilterChain passed in to this
-	 * method allows the Filter to pass on the request and response to the next
-	 * entity in the chain.
-	 * 
-	 * @param req
-	 *            Request object to be processed
-	 * @param resp
-	 *            Response object
-	 * @param chain
-	 *            current FilterChain
-	 * @exception IOException
-	 *                if any occurs
-	 */
-	public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException {
-		HttpServletRequest request = (HttpServletRequest) req;
-		HttpServletResponse response = (HttpServletResponse) resp;
-		ESAPI.httpUtilities().setCurrentHTTP(request, response);
-		
-		try {
-			// figure out who the current user is
-			try {
-				ESAPI.authenticator().login(request, response);
-			} catch( AuthenticationException e ) {
-				ESAPI.authenticator().logout();
-				request.setAttribute("message", "Authentication failed");
-				RequestDispatcher dispatcher = request.getRequestDispatcher(loginPage);
-				dispatcher.forward(request, response);
-				return;
-			}
-
-			// log this request, obfuscating any parameter named password
-			ESAPI.httpUtilities().logHTTPRequest(request, logger, Arrays.asList(obfuscate));
-
-			// check access to this URL
-			if ( !ESAPI.accessController().isAuthorizedForURL(request.getRequestURI()) ) {
-				request.setAttribute("message", "Unauthorized" );
-				RequestDispatcher dispatcher = request.getRequestDispatcher(publicUnauthorizedLandingPage);
-				dispatcher.forward(request, response);
-				return;
-			}
-
-			// check for CSRF attacks
-			// ESAPI.httpUtilities().checkCSRFToken();
-			
-			// forward this request on to the web application
-			chain.doFilter(request, response);
-
-			// set up response with content type
-			ESAPI.httpUtilities().setContentType( response );
+    }
+
+    /**
+     * The doFilter method of the Filter is called by the container each time a
+     * request/response pair is passed through the chain due to a client request
+     * for a resource at the end of the chain. The FilterChain passed in to this
+     * method allows the Filter to pass on the request and response to the next
+     * entity in the chain.
+     *
+     * @param req
+     *            Request object to be processed
+     * @param resp
+     *            Response object
+     * @param chain
+     *            current FilterChain
+     * @exception IOException
+     *                if any occurs
+     */
+    public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException {
+        HttpServletRequest request = (HttpServletRequest) req;
+        HttpServletResponse response = (HttpServletResponse) resp;
+        ESAPI.httpUtilities().setCurrentHTTP(request, response);
+
+        try {
+            // figure out who the current user is
+            try {
+                ESAPI.authenticator().login(request, response);
+            } catch( AuthenticationException e ) {
+                ESAPI.authenticator().logout();
+                request.setAttribute("message", "Authentication failed");
+                RequestDispatcher dispatcher = request.getRequestDispatcher(loginPage);
+                dispatcher.forward(request, response);
+                return;
+            }
+
+            // log this request, obfuscating any parameter named password
+            ESAPI.httpUtilities().logHTTPRequest(request, logger, Arrays.asList(obfuscate));
+
+            // check access to this URL
+            if ( !ESAPI.accessController().isAuthorizedForURL(request.getRequestURI()) ) {
+                request.setAttribute("message", "Unauthorized" );
+                RequestDispatcher dispatcher = request.getRequestDispatcher(publicUnauthorizedLandingPage);
+                dispatcher.forward(request, response);
+                return;
+            }
+
+            // check for CSRF attacks
+            // ESAPI.httpUtilities().checkCSRFToken();
+
+            // forward this request on to the web application
+            chain.doFilter(request, response);
+
+            // set up response with content type
+            ESAPI.httpUtilities().setContentType( response );
 
             // set no-cache headers on every response
             // only do this if the entire site should not be cached
             // otherwise you should do this strategically in your controller or actions
-			ESAPI.httpUtilities().setNoCacheHeaders( response );
-            
-		} catch (Exception e) {
-			logger.error( Logger.SECURITY_FAILURE, "Error in ESAPI security filter: " + e.getMessage(), e );
-			request.setAttribute("message", e.getMessage() );
-			
-		} finally {
-			// VERY IMPORTANT
-			// clear out the ThreadLocal variables in the authenticator
-			// some containers could possibly reuse this thread without clearing the User
-			ESAPI.clearCurrent();
-		}
-	}
-
-	/**
-	 * Called by the web container to indicate to a filter that it is being
-	 * taken out of service. This method is only called once all threads within
-	 * the filter's doFilter method have exited or after a timeout period has
-	 * passed. After the web container calls this method, it will not call the
-	 * doFilter method again on this instance of the filter.
-	 */
-	public void destroy() {
-		// finalize
-	}
+            ESAPI.httpUtilities().setNoCacheHeaders( response );
+
+        } catch (Exception e) {
+            logger.error( Logger.SECURITY_FAILURE, "Error in ESAPI security filter: " + e.getMessage(), e );
+            request.setAttribute("message", e.getMessage() );
+
+        } finally {
+            // VERY IMPORTANT
+            // clear out the ThreadLocal variables in the authenticator
+            // some containers could possibly reuse this thread without clearing the User
+            ESAPI.clearCurrent();
+        }
+    }
+
+    /**
+     * Called by the web container to indicate to a filter that it is being
+     * taken out of service. This method is only called once all threads within
+     * the filter's doFilter method have exited or after a timeout period has
+     * passed. After the web container calls this method, it will not call the
+     * doFilter method again on this instance of the filter.
+     */
+    public void destroy() {
+        // finalize
+    }
 
 }
diff --git a/src/main/java/org/owasp/esapi/filters/RequestRateThrottleFilter.java b/src/main/java/org/owasp/esapi/filters/RequestRateThrottleFilter.java
index 31fbfef..ed263e5 100644
--- a/src/main/java/org/owasp/esapi/filters/RequestRateThrottleFilter.java
+++ b/src/main/java/org/owasp/esapi/filters/RequestRateThrottleFilter.java
@@ -1,15 +1,15 @@
 /**
  * OWASP Enterprise Security API (ESAPI)
- * 
+ *
  * This file is part of the Open Web Application Security Project (OWASP)
  * Enterprise Security API (ESAPI) project. For details, please see
  * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
  *
  * Copyright (c) 2007 - The OWASP Foundation
- * 
+ *
  * The ESAPI is published by OWASP under the BSD license. You should read and accept the
  * LICENSE before you use, modify, and/or redistribute this software.
- * 
+ *
  * @author Jeff Williams <a href="http://www.aspectsecurity.com">Aspect Security</a>
  * @created 2007
  */
@@ -48,7 +48,7 @@ public class RequestRateThrottleFilter implements Filter
      * placed into service. The servlet container calls the init method exactly
      * once after instantiating the filter. The init method must complete
      * successfully before the filter is asked to do any filtering work.
-     * 
+     *
      * @param filterConfig
      *            configuration object
      */
@@ -64,9 +64,9 @@ public class RequestRateThrottleFilter implements Filter
      * exceeded, then a short error message is written to the output stream and
      * no further processing is done on the request. Otherwise the request is
      * processed as normal.
-     * @param request 
-     * @param response 
-     * @param chain 
+     * @param request
+     * @param response
+     * @param chain
      * @throws IOException
      * @throws ServletException
      */
@@ -74,7 +74,7 @@ public class RequestRateThrottleFilter implements Filter
     {
         HttpServletRequest httpRequest = (HttpServletRequest) request;
         HttpSession session = httpRequest.getSession(true);
-        
+
         synchronized( session.getId().intern() ) {
             List<Long> times = ESAPI.httpUtilities().getSessionAttribute("times");
             if (times == null) {
diff --git a/src/main/java/org/owasp/esapi/filters/SecurityWrapper.java b/src/main/java/org/owasp/esapi/filters/SecurityWrapper.java
index 82d6ce1..cea61ba 100644
--- a/src/main/java/org/owasp/esapi/filters/SecurityWrapper.java
+++ b/src/main/java/org/owasp/esapi/filters/SecurityWrapper.java
@@ -1,15 +1,15 @@
 /**
  * OWASP Enterprise Security API (ESAPI)
- * 
+ *
  * This file is part of the Open Web Application Security Project (OWASP)
  * Enterprise Security API (ESAPI) project. For details, please see
  * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
  *
  * Copyright (c) 2007 - The OWASP Foundation
- * 
+ *
  * The ESAPI is published by OWASP under the BSD license. You should read and accept the
  * LICENSE before you use, modify, and/or redistribute this software.
- * 
+ *
  * @author Jeff Williams <a href="http://www.aspectsecurity.com">Aspect Security</a>
  * @created 2007
  */
@@ -121,8 +121,8 @@ public class SecurityWrapper implements Filter {
      *
      */
     public void destroy() {
-		// no special action
-	}
+        // no special action
+    }
 
     /**
      *
@@ -130,7 +130,7 @@ public class SecurityWrapper implements Filter {
      * @throws javax.servlet.ServletException
      */
     public void init(FilterConfig filterConfig) throws ServletException {
-		this.allowableResourcesRoot = StringUtilities.replaceNull( filterConfig.getInitParameter( "allowableResourcesRoot" ), allowableResourcesRoot );
-	}
-	
+        this.allowableResourcesRoot = StringUtilities.replaceNull( filterConfig.getInitParameter( "allowableResourcesRoot" ), allowableResourcesRoot );
+    }
+
 }
diff --git a/src/main/java/org/owasp/esapi/filters/SecurityWrapperRequest.java b/src/main/java/org/owasp/esapi/filters/SecurityWrapperRequest.java
index dae6a84..26fa7a7 100644
--- a/src/main/java/org/owasp/esapi/filters/SecurityWrapperRequest.java
+++ b/src/main/java/org/owasp/esapi/filters/SecurityWrapperRequest.java
@@ -6,7 +6,7 @@
  * www.owasp.org/index.php/ESAPI</a>. Copyright (c) 2007 - The OWASP Foundation
  * The ESAPI is published by OWASP under the BSD license. You should read and
  * accept the LICENSE before you use, modify, and/or redistribute this software.
- * 
+ *
  * @author Jeff Williams <a href="http://www.aspectsecurity.com">Aspect
  *         Security</a>
  * @created 2007
@@ -57,10 +57,10 @@ public class SecurityWrapperRequest extends HttpServletRequestWrapper implements
 
     private String allowableContentRoot = "WEB-INF";
 
-    /** 
+    /**
      * Construct a safe request that overrides the default request methods with
      * safer versions.
-     * 
+     *
      * @param request The {@code HttpServletRequest} we are wrapping.
      */
     public SecurityWrapperRequest(HttpServletRequest request) {
@@ -70,7 +70,7 @@ public class SecurityWrapperRequest extends HttpServletRequestWrapper implements
     private HttpServletRequest getHttpServletRequest() {
         return (HttpServletRequest)super.getRequest();
     }
-    
+
     /**
      * Same as HttpServletRequest, no security changes required.
      * @param name The attribute name
@@ -159,7 +159,7 @@ public class SecurityWrapperRequest extends HttpServletRequestWrapper implements
                 int maxAge = c.getMaxAge();
                 String domain = c.getDomain();
                 String path = c.getPath();
-                
+
                 Cookie n = new Cookie(name, value);
                 n.setMaxAge(maxAge);
 
@@ -398,7 +398,7 @@ public class SecurityWrapperRequest extends HttpServletRequestWrapper implements
                 String name = (String) e.getKey();
                 SecurityConfiguration sc = ESAPI.securityConfiguration();
                 String cleanName = ESAPI.validator().getValidInput("HTTP parameter name: " + name, name, "HTTPParameterName", sc.getIntProp("HttpUtilities.httpQueryParamNameLength"), true);
-                
+
                 String[] value = (String[]) e.getValue();
                 String[] cleanValues = new String[value.length];
                 for (int j = 0; j < value.length; j++) {
@@ -520,7 +520,7 @@ public class SecurityWrapperRequest extends HttpServletRequestWrapper implements
      * Same as HttpServletRequest, no security changes required. Note that this
      * reader may contain attacks and the developer is responsible for
      * canonicalizing, validating, and encoding any data from this stream.
-     * @return aA {@code BufferedReader} containing the body of the request. 
+     * @return aA {@code BufferedReader} containing the body of the request.
      * @throws IOException If an input error occurred while reading the request
      *                     body (e.g., premature EOF).
      */
@@ -689,7 +689,7 @@ public class SecurityWrapperRequest extends HttpServletRequestWrapper implements
         }
         return port;
     }
-    
+
 
     /**
      * Returns the server path from the HttpServletRequest after canonicalizing
diff --git a/src/main/java/org/owasp/esapi/filters/SecurityWrapperResponse.java b/src/main/java/org/owasp/esapi/filters/SecurityWrapperResponse.java
index 3cb1524..f05682c 100644
--- a/src/main/java/org/owasp/esapi/filters/SecurityWrapperResponse.java
+++ b/src/main/java/org/owasp/esapi/filters/SecurityWrapperResponse.java
@@ -6,7 +6,7 @@
  * www.owasp.org/index.php/ESAPI</a>. Copyright (c) 2007 - The OWASP Foundation
  * The ESAPI is published by OWASP under the BSD license. You should read and
  * accept the LICENSE before you use, modify, and/or redistribute this software.
- * 
+ *
  * @author Jeff Williams <a href="http://www.aspectsecurity.com">Aspect
  *         Security</a>
  * @created 2007
@@ -45,7 +45,7 @@ public class SecurityWrapperResponse extends HttpServletResponseWrapper implemen
     /**
      * Construct a safe response that overrides the default response methods
      * with safer versions. Default is 'log' mode.
-     * 
+     *
      * @param response
      */
     public SecurityWrapperResponse(HttpServletResponse response) {
@@ -54,8 +54,8 @@ public class SecurityWrapperResponse extends HttpServletResponseWrapper implemen
 
     /**
      * Construct a safe response that overrides the default response methods
-     * with safer versions. 
-     * 
+     * with safer versions.
+     *
      * @param response
      * @param mode The mode for this wrapper. Legal modes are "log", "skip", "sanitize", "throw".
      */
@@ -149,7 +149,7 @@ public class SecurityWrapperResponse extends HttpServletResponseWrapper implemen
     /**
      * Add a cookie to the response after ensuring that there are no encoded or
      * illegal characters in the name.
-     * @param name 
+     * @param name
      * @param date
      */
     public void addDateHeader(String name, long date) {
@@ -183,25 +183,25 @@ public class SecurityWrapperResponse extends HttpServletResponseWrapper implemen
         } catch (ValidationException e) {
             logger.warning(Logger.SECURITY_FAILURE, "Attempt to add invalid header NAME denied: HTTPHeaderName:"+ name, e);
         }
-        
+
         try {
             safeValue = ESAPI.validator().getValidInput("addHeader", strippedValue, "HTTPHeaderValue", sc.getIntProp("HttpUtilities.MaxHeaderValueSize"), false);
         } catch (ValidationException e) {
             logger.warning(Logger.SECURITY_FAILURE, "Attempt to add invalid header VALUE denied: HTTPHeaderName:"+ name, e);
         }
-        
+
         boolean validName = StringUtilities.notNullOrEmpty(safeName, true);
         boolean validValue = StringUtilities.notNullOrEmpty(safeValue, true);
-        
+
         if (validName && validValue) {
             getHttpServletResponse().addHeader(safeName, safeValue);
         }
     }
-    
+
     /**
-     * Add a referer header to the response, after validating there are no illegal characters according to the 
-     * Validator.isValidURI() method, as well as ensuring there are no instances of mixed or double encoding 
-     * depending on how you have configured ESAPI defaults.  
+     * Add a referer header to the response, after validating there are no illegal characters according to the
+     * Validator.isValidURI() method, as well as ensuring there are no instances of mixed or double encoding
+     * depending on how you have configured ESAPI defaults.
      * @param uri
      */
     public void addReferer( String uri) {
@@ -213,14 +213,14 @@ public class SecurityWrapperResponse extends HttpServletResponseWrapper implemen
         if(isValidURI) {
             safeValue = strippedValue;
         }
-        
+
         getHttpServletResponse().addHeader("referer", safeValue);
     }
 
     /**
      * Add an int header to the response after ensuring that there are no
      * encoded or illegal characters in the name and value. git
-     * @param name 
+     * @param name
      * @param value
      */
     public void addIntHeader(String name, int value) {
@@ -248,7 +248,7 @@ public class SecurityWrapperResponse extends HttpServletResponseWrapper implemen
      * Session ID to the URL if support for cookies is not detected. This
      * exposes the Session ID credential in bookmarks, referer headers, server
      * logs, and more.
-     * 
+     *
      * @param url
      * @return original url
      * @deprecated in servlet spec 2.1. Use
@@ -265,7 +265,7 @@ public class SecurityWrapperResponse extends HttpServletResponseWrapper implemen
      * Session ID to the URL if support for cookies is not detected. This
      * exposes the Session ID credential in bookmarks, referer headers, server
      * logs, and more.
-     * 
+     *
      * @param url
      * @return original url
      */
@@ -279,7 +279,7 @@ public class SecurityWrapperResponse extends HttpServletResponseWrapper implemen
      * Session ID to the URL if support for cookies is not detected. This
      * exposes the Session ID credential in bookmarks, referer headers, server
      * logs, and more.
-     * 
+     *
      * @param url
      * @return original url
      * @deprecated in servlet spec 2.1. Use
@@ -296,7 +296,7 @@ public class SecurityWrapperResponse extends HttpServletResponseWrapper implemen
      * Session ID to the URL if support for cookies is not detected. This
      * exposes the Session ID credential in bookmarks, referer headers, server
      * logs, and more.
-     * 
+     *
      * @param url
      * @return original url
      */
@@ -387,7 +387,7 @@ public class SecurityWrapperResponse extends HttpServletResponseWrapper implemen
     /**
      * Override the error code with a 200 in order to confound attackers using
      * automated scanners.  Overwriting is controlled by {@code HttpUtilities.OverwriteStatusCodes}
-     * in ESAPI.properties. 
+     * in ESAPI.properties.
      * @param sc -- http status code
      * @throws IOException
      */
@@ -404,7 +404,7 @@ public class SecurityWrapperResponse extends HttpServletResponseWrapper implemen
      * Override the error code with a 200 in order to confound attackers using
      * automated scanners. The message is canonicalized and filtered for
      * dangerous characters.  Overwriting is controlled by {@code HttpUtilities.OverwriteStatusCodes}
-     * in ESAPI.properties.  
+     * in ESAPI.properties.
      * @param sc -- http status code
      * @param msg -- error message
      * @throws IOException
@@ -425,7 +425,7 @@ public class SecurityWrapperResponse extends HttpServletResponseWrapper implemen
      * be modified by attackers, so do not rely information contained within
      * redirect requests, and do not include sensitive information in a
      * redirect.
-     * @param location 
+     * @param location
      * @throws IOException
      */
     public void sendRedirect(String location) throws IOException {
@@ -472,7 +472,7 @@ public class SecurityWrapperResponse extends HttpServletResponseWrapper implemen
     /**
      * Add a date header to the response after ensuring that there are no
      * encoded or illegal characters in the name.
-     * @param name 
+     * @param name
      * @param date
      */
     public void setDateHeader(String name, long date) {
@@ -491,7 +491,7 @@ public class SecurityWrapperResponse extends HttpServletResponseWrapper implemen
      * linear white space with a single SP before interpreting the field value
      * or forwarding the message downstream."
      * http://www.w3.org/Protocols/rfc2616/rfc2616-sec2.html#sec2.2
-     * @param name 
+     * @param name
      * @param value
      */
     public void setHeader(String name, String value) {
@@ -505,16 +505,16 @@ public class SecurityWrapperResponse extends HttpServletResponseWrapper implemen
         } catch (ValidationException e) {
             logger.warning(Logger.SECURITY_FAILURE, "Attempt to set invalid header NAME denied: HTTPHeaderName:"+ name, e);
         }
-        
+
         try {
             safeValue = ESAPI.validator().getValidInput("setHeader", strippedValue, "HTTPHeaderValue", sc.getIntProp("HttpUtilities.MaxHeaderValueSize"), false);
         } catch (ValidationException e) {
             logger.warning(Logger.SECURITY_FAILURE, "Attempt to set invalid header VALUE denied: HTTPHeaderName:"+ name, e);
         }
-        
+
         boolean validName = StringUtilities.notNullOrEmpty(safeName, true);
         boolean validValue = StringUtilities.notNullOrEmpty(safeValue, true);
-        
+
         if (validName && validValue) {
             getHttpServletResponse().setHeader(safeName, safeValue);
         }
@@ -523,7 +523,7 @@ public class SecurityWrapperResponse extends HttpServletResponseWrapper implemen
     /**
      * Add an int header to the response after ensuring that there are no
      * encoded or illegal characters in the name.
-     * @param name 
+     * @param name
      * @param value
      */
     public void setIntHeader(String name, int value) {
@@ -557,14 +557,14 @@ public class SecurityWrapperResponse extends HttpServletResponseWrapper implemen
         }else{
             getHttpServletResponse().setStatus(sc);
         }
-        
+
     }
 
     /**
      * Override the status code with a 200 in order to confound attackers using
      * automated scanners. The message is canonicalized and filtered for
      * dangerous characters.
-     * @param sc 
+     * @param sc
      * @param sm
      * @deprecated In Servlet spec 2.1.
      */
diff --git a/src/main/java/org/owasp/esapi/logging/appender/ClientInfoSupplier.java b/src/main/java/org/owasp/esapi/logging/appender/ClientInfoSupplier.java
index 5a85243..cfb8bea 100644
--- a/src/main/java/org/owasp/esapi/logging/appender/ClientInfoSupplier.java
+++ b/src/main/java/org/owasp/esapi/logging/appender/ClientInfoSupplier.java
@@ -1,15 +1,15 @@
 /**
  * OWASP Enterprise Security API (ESAPI)
- * 
+ *
  * This file is part of the Open Web Application Security Project (OWASP)
  * Enterprise Security API (ESAPI) project. For details, please see
  * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
  *
  * Copyright (c) 2007 - The OWASP Foundation
- * 
+ *
  * The ESAPI is published by OWASP under the BSD license. You should read and accept the
  * LICENSE before you use, modify, and/or redistribute this software.
- * 
+ *
  * @created 2019
  */
 
@@ -83,7 +83,7 @@ public class ClientInfoSupplier // implements Supplier<String>
 
     /**
      * Specify whether the instance should record the client info.
-     * 
+     *
      * @param log {@code true} to record
      */
     public void setLogClientInfo(boolean log) {
diff --git a/src/main/java/org/owasp/esapi/logging/appender/EventTypeLogSupplier.java b/src/main/java/org/owasp/esapi/logging/appender/EventTypeLogSupplier.java
index 4af1bd5..681839a 100644
--- a/src/main/java/org/owasp/esapi/logging/appender/EventTypeLogSupplier.java
+++ b/src/main/java/org/owasp/esapi/logging/appender/EventTypeLogSupplier.java
@@ -1,15 +1,15 @@
 /**
  * OWASP Enterprise Security API (ESAPI)
- * 
+ *
  * This file is part of the Open Web Application Security Project (OWASP)
  * Enterprise Security API (ESAPI) project. For details, please see
  * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
  *
  * Copyright (c) 2007 - The OWASP Foundation
- * 
+ *
  * The ESAPI is published by OWASP under the BSD license. You should read and accept the
  * LICENSE before you use, modify, and/or redistribute this software.
- * 
+ *
  * @created 2019
  */
 
@@ -33,7 +33,7 @@ public class EventTypeLogSupplier // implements Supplier<String>
 
     /**
      * Ctr
-     * 
+     *
      * @param evtyp EventType reference to supply log representation for
      */
     public EventTypeLogSupplier(EventType evtyp) {
diff --git a/src/main/java/org/owasp/esapi/logging/appender/LogAppender.java b/src/main/java/org/owasp/esapi/logging/appender/LogAppender.java
index b3aba05..b764a7a 100644
--- a/src/main/java/org/owasp/esapi/logging/appender/LogAppender.java
+++ b/src/main/java/org/owasp/esapi/logging/appender/LogAppender.java
@@ -1,15 +1,15 @@
 /**
  * OWASP Enterprise Security API (ESAPI)
- * 
+ *
  * This file is part of the Open Web Application Security Project (OWASP)
  * Enterprise Security API (ESAPI) project. For details, please see
  * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
  *
  * Copyright (c) 2007 - The OWASP Foundation
- * 
+ *
  * The ESAPI is published by OWASP under the BSD license. You should read and accept the
  * LICENSE before you use, modify, and/or redistribute this software.
- * 
+ *
  * @created 2019
  */
 
diff --git a/src/main/java/org/owasp/esapi/logging/appender/LogPrefixAppender.java b/src/main/java/org/owasp/esapi/logging/appender/LogPrefixAppender.java
index 9beb1a9..20f692e 100644
--- a/src/main/java/org/owasp/esapi/logging/appender/LogPrefixAppender.java
+++ b/src/main/java/org/owasp/esapi/logging/appender/LogPrefixAppender.java
@@ -1,15 +1,15 @@
 /**
  * OWASP Enterprise Security API (ESAPI)
- * 
+ *
  * This file is part of the Open Web Application Security Project (OWASP)
  * Enterprise Security API (ESAPI) project. For details, please see
  * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
  *
  * Copyright (c) 2007 - The OWASP Foundation
- * 
+ *
  * The ESAPI is published by OWASP under the BSD license. You should read and accept the
  * LICENSE before you use, modify, and/or redistribute this software.
- * 
+ *
  * @created 2019
  */
 
@@ -38,7 +38,7 @@ public class LogPrefixAppender implements LogAppender {
 
     /**
      * Ctr.
-     * 
+     *
      * @param logUserInfo      Whether or not to record user information
      * @param logClientInfo      Whether or not to record client information
      * @param logServerIp        Whether or not to record server ip information
@@ -59,10 +59,10 @@ public class LogPrefixAppender implements LogAppender {
 
         UserInfoSupplier userInfoSupplier = new UserInfoSupplier();
         userInfoSupplier.setLogUserInfo(logUserInfo);
-        
+
         ClientInfoSupplier clientInfoSupplier = new ClientInfoSupplier();
         clientInfoSupplier.setLogClientInfo(logClientInfo);
-        
+
         ServerInfoSupplier serverInfoSupplier = new ServerInfoSupplier(logName);
         serverInfoSupplier.setLogServerIp(logServerIp);
         serverInfoSupplier.setLogApplicationName(logApplicationName, appName);
@@ -71,10 +71,10 @@ public class LogPrefixAppender implements LogAppender {
         String userInfoMsg = userInfoSupplier.get().trim();
         String clientInfoMsg = clientInfoSupplier.get().trim();
         String serverInfoMsg = serverInfoSupplier.get().trim();
-        
+
         //If both user and client have content, then postfix the semicolon to the userInfoMsg at this point to simplify the StringBuilder operations later.
         userInfoMsg = (!userInfoMsg.isEmpty() && !clientInfoMsg.isEmpty()) ? userInfoMsg + ":" : userInfoMsg;
-      
+
         //If both server has content, then prefix the arrow to the serverInfoMsg at this point to simplify the StringBuilder operations later.
         serverInfoMsg = (!serverInfoMsg.isEmpty()) ? "-> " + serverInfoMsg: serverInfoMsg;
 
@@ -83,14 +83,14 @@ public class LogPrefixAppender implements LogAppender {
         StringBuilder logPrefix = new StringBuilder();
         //EventType is always appended
         logPrefix.append(eventTypeMsg);
-        
+
         for (String element : optionalPrefixContent) {
             if (!element.isEmpty()) {
                 logPrefix.append(" ");
                 logPrefix.append(element);
             }
         }
-      
+
         return String.format(RESULT_FORMAT, logPrefix.toString(), message);
     }
 }
diff --git a/src/main/java/org/owasp/esapi/logging/appender/ServerInfoSupplier.java b/src/main/java/org/owasp/esapi/logging/appender/ServerInfoSupplier.java
index c9e0d8e..8fbef3e 100644
--- a/src/main/java/org/owasp/esapi/logging/appender/ServerInfoSupplier.java
+++ b/src/main/java/org/owasp/esapi/logging/appender/ServerInfoSupplier.java
@@ -1,15 +1,15 @@
 /**
  * OWASP Enterprise Security API (ESAPI)
- * 
+ *
  * This file is part of the Open Web Application Security Project (OWASP)
  * Enterprise Security API (ESAPI) project. For details, please see
  * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
  *
  * Copyright (c) 2007 - The OWASP Foundation
- * 
+ *
  * The ESAPI is published by OWASP under the BSD license. You should read and accept the
  * LICENSE before you use, modify, and/or redistribute this software.
- * 
+ *
  * @created 2019
  */
 
@@ -40,7 +40,7 @@ public class ServerInfoSupplier     // implements Supplier<String>
 
     /**
      * Ctr.
-     * 
+     *
      * @param logName Reference to the logName to record as the module information
      */
     public ServerInfoSupplier(String logName) {
@@ -65,7 +65,7 @@ public class ServerInfoSupplier     // implements Supplier<String>
 
     /**
      * Specify whether the instance should record the server connection info.
-     * 
+     *
      * @param log {@code true} to record
      */
     public void setLogServerIp(boolean log) {
@@ -74,7 +74,7 @@ public class ServerInfoSupplier     // implements Supplier<String>
 
     /**
      * Specify whether the instance should record the application name
-     * 
+     *
      * @param log     {@code true} to record
      * @param appName String to record as the application name
      */
diff --git a/src/main/java/org/owasp/esapi/logging/appender/UserInfoSupplier.java b/src/main/java/org/owasp/esapi/logging/appender/UserInfoSupplier.java
index 6065ed3..445be3d 100644
--- a/src/main/java/org/owasp/esapi/logging/appender/UserInfoSupplier.java
+++ b/src/main/java/org/owasp/esapi/logging/appender/UserInfoSupplier.java
@@ -1,15 +1,15 @@
 /**
  * OWASP Enterprise Security API (ESAPI)
- * 
+ *
  * This file is part of the Open Web Application Security Project (OWASP)
  * Enterprise Security API (ESAPI) project. For details, please see
  * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
  *
  * Copyright (c) 2007 - The OWASP Foundation
- * 
+ *
  * The ESAPI is published by OWASP under the BSD license. You should read and accept the
  * LICENSE before you use, modify, and/or redistribute this software.
- * 
+ *
  * @created 2019
  */
 
@@ -29,30 +29,30 @@ public class UserInfoSupplier   // implements Supplier<String>
 {
     /** Default UserName string if the Authenticated user is null.*/
     private static final String DEFAULT_USERNAME = "#ANONYMOUS#";
-    
+
     /** Whether to log the user info from this instance. */
     private boolean logUserInfo = true;
-    
+
     // @Override    -- Uncomment when we switch to Java 8 as minimal baseline.
     public String get() {
         // log user information - username:session@ipaddr
         User user = ESAPI.authenticator().getCurrentUser();
-        
+
         String userInfo = "";
         if (logUserInfo) {
             if (user == null) {
                 userInfo = DEFAULT_USERNAME;
             } else {
-                userInfo = user.getAccountName();            
+                userInfo = user.getAccountName();
             }
-        } 
-        
+        }
+
         return userInfo;
     }
 
     /**
      * Specify whether the instance should record the client info.
-     * 
+     *
      * @param log {@code true} to record
      */
     public void setLogUserInfo(boolean log) {
diff --git a/src/main/java/org/owasp/esapi/logging/cleaning/CodecLogScrubber.java b/src/main/java/org/owasp/esapi/logging/cleaning/CodecLogScrubber.java
index 257ba14..4ce14ba 100644
--- a/src/main/java/org/owasp/esapi/logging/cleaning/CodecLogScrubber.java
+++ b/src/main/java/org/owasp/esapi/logging/cleaning/CodecLogScrubber.java
@@ -1,15 +1,15 @@
 /**
  * OWASP Enterprise Security API (ESAPI)
- * 
+ *
  * This file is part of the Open Web Application Security Project (OWASP)
  * Enterprise Security API (ESAPI) project. For details, please see
  * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
  *
  * Copyright (c) 2007 - The OWASP Foundation
- * 
+ *
  * The ESAPI is published by OWASP under the BSD license. You should read and accept the
  * LICENSE before you use, modify, and/or redistribute this software.
- * 
+ *
  * @created 2018
  */
 package org.owasp.esapi.logging.cleaning;
@@ -31,7 +31,7 @@ public class CodecLogScrubber implements LogScrubber {
 
     /**
      * Ctr.
-     * 
+     *
      * @param messageCodec
      *            Delegate codec. Cannot be {@code null}
      * @param immuneChars
diff --git a/src/main/java/org/owasp/esapi/logging/cleaning/CompositeLogScrubber.java b/src/main/java/org/owasp/esapi/logging/cleaning/CompositeLogScrubber.java
index 79ad7d4..1638ca5 100644
--- a/src/main/java/org/owasp/esapi/logging/cleaning/CompositeLogScrubber.java
+++ b/src/main/java/org/owasp/esapi/logging/cleaning/CompositeLogScrubber.java
@@ -1,15 +1,15 @@
 /**
  * OWASP Enterprise Security API (ESAPI)
- * 
+ *
  * This file is part of the Open Web Application Security Project (OWASP)
  * Enterprise Security API (ESAPI) project. For details, please see
  * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
  *
  * Copyright (c) 2007 - The OWASP Foundation
- * 
+ *
  * The ESAPI is published by OWASP under the BSD license. You should read and accept the
  * LICENSE before you use, modify, and/or redistribute this software.
- * 
+ *
  * @created 2018
  */
 package org.owasp.esapi.logging.cleaning;
@@ -31,7 +31,7 @@ public class CompositeLogScrubber implements LogScrubber {
 
     /**
      * Ctr.
-     * 
+     *
      * @param orderedCleaner
      *            Ordered List of delegate implementations. Cannot be {@code null}
      */
diff --git a/src/main/java/org/owasp/esapi/logging/cleaning/LogScrubber.java b/src/main/java/org/owasp/esapi/logging/cleaning/LogScrubber.java
index 4e833cd..fd8a54a 100644
--- a/src/main/java/org/owasp/esapi/logging/cleaning/LogScrubber.java
+++ b/src/main/java/org/owasp/esapi/logging/cleaning/LogScrubber.java
@@ -1,15 +1,15 @@
 /**
  * OWASP Enterprise Security API (ESAPI)
- * 
+ *
  * This file is part of the Open Web Application Security Project (OWASP)
  * Enterprise Security API (ESAPI) project. For details, please see
  * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
  *
  * Copyright (c) 2007 - The OWASP Foundation
- * 
+ *
  * The ESAPI is published by OWASP under the BSD license. You should read and accept the
  * LICENSE before you use, modify, and/or redistribute this software.
- * 
+ *
  * @created 2018
  */
 
@@ -24,7 +24,7 @@ public interface LogScrubber {
     /**
      * Updates the given message to account for restrictions for this implementation
      * and returns the result.
-     * 
+     *
      * @param message
      *            Original message to clean.
      * @return Cleaned message.
diff --git a/src/main/java/org/owasp/esapi/logging/cleaning/NewlineLogScrubber.java b/src/main/java/org/owasp/esapi/logging/cleaning/NewlineLogScrubber.java
index 5ba267a..0258968 100644
--- a/src/main/java/org/owasp/esapi/logging/cleaning/NewlineLogScrubber.java
+++ b/src/main/java/org/owasp/esapi/logging/cleaning/NewlineLogScrubber.java
@@ -1,15 +1,15 @@
 /**
  * OWASP Enterprise Security API (ESAPI)
- * 
+ *
  * This file is part of the Open Web Application Security Project (OWASP)
  * Enterprise Security API (ESAPI) project. For details, please see
  * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
  *
  * Copyright (c) 2007 - The OWASP Foundation
- * 
+ *
  * The ESAPI is published by OWASP under the BSD license. You should read and accept the
  * LICENSE before you use, modify, and/or redistribute this software.
- * 
+ *
  * @created 2018
  */
 package org.owasp.esapi.logging.cleaning;
diff --git a/src/main/java/org/owasp/esapi/logging/java/ESAPICustomJavaLevel.java b/src/main/java/org/owasp/esapi/logging/java/ESAPICustomJavaLevel.java
index 1480829..36a005e 100644
--- a/src/main/java/org/owasp/esapi/logging/java/ESAPICustomJavaLevel.java
+++ b/src/main/java/org/owasp/esapi/logging/java/ESAPICustomJavaLevel.java
@@ -1,15 +1,15 @@
 /**
  * OWASP Enterprise Security API (ESAPI)
- * 
+ *
  * This file is part of the Open Web Application Security Project (OWASP)
  * Enterprise Security API (ESAPI) project. For details, please see
  * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
  *
  * Copyright (c) 2007 - The OWASP Foundation
- * 
+ *
  * The ESAPI is published by OWASP under the BSD license. You should read and accept the
  * LICENSE before you use, modify, and/or redistribute this software.
- * 
+ *
  * @created 2019
  */
 
@@ -34,11 +34,11 @@ public class ESAPICustomJavaLevel extends Level {
      * Defines a custom level that should result in content always being recorded, unless the Java Logging configuration is set to OFF.
      */
     public static final Level ALWAYS_LEVEL = new ESAPICustomJavaLevel( "ALWAYS", Level.OFF.intValue() - 1);
-    
+
     /**
      * Constructs an instance of a JavaLoggerLevel which essentially provides a mapping between the name of
      * the defined level and its numeric value.
-     * 
+     *
      * @param name The name of the JavaLoggerLevel
      * @param value The associated numeric value
      */
diff --git a/src/main/java/org/owasp/esapi/logging/java/ESAPIErrorJavaLevel.java b/src/main/java/org/owasp/esapi/logging/java/ESAPIErrorJavaLevel.java
index 9a2b98a..f8288c3 100644
--- a/src/main/java/org/owasp/esapi/logging/java/ESAPIErrorJavaLevel.java
+++ b/src/main/java/org/owasp/esapi/logging/java/ESAPIErrorJavaLevel.java
@@ -1,15 +1,15 @@
 /**
  * OWASP Enterprise Security API (ESAPI)
- * 
+ *
  * This file is part of the Open Web Application Security Project (OWASP)
  * Enterprise Security API (ESAPI) project. For details, please see
  * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
  *
  * Copyright (c) 2007 - The OWASP Foundation
- * 
+ *
  * The ESAPI is published by OWASP under the BSD license. You should read and accept the
  * LICENSE before you use, modify, and/or redistribute this software.
- * 
+ *
  * @created 2019
  */
 
@@ -39,7 +39,7 @@ public class ESAPIErrorJavaLevel extends Level {
     /**
      * Constructs an instance of a JavaLoggerLevel which essentially provides a mapping between the name of
      * the defined level and its numeric value.
-     * 
+     *
      * @param name The name of the JavaLoggerLevel
      * @param value The associated numeric value
      */
diff --git a/src/main/java/org/owasp/esapi/logging/java/JavaLogBridge.java b/src/main/java/org/owasp/esapi/logging/java/JavaLogBridge.java
index c085766..078afdf 100644
--- a/src/main/java/org/owasp/esapi/logging/java/JavaLogBridge.java
+++ b/src/main/java/org/owasp/esapi/logging/java/JavaLogBridge.java
@@ -1,15 +1,15 @@
 /**
  * OWASP Enterprise Security API (ESAPI)
- * 
+ *
  * This file is part of the Open Web Application Security Project (OWASP)
  * Enterprise Security API (ESAPI) project. For details, please see
  * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
  *
  * Copyright (c) 2007 - The OWASP Foundation
- * 
+ *
  * The ESAPI is published by OWASP under the BSD license. You should read and accept the
  * LICENSE before you use, modify, and/or redistribute this software.
- * 
+ *
  * @created 2019
  */
 package org.owasp.esapi.logging.java;
@@ -20,7 +20,7 @@ import org.owasp.esapi.Logger.EventType;
 
 /**
  * Contract for translating an ESAPI log event into an Java log event.
- * 
+ *
  */
 public interface JavaLogBridge {
     /**
diff --git a/src/main/java/org/owasp/esapi/logging/java/JavaLogBridgeImpl.java b/src/main/java/org/owasp/esapi/logging/java/JavaLogBridgeImpl.java
index df599ea..042a562 100644
--- a/src/main/java/org/owasp/esapi/logging/java/JavaLogBridgeImpl.java
+++ b/src/main/java/org/owasp/esapi/logging/java/JavaLogBridgeImpl.java
@@ -1,15 +1,15 @@
 /**
  * OWASP Enterprise Security API (ESAPI)
- * 
+ *
  * This file is part of the Open Web Application Security Project (OWASP)
  * Enterprise Security API (ESAPI) project. For details, please see
  * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
  *
  * Copyright (c) 2007 - The OWASP Foundation
- * 
+ *
  * The ESAPI is published by OWASP under the BSD license. You should read and accept the
  * LICENSE before you use, modify, and/or redistribute this software.
- * 
+ *
  * @created 2019
  */
 
diff --git a/src/main/java/org/owasp/esapi/logging/java/JavaLogFactory.java b/src/main/java/org/owasp/esapi/logging/java/JavaLogFactory.java
index 3a43c2c..a45eb2a 100644
--- a/src/main/java/org/owasp/esapi/logging/java/JavaLogFactory.java
+++ b/src/main/java/org/owasp/esapi/logging/java/JavaLogFactory.java
@@ -1,15 +1,15 @@
 /**
  * OWASP Enterprise Security API (ESAPI)
- * 
+ *
  * This file is part of the Open Web Application Security Project (OWASP)
  * Enterprise Security API (ESAPI) project. For details, please see
  * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
  *
  * Copyright (c) 2007 - The OWASP Foundation
- * 
+ *
  * The ESAPI is published by OWASP under the BSD license. You should read and accept the
  * LICENSE before you use, modify, and/or redistribute this software.
- * 
+ *
  * @created 2019
  */
 package org.owasp.esapi.logging.java;
@@ -25,6 +25,7 @@ import java.util.logging.LogManager;
 import org.owasp.esapi.ESAPI;
 import org.owasp.esapi.LogFactory;
 import org.owasp.esapi.Logger;
+import org.owasp.esapi.PropNames;
 import org.owasp.esapi.codecs.HTMLEntityCodec;
 import org.owasp.esapi.errors.ConfigurationException;
 import org.owasp.esapi.logging.appender.LogAppender;
@@ -33,13 +34,27 @@ import org.owasp.esapi.logging.cleaning.CodecLogScrubber;
 import org.owasp.esapi.logging.cleaning.CompositeLogScrubber;
 import org.owasp.esapi.logging.cleaning.LogScrubber;
 import org.owasp.esapi.logging.cleaning.NewlineLogScrubber;
-import org.owasp.esapi.reference.DefaultSecurityConfiguration;
+
+import static org.owasp.esapi.PropNames.LOG_ENCODING_REQUIRED;
+import static org.owasp.esapi.PropNames.LOG_USER_INFO;
+import static org.owasp.esapi.PropNames.LOG_CLIENT_INFO;
+import static org.owasp.esapi.PropNames.LOG_APPLICATION_NAME;
+import static org.owasp.esapi.PropNames.APPLICATION_NAME;
+import static org.owasp.esapi.PropNames.LOG_SERVER_IP;
+
 /**
  * LogFactory implementation which creates JAVA supporting Loggers.
+ * <br><br>
+ * Options for customizing this configuration (in recommended order)
+ * <ol>
+ * <li>Consider using the <i>SLF4JLogFactory</i> with a java-logging implementation.</li>
+ * <li>Configure the runtime startup command to set the desired system properties for the <i>java.util.logging.LogManager</i> instance.  EG: <code>-Djava.util.logging.config.file=/custom/file/path.properties</code></li>
+ * <li>Overwrite the esapi-java-logging.properties file with the desired logging configurations. <br>A default file implementation is available in the configuration jar on GitHub under the 'Releases'</li>
+ * <li>Apply custom-code solution to set the system properties for the <i>java.util.logging.LogManager</i> at runtime. EG: <code>System.setProperty("java.util.logging.config.file", "/custom/file/path.properties");</code></li>
+ * <li>Create a custom JavaLogFactory class in client project baseline and update the ESAPI.properties configuration to use that reference.</li>
+ * </ol>
  * 
- * This implementation requires that a file named 'esapi-java-logging.properties' exists on the classpath.
- * <br>
- * A default file implementation is available in the configuration jar on GitHub under the 'Releases'
+ * @see <a href="https://github.com/ESAPI/esapi-java-legacy/wiki/Configuration-Reference:-JavaLogFactory">ESAPI Wiki - Configuration Reference: JavaLogFactory</a>
  *
  */
 public class JavaLogFactory implements LogFactory {
@@ -55,15 +70,15 @@ public class JavaLogFactory implements LogFactory {
     private static JavaLogBridge LOG_BRIDGE;
 
     static {
-        boolean encodeLog = ESAPI.securityConfiguration().getBooleanProp(DefaultSecurityConfiguration.LOG_ENCODING_REQUIRED);
+        boolean encodeLog = ESAPI.securityConfiguration().getBooleanProp(LOG_ENCODING_REQUIRED);
         JAVA_LOG_SCRUBBER = createLogScrubber(encodeLog);
 
 
-        boolean logUserInfo = ESAPI.securityConfiguration().getBooleanProp(DefaultSecurityConfiguration.LOG_USER_INFO);
-        boolean logClientInfo = ESAPI.securityConfiguration().getBooleanProp(DefaultSecurityConfiguration.LOG_CLIENT_INFO);
-        boolean logApplicationName = ESAPI.securityConfiguration().getBooleanProp(DefaultSecurityConfiguration.LOG_APPLICATION_NAME);
-        String appName = ESAPI.securityConfiguration().getStringProp(DefaultSecurityConfiguration.APPLICATION_NAME);
-        boolean logServerIp = ESAPI.securityConfiguration().getBooleanProp(DefaultSecurityConfiguration.LOG_SERVER_IP);
+        boolean logUserInfo = ESAPI.securityConfiguration().getBooleanProp(LOG_USER_INFO);
+        boolean logClientInfo = ESAPI.securityConfiguration().getBooleanProp(LOG_CLIENT_INFO);
+        boolean logApplicationName = ESAPI.securityConfiguration().getBooleanProp(LOG_APPLICATION_NAME);
+        String appName = ESAPI.securityConfiguration().getStringProp(APPLICATION_NAME);
+        boolean logServerIp = ESAPI.securityConfiguration().getBooleanProp(LOG_SERVER_IP);
         JAVA_LOG_APPENDER = createLogAppender(logUserInfo, logClientInfo, logServerIp, logApplicationName, appName);
 
         Map<Integer, JavaLogLevelHandler> levelLookup = new HashMap<>();
@@ -86,6 +101,24 @@ public class JavaLogFactory implements LogFactory {
      * @param logManager LogManager which is being configured.
      */
     /*package*/ static void readLoggerConfiguration(LogManager logManager) {
+        if (System.getProperties().keySet().stream().anyMatch(propKey ->
+        "java.util.logging.config.class".equals(propKey) || "java.util.logging.config.file".equals(propKey))) {
+            // LogManager has external configuration.  Do not load ESAPI defaults.
+            // See javadoc for the LogManager class for more information on properties.
+            boolean isStartupSysoutDisabled = Boolean.valueOf(System.getProperty(PropNames.DISCARD_LOGSPECIAL, Boolean.FALSE.toString()));
+            if (!isStartupSysoutDisabled) {
+                String logManagerPreferredMsg = String.format("[ESAPI-STARTUP] ESAPI JavaLogFactory Configuration will not be applied. "
+                        + "java.util.LogManager configuration Detected. "
+                        + "{\"java.util.logging.config.class\":\"%s\",\"java.util.logging.config.file\":\"%s\"}",
+                        System.getProperty("java.util.logging.config.class"), System.getProperty("java.util.logging.config.file"));
+
+                System.out.println(logManagerPreferredMsg);
+                // ::SAMPLE OUTPUT::
+                //[ESAPI-STARTUP] ESAPI JavaLogFactory Configuration will not be applied.  java.util.LogManager configuration Detected.{"java.util.logging.config.class":"some.defined.value","java.util.logging.config.file":"null"}
+            }
+
+            return;
+        }
         /*
          * This will load the logging properties file to control the format of the output for Java logs.
          */
@@ -96,7 +129,7 @@ public class JavaLogFactory implements LogFactory {
             }
             logManager.readConfiguration(stream);
         } catch (IOException ioe) {
-            throw new ConfigurationException("Failed to load esapi-java-logging.properties.", ioe);        	
+            throw new ConfigurationException("Failed to load esapi-java-logging.properties.", ioe);
         }
     }
 
@@ -119,21 +152,21 @@ public class JavaLogFactory implements LogFactory {
 
     /**
      * Populates the default log appender for use in factory-created loggers.
-     * @param appName 
-     * @param logApplicationName 
-     * @param logServerIp 
-     * @param logClientInfo 
-     * 
+     * @param appName
+     * @param logApplicationName
+     * @param logServerIp
+     * @param logClientInfo
+     *
      * @return LogAppender instance.
      */
     /*package*/ static LogAppender createLogAppender(boolean logUserInfo, boolean logClientInfo, boolean logServerIp, boolean logApplicationName, String appName) {
-        return new LogPrefixAppender(logUserInfo, logClientInfo, logServerIp, logApplicationName, appName);  
+        return new LogPrefixAppender(logUserInfo, logClientInfo, logServerIp, logApplicationName, appName);
     }
 
 
     @Override
     public Logger getLogger(String moduleName) {
-        java.util.logging.Logger javaLogger = java.util.logging.Logger.getLogger(moduleName); 
+        java.util.logging.Logger javaLogger = java.util.logging.Logger.getLogger(moduleName);
         return new JavaLogger(javaLogger, LOG_BRIDGE, Logger.ALL);
     }
 
diff --git a/src/main/java/org/owasp/esapi/logging/java/JavaLogLevelHandler.java b/src/main/java/org/owasp/esapi/logging/java/JavaLogLevelHandler.java
index ee28a1a..ea23745 100644
--- a/src/main/java/org/owasp/esapi/logging/java/JavaLogLevelHandler.java
+++ b/src/main/java/org/owasp/esapi/logging/java/JavaLogLevelHandler.java
@@ -1,15 +1,15 @@
 /**
  * OWASP Enterprise Security API (ESAPI)
- * 
+ *
  * This file is part of the Open Web Application Security Project (OWASP)
  * Enterprise Security API (ESAPI) project. For details, please see
  * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
  *
  * Copyright (c) 2007 - The OWASP Foundation
- * 
+ *
  * The ESAPI is published by OWASP under the BSD license. You should read and accept the
  * LICENSE before you use, modify, and/or redistribute this software.
- * 
+ *
  * @created 2019
  */
 package org.owasp.esapi.logging.java;
@@ -18,7 +18,7 @@ import java.util.logging.Logger;
 
 /**
  * Contract used to isolate translations for each Java Logging Level.
- * 
+ *
  * @see JavaLogLevelHandlers
  * @see JavaLogBridgeImpl
  *
diff --git a/src/main/java/org/owasp/esapi/logging/java/JavaLogLevelHandlers.java b/src/main/java/org/owasp/esapi/logging/java/JavaLogLevelHandlers.java
index cce4986..57a90da 100644
--- a/src/main/java/org/owasp/esapi/logging/java/JavaLogLevelHandlers.java
+++ b/src/main/java/org/owasp/esapi/logging/java/JavaLogLevelHandlers.java
@@ -1,15 +1,15 @@
 /**
  * OWASP Enterprise Security API (ESAPI)
- * 
+ *
  * This file is part of the Open Web Application Security Project (OWASP)
  * Enterprise Security API (ESAPI) project. For details, please see
  * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
  *
  * Copyright (c) 2007 - The OWASP Foundation
- * 
+ *
  * The ESAPI is published by OWASP under the BSD license. You should read and accept the
  * LICENSE before you use, modify, and/or redistribute this software.
- * 
+ *
  * @created 2019
  */
 package org.owasp.esapi.logging.java;
@@ -19,34 +19,34 @@ import java.util.logging.Logger;
 
 public enum JavaLogLevelHandlers implements JavaLogLevelHandler {
 
-	SEVERE(Level.SEVERE),
-	WARNING(Level.WARNING),
-	INFO(Level.INFO),
-	CONFIG(Level.CONFIG),
-	FINE(Level.FINE),
-	FINER(Level.FINER),
-	FINEST(Level.FINEST),
-	ALWAYS(ESAPICustomJavaLevel.ALWAYS_LEVEL),
-	ERROR(ESAPICustomJavaLevel.ERROR_LEVEL);
-
-	private final Level level;
-	
-	private JavaLogLevelHandlers(Level lvl) {
-		this.level = lvl;
-	}
-	
-	@Override
-	public boolean isEnabled(Logger logger) {
-		return logger.isLoggable(level);
-	}
-
-	@Override
-	public void log(Logger logger, String msg) {
-		logger.log(level, msg);
-	}
-
-	@Override
-	public void log(Logger logger, String msg, Throwable th) {
-		logger.log(level, msg, th);
-	}
+    SEVERE(Level.SEVERE),
+    WARNING(Level.WARNING),
+    INFO(Level.INFO),
+    CONFIG(Level.CONFIG),
+    FINE(Level.FINE),
+    FINER(Level.FINER),
+    FINEST(Level.FINEST),
+    ALWAYS(ESAPICustomJavaLevel.ALWAYS_LEVEL),
+    ERROR(ESAPICustomJavaLevel.ERROR_LEVEL);
+
+    private final Level level;
+
+    private JavaLogLevelHandlers(Level lvl) {
+        this.level = lvl;
+    }
+
+    @Override
+    public boolean isEnabled(Logger logger) {
+        return logger.isLoggable(level);
+    }
+
+    @Override
+    public void log(Logger logger, String msg) {
+        logger.log(level, msg);
+    }
+
+    @Override
+    public void log(Logger logger, String msg, Throwable th) {
+        logger.log(level, msg, th);
+    }
 }
diff --git a/src/main/java/org/owasp/esapi/logging/java/JavaLogger.java b/src/main/java/org/owasp/esapi/logging/java/JavaLogger.java
index 6e57c39..1ac4a48 100644
--- a/src/main/java/org/owasp/esapi/logging/java/JavaLogger.java
+++ b/src/main/java/org/owasp/esapi/logging/java/JavaLogger.java
@@ -1,15 +1,15 @@
 /**
  * OWASP Enterprise Security API (ESAPI)
- * 
+ *
  * This file is part of the Open Web Application Security Project (OWASP)
  * Enterprise Security API (ESAPI) project. For details, please see
  * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
  *
  * Copyright (c) 2007 - The OWASP Foundation
- * 
+ *
  * The ESAPI is published by OWASP under the BSD license. You should read and accept the
  * LICENSE before you use, modify, and/or redistribute this software.
- * 
+ *
  * @created 2019
  */
 package org.owasp.esapi.logging.java;
@@ -27,7 +27,7 @@ public class JavaLogger implements org.owasp.esapi.Logger {
     private int loggingLevel;
 
     /**
-     * Constructs a new instance. 
+     * Constructs a new instance.
      * @param JavaLogger Delegate Java logger.
      * @param bridge Translator for ESAPI -> Java logging events.
      * @param defaultEsapiLevel Maximum ESAPI log level events to propagate.
@@ -112,7 +112,7 @@ public class JavaLogger implements org.owasp.esapi.Logger {
 
     @Override
     public void error(EventType type, String message, Throwable throwable) {
-        log (Logger.ERROR, type, message, throwable);   
+        log (Logger.ERROR, type, message, throwable);
     }
 
     @Override
@@ -141,7 +141,7 @@ public class JavaLogger implements org.owasp.esapi.Logger {
     }
     @Override
     public boolean isInfoEnabled() {
-        return isEnabled(Logger.INFO); 
+        return isEnabled(Logger.INFO);
     }
     @Override
     public boolean isWarningEnabled() {
diff --git a/src/main/java/org/owasp/esapi/logging/log4j/Log4JLogBridge.java b/src/main/java/org/owasp/esapi/logging/log4j/Log4JLogBridge.java
deleted file mode 100644
index b89acb8..0000000
--- a/src/main/java/org/owasp/esapi/logging/log4j/Log4JLogBridge.java
+++ /dev/null
@@ -1,43 +0,0 @@
-/**
- * OWASP Enterprise Security API (ESAPI)
- * 
- * This file is part of the Open Web Application Security Project (OWASP)
- * Enterprise Security API (ESAPI) project. For details, please see
- * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
- *
- * Copyright (c) 2007 - The OWASP Foundation
- * 
- * The ESAPI is published by OWASP under the BSD license. You should read and accept the
- * LICENSE before you use, modify, and/or redistribute this software.
- * 
- * @created 2019
- */
-package org.owasp.esapi.logging.log4j;
-
-import org.apache.log4j.Logger;
-import org.owasp.esapi.Logger.EventType;
-/**
- * Contract for translating an ESAPI log event into an Log4J log event.
- * 
- */
-@Deprecated
-public interface Log4JLogBridge {
-    /**
-     * Translation for the provided ESAPI level, type, and message to the specified Log4J Logger.
-     * @param logger Logger to receive the translated message.
-     * @param esapiLevel ESAPI level of event.
-     * @param type ESAPI event type
-     * @param message ESAPI event message content.
-     */
-    void log(Logger logger, int esapiLevel, EventType type, String message) ;
-    /**
-     * Translation for the provided ESAPI level, type, message, and Throwable to the specified Log4J Logger.
-     * @param logger Logger to receive the translated message.
-     * @param esapiLevel ESAPI level of event.
-     * @param type ESAPI event type
-     * @param message ESAPI event message content.
-     * @param throwable ESAPI event Throwable content
-     */
-    void log(Logger logger, int esapiLevel, EventType type, String message, Throwable throwable) ;
-
-}
diff --git a/src/main/java/org/owasp/esapi/logging/log4j/Log4JLogBridgeImpl.java b/src/main/java/org/owasp/esapi/logging/log4j/Log4JLogBridgeImpl.java
deleted file mode 100644
index 58be15b..0000000
--- a/src/main/java/org/owasp/esapi/logging/log4j/Log4JLogBridgeImpl.java
+++ /dev/null
@@ -1,76 +0,0 @@
-/**
- * OWASP Enterprise Security API (ESAPI)
- * 
- * This file is part of the Open Web Application Security Project (OWASP)
- * Enterprise Security API (ESAPI) project. For details, please see
- * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
- *
- * Copyright (c) 2007 - The OWASP Foundation
- * 
- * The ESAPI is published by OWASP under the BSD license. You should read and accept the
- * LICENSE before you use, modify, and/or redistribute this software.
- * 
- * @created 2019
- */
-
-package org.owasp.esapi.logging.log4j;
-
-import java.util.HashMap;
-import java.util.Map;
-
-import org.apache.log4j.Logger;
-import org.owasp.esapi.Logger.EventType;
-import org.owasp.esapi.logging.appender.LogAppender;
-import org.owasp.esapi.logging.cleaning.LogScrubber;
-
-/**
- * Implementation which is intended to bridge the ESAPI Logging API into LOG4J supported Object structures.
- *
- */
-@Deprecated
-public class Log4JLogBridgeImpl implements Log4JLogBridge {
-    /** Configuration providing associations between esapi log levels and LOG4J levels.*/
-    private final Map<Integer,Log4JLogLevelHandler> esapiSlfLevelMap;
-    /** Cleaner used for log content.*/
-    private final LogScrubber scrubber;
-    /** Appender used for assembling default message content for all logs.*/
-    private final LogAppender appender;
-
-    /**
-     * Constructor.
-     * @param logScrubber  Log message cleaner.
-     * @param esapiSlfHandlerMap Map identifying ESAPI -> LOG4J log level associations.
-     */
-    public Log4JLogBridgeImpl(LogAppender messageAppender, LogScrubber logScrubber, Map<Integer, Log4JLogLevelHandler> esapiSlfHandlerMap) {
-        //Defensive copy to prevent external mutations.
-        this.esapiSlfLevelMap = new HashMap<>(esapiSlfHandlerMap);
-        this.scrubber = logScrubber;
-        this.appender = messageAppender;
-    }
-    @Override
-    public void log(Logger logger, int esapiLevel, EventType type, String message) {
-        Log4JLogLevelHandler handler = esapiSlfLevelMap.get(esapiLevel);
-        if (handler == null) {
-            throw new IllegalArgumentException("Unable to lookup LOG4J level mapping for esapi value of " + esapiLevel);
-        }
-        if (handler.isEnabled(logger)) {
-            String fullMessage = appender.appendTo(logger.getName(), type, message);
-            String cleanString = scrubber.cleanMessage(fullMessage);
-
-            handler.log(logger, cleanString);
-        }
-    }
-    @Override
-    public void log(Logger logger, int esapiLevel, EventType type, String message, Throwable throwable) {
-        Log4JLogLevelHandler handler = esapiSlfLevelMap.get(esapiLevel);
-        if (handler == null) {
-            throw new IllegalArgumentException("Unable to lookup LOG4J level mapping for esapi value of " + esapiLevel);
-        }
-        if (handler.isEnabled(logger)) {
-            String fullMessage = appender.appendTo(logger.getName(), type, message);
-            String cleanString = scrubber.cleanMessage(fullMessage);
-
-            handler.log(logger, cleanString, throwable);
-        }
-    }
-}
diff --git a/src/main/java/org/owasp/esapi/logging/log4j/Log4JLogFactory.java b/src/main/java/org/owasp/esapi/logging/log4j/Log4JLogFactory.java
deleted file mode 100644
index 0f31860..0000000
--- a/src/main/java/org/owasp/esapi/logging/log4j/Log4JLogFactory.java
+++ /dev/null
@@ -1,118 +0,0 @@
-/**
- * OWASP Enterprise Security API (ESAPI)
- * 
- * This file is part of the Open Web Application Security Project (OWASP)
- * Enterprise Security API (ESAPI) project. For details, please see
- * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
- *
- * Copyright (c) 2007 - The OWASP Foundation
- * 
- * The ESAPI is published by OWASP under the BSD license. You should read and accept the
- * LICENSE before you use, modify, and/or redistribute this software.
- * 
- * @created 2019
- */
-package org.owasp.esapi.logging.log4j;
-
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-import org.owasp.esapi.ESAPI;
-import org.owasp.esapi.LogFactory;
-import org.owasp.esapi.Logger;
-import org.owasp.esapi.codecs.HTMLEntityCodec;
-import org.owasp.esapi.logging.appender.LogAppender;
-import org.owasp.esapi.logging.appender.LogPrefixAppender;
-import org.owasp.esapi.logging.cleaning.CodecLogScrubber;
-import org.owasp.esapi.logging.cleaning.CompositeLogScrubber;
-import org.owasp.esapi.logging.cleaning.LogScrubber;
-import org.owasp.esapi.logging.cleaning.NewlineLogScrubber;
-import org.owasp.esapi.reference.DefaultSecurityConfiguration;
-/**
- * LogFactory implementation which creates Log4J supporting Loggers.
- *
- */
-@Deprecated
-public class Log4JLogFactory implements LogFactory {
-    /** Immune characters for the codec log scrubber for JAVA context.*/
-    private static final char[] IMMUNE_LOG4J_HTML = {',', '.', '-', '_', ' ' };
-    /** Codec being used to clean messages for logging.*/
-    private static final HTMLEntityCodec HTML_CODEC = new HTMLEntityCodec();
-    /** Log appender instance.*/
-    private static LogAppender Log4J_LOG_APPENDER;
-    /** Log cleaner instance.*/
-    private static LogScrubber Log4J_LOG_SCRUBBER;
-    /** Bridge class for mapping esapi -> log4j log levels.*/
-    private static Log4JLogBridge LOG_BRIDGE;
-
-    static {
-        boolean encodeLog = ESAPI.securityConfiguration().getBooleanProp(DefaultSecurityConfiguration.LOG_ENCODING_REQUIRED);
-        Log4J_LOG_SCRUBBER = createLogScrubber(encodeLog);
-
-        
-        boolean logUserInfo = ESAPI.securityConfiguration().getBooleanProp(DefaultSecurityConfiguration.LOG_USER_INFO);
-        boolean logClientInfo = ESAPI.securityConfiguration().getBooleanProp(DefaultSecurityConfiguration.LOG_CLIENT_INFO);
-        boolean logApplicationName = ESAPI.securityConfiguration().getBooleanProp(DefaultSecurityConfiguration.LOG_APPLICATION_NAME);
-        String appName = ESAPI.securityConfiguration().getStringProp(DefaultSecurityConfiguration.APPLICATION_NAME);
-        boolean logServerIp = ESAPI.securityConfiguration().getBooleanProp(DefaultSecurityConfiguration.LOG_SERVER_IP);
-        Log4J_LOG_APPENDER = createLogAppender(logUserInfo, logClientInfo, logServerIp, logApplicationName, appName);
-
-        Map<Integer, Log4JLogLevelHandler> levelLookup = new HashMap<>();
-        levelLookup.put(Logger.ALL, Log4JLogLevelHandlers.TRACE);
-        levelLookup.put(Logger.TRACE, Log4JLogLevelHandlers.TRACE);
-        levelLookup.put(Logger.DEBUG, Log4JLogLevelHandlers.DEBUG);
-        levelLookup.put(Logger.INFO, Log4JLogLevelHandlers.INFO);
-        levelLookup.put(Logger.ERROR, Log4JLogLevelHandlers.ERROR);
-        levelLookup.put(Logger.WARNING, Log4JLogLevelHandlers.WARN);
-        levelLookup.put(Logger.FATAL, Log4JLogLevelHandlers.FATAL);
-        //LEVEL.OFF not used.  If it's off why would we try to log it?
-
-        LOG_BRIDGE = new Log4JLogBridgeImpl(Log4J_LOG_APPENDER, Log4J_LOG_SCRUBBER, levelLookup);
-    }
-
-    /**
-     * Populates the default log scrubber for use in factory-created loggers.
-     * @param requiresEncoding {@code true} if encoding is required for log content.
-     * @return LogScrubber instance.
-     */
-    /*package*/ static LogScrubber createLogScrubber(boolean requiresEncoding) {
-        List<LogScrubber> messageScrubber = new ArrayList<>();
-        messageScrubber.add(new NewlineLogScrubber());
-
-        if (requiresEncoding) {
-            messageScrubber.add(new CodecLogScrubber(HTML_CODEC, IMMUNE_LOG4J_HTML));
-        }
-
-        return new CompositeLogScrubber(messageScrubber);
-
-    }
-
-    /**
-     * Populates the default log appender for use in factory-created loggers.
-     * @param appName 
-     * @param logApplicationName 
-     * @param logServerIp 
-     * @param logClientInfo 
-     * 
-     * @return LogAppender instance.
-     */
-    /*package*/ static LogAppender createLogAppender(boolean logUserInfo, boolean logClientInfo, boolean logServerIp, boolean logApplicationName, String appName) {
-        return new LogPrefixAppender(logUserInfo, logClientInfo, logServerIp, logApplicationName, appName);       
-    }
-
-
-    @Override
-    public Logger getLogger(String moduleName) {
-        org.apache.log4j.Logger log4JLogger = org.apache.log4j.Logger.getLogger(moduleName);
-        return new Log4JLogger(log4JLogger, LOG_BRIDGE, Logger.ALL);
-    }
-
-    @Override
-    public Logger getLogger(@SuppressWarnings("rawtypes") Class clazz) {
-        org.apache.log4j.Logger log4JLogger = org.apache.log4j.Logger.getLogger(clazz);
-        return new Log4JLogger(log4JLogger, LOG_BRIDGE, Logger.ALL);
-    }
-
-}
diff --git a/src/main/java/org/owasp/esapi/logging/log4j/Log4JLogLevelHandler.java b/src/main/java/org/owasp/esapi/logging/log4j/Log4JLogLevelHandler.java
deleted file mode 100644
index 7b6b57e..0000000
--- a/src/main/java/org/owasp/esapi/logging/log4j/Log4JLogLevelHandler.java
+++ /dev/null
@@ -1,43 +0,0 @@
-/**
- * OWASP Enterprise Security API (ESAPI)
- * 
- * This file is part of the Open Web Application Security Project (OWASP)
- * Enterprise Security API (ESAPI) project. For details, please see
- * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
- *
- * Copyright (c) 2007 - The OWASP Foundation
- * 
- * The ESAPI is published by OWASP under the BSD license. You should read and accept the
- * LICENSE before you use, modify, and/or redistribute this software.
- * 
- * @created 2019
- */
-package org.owasp.esapi.logging.log4j;
-
-import org.apache.log4j.Logger;
-
-/**
- * Contract used to isolate translations for each SLF4J Logging Level.
- * 
- * @see Log4JLogLevelHandlers
- * @see Log4JLogBridgeImpl
- *
- */
-@Deprecated
-interface Log4JLogLevelHandler {
-    /** Check if the logging level is enabled for the specified logger.*/
-    boolean isEnabled(Logger logger);
-    /**
-     * Calls the appropriate log level event on the specified logger.
-     * @param logger Logger to invoke.
-     * @param msg Message to log.
-     */
-    void log(Logger logger, String msg);
-    /**
-     * Calls the appropriate log level event on the specified logger.
-     * @param logger Logger to invoke
-     * @param msg Message to log
-     * @param th Throwable to log.
-     */
-    void log(Logger logger, String msg, Throwable th);
-}
diff --git a/src/main/java/org/owasp/esapi/logging/log4j/Log4JLogLevelHandlers.java b/src/main/java/org/owasp/esapi/logging/log4j/Log4JLogLevelHandlers.java
deleted file mode 100644
index e6ee6a4..0000000
--- a/src/main/java/org/owasp/esapi/logging/log4j/Log4JLogLevelHandlers.java
+++ /dev/null
@@ -1,56 +0,0 @@
-/**
- * OWASP Enterprise Security API (ESAPI)
- * 
- * This file is part of the Open Web Application Security Project (OWASP)
- * Enterprise Security API (ESAPI) project. For details, please see
- * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
- *
- * Copyright (c) 2007 - The OWASP Foundation
- * 
- * The ESAPI is published by OWASP under the BSD license. You should read and accept the
- * LICENSE before you use, modify, and/or redistribute this software.
- * 
- * @created 2019
- */
-
-package org.owasp.esapi.logging.log4j;
-
-
-import org.apache.log4j.Level;
-import org.apache.log4j.Logger;
-
-/**
- * Enumeration capturing the propagation of Log4J level events.
- *
- */
-@Deprecated
-public enum Log4JLogLevelHandlers implements Log4JLogLevelHandler {
-    FATAL(Level.FATAL),
-    ERROR(Level.ERROR),
-    WARN(Level.WARN),
-    INFO(Level.INFO),
-    DEBUG(Level.DEBUG),
-    TRACE(Level.TRACE),
-    ALL(Level.ALL);
-
-    private final Level level;
-
-    private Log4JLogLevelHandlers(Level lvl) {
-        this.level = lvl;
-    }
-
-    @Override
-    public boolean isEnabled(Logger logger) {
-        return logger.isEnabledFor(level);
-    }
-
-    @Override
-    public void log(Logger logger, String msg) {
-        logger.log(level, msg);
-    }
-
-    @Override
-    public void log(Logger logger, String msg, Throwable th) {
-        logger.log(level, msg, th);
-    }    
-}
diff --git a/src/main/java/org/owasp/esapi/logging/log4j/Log4JLogger.java b/src/main/java/org/owasp/esapi/logging/log4j/Log4JLogger.java
deleted file mode 100644
index cbbda21..0000000
--- a/src/main/java/org/owasp/esapi/logging/log4j/Log4JLogger.java
+++ /dev/null
@@ -1,168 +0,0 @@
-/**
- * OWASP Enterprise Security API (ESAPI)
- * 
- * This file is part of the Open Web Application Security Project (OWASP)
- * Enterprise Security API (ESAPI) project. For details, please see
- * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
- *
- * Copyright (c) 2007 - The OWASP Foundation
- * 
- * The ESAPI is published by OWASP under the BSD license. You should read and accept the
- * LICENSE before you use, modify, and/or redistribute this software.
- * 
- * @created 2019
- */
-package org.owasp.esapi.logging.log4j;
-
-import org.owasp.esapi.Logger;
-/**
- * ESAPI Logger implementation which relays events to an Log4j delegate.
- */
-@Deprecated
-public class Log4JLogger implements org.owasp.esapi.Logger {
-    /** Delegate Logger.*/
-    private final org.apache.log4j.Logger delegate;
-    /** Handler for translating events from ESAPI context for SLF4J processing.*/
-    private final Log4JLogBridge logBridge;
-    /** Maximum log level that will be forwarded to SLF4J from the ESAPI context.*/
-    private int loggingLevel;
-
-    /**
-     * Constructs a new instance. 
-     * @param slf4JLogger Delegate SLF4J logger.
-     * @param bridge Translator for ESAPI -> SLF4J logging events.
-     * @param defaultEsapiLevel Maximum ESAPI log level events to propagate.
-     */
-    public Log4JLogger(org.apache.log4j.Logger slf4JLogger, Log4JLogBridge bridge, int defaultEsapiLevel) {
-        delegate = slf4JLogger;
-        this.logBridge = bridge;
-        loggingLevel = defaultEsapiLevel;
-    }
-
-    private void log(int esapiLevel, EventType type, String message) {
-        if (isEnabled(esapiLevel)) {
-            logBridge.log(delegate, esapiLevel, type, message);
-        }
-    }
-
-    private void log(int esapiLevel, EventType type, String message, Throwable throwable) {
-        if (isEnabled(esapiLevel)) {
-            logBridge.log(delegate, esapiLevel, type, message, throwable);
-        }
-    }
-
-
-    private boolean isEnabled(int esapiLevel) {
-        return esapiLevel >= loggingLevel;
-    }
-
-    @Override
-    public void always(EventType type, String message) {
-        log (Logger.ALL, type, message);
-    }
-
-    @Override
-    public void always(EventType type, String message, Throwable throwable) {
-        log (Logger.ALL, type, message, throwable);
-    }
-
-    @Override
-    public void trace(EventType type, String message) {
-        log (Logger.TRACE, type, message);
-    }
-
-    @Override
-    public void trace(EventType type, String message, Throwable throwable) {
-        log (Logger.TRACE, type, message, throwable);
-    }
-
-    @Override
-    public void debug(EventType type, String message) {
-        log (Logger.DEBUG, type, message);
-    }
-
-    @Override
-    public void debug(EventType type, String message, Throwable throwable) {
-        log (Logger.DEBUG, type, message, throwable);
-    }
-
-    @Override
-    public void info(EventType type, String message) {
-        log (Logger.INFO, type, message);
-    }
-
-    @Override
-    public void info(EventType type, String message, Throwable throwable) {
-        log (Logger.INFO, type, message, throwable);
-    }
-
-    @Override
-    public void warning(EventType type, String message) {
-        log (Logger.WARNING, type, message);
-    }
-
-    @Override
-    public void warning(EventType type, String message, Throwable throwable) {
-        log (Logger.WARNING, type, message, throwable);
-    }
-
-    @Override
-    public void error(EventType type, String message) {
-        log (Logger.ERROR, type, message);
-    }
-
-    @Override
-    public void error(EventType type, String message, Throwable throwable) {
-        log (Logger.ERROR, type, message, throwable);   
-    }
-
-    @Override
-    public void fatal(EventType type, String message) {
-        log (Logger.FATAL, type, message);
-    }
-
-    @Override
-    public void fatal(EventType type, String message, Throwable throwable) {
-        log (Logger.FATAL, type, message, throwable);
-    }
-
-    @Override
-    public int getESAPILevel() {
-        return loggingLevel;
-    }
-
-    @Override
-    public boolean isTraceEnabled() {
-        return isEnabled(Logger.TRACE);
-    }
-
-    @Override
-    public boolean isDebugEnabled() {
-        return isEnabled(Logger.DEBUG);
-    }
-    @Override
-    public boolean isInfoEnabled() {
-        return isEnabled(Logger.INFO); 
-    }
-    @Override
-    public boolean isWarningEnabled() {
-        return isEnabled(Logger.WARNING);
-    }
-
-    @Override
-    public boolean isErrorEnabled() {
-        return isEnabled(Logger.ERROR);
-    }
-
-    @Override
-    public boolean isFatalEnabled() {
-        return isEnabled(Logger.FATAL);
-    }
-
-
-    @Override
-    public void setLevel(int level) {
-        loggingLevel = level;
-    }
-
-}
diff --git a/src/main/java/org/owasp/esapi/logging/log4j/Log4JLoggerFactory.java b/src/main/java/org/owasp/esapi/logging/log4j/Log4JLoggerFactory.java
deleted file mode 100644
index bfa0914..0000000
--- a/src/main/java/org/owasp/esapi/logging/log4j/Log4JLoggerFactory.java
+++ /dev/null
@@ -1,84 +0,0 @@
-/**
- * OWASP Enterprise Security API (ESAPI)
- *
- * This file is part of the Open Web Application Security Project (OWASP)
- * Enterprise Security API (ESAPI) project. For details, please see
- * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
- *
- * Copyright (c) 2007 - The OWASP Foundation
- *
- * The ESAPI is published by OWASP under the BSD license. You should read and accept the
- * LICENSE before you use, modify, and/or redistribute this software.
- *
- * @author Jeff Williams <a href="http://www.aspectsecurity.com">Aspect Security</a>
- * @created 2007
- */
-package org.owasp.esapi.logging.log4j;
-
-import org.apache.log4j.Priority;
-import org.apache.log4j.spi.LoggerFactory;
-import org.owasp.esapi.ESAPI;
-import org.owasp.esapi.logging.appender.LogAppender;
-import org.owasp.esapi.logging.cleaning.LogScrubber;
-import org.owasp.esapi.reference.DefaultSecurityConfiguration;
-
-/**
- * Service Provider Interface implementation that can be provided as the org.apache.log4j.spi.LoggerFactory reference in a Log4J configuration.
- * <br>
- * <code>
- *   &ltloggerFactory class="org.owasp.esapi.logging.log4j.Log4JLoggerFactory"/&gt
- * </code>
- */
-@Deprecated
-public class Log4JLoggerFactory implements LoggerFactory {
-    /** Log appender instance.*/
-    private static LogAppender LOG4J_LOG_APPENDER;
-    /** Log cleaner instance.*/
-    private static LogScrubber LOG4J_LOG_SCRUBBER;
-
-    static {
-        boolean encodeLog = ESAPI.securityConfiguration().getBooleanProp(DefaultSecurityConfiguration.LOG_ENCODING_REQUIRED);
-        LOG4J_LOG_SCRUBBER = Log4JLogFactory.createLogScrubber(encodeLog);
-
-        boolean logUserInfo = ESAPI.securityConfiguration().getBooleanProp(DefaultSecurityConfiguration.LOG_USER_INFO);
-        boolean logClientInfo = ESAPI.securityConfiguration().getBooleanProp(DefaultSecurityConfiguration.LOG_CLIENT_INFO);
-        boolean logApplicationName = ESAPI.securityConfiguration().getBooleanProp(DefaultSecurityConfiguration.LOG_APPLICATION_NAME);
-        String appName = ESAPI.securityConfiguration().getStringProp(DefaultSecurityConfiguration.APPLICATION_NAME);
-        boolean logServerIp = ESAPI.securityConfiguration().getBooleanProp(DefaultSecurityConfiguration.LOG_SERVER_IP);
-        LOG4J_LOG_APPENDER = Log4JLogFactory.createLogAppender(logUserInfo, logClientInfo, logServerIp, logApplicationName, appName);
-    }
-
-    /**
-     * This constructor must be public so it can be accessed from within log4j
-     */
-    public Log4JLoggerFactory() {}
-
-    /**
-     * Overridden to return instances of org.owasp.esapi.reference.Log4JLogger.
-     * 
-     * @param name The class name to return a logger for.
-     * @return org.owasp.esapi.reference.Log4JLogger
-     */
-    public org.apache.log4j.Logger makeNewLoggerInstance(String name) {		
-        return new EsapiLog4JWrapper(name);
-    }
-
-
-    public static class EsapiLog4JWrapper extends org.apache.log4j.Logger {
-
-        protected EsapiLog4JWrapper(String name) {
-            super(name);			
-        }
-
-        @Override
-        protected void forcedLog(String fqcn, Priority level, Object message, Throwable t) {
-            String toClean = message.toString();
-
-            String fullMessage = LOG4J_LOG_APPENDER.appendTo(getName(), null, toClean);
-            String cleanMsg = LOG4J_LOG_SCRUBBER.cleanMessage(fullMessage);
-
-            super.forcedLog(fqcn, level, cleanMsg, t);
-        }
-
-    }
-}
diff --git a/src/main/java/org/owasp/esapi/logging/slf4j/Slf4JLogBridge.java b/src/main/java/org/owasp/esapi/logging/slf4j/Slf4JLogBridge.java
index 5c17ee4..4b73f7a 100644
--- a/src/main/java/org/owasp/esapi/logging/slf4j/Slf4JLogBridge.java
+++ b/src/main/java/org/owasp/esapi/logging/slf4j/Slf4JLogBridge.java
@@ -1,15 +1,15 @@
 /**
  * OWASP Enterprise Security API (ESAPI)
- * 
+ *
  * This file is part of the Open Web Application Security Project (OWASP)
  * Enterprise Security API (ESAPI) project. For details, please see
  * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
  *
  * Copyright (c) 2007 - The OWASP Foundation
- * 
+ *
  * The ESAPI is published by OWASP under the BSD license. You should read and accept the
  * LICENSE before you use, modify, and/or redistribute this software.
- * 
+ *
  * @created 2018
  */
 package org.owasp.esapi.logging.slf4j;
@@ -18,7 +18,7 @@ import org.owasp.esapi.Logger.EventType;
 import org.slf4j.Logger;
 /**
  * Contract for translating an ESAPI log event into an SLF4J log event.
- * 
+ *
  */
 public interface Slf4JLogBridge {
     /**
@@ -38,5 +38,5 @@ public interface Slf4JLogBridge {
      * @param throwable ESAPI event Throwable content
      */
     void log(Logger logger, int esapiLevel, EventType type, String message, Throwable throwable) ;
-      
+
 }
diff --git a/src/main/java/org/owasp/esapi/logging/slf4j/Slf4JLogBridgeImpl.java b/src/main/java/org/owasp/esapi/logging/slf4j/Slf4JLogBridgeImpl.java
index 79e13dc..44c1a76 100644
--- a/src/main/java/org/owasp/esapi/logging/slf4j/Slf4JLogBridgeImpl.java
+++ b/src/main/java/org/owasp/esapi/logging/slf4j/Slf4JLogBridgeImpl.java
@@ -1,15 +1,15 @@
 /**
  * OWASP Enterprise Security API (ESAPI)
- * 
+ *
  * This file is part of the Open Web Application Security Project (OWASP)
  * Enterprise Security API (ESAPI) project. For details, please see
  * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
  *
  * Copyright (c) 2007 - The OWASP Foundation
- * 
+ *
  * The ESAPI is published by OWASP under the BSD license. You should read and accept the
  * LICENSE before you use, modify, and/or redistribute this software.
- * 
+ *
  * @created 2018
  */
 
@@ -39,7 +39,7 @@ public class Slf4JLogBridgeImpl implements Slf4JLogBridge {
     private final LogScrubber scrubber;
     /** Appender used for assembling default message content for all logs.*/
     private final LogAppender appender;
-    
+
     /**
      * Constructor.
      * @param logScrubber  Log message cleaner.
@@ -58,13 +58,15 @@ public class Slf4JLogBridgeImpl implements Slf4JLogBridge {
             throw new IllegalArgumentException("Unable to lookup SLF4J level mapping for esapi value of " + esapiLevel);
         }
         if (handler.isEnabled(logger)) {
-        	String fullMessage = appender.appendTo(logger.getName(), type, message);
+            type = type == null ? org.owasp.esapi.Logger.EVENT_UNSPECIFIED : type;
+            String fullMessage = appender.appendTo(logger.getName(), type, message);
             String cleanString = scrubber.cleanMessage(fullMessage);
-            
+
             Marker typeMarker = MARKER_FACTORY.getMarker(type.toString());
             handler.log(logger, typeMarker, cleanString);
         }
     }
+
     @Override
     public void log(Logger logger, int esapiLevel, EventType type, String message, Throwable throwable) {
         Slf4JLogLevelHandler handler = esapiSlfLevelMap.get(esapiLevel);
@@ -72,7 +74,8 @@ public class Slf4JLogBridgeImpl implements Slf4JLogBridge {
             throw new IllegalArgumentException("Unable to lookup SLF4J level mapping for esapi value of " + esapiLevel);
         }
         if (handler.isEnabled(logger)) {
-        	String fullMessage = appender.appendTo(logger.getName(), type, message);
+            type = type == null ? org.owasp.esapi.Logger.EVENT_UNSPECIFIED : type;
+            String fullMessage = appender.appendTo(logger.getName(), type, message);
             String cleanString = scrubber.cleanMessage(fullMessage);
 
             Marker typeMarker = MARKER_FACTORY.getMarker(type.toString());
diff --git a/src/main/java/org/owasp/esapi/logging/slf4j/Slf4JLogFactory.java b/src/main/java/org/owasp/esapi/logging/slf4j/Slf4JLogFactory.java
index fab6450..af113b8 100644
--- a/src/main/java/org/owasp/esapi/logging/slf4j/Slf4JLogFactory.java
+++ b/src/main/java/org/owasp/esapi/logging/slf4j/Slf4JLogFactory.java
@@ -1,15 +1,15 @@
 /**
  * OWASP Enterprise Security API (ESAPI)
- * 
+ *
  * This file is part of the Open Web Application Security Project (OWASP)
  * Enterprise Security API (ESAPI) project. For details, please see
  * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
  *
  * Copyright (c) 2007 - The OWASP Foundation
- * 
+ *
  * The ESAPI is published by OWASP under the BSD license. You should read and accept the
  * LICENSE before you use, modify, and/or redistribute this software.
- * 
+ *
  * @created 2018
  */
 package org.owasp.esapi.logging.slf4j;
@@ -29,7 +29,13 @@ import org.owasp.esapi.logging.cleaning.CodecLogScrubber;
 import org.owasp.esapi.logging.cleaning.CompositeLogScrubber;
 import org.owasp.esapi.logging.cleaning.LogScrubber;
 import org.owasp.esapi.logging.cleaning.NewlineLogScrubber;
-import org.owasp.esapi.reference.DefaultSecurityConfiguration;
+
+import static org.owasp.esapi.PropNames.LOG_ENCODING_REQUIRED;
+import static org.owasp.esapi.PropNames.LOG_USER_INFO;
+import static org.owasp.esapi.PropNames.LOG_CLIENT_INFO;
+import static org.owasp.esapi.PropNames.LOG_APPLICATION_NAME;
+import static org.owasp.esapi.PropNames.APPLICATION_NAME;
+import static org.owasp.esapi.PropNames.LOG_SERVER_IP;
 import org.slf4j.LoggerFactory;
 /**
  * LogFactory implementation which creates SLF4J supporting Loggers.
@@ -52,19 +58,19 @@ public class Slf4JLogFactory implements LogFactory {
     private static LogScrubber SLF4J_LOG_SCRUBBER;
     /** Bridge class for mapping esapi -> slf4j log levels.*/
     private static Slf4JLogBridge LOG_BRIDGE;
-    
+
     static {
-        boolean encodeLog = ESAPI.securityConfiguration().getBooleanProp(DefaultSecurityConfiguration.LOG_ENCODING_REQUIRED);
+        boolean encodeLog = ESAPI.securityConfiguration().getBooleanProp(LOG_ENCODING_REQUIRED);
         SLF4J_LOG_SCRUBBER = createLogScrubber(encodeLog);
-        
 
-        boolean logUserInfo = ESAPI.securityConfiguration().getBooleanProp(DefaultSecurityConfiguration.LOG_USER_INFO);
-        boolean logClientInfo = ESAPI.securityConfiguration().getBooleanProp(DefaultSecurityConfiguration.LOG_CLIENT_INFO);
-		boolean logApplicationName = ESAPI.securityConfiguration().getBooleanProp(DefaultSecurityConfiguration.LOG_APPLICATION_NAME);
-		String appName = ESAPI.securityConfiguration().getStringProp(DefaultSecurityConfiguration.APPLICATION_NAME);
-		boolean logServerIp = ESAPI.securityConfiguration().getBooleanProp(DefaultSecurityConfiguration.LOG_SERVER_IP);
+
+        boolean logUserInfo = ESAPI.securityConfiguration().getBooleanProp(LOG_USER_INFO);
+        boolean logClientInfo = ESAPI.securityConfiguration().getBooleanProp(LOG_CLIENT_INFO);
+        boolean logApplicationName = ESAPI.securityConfiguration().getBooleanProp(LOG_APPLICATION_NAME);
+        String appName = ESAPI.securityConfiguration().getStringProp(APPLICATION_NAME);
+        boolean logServerIp = ESAPI.securityConfiguration().getBooleanProp(LOG_SERVER_IP);
         SLF4J_LOG_APPENDER = createLogAppender(logUserInfo, logClientInfo, logServerIp, logApplicationName, appName);
-        
+
         Map<Integer, Slf4JLogLevelHandler> levelLookup = new HashMap<>();
         levelLookup.put(Logger.ALL, Slf4JLogLevelHandlers.TRACE);
         levelLookup.put(Logger.TRACE, Slf4JLogLevelHandlers.TRACE);
@@ -74,10 +80,10 @@ public class Slf4JLogFactory implements LogFactory {
         levelLookup.put(Logger.WARNING, Slf4JLogLevelHandlers.WARN);
         levelLookup.put(Logger.FATAL, Slf4JLogLevelHandlers.ERROR);
         //LEVEL.OFF not used.  If it's off why would we try to log it?
-        
+
         LOG_BRIDGE = new Slf4JLogBridgeImpl(SLF4J_LOG_APPENDER, SLF4J_LOG_SCRUBBER, levelLookup);
     }
-    
+
     /**
      * Populates the default log scrubber for use in factory-created loggers.
      * @param requiresEncoding {@code true} if encoding is required for log content.
@@ -86,29 +92,29 @@ public class Slf4JLogFactory implements LogFactory {
     /*package*/ static LogScrubber createLogScrubber(boolean requiresEncoding) {
         List<LogScrubber> messageScrubber = new ArrayList<>();
         messageScrubber.add(new NewlineLogScrubber());
-        
+
         if (requiresEncoding) {
             messageScrubber.add(new CodecLogScrubber(HTML_CODEC, IMMUNE_SLF4J_HTML));
         }
-        
+
         return new CompositeLogScrubber(messageScrubber);
-        
+
     }
-    
+
     /**
      * Populates the default log appender for use in factory-created loggers.
-     * @param appName 
-     * @param logApplicationName 
-     * @param logServerIp 
-     * @param logClientInfo 
-     * 
+     * @param appName
+     * @param logApplicationName
+     * @param logServerIp
+     * @param logClientInfo
+     *
      * @return LogAppender instance.
      */
     /*package*/ static LogAppender createLogAppender(boolean logUserInfo, boolean logClientInfo, boolean logServerIp, boolean logApplicationName, String appName) {
-        return new LogPrefixAppender(logUserInfo, logClientInfo, logServerIp, logApplicationName, appName);       
+        return new LogPrefixAppender(logUserInfo, logClientInfo, logServerIp, logApplicationName, appName);
     }
-    
-    
+
+
     @Override
     public Logger getLogger(String moduleName) {
         org.slf4j.Logger slf4JLogger = LoggerFactory.getLogger(moduleName);
diff --git a/src/main/java/org/owasp/esapi/logging/slf4j/Slf4JLogLevelHandler.java b/src/main/java/org/owasp/esapi/logging/slf4j/Slf4JLogLevelHandler.java
index 1e8bb7f..1232374 100644
--- a/src/main/java/org/owasp/esapi/logging/slf4j/Slf4JLogLevelHandler.java
+++ b/src/main/java/org/owasp/esapi/logging/slf4j/Slf4JLogLevelHandler.java
@@ -1,15 +1,15 @@
 /**
  * OWASP Enterprise Security API (ESAPI)
- * 
+ *
  * This file is part of the Open Web Application Security Project (OWASP)
  * Enterprise Security API (ESAPI) project. For details, please see
  * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
  *
  * Copyright (c) 2007 - The OWASP Foundation
- * 
+ *
  * The ESAPI is published by OWASP under the BSD license. You should read and accept the
  * LICENSE before you use, modify, and/or redistribute this software.
- * 
+ *
  * @created 2018
  */
 package org.owasp.esapi.logging.slf4j;
@@ -18,7 +18,7 @@ import org.slf4j.Logger;
 import org.slf4j.Marker;
 /**
  * Contract used to isolate translations for each SLF4J Logging Level.
- * 
+ *
  * @see Slf4JLogLevelHandlers
  * @see Slf4JLogBridgeImpl
  *
diff --git a/src/main/java/org/owasp/esapi/logging/slf4j/Slf4JLogLevelHandlers.java b/src/main/java/org/owasp/esapi/logging/slf4j/Slf4JLogLevelHandlers.java
index d2748fe..e26da65 100644
--- a/src/main/java/org/owasp/esapi/logging/slf4j/Slf4JLogLevelHandlers.java
+++ b/src/main/java/org/owasp/esapi/logging/slf4j/Slf4JLogLevelHandlers.java
@@ -1,15 +1,15 @@
 /**
  * OWASP Enterprise Security API (ESAPI)
- * 
+ *
  * This file is part of the Open Web Application Security Project (OWASP)
  * Enterprise Security API (ESAPI) project. For details, please see
  * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
  *
  * Copyright (c) 2007 - The OWASP Foundation
- * 
+ *
  * The ESAPI is published by OWASP under the BSD license. You should read and accept the
  * LICENSE before you use, modify, and/or redistribute this software.
- * 
+ *
  * @created 2018
  */
 
@@ -78,7 +78,7 @@ public enum Slf4JLogLevelHandlers implements Slf4JLogLevelHandler {
 
         @Override
         public void log(Logger logger, Marker marker, String msg) {
-            logger.debug(marker, msg);   
+            logger.debug(marker, msg);
         }
 
         @Override
diff --git a/src/main/java/org/owasp/esapi/logging/slf4j/Slf4JLogger.java b/src/main/java/org/owasp/esapi/logging/slf4j/Slf4JLogger.java
index 62fead5..adb64ce 100644
--- a/src/main/java/org/owasp/esapi/logging/slf4j/Slf4JLogger.java
+++ b/src/main/java/org/owasp/esapi/logging/slf4j/Slf4JLogger.java
@@ -1,15 +1,15 @@
 /**
  * OWASP Enterprise Security API (ESAPI)
- * 
+ *
  * This file is part of the Open Web Application Security Project (OWASP)
  * Enterprise Security API (ESAPI) project. For details, please see
  * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
  *
  * Copyright (c) 2007 - The OWASP Foundation
- * 
+ *
  * The ESAPI is published by OWASP under the BSD license. You should read and accept the
  * LICENSE before you use, modify, and/or redistribute this software.
- * 
+ *
  * @created 2018
  */
 package org.owasp.esapi.logging.slf4j;
@@ -25,9 +25,9 @@ public class Slf4JLogger implements org.owasp.esapi.Logger {
     private final Slf4JLogBridge logBridge;
     /** Maximum log level that will be forwarded to SLF4J from the ESAPI context.*/
     private int loggingLevel;
-    
+
     /**
-     * Constructs a new instance. 
+     * Constructs a new instance.
      * @param slf4JLogger Delegate SLF4J logger.
      * @param bridge Translator for ESAPI -> SLF4J logging events.
      * @param defaultEsapiLevel Maximum ESAPI log level events to propagate.
@@ -37,24 +37,24 @@ public class Slf4JLogger implements org.owasp.esapi.Logger {
         this.logBridge = bridge;
         loggingLevel = defaultEsapiLevel;
     }
-    
+
     private void log(int esapiLevel, EventType type, String message) {
         if (isEnabled(esapiLevel)) {
             logBridge.log(delegate, esapiLevel, type, message);
         }
     }
-    
+
     private void log(int esapiLevel, EventType type, String message, Throwable throwable) {
         if (isEnabled(esapiLevel)) {
             logBridge.log(delegate, esapiLevel, type, message, throwable);
         }
     }
-    
+
 
     private boolean isEnabled(int esapiLevel) {
        return esapiLevel >= loggingLevel;
     }
-    
+
     @Override
     public void always(EventType type, String message) {
         log (Logger.ALL, type, message);
@@ -69,7 +69,7 @@ public class Slf4JLogger implements org.owasp.esapi.Logger {
     public void trace(EventType type, String message) {
         log (Logger.TRACE, type, message);
     }
-    
+
     @Override
     public void trace(EventType type, String message, Throwable throwable) {
         log (Logger.TRACE, type, message, throwable);
@@ -84,22 +84,22 @@ public class Slf4JLogger implements org.owasp.esapi.Logger {
     public void debug(EventType type, String message, Throwable throwable) {
         log (Logger.DEBUG, type, message, throwable);
     }
-    
+
     @Override
     public void info(EventType type, String message) {
         log (Logger.INFO, type, message);
     }
-    
+
     @Override
     public void info(EventType type, String message, Throwable throwable) {
         log (Logger.INFO, type, message, throwable);
     }
-    
+
     @Override
     public void warning(EventType type, String message) {
         log (Logger.WARNING, type, message);
     }
-    
+
     @Override
     public void warning(EventType type, String message, Throwable throwable) {
         log (Logger.WARNING, type, message, throwable);
@@ -112,7 +112,7 @@ public class Slf4JLogger implements org.owasp.esapi.Logger {
 
     @Override
     public void error(EventType type, String message, Throwable throwable) {
-        log (Logger.ERROR, type, message, throwable);   
+        log (Logger.ERROR, type, message, throwable);
     }
 
     @Override
@@ -124,44 +124,44 @@ public class Slf4JLogger implements org.owasp.esapi.Logger {
     public void fatal(EventType type, String message, Throwable throwable) {
         log (Logger.FATAL, type, message, throwable);
     }
-    
+
     @Override
     public int getESAPILevel() {
         return loggingLevel;
     }
-    
+
     @Override
     public boolean isTraceEnabled() {
         return isEnabled(Logger.TRACE);
     }
-    
+
     @Override
     public boolean isDebugEnabled() {
         return isEnabled(Logger.DEBUG);
     }
     @Override
     public boolean isInfoEnabled() {
-        return isEnabled(Logger.INFO); 
+        return isEnabled(Logger.INFO);
     }
     @Override
     public boolean isWarningEnabled() {
         return isEnabled(Logger.WARNING);
     }
-    
+
     @Override
     public boolean isErrorEnabled() {
         return isEnabled(Logger.ERROR);
     }
-    
+
     @Override
     public boolean isFatalEnabled() {
        return isEnabled(Logger.FATAL);
     }
-    
+
 
     @Override
     public void setLevel(int level) {
        loggingLevel = level;
     }
-    
+
 }
diff --git a/src/main/java/org/owasp/esapi/package.html b/src/main/java/org/owasp/esapi/package.html
index cb23a58..02df5ed 100644
--- a/src/main/java/org/owasp/esapi/package.html
+++ b/src/main/java/org/owasp/esapi/package.html
@@ -28,46 +28,46 @@ can make informed decisions about application security risks. Everyone
 is free to participate in OWASP and all of our materials are available
 under an open source license. The OWASP Foundation is a 501c3
 not-for-profit charitable organization that ensures the ongoing
-availability and support for our work.</p> 
- 
+availability and support for our work.</p>
+
 <p>The
 <a href="http://www.owasp.org/index.php/Category:OWASP_Enterprise_Security_API">
 OWASP ESAPI Project</a>
 is led by Jeff Williams,
 <a href="http://www.aspectsecurity.com">Aspect Security</a>.
- 
+
 <p>You can find more information about the ESAPI Java project, or join
 the mailing list and help us make it better from the OWASP project page
 at <a
-href="http://www.owasp.org/index.php/ESAPI#tab=Java_EE">http://www.owasp.org/index.php/ESAPI#tab=Java_EE</a>.</p> 
- 
+href="http://www.owasp.org/index.php/ESAPI#tab=Java_EE">http://www.owasp.org/index.php/ESAPI#tab=Java_EE</a>.</p>
+
 <h2>ESAPI Architecture</h2>
- 
+
 <p>The ESAPI class library builds on the excellent security libraries available,
 such as Java Logging, JCE, and Adobe Commons FileUpload. It uses the
 concepts from many of the security packages out there, such as ACEGI,
 Apache Commons Validator, Microsoft's AntiXSS library, and many many
 more. This library provides a single consistent interface to security
-functions that is intuitive for enterprise developers.</p> 
+functions that is intuitive for enterprise developers.</p>
 
-<img src="doc-files/Architecture.jpg"> 
+<img src="doc-files/Architecture.jpg">
 
 <h2>Addressing OWASP Top Ten</h2>
- 
+
 <p>Used properly, the ESAPI provides enough functions to protect
 against most of the
 <a href="http://www.owasp.org/index.php/Category:OWASP_Top_Ten_Project">
 OWASP Top Ten</a>.  The only real exception is the
 Insecure Communications category, which is generally outside the control
-of the software developer.</p> 
-<img src="doc-files/OWASPTopTen.jpg"> 
+of the software developer.</p>
+<img src="doc-files/OWASPTopTen.jpg">
 
 <h2>Copyright and License</h2>
- 
-<p>This project and all associated code is Copyright (c) 2007 - The OWASP Foundation</p> 
- 
-<p>This project licensed under the <a href="http://en.wikipedia.org/wiki/BSD_license">BSD license</a>, 
-which is very permissive and about as close to public domain as is possible. You can use or modify 
+
+<p>This project and all associated code is Copyright (c) 2007 - The OWASP Foundation</p>
+
+<p>This project licensed under the <a href="http://en.wikipedia.org/wiki/BSD_license">BSD license</a>,
+which is very permissive and about as close to public domain as is possible. You can use or modify
 ESAPI however you want, even include it in commercial products.</p>
 
 <h2>References</h2>
diff --git a/src/main/java/org/owasp/esapi/reference/AbstractAccessReferenceMap.java b/src/main/java/org/owasp/esapi/reference/AbstractAccessReferenceMap.java
index 4bd77af..242ff3e 100644
--- a/src/main/java/org/owasp/esapi/reference/AbstractAccessReferenceMap.java
+++ b/src/main/java/org/owasp/esapi/reference/AbstractAccessReferenceMap.java
@@ -28,16 +28,16 @@ import org.owasp.esapi.errors.AccessControlException;
 /**
  * Abstract Implementation of the AccessReferenceMap.
  * <br>
- * Implementation offers default synchronization on all public API 
+ * Implementation offers default synchronization on all public API
  * to assist with thread safety.
  * <br>
- * For complex interactions spanning multiple calls, it is recommended 
+ * For complex interactions spanning multiple calls, it is recommended
  * to add a synchronized block around all invocations to maintain intended data integrity.
- * 
+ *
  * <pre>
  * public MyClassUsingAARM {
  *  private AbstractAccessReferenceMap<Object> aarm;
- * 
+ *
  *  public void replaceAARMDirect(Object oldDirect, Object newDirect) {
  *     synchronized (aarm) {
  *        aarm.removeDirectReference(oldDirect);
@@ -89,13 +89,13 @@ public abstract class AbstractAccessReferenceMap<K> implements AccessReferenceMa
     * @param directReferences
     *            the direct references
     * @deprecated This constructor internally calls the abstract method
-    *	{@link #getUniqueReference()}. Since this is a constructor, any
-    *	subclass that implements getUniqueReference() has not had it's
-    *	own constructor run. This leads to strange bugs because subclass
-    *	internal state is initializaed after calls to getUniqueReference()
-    *	have already happened. If this constructor is desired in a
-    *	subclass, consider running {@link #update(Set)} in the subclass
-    *	constructor instead.
+    *    {@link #getUniqueReference()}. Since this is a constructor, any
+    *    subclass that implements getUniqueReference() has not had it's
+    *    own constructor run. This leads to strange bugs because subclass
+    *    internal state is initializaed after calls to getUniqueReference()
+    *    have already happened. If this constructor is desired in a
+    *    subclass, consider running {@link #update(Set)} in the subclass
+    *    constructor instead.
     */
    @Deprecated
    public AbstractAccessReferenceMap( Set<Object> directReferences ) {
@@ -118,13 +118,13 @@ public abstract class AbstractAccessReferenceMap<K> implements AccessReferenceMa
     *          The initial size to set the map to.
     *
     * @deprecated This constructor internally calls the abstract method
-    *	{@link #getUniqueReference()}. Since this is a constructor, any
-    *	subclass that implements getUniqueReference() has not had it's
-    *	own constructor run. This leads to strange bugs because subclass
-    *	internal state is initializaed after calls to getUniqueReference()
-    *	have already happened. If this constructor is desired in a
-    *	subclass, consider running {@link #update(Set)} in the subclass
-    *	constructor instead.
+    *    {@link #getUniqueReference()}. Since this is a constructor, any
+    *    subclass that implements getUniqueReference() has not had it's
+    *    own constructor run. This leads to strange bugs because subclass
+    *    internal state is initializaed after calls to getUniqueReference()
+    *    have already happened. If this constructor is desired in a
+    *    subclass, consider running {@link #update(Set)} in the subclass
+    *    constructor instead.
     */
    @Deprecated
    public AbstractAccessReferenceMap( Set<Object> directReferences, int initialSize ) {
@@ -181,23 +181,23 @@ public abstract class AbstractAccessReferenceMap<K> implements AccessReferenceMa
    public final synchronized void update(Set directReferences) {
        Map<Object,K> new_dtoi = new HashMap<Object,K>( directReferences.size() );
        Map<K,Object> new_itod = new HashMap<K,Object>( directReferences.size() );
-       
+
        Set<Object> newDirect = new HashSet<>(directReferences);
        Set<Object> dtoiCurrent = new HashSet<>(dtoi.keySet());
 
        //Preserve all keys that are in the new set
        dtoiCurrent.retainAll(newDirect);
-       
+
        //Transfer existing values into the new map
        for (Object current: dtoiCurrent) {
            K idCurrent = dtoi.get(current);
            new_dtoi.put(current, idCurrent);
            new_itod.put(idCurrent, current);
        }
-       
+
        //Trim the new map to only new values
        newDirect.removeAll(dtoiCurrent);
-       
+
        //Add new values with new indirect keys to the new map
        for (Object newD : newDirect) {
            K idCurrent;
@@ -205,11 +205,11 @@ public abstract class AbstractAccessReferenceMap<K> implements AccessReferenceMa
                idCurrent = getUniqueReference();
                //Unlikey, but just in case we generate the exact same key multiple times...
            } while (dtoi.containsValue(idCurrent));
-           
+
            new_dtoi.put(newD, idCurrent);
            new_itod.put(idCurrent, newD);
        }
-    
+
        dtoi = new_dtoi;
        itod = new_itod;
    }
diff --git a/src/main/java/org/owasp/esapi/reference/AbstractAuthenticator.java b/src/main/java/org/owasp/esapi/reference/AbstractAuthenticator.java
index e6976c7..9e3f784 100644
--- a/src/main/java/org/owasp/esapi/reference/AbstractAuthenticator.java
+++ b/src/main/java/org/owasp/esapi/reference/AbstractAuthenticator.java
@@ -23,13 +23,13 @@ import org.owasp.esapi.errors.EnterpriseSecurityException;
  */
 public abstract class AbstractAuthenticator implements org.owasp.esapi.Authenticator {
 
-	/**
+    /**
      * Key for user in session
      */
     protected static final String USER = "ESAPIUserSessionKey";
-    
+
     private final Logger logger = ESAPI.getLogger("Authenticator");
-    
+
     /**
      * The currentUser ThreadLocal variable is used to make the currentUser available to any call in any part of an
      * application. Otherwise, each thread would have to pass the User object through the calltree to any methods that
@@ -53,14 +53,14 @@ public abstract class AbstractAuthenticator implements org.owasp.esapi.Authentic
             super.set(newUser);
         }
     }
-    
-	/**
-	 *
-	 */
-	public AbstractAuthenticator() {
-		super();
-	}
-	
+
+    /**
+     *
+     */
+    public AbstractAuthenticator() {
+        super();
+    }
+
     /**
      * {@inheritDoc}
      */
@@ -68,14 +68,14 @@ public abstract class AbstractAuthenticator implements org.owasp.esapi.Authentic
         // logger.logWarning(Logger.SECURITY, "************Clearing threadlocals. Thread" + Thread.currentThread().getName() );
         currentUser.setUser(null);
     }
-    
+
     /**
      * {@inheritDoc}
      */
     public boolean exists(String accountName) {
         return getUser(accountName) != null;
     }
-    
+
     /**
      * {@inheritDoc}
      * <p/>
@@ -89,20 +89,20 @@ public abstract class AbstractAuthenticator implements org.owasp.esapi.Authentic
         }
         return user;
     }
-    
+
     /**
      * Gets the user from session.
      *
      * @return the user from session or null if no user is found in the session
      */
     protected User getUserFromSession() {
-    	HTTPUtilities httpUtils = ESAPI.httpUtilities();
-    	HttpServletRequest req = httpUtils.getCurrentRequest();
+        HTTPUtilities httpUtils = ESAPI.httpUtilities();
+        HttpServletRequest req = httpUtils.getCurrentRequest();
         HttpSession session = req.getSession(false);
         if (session == null) return null;
         return ESAPI.httpUtilities().getSessionAttribute(USER);
     }
-    
+
     /**
      * Returns the user if a matching remember token is found, or null if the token
      * is missing, token is corrupt, token is expired, account name does not match
@@ -114,10 +114,10 @@ public abstract class AbstractAuthenticator implements org.owasp.esapi.Authentic
      */
     protected DefaultUser getUserFromRememberToken() {
         try {
-        	HTTPUtilities utils =ESAPI.httpUtilities();
+            HTTPUtilities utils =ESAPI.httpUtilities();
             String token = utils.getCookie(ESAPI.currentRequest(), HTTPUtilities.REMEMBER_TOKEN_COOKIE_NAME);
             if (token == null) return null;
-            
+
             // See Google Issue 144 regarding first URLDecode the token and THEN unsealing.
             // Note that this Google Issue was marked as "WontFix".
 
@@ -147,7 +147,7 @@ public abstract class AbstractAuthenticator implements org.owasp.esapi.Authentic
         ESAPI.httpUtilities().killCookie(ESAPI.currentRequest(), ESAPI.currentResponse(), HTTPUtilities.REMEMBER_TOKEN_COOKIE_NAME);
         return null;
     }
-    
+
     /**
      * Utility method to extract credentials and verify them.
      *
@@ -183,14 +183,14 @@ public abstract class AbstractAuthenticator implements org.owasp.esapi.Authentic
         request.setAttribute(user.getCSRFToken(), "authenticated");
         return user;
     }
-    
+
     /**
      * {@inheritDoc}
      */
     public User login() throws AuthenticationException {
         return login(ESAPI.currentRequest(), ESAPI.currentResponse());
     }
-    
+
     /**
      * {@inheritDoc}
      */
@@ -279,7 +279,7 @@ public abstract class AbstractAuthenticator implements org.owasp.esapi.Authentic
         setCurrentUser(user);
         return user;
     }
-    
+
     /**
      * {@inheritDoc}
      */
diff --git a/src/main/java/org/owasp/esapi/reference/DefaultAccessController.java b/src/main/java/org/owasp/esapi/reference/DefaultAccessController.java
index 5e8adf9..7f978ca 100644
--- a/src/main/java/org/owasp/esapi/reference/DefaultAccessController.java
+++ b/src/main/java/org/owasp/esapi/reference/DefaultAccessController.java
@@ -11,7 +11,7 @@ import org.owasp.esapi.reference.accesscontrol.policyloader.ACRPolicyFileLoader;
 import org.owasp.esapi.reference.accesscontrol.policyloader.PolicyDTO;
 
 public class DefaultAccessController implements AccessController {
-	private Map ruleMap;
+    private Map ruleMap;
 
     private static volatile AccessController singletonInstance = null;
 
@@ -26,122 +26,122 @@ public class DefaultAccessController implements AccessController {
         return singletonInstance;
     }
 
-	protected final Logger logger = ESAPI.getLogger("DefaultAccessController");
+    protected final Logger logger = ESAPI.getLogger("DefaultAccessController");
 
-	private DefaultAccessController() throws AccessControlException {
-		ACRPolicyFileLoader policyDescriptor = new ACRPolicyFileLoader();
-		PolicyDTO policyDTO = policyDescriptor.load();		
-		ruleMap = policyDTO.getAccessControlRules();
-	}
+    private DefaultAccessController() throws AccessControlException {
+        ACRPolicyFileLoader policyDescriptor = new ACRPolicyFileLoader();
+        PolicyDTO policyDTO = policyDescriptor.load();
+        ruleMap = policyDTO.getAccessControlRules();
+    }
 
     /**
      * {@inheritDoc}
      */
-	public boolean isAuthorized(Object key, Object runtimeParameter) {
-		try {
-			AccessControlRule rule = (AccessControlRule)ruleMap.get(key);
-			if(rule == null) {
-				throw new AccessControlException("Access Denied",
-						"AccessControlRule was not found for key: " + key); 
-			}
-			if(logger.isDebugEnabled()){ logger.debug(Logger.EVENT_SUCCESS, "Evaluating Authorization Rule \"" + key + "\" Using class: " + rule.getClass().getCanonicalName()); }
-			return rule.isAuthorized(runtimeParameter);
-		} catch(Exception e) {
-			try {
-				//Log the exception by throwing and then catching it.
-				//TODO figure out what which string goes where.		
-				throw new AccessControlException("Access Denied",
-					"An unhandled Exception was " +
-					"caught, so access is denied.",  
-					e);	
-			} catch(AccessControlException ace) {
-				//the exception was just logged. There's nothing left to do.
-			}
-			return false; //fail closed
-		}
-	}
+    public boolean isAuthorized(Object key, Object runtimeParameter) {
+        try {
+            AccessControlRule rule = (AccessControlRule)ruleMap.get(key);
+            if(rule == null) {
+                throw new AccessControlException("Access Denied",
+                        "AccessControlRule was not found for key: " + key);
+            }
+            if(logger.isDebugEnabled()){ logger.debug(Logger.EVENT_SUCCESS, "Evaluating Authorization Rule \"" + key + "\" Using class: " + rule.getClass().getCanonicalName()); }
+            return rule.isAuthorized(runtimeParameter);
+        } catch(Exception e) {
+            try {
+                //Log the exception by throwing and then catching it.
+                //TODO figure out what which string goes where.
+                throw new AccessControlException("Access Denied",
+                    "An unhandled Exception was " +
+                    "caught, so access is denied.",
+                    e);
+            } catch(AccessControlException ace) {
+                //the exception was just logged. There's nothing left to do.
+            }
+            return false; //fail closed
+        }
+    }
 
     /** {@inheritDoc} */
-	public void assertAuthorized(Object key, Object runtimeParameter) throws AccessControlException {
-		boolean isAuthorized;
-		try {
-			AccessControlRule rule = (AccessControlRule)ruleMap.get(key);
-			if(rule == null) {
-				throw new AccessControlException("Access Denied", 
-						"AccessControlRule was not found for key: " + key); 
-			}
-			if(logger.isDebugEnabled()){ logger.debug(Logger.EVENT_SUCCESS, "Asserting Authorization Rule \"" + key + "\" Using class: " + rule.getClass().getCanonicalName()); }
-			isAuthorized = rule.isAuthorized(runtimeParameter);
-		} catch(Exception e) {
-			//TODO figure out what which string goes where.		
-			throw new AccessControlException("Access Denied", "An unhandled Exception was " +
-					"caught, so access is denied." +
-					"AccessControlException.",
-					e);
-		}
-		if(!isAuthorized) {
-			throw new AccessControlException("Access Denied", 
-					"Access Denied for key: " + key + 
-					" runtimeParameter: " + runtimeParameter);
-		}
-	}
-	
+    public void assertAuthorized(Object key, Object runtimeParameter) throws AccessControlException {
+        boolean isAuthorized;
+        try {
+            AccessControlRule rule = (AccessControlRule)ruleMap.get(key);
+            if(rule == null) {
+                throw new AccessControlException("Access Denied",
+                        "AccessControlRule was not found for key: " + key);
+            }
+            if(logger.isDebugEnabled()){ logger.debug(Logger.EVENT_SUCCESS, "Asserting Authorization Rule \"" + key + "\" Using class: " + rule.getClass().getCanonicalName()); }
+            isAuthorized = rule.isAuthorized(runtimeParameter);
+        } catch(Exception e) {
+            //TODO figure out what which string goes where.
+            throw new AccessControlException("Access Denied", "An unhandled Exception was " +
+                    "caught, so access is denied." +
+                    "AccessControlException.",
+                    e);
+        }
+        if(!isAuthorized) {
+            throw new AccessControlException("Access Denied",
+                    "Access Denied for key: " + key +
+                    " runtimeParameter: " + runtimeParameter);
+        }
+    }
+
     /** {@inheritDoc} */
-	public void assertAuthorizedForData(String action, Object data)
-			throws AccessControlException {
-		this.assertAuthorized("AC 1.0 Data", new Object[] {action, data});
-	}
+    public void assertAuthorizedForData(String action, Object data)
+            throws AccessControlException {
+        this.assertAuthorized("AC 1.0 Data", new Object[] {action, data});
+    }
 
-	/**
+    /**
      * {@inheritDoc}
-	 * @deprecated
-	 */
+     * @deprecated
+     */
     @Deprecated
-	public void assertAuthorizedForFile(String filepath)
-			throws AccessControlException {
-		this.assertAuthorized("AC 1.0 File", new Object[] {filepath});
-	}
+    public void assertAuthorizedForFile(String filepath)
+            throws AccessControlException {
+        this.assertAuthorized("AC 1.0 File", new Object[] {filepath});
+    }
 
     /** {@inheritDoc} */
-	public void assertAuthorizedForFunction(String functionName)
-			throws AccessControlException {
-		this.assertAuthorized("AC 1.0 Function", new Object[] {functionName});
-	}
+    public void assertAuthorizedForFunction(String functionName)
+            throws AccessControlException {
+        this.assertAuthorized("AC 1.0 Function", new Object[] {functionName});
+    }
 
     /** {@inheritDoc} */
-	public void assertAuthorizedForService(String serviceName)
-			throws AccessControlException {
-		this.assertAuthorized("AC 1.0 Service", new Object[] {serviceName});
-	}
+    public void assertAuthorizedForService(String serviceName)
+            throws AccessControlException {
+        this.assertAuthorized("AC 1.0 Service", new Object[] {serviceName});
+    }
 
     /** {@inheritDoc} */
-	public void assertAuthorizedForURL(String url)
-			throws AccessControlException {
-		this.assertAuthorized("AC 1.0 URL", new Object[] {url});
-	}
+    public void assertAuthorizedForURL(String url)
+            throws AccessControlException {
+        this.assertAuthorized("AC 1.0 URL", new Object[] {url});
+    }
 
     /** {@inheritDoc} */
-	public boolean isAuthorizedForData(String action, Object data) {
-		return this.isAuthorized("AC 1.0 Data", new Object[] {action, data});
-	}
+    public boolean isAuthorizedForData(String action, Object data) {
+        return this.isAuthorized("AC 1.0 Data", new Object[] {action, data});
+    }
 
     /** {@inheritDoc} */
-	public boolean isAuthorizedForFile(String filepath) {
-		return this.isAuthorized("AC 1.0 File", new Object[] {filepath});
-	}
+    public boolean isAuthorizedForFile(String filepath) {
+        return this.isAuthorized("AC 1.0 File", new Object[] {filepath});
+    }
 
     /** {@inheritDoc} */
-	public boolean isAuthorizedForFunction(String functionName) {
-		return this.isAuthorized("AC 1.0 Function", new Object[] {functionName});
-	}
+    public boolean isAuthorizedForFunction(String functionName) {
+        return this.isAuthorized("AC 1.0 Function", new Object[] {functionName});
+    }
 
     /** {@inheritDoc} */
-	public boolean isAuthorizedForService(String serviceName) {
-		return this.isAuthorized("AC 1.0 Service", new Object[] {serviceName});
-	}
+    public boolean isAuthorizedForService(String serviceName) {
+        return this.isAuthorized("AC 1.0 Service", new Object[] {serviceName});
+    }
 
     /** {@inheritDoc} */
-	public boolean isAuthorizedForURL(String url) {
-		return this.isAuthorized("AC 1.0 URL", new Object[] {url});
-	}
+    public boolean isAuthorizedForURL(String url) {
+        return this.isAuthorized("AC 1.0 URL", new Object[] {url});
+    }
 }
diff --git a/src/main/java/org/owasp/esapi/reference/DefaultEncoder.java b/src/main/java/org/owasp/esapi/reference/DefaultEncoder.java
index 5ecd5c0..5647a5b 100644
--- a/src/main/java/org/owasp/esapi/reference/DefaultEncoder.java
+++ b/src/main/java/org/owasp/esapi/reference/DefaultEncoder.java
@@ -1,15 +1,15 @@
 /**
  * OWASP Enterprise Security API (ESAPI)
- * 
+ *
  * This file is part of the Open Web Application Security Project (OWASP)
  * Enterprise Security API (ESAPI) project. For details, please see
  * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
  *
  * Copyright (c) 2007 - The OWASP Foundation
- * 
+ *
  * The ESAPI is published by OWASP under the BSD license. You should read and accept the
  * LICENSE before you use, modify, and/or redistribute this software.
- * 
+ *
  * @author Jeff Williams <a href="http://www.aspectsecurity.com">Aspect Security</a>
  * @created 2007
  */
@@ -42,6 +42,7 @@ import org.owasp.esapi.codecs.JavaScriptCodec;
 import org.owasp.esapi.codecs.PercentCodec;
 import org.owasp.esapi.codecs.VBScriptCodec;
 import org.owasp.esapi.codecs.XMLEntityCodec;
+import org.owasp.esapi.codecs.JSONCodec;
 import org.owasp.esapi.errors.EncodingException;
 import org.owasp.esapi.errors.IntrusionException;
 
@@ -50,7 +51,7 @@ import org.owasp.esapi.errors.IntrusionException;
  * Reference implementation of the Encoder interface. This implementation takes
  * a whitelist approach to encoding, meaning that everything not specifically identified in a
  * list of "immune" characters is encoded.
- * 
+ *
  * @author Jeff Williams (jeff.williams .at. aspectsecurity.com) <a
  *         href="http://www.aspectsecurity.com">Aspect Security</a>
  * @since June 1, 2007
@@ -71,84 +72,90 @@ public class DefaultEncoder implements Encoder {
         return singletonInstance;
     }
 
-	// Codecs
-	private List codecs = new ArrayList();
-	private HTMLEntityCodec htmlCodec = new HTMLEntityCodec();
-	private XMLEntityCodec xmlCodec = new XMLEntityCodec();
-	private PercentCodec percentCodec = new PercentCodec();
-	private JavaScriptCodec javaScriptCodec = new JavaScriptCodec();
-	private VBScriptCodec vbScriptCodec = new VBScriptCodec();
-	private CSSCodec cssCodec = new CSSCodec();
-
-	private final Logger logger = ESAPI.getLogger("Encoder");
-	
-	/**
-	 *  Character sets that define characters (in addition to alphanumerics) that are
-	 * immune from encoding in various formats
-	 */
-	private final static char[]     IMMUNE_HTML = { ',', '.', '-', '_', ' ' };
-	private final static char[] IMMUNE_HTMLATTR = { ',', '.', '-', '_' };
-	private final static char[] IMMUNE_CSS = { '#' };
-	private final static char[] IMMUNE_JAVASCRIPT = { ',', '.', '_' };
-	private final static char[] IMMUNE_VBSCRIPT = { ',', '.', '_' };
-	private final static char[] IMMUNE_XML = { ',', '.', '-', '_', ' ' };
-	private final static char[] IMMUNE_SQL = { ' ' };
-	private final static char[] IMMUNE_OS = { '-' };
-	private final static char[] IMMUNE_XMLATTR = { ',', '.', '-', '_' };
-	private final static char[] IMMUNE_XPATH = { ',', '.', '-', '_', ' ' };
-	
-	
-	/**
-	 * Instantiates a new DefaultEncoder
-	 */
-	private DefaultEncoder() {
-		codecs.add( htmlCodec );
-		codecs.add( percentCodec );
-		codecs.add( javaScriptCodec );
-	}
-	
-	public DefaultEncoder( List<String> codecNames ) {
-		for ( String clazz : codecNames ) {
-			try {
-				if ( clazz.indexOf( '.' ) == -1 ) clazz = "org.owasp.esapi.codecs." + clazz;
-				codecs.add( Class.forName( clazz ).newInstance() );
-			} catch ( Exception e ) {
-				logger.warning( Logger.EVENT_FAILURE, "Codec " + clazz + " listed in ESAPI.properties not on classpath" );
-			}
-		}
-	}
-	
-	/**
-	 * {@inheritDoc}
-	 */
-	public String canonicalize( String input ) {
-		if ( input == null ) {
-			return null;
-		}
+    // Codecs
+    private List codecs = new ArrayList();
+    private HTMLEntityCodec htmlCodec = new HTMLEntityCodec();
+    private XMLEntityCodec xmlCodec = new XMLEntityCodec();
+    private PercentCodec percentCodec = new PercentCodec();
+    private JavaScriptCodec javaScriptCodec = new JavaScriptCodec();
+    private VBScriptCodec vbScriptCodec = new VBScriptCodec();
+    private CSSCodec cssCodec = new CSSCodec();
+    private JSONCodec jsonCodec = new JSONCodec();
+
+    private final Logger logger = ESAPI.getLogger("Encoder");
+
+    /**
+     *  Character sets that define characters (in addition to alphanumerics) that are
+     * immune from encoding in various formats
+     */
+    private final static char[] IMMUNE_HTML = { ',', '.', '-', '_', ' ' };
+    private final static char[] IMMUNE_HTMLATTR = { ',', '.', '-', '_' };
+    private final static char[] IMMUNE_CSS = { '#' };
+    private final static char[] IMMUNE_JAVASCRIPT = { ',', '.', '_' };
+    private final static char[] IMMUNE_VBSCRIPT = { ',', '.', '_' };
+    private final static char[] IMMUNE_XML = { ',', '.', '-', '_', ' ' };
+    private final static char[] IMMUNE_SQL = { ' ' };
+    private final static char[] IMMUNE_OS = { '-' };
+    private final static char[] IMMUNE_XMLATTR = { ',', '.', '-', '_' };
+    private final static char[] IMMUNE_XPATH = { ',', '.', '-', '_', ' ' };
+    private final static char[] IMMUNE_JSON = { };
+
+
+    /**
+     * Instantiates a new {@code DefaultEncoder} based on the property {@code Encoder.DefaultCodecList}
+     * from the {@code ESAPI.properties} file.
+     */
+    private DefaultEncoder() {
+        this( ESAPI.securityConfiguration().getDefaultCanonicalizationCodecs() );
+    }
+
+    /**
+     * Instantiates a new {@code DefaultEncoder} based on the specified list of
+     * codec names. Unqualified codec names are assumed to belong to the package
+     * "org.owasp.esapi.codecs".
+     */
+    public DefaultEncoder( List<String> codecNames ) {
+        for ( String clazz : codecNames ) {
+            try {
+                if ( clazz.indexOf( '.' ) == -1 ) clazz = "org.owasp.esapi.codecs." + clazz;
+                codecs.add( Class.forName( clazz ).newInstance() );
+            } catch ( Exception e ) {
+                logger.warning( Logger.EVENT_FAILURE, "Codec " + clazz + " listed in ESAPI.properties not on classpath" );
+            }
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public String canonicalize( String input ) {
+        if ( input == null ) {
+            return null;
+        }
 
         // Issue 231 - These are reverse boolean logic in the Encoder interface, so we need to invert these values - CS
-		return canonicalize(input, 
-							!ESAPI.securityConfiguration().getAllowMultipleEncoding(),
-							!ESAPI.securityConfiguration().getAllowMixedEncoding() );
-	}
-
-	
-	/**
-	 * {@inheritDoc}
-	 */
-	public String canonicalize( String input, boolean strict) {
-		return canonicalize(input, strict, strict);
-	}
-
-
-	/**
-	 * {@inheritDoc}
-	 */
-	public String canonicalize( String input, boolean restrictMultiple, boolean restrictMixed ) {
-		if ( input == null ) {
-			return null;
-		}
-		
+        return canonicalize(input,
+                            !ESAPI.securityConfiguration().getAllowMultipleEncoding(),
+                            !ESAPI.securityConfiguration().getAllowMixedEncoding() );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public String canonicalize( String input, boolean strict) {
+        return canonicalize(input, strict, strict);
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public String canonicalize( String input, boolean restrictMultiple, boolean restrictMixed ) {
+        if ( input == null ) {
+            return null;
+        }
+
         String working = input;
         Codec codecFound = null;
         int mixedCount = 1;
@@ -156,7 +163,7 @@ public class DefaultEncoder implements Encoder {
         boolean clean = false;
         while( !clean ) {
             clean = true;
-            
+
             // try each codec and keep track of which ones work
             Iterator i = codecs.iterator();
             while ( i.hasNext() ) {
@@ -175,7 +182,7 @@ public class DefaultEncoder implements Encoder {
                 }
             }
         }
-        
+
         // do strict tests and handle if any mixed, multiple, nested encoding were found
         if ( foundCount >= 2 && mixedCount > 1 ) {
             if ( restrictMultiple || restrictMixed ) {
@@ -199,418 +206,452 @@ public class DefaultEncoder implements Encoder {
             }
         }
         return working;
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	public String encodeForHTML(String input) {
-	    if( input == null ) {
-	    	return null;
-	    }
-	    return htmlCodec.encode( IMMUNE_HTML, input);	    
-	 }
-	
-	/**
-	 * {@inheritDoc}
-	 */
-	public String decodeForHTML(String input) {
-		
-		if( input == null ) {
-	    	return null;
-	    }
-	    return htmlCodec.decode( input);	 
     }
-	 
-	/**
-	 * {@inheritDoc}
-	 */
-	public String encodeForHTMLAttribute(String input) {
-	    if( input == null ) {
-	    	return null;
-	    }
-	    return htmlCodec.encode( IMMUNE_HTMLATTR, input);
-	}
-
-	
-	/**
-	 * {@inheritDoc}
-	 */
-	public String encodeForCSS(String input) {
-	    if( input == null ) {
-	    	return null;
-	    }
-	    return cssCodec.encode( IMMUNE_CSS, input);
-	}
-
-	
-	/**
-	 * {@inheritDoc}
-	 */
-	public String encodeForJavaScript(String input) {
-	    if( input == null ) {
-	    	return null;
-	    }
-	    return javaScriptCodec.encode(IMMUNE_JAVASCRIPT, input);
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	public String encodeForVBScript(String input) {
-	    if( input == null ) {
-	    	return null;
-	    }
-	    return vbScriptCodec.encode(IMMUNE_VBSCRIPT, input);	    
-	}
-
-	
-	/**
-	 * {@inheritDoc}
-	 */
-	public String encodeForSQL(Codec codec, String input) {
-	    if( input == null ) {
-	    	return null;
-	    }
-	    return codec.encode(IMMUNE_SQL, input);
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	public String encodeForOS(Codec codec, String input) {
-	    if( input == null ) {
-	    	return null;	
-	    }
-	    return codec.encode( IMMUNE_OS, input);
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	public String encodeForLDAP(String input) {
-		return encodeForLDAP(input, true);
-	}
-	
-	/**
-	 * {@inheritDoc}
-	 */
-	public String encodeForLDAP(String input, boolean encodeWildcards) {
-	    if( input == null ) {
-	    	return null;	
-	    }
-		// TODO: replace with LDAP codec
-	    StringBuilder sb = new StringBuilder();
-	    for (int i = 0; i < input.length(); i++) {
-	        char c = input.charAt(i);
-
-	        switch (c) {
-	            case '\\':
-	                sb.append("\\5c");
-	                break;
-	            case '*': 
-	                if (encodeWildcards) {
-	                    sb.append("\\2a"); 
-	                }
-	                else {
-	                    sb.append(c);
-	                }
-	                
-	                break;
-	            case '(':
-	                sb.append("\\28");
-	                break;
-	            case ')':
-	                sb.append("\\29");
-	                break;
-	            case '\0':
-	                sb.append("\\00");
-	                break;
-	            default:
-	                sb.append(c);
-	        }
-	    }
-		return sb.toString();
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	public String encodeForDN(String input) {
-	    if( input == null ) {
-	    	return null;	
-	    }
-		// TODO: replace with DN codec
-	    StringBuilder sb = new StringBuilder();
-		if ((input.length() > 0) && ((input.charAt(0) == ' ') || (input.charAt(0) == '#'))) {
-			sb.append('\\'); // add the leading backslash if needed
-		}
-		for (int i = 0; i < input.length(); i++) {
-			char c = input.charAt(i);
-			switch (c) {
-			case '\\':
-				sb.append("\\\\");
-				break;
-			case ',':
-				sb.append("\\,");
-				break;
-			case '+':
-				sb.append("\\+");
-				break;
-			case '"':
-				sb.append("\\\"");
-				break;
-			case '<':
-				sb.append("\\<");
-				break;
-			case '>':
-				sb.append("\\>");
-				break;
-			case ';':
-				sb.append("\\;");
-				break;
-			default:
-				sb.append(c);
-			}
-		}
-		// add the trailing backslash if needed
-		if ((input.length() > 1) && (input.charAt(input.length() - 1) == ' ')) {
-			sb.insert(sb.length() - 1, '\\');
-		}
-		return sb.toString();
-	}
-
-
-	/**
-	 * {@inheritDoc}
-	 */
-	public String encodeForXPath(String input) {
-	    if( input == null ) {
-	    	return null;	
-	    }
-	    return htmlCodec.encode( IMMUNE_XPATH, input);
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	public String encodeForXML(String input) {
-	    if( input == null ) {
-	    	return null;	
-	    }
-	    return xmlCodec.encode( IMMUNE_XML, input);
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	public String encodeForXMLAttribute(String input) {
-	    if( input == null ) {
-	    	return null;	
-	    }
-	    return xmlCodec.encode( IMMUNE_XMLATTR, input);
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	public String encodeForURL(String input) throws EncodingException {
-		if ( input == null ) {
-			return null;
-		}
-		try {
-			return URLEncoder.encode(input, ESAPI.securityConfiguration().getCharacterEncoding());
-		} catch (UnsupportedEncodingException ex) {
-			throw new EncodingException("Encoding failure", "Character encoding not supported", ex);
-		} catch (Exception e) {
-			throw new EncodingException("Encoding failure", "Problem URL encoding input", e);
-		}
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	public String decodeFromURL(String input) throws EncodingException {
-		if ( input == null ) {
-			return null;
-		}
-		String canonical = canonicalize(input);
-		try {
-			return URLDecoder.decode(canonical, ESAPI.securityConfiguration().getCharacterEncoding());
-		} catch (UnsupportedEncodingException ex) {
-			throw new EncodingException("Decoding failed", "Character encoding not supported", ex);
-		} catch (Exception e) {
-			throw new EncodingException("Decoding failed", "Problem URL decoding input", e);
-		}
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	public String encodeForBase64(byte[] input, boolean wrap) {
-		if ( input == null ) {
-			return null;
-		}
-		int options = 0;
-		if ( !wrap ) {
-			options |= Base64.DONT_BREAK_LINES;
-		}
-		return Base64.encodeBytes(input, options);
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	public byte[] decodeFromBase64(String input) throws IOException {
-		if ( input == null ) {
-			return null;
-		}
-		return Base64.decode( input );
-	}
-	
-	/**
-	 * {@inheritDoc}
-	 * 
-	 * This will extract each piece of a URI according to parse zone as specified in <a href="https://www.ietf.org/rfc/rfc3986.txt">RFC-3986</a> section 3, 
-	 * and it will construct a canonicalized String representing a version of the URI that is safe to 
-	 * run regex against. 
-	 * 
-	 * @param dirtyUri
-	 * @return Canonicalized URI string.
-	 * @throws IntrusionException
-	 */
-	public String getCanonicalizedURI(URI dirtyUri) throws IntrusionException{
-		
-//		From RFC-3986 section 3		
-//	      URI         = scheme ":" hier-part [ "?" query ] [ "#" fragment ]
+
+    /**
+     * {@inheritDoc}
+     */
+    public String encodeForHTML(String input) {
+        if( input == null ) {
+            return null;
+        }
+        return htmlCodec.encode( IMMUNE_HTML, input);
+     }
+
+    /**
+     * {@inheritDoc}
+     */
+    public String decodeForHTML(String input) {
+
+        if( input == null ) {
+            return null;
+        }
+        return htmlCodec.decode( input);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public String encodeForHTMLAttribute(String input) {
+        if( input == null ) {
+            return null;
+        }
+        return htmlCodec.encode( IMMUNE_HTMLATTR, input);
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public String encodeForCSS(String input) {
+        if( input == null ) {
+            return null;
+        }
+        return cssCodec.encode( IMMUNE_CSS, input);
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public String encodeForJavaScript(String input) {
+        if( input == null ) {
+            return null;
+        }
+        return javaScriptCodec.encode(IMMUNE_JAVASCRIPT, input);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public String encodeForVBScript(String input) {
+        if( input == null ) {
+            return null;
+        }
+        return vbScriptCodec.encode(IMMUNE_VBSCRIPT, input);
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public String encodeForSQL(Codec codec, String input) {
+        if( input == null ) {
+            return null;
+        }
+        return codec.encode(IMMUNE_SQL, input);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public String encodeForOS(Codec codec, String input) {
+        if( input == null ) {
+            return null;
+        }
+        return codec.encode( IMMUNE_OS, input);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public String encodeForLDAP(String input) {
+        return encodeForLDAP(input, true);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public String encodeForLDAP(String input, boolean encodeWildcards) {
+        if( input == null ) {
+            return null;
+        }
+        // TODO: replace with LDAP codec
+        StringBuilder sb = new StringBuilder();
+        // According to Microsoft docs [1,2], the forward slash ('/') MUST be escaped.
+        // According to RFC 4513 Section 3 [3], the forward slash (and other characters) MAY be escaped.
+        // Since Microsoft is a MUST, escape forward slash for all implementations. Also see discussion at [4].
+        // [1] https://docs.microsoft.com/en-us/windows/win32/adsi/search-filter-syntax
+        // [2] https://social.technet.microsoft.com/wiki/contents/articles/5312.active-directory-characters-to-escape.aspx
+        // [3] https://tools.ietf.org/search/rfc4515#section-3
+        // [4] https://lists.openldap.org/hyperkitty/list/openldap-technical@openldap.org/thread/3QPDDLO356ONSJM3JUKD7NMPOOIKIQ5T/
+        for (int i = 0; i < input.length(); i++) {
+            char c = input.charAt(i);
+            switch (c) {
+                case '\\':
+                    sb.append("\\5c");
+                    break;
+                case '/':
+                    sb.append("\\2f");
+                    break;
+                case '*':
+                    if (encodeWildcards) {
+                        sb.append("\\2a");
+                    }
+                    else {
+                        sb.append(c);
+                    }
+
+                    break;
+                case '(':
+                    sb.append("\\28");
+                    break;
+                case ')':
+                    sb.append("\\29");
+                    break;
+                case '\0':
+                    sb.append("\\00");
+                    break;
+                default:
+                    sb.append(c);
+            }
+        }
+        return sb.toString();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public String encodeForDN(String input) {
+        if( input == null ) {
+            return null;
+        }
+        // TODO: replace with DN codec
+        StringBuilder sb = new StringBuilder();
+        if ((input.length() > 0) && ((input.charAt(0) == ' ') || (input.charAt(0) == '#'))) {
+            sb.append('\\'); // add the leading backslash if needed
+        }
+        // See discussion of forward slash ('/') in encodeForLDAP()
+        for (int i = 0; i < input.length(); i++) {
+            char c = input.charAt(i);
+            switch (c) {
+            case '\\':
+                sb.append("\\\\");
+                break;
+            case '/':
+                sb.append("\\/");
+                break;
+            case ',':
+                sb.append("\\,");
+                break;
+            case '+':
+                sb.append("\\+");
+                break;
+            case '"':
+                sb.append("\\\"");
+                break;
+            case '<':
+                sb.append("\\<");
+                break;
+            case '>':
+                sb.append("\\>");
+                break;
+            case ';':
+                sb.append("\\;");
+                break;
+            default:
+                sb.append(c);
+            }
+        }
+        // add the trailing backslash if needed
+        if ((input.length() > 1) && (input.charAt(input.length() - 1) == ' ')) {
+            sb.insert(sb.length() - 1, '\\');
+        }
+        return sb.toString();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public String encodeForXPath(String input) {
+        if( input == null ) {
+            return null;
+        }
+        return htmlCodec.encode( IMMUNE_XPATH, input);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public String encodeForXML(String input) {
+        if( input == null ) {
+            return null;
+        }
+        return xmlCodec.encode( IMMUNE_XML, input);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public String encodeForXMLAttribute(String input) {
+        if( input == null ) {
+            return null;
+        }
+        return xmlCodec.encode( IMMUNE_XMLATTR, input);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public String encodeForURL(String input) throws EncodingException {
+        if ( input == null ) {
+            return null;
+        }
+        try {
+            return URLEncoder.encode(input, ESAPI.securityConfiguration().getCharacterEncoding());
+        } catch (UnsupportedEncodingException ex) {
+            throw new EncodingException("Encoding failure", "Character encoding not supported", ex);
+        } catch (Exception e) {
+            throw new EncodingException("Encoding failure", "Problem URL encoding input", e);
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public String decodeFromURL(String input) throws EncodingException {
+        if ( input == null ) {
+            return null;
+        }
+        String canonical = canonicalize(input);
+        try {
+            return URLDecoder.decode(canonical, ESAPI.securityConfiguration().getCharacterEncoding());
+        } catch (UnsupportedEncodingException ex) {
+            throw new EncodingException("Decoding failed", "Character encoding not supported", ex);
+        } catch (Exception e) {
+            throw new EncodingException("Decoding failed", "Problem URL decoding input", e);
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public String encodeForBase64(byte[] input, boolean wrap) {
+        if ( input == null ) {
+            return null;
+        }
+        int options = 0;
+        if ( !wrap ) {
+            options |= Base64.DONT_BREAK_LINES;
+        }
+        return Base64.encodeBytes(input, options);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public byte[] decodeFromBase64(String input) throws IOException {
+        if ( input == null ) {
+            return null;
+        }
+        return Base64.decode( input );
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * This will extract each piece of a URI according to parse zone as specified in <a href="https://www.ietf.org/rfc/rfc3986.txt">RFC-3986</a> section 3,
+     * and it will construct a canonicalized String representing a version of the URI that is safe to
+     * run regex against.
+     *
+     * @param dirtyUri
+     * @return Canonicalized URI string.
+     * @throws IntrusionException
+     */
+    public String getCanonicalizedURI(URI dirtyUri) throws IntrusionException{
+
+//        From RFC-3986 section 3
+//          URI         = scheme ":" hier-part [ "?" query ] [ "#" fragment ]
 //
-//	    	      hier-part   = "//" authority path-abempty
-//	    	                  / path-absolute
-//	    	                  / path-rootless
-//	    	                  / path-empty
-		
-//		   The following are two example URIs and their component parts:
+//                  hier-part   = "//" authority path-abempty
+//                              / path-absolute
+//                              / path-rootless
+//                              / path-empty
+
+//           The following are two example URIs and their component parts:
 //
-//		         foo://example.com:8042/over/there?name=ferret#nose
-//		         \_/   \______________/\_________/ \_________/ \__/
-//		          |           |            |            |        |
-//		       scheme     authority       path        query   fragment
-//		          |   _____________________|__
-//		         / \ /                        \
-//		         urn:example:animal:ferret:nose
-		Map<UriSegment, String> parseMap = new EnumMap<UriSegment, String>(UriSegment.class);
-		parseMap.put(UriSegment.SCHEME, dirtyUri.getScheme());
-		//authority   = [ userinfo "@" ] host [ ":" port ]
-		parseMap.put(UriSegment.AUTHORITY, dirtyUri.getRawAuthority());
-		parseMap.put(UriSegment.SCHEMSPECIFICPART, dirtyUri.getRawSchemeSpecificPart());
-		parseMap.put(UriSegment.HOST, dirtyUri.getHost());
-		//if port is undefined, it will return -1
-		Integer port = new Integer(dirtyUri.getPort());
-		parseMap.put(UriSegment.PORT, port == -1 ? "": port.toString());
-		parseMap.put(UriSegment.PATH, dirtyUri.getRawPath());
-		parseMap.put(UriSegment.QUERY, dirtyUri.getRawQuery());
-		parseMap.put(UriSegment.FRAGMENT, dirtyUri.getRawFragment());
-		
-		//Now we canonicalize each part and build our string.  
-		StringBuilder sb = new StringBuilder();
-		
-		//Replace all the items in the map with canonicalized versions.
-		
-		Set<UriSegment> set = parseMap.keySet();
-		
-		SecurityConfiguration sg = ESAPI.securityConfiguration();
-		boolean allowMixed = sg.getBooleanProp("Encoder.AllowMixedEncoding");
-		boolean allowMultiple = sg.getBooleanProp("Encoder.AllowMultipleEncoding");
-		for(UriSegment seg: set){
-			String value = canonicalize(parseMap.get(seg), allowMultiple, allowMixed);
-			value = value == null ? "" : value;
-			//In the case of a uri query, we need to break up and canonicalize the internal parts of the query.
-			if(seg == UriSegment.QUERY && null != parseMap.get(seg)){
-				StringBuilder qBuilder = new StringBuilder();
-				try {
-					Map<String, List<String>> canonicalizedMap = this.splitQuery(dirtyUri);
-					Set<Entry<String, List<String>>> query = canonicalizedMap.entrySet();
-					Iterator<Entry<String, List<String>>> i = query.iterator();
-					while(i.hasNext()){
-						Entry<String, List<String>> e = i.next(); 
-						String key = e.getKey();
-						String qVal = "";
-						List<String> list = e.getValue();
-						if(!list.isEmpty()){
-							qVal = list.get(0);
-						}
-						qBuilder.append(key)
-						.append("=")
-						.append(qVal);
-						
-						if(i.hasNext()){
-							qBuilder.append("&");
-						}
-					}
-					value = qBuilder.toString();
-				} catch (UnsupportedEncodingException e) {
-					logger.debug(Logger.EVENT_FAILURE, "decoding error when parsing [" + dirtyUri.toString() + "]");
-				}
-			}
-			//Check if the port is -1, if it is, omit it from the output.
-			if(seg == UriSegment.PORT){
-				if("-1" == parseMap.get(seg)){
-					value = "";
-				}
-			}
-			parseMap.put(seg, value );
-		}
-		
-		return buildUrl(parseMap);
-	}
-	
-	/**
-	 * All the parts should be canonicalized by this point.  This is straightforward assembly.  
-	 * 
-	 * @param parseMap The parts of the URL to put back together.
-	 * @return The canonicalized URL.
-	 */
-	protected String buildUrl(Map<UriSegment, String> parseMap){
-		StringBuilder sb = new StringBuilder();
-		sb.append(parseMap.get(UriSegment.SCHEME))
-		.append("://")
-		//can't use SCHEMESPECIFICPART for this, because we need to canonicalize all the parts of the query.
-		//USERINFO is also deprecated.  So we technically have more than we need.  
-		.append(parseMap.get(UriSegment.AUTHORITY) == null || parseMap.get(UriSegment.AUTHORITY).equals("") ? "" : parseMap.get(UriSegment.AUTHORITY))
-		.append(parseMap.get(UriSegment.PATH) == null || parseMap.get(UriSegment.PATH).equals("") ? ""  : parseMap.get(UriSegment.PATH))
-		.append(parseMap.get(UriSegment.QUERY) == null || parseMap.get(UriSegment.QUERY).equals("") 
-				? "" : "?" + parseMap.get(UriSegment.QUERY))
-		.append((parseMap.get(UriSegment.FRAGMENT) == null) || parseMap.get(UriSegment.FRAGMENT).equals("")
-				? "": "#" + parseMap.get(UriSegment.FRAGMENT))
-		;
-		return sb.toString();
-	}
-	
-	public enum UriSegment {
-		AUTHORITY, SCHEME, SCHEMSPECIFICPART, USERINFO, HOST, PORT, PATH, QUERY, FRAGMENT
-	}
-	
-	
-	/**
-	 * The meat of this method was taken from StackOverflow:  http://stackoverflow.com/a/13592567/557153
-	 * It has been modified to return a canonicalized key and value pairing.  
-	 * 
-	 * @param uri The URI to analyze.
-	 * @return a map of canonicalized query parameters.  
-	 * @throws UnsupportedEncodingException
-	 */
-	public Map<String, List<String>> splitQuery(URI uri) throws UnsupportedEncodingException {
-	  final Map<String, List<String>> query_pairs = new LinkedHashMap<String, List<String>>();
-	  final String[] pairs = uri.getQuery().split("&");
-	  for (String pair : pairs) {
-	    final int idx = pair.indexOf("=");
-	    final String key = idx > 0 ? canonicalize(pair.substring(0, idx)) : pair;
-	    if (!query_pairs.containsKey(key)) {
-	      query_pairs.put(key, new LinkedList<String>());
-	    }
-	    final String value = idx > 0 && pair.length() > idx + 1 ? URLDecoder.decode(pair.substring(idx + 1), "UTF-8") : null;
-	    query_pairs.get(key).add(canonicalize(value));
-	  }
-	  return query_pairs;
-	}
+//                 foo://example.com:8042/over/there?name=ferret#nose
+//                 \_/   \______________/\_________/ \_________/ \__/
+//                  |           |            |            |        |
+//               scheme     authority       path        query   fragment
+//                  |   _____________________|__
+//                 / \ /                        \
+//                 urn:example:animal:ferret:nose
+        Map<UriSegment, String> parseMap = new EnumMap<UriSegment, String>(UriSegment.class);
+        parseMap.put(UriSegment.SCHEME, dirtyUri.getScheme());
+        //authority   = [ userinfo "@" ] host [ ":" port ]
+        parseMap.put(UriSegment.AUTHORITY, dirtyUri.getRawAuthority());
+        parseMap.put(UriSegment.SCHEMSPECIFICPART, dirtyUri.getRawSchemeSpecificPart());
+        parseMap.put(UriSegment.HOST, dirtyUri.getHost());
+        //if port is undefined, it will return -1
+        Integer port = new Integer(dirtyUri.getPort());
+        parseMap.put(UriSegment.PORT, port == -1 ? "": port.toString());
+        parseMap.put(UriSegment.PATH, dirtyUri.getRawPath());
+        parseMap.put(UriSegment.QUERY, dirtyUri.getRawQuery());
+        parseMap.put(UriSegment.FRAGMENT, dirtyUri.getRawFragment());
+
+        //Now we canonicalize each part and build our string.
+        StringBuilder sb = new StringBuilder();
+
+        //Replace all the items in the map with canonicalized versions.
+
+        Set<UriSegment> set = parseMap.keySet();
+
+        SecurityConfiguration sg = ESAPI.securityConfiguration();
+        boolean allowMixed = sg.getBooleanProp("Encoder.AllowMixedEncoding");
+        boolean allowMultiple = sg.getBooleanProp("Encoder.AllowMultipleEncoding");
+        for(UriSegment seg: set){
+            String value = canonicalize(parseMap.get(seg), allowMultiple, allowMixed);
+            value = value == null ? "" : value;
+            //In the case of a uri query, we need to break up and canonicalize the internal parts of the query.
+            if(seg == UriSegment.QUERY && null != parseMap.get(seg)){
+                StringBuilder qBuilder = new StringBuilder();
+                try {
+                    Map<String, List<String>> canonicalizedMap = this.splitQuery(dirtyUri);
+                    Set<Entry<String, List<String>>> query = canonicalizedMap.entrySet();
+                    Iterator<Entry<String, List<String>>> i = query.iterator();
+                    while(i.hasNext()){
+                        Entry<String, List<String>> e = i.next();
+                        String key = e.getKey();
+                        String qVal = "";
+                        List<String> list = e.getValue();
+                        if(!list.isEmpty()){
+                            qVal = list.get(0);
+                        }
+                        qBuilder.append(key)
+                        .append("=")
+                        .append(qVal);
+
+                        if(i.hasNext()){
+                            qBuilder.append("&");
+                        }
+                    }
+                    value = qBuilder.toString();
+                } catch (UnsupportedEncodingException e) {
+                    logger.debug(Logger.EVENT_FAILURE, "decoding error when parsing [" + dirtyUri.toString() + "]");
+                }
+            }
+            //Check if the port is -1, if it is, omit it from the output.
+            if(seg == UriSegment.PORT){
+                if("-1" == parseMap.get(seg)){
+                    value = "";
+                }
+            }
+            parseMap.put(seg, value );
+        }
+
+        return buildUrl(parseMap);
+    }
+
+    /**
+     * All the parts should be canonicalized by this point.  This is straightforward assembly.
+     *
+     * @param parseMap The parts of the URL to put back together.
+     * @return The canonicalized URL.
+     */
+    protected String buildUrl(Map<UriSegment, String> parseMap){
+        StringBuilder sb = new StringBuilder();
+        sb.append(parseMap.get(UriSegment.SCHEME))
+        .append("://")
+        //can't use SCHEMESPECIFICPART for this, because we need to canonicalize all the parts of the query.
+        //USERINFO is also deprecated.  So we technically have more than we need.
+        .append(parseMap.get(UriSegment.AUTHORITY) == null || parseMap.get(UriSegment.AUTHORITY).equals("") ? "" : parseMap.get(UriSegment.AUTHORITY))
+        .append(parseMap.get(UriSegment.PATH) == null || parseMap.get(UriSegment.PATH).equals("") ? ""  : parseMap.get(UriSegment.PATH))
+        .append(parseMap.get(UriSegment.QUERY) == null || parseMap.get(UriSegment.QUERY).equals("")
+                ? "" : "?" + parseMap.get(UriSegment.QUERY))
+        .append((parseMap.get(UriSegment.FRAGMENT) == null) || parseMap.get(UriSegment.FRAGMENT).equals("")
+                ? "": "#" + parseMap.get(UriSegment.FRAGMENT))
+        ;
+        return sb.toString();
+    }
+
+    public enum UriSegment {
+        AUTHORITY, SCHEME, SCHEMSPECIFICPART, USERINFO, HOST, PORT, PATH, QUERY, FRAGMENT
+    }
+
+
+    /**
+     * The meat of this method was taken from StackOverflow:  http://stackoverflow.com/a/13592567/557153
+     * It has been modified to return a canonicalized key and value pairing.
+     *
+     * @param uri The URI to analyze.
+     * @return a map of canonicalized query parameters.
+     * @throws UnsupportedEncodingException
+     */
+    public Map<String, List<String>> splitQuery(URI uri) throws UnsupportedEncodingException {
+      final Map<String, List<String>> query_pairs = new LinkedHashMap<String, List<String>>();
+      final String[] pairs = uri.getQuery().split("&");
+      for (String pair : pairs) {
+        final int idx = pair.indexOf("=");
+        final String key = idx > 0 ? canonicalize(pair.substring(0, idx)) : pair;
+        if (!query_pairs.containsKey(key)) {
+          query_pairs.put(key, new LinkedList<String>());
+        }
+        final String value = idx > 0 && pair.length() > idx + 1 ? URLDecoder.decode(pair.substring(idx + 1), "UTF-8") : null;
+        query_pairs.get(key).add(canonicalize(value));
+      }
+      return query_pairs;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public String encodeForJSON(String input) {
+        if( input == null ) {
+            return null;
+        }
+        return jsonCodec.encode(IMMUNE_JSON, input);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public String decodeFromJSON(String input) {
+        if( input == null ) {
+            return null;
+        }
+        return jsonCodec.decode(input);
+    }
+
 }
diff --git a/src/main/java/org/owasp/esapi/reference/DefaultExecutor.java b/src/main/java/org/owasp/esapi/reference/DefaultExecutor.java
index eabb840..619e633 100644
--- a/src/main/java/org/owasp/esapi/reference/DefaultExecutor.java
+++ b/src/main/java/org/owasp/esapi/reference/DefaultExecutor.java
@@ -1,15 +1,15 @@
 /**
  * OWASP Enterprise Security API (ESAPI)
- * 
+ *
  * This file is part of the Open Web Application Security Project (OWASP)
  * Enterprise Security API (ESAPI) project. For details, please see
  * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
  *
  * Copyright (c) 2007 - The OWASP Foundation
- * 
+ *
  * The ESAPI is published by OWASP under the BSD license. You should read and accept the
  * LICENSE before you use, modify, and/or redistribute this software.
- * 
+ *
  * @author Jeff Williams <a href="http://www.aspectsecurity.com">Aspect Security</a>
  * @created 2007
  */
@@ -34,10 +34,10 @@ import org.owasp.esapi.errors.ExecutorException;
 
 /**
  * Reference implementation of the Executor interface. This implementation is very restrictive. Commands must exactly
- * equal the canonical path to an executable on the system. 
- * 
+ * equal the canonical path to an executable on the system.
+ *
  * <p>Valid characters for parameters are codec dependent, but will usually only include alphanumeric, forward-slash, and dash.</p>
- * 
+ *
  * @author Jeff Williams (jeff.williams .at. aspectsecurity.com) <a href="http://www.aspectsecurity.com">Aspect Security</a>
  * @since June 1, 2007
  * @see org.owasp.esapi.Executor
@@ -60,29 +60,29 @@ public class DefaultExecutor implements org.owasp.esapi.Executor {
     private final Logger logger = ESAPI.getLogger("Executor");
     private Codec codec = null;
     //private final int MAX_SYSTEM_COMMAND_LENGTH = 2500;
-    
+
 
     /**
      * Instantiate a new Executor
      */
     private DefaultExecutor() {
-		if ( System.getProperty("os.name").indexOf("Windows") != -1 ) {
-			logger.warning( Logger.SECURITY_SUCCESS, "Using WindowsCodec for Executor. If this is not running on Windows this could allow injection" );
-			codec = new WindowsCodec();
-		} else {
-			logger.warning( Logger.SECURITY_SUCCESS, "Using UnixCodec for Executor. If this is not running on Unix this could allow injection" );
-			codec = new UnixCodec();
-		}
+        if ( System.getProperty("os.name").indexOf("Windows") != -1 ) {
+            logger.warning( Logger.SECURITY_SUCCESS, "Using WindowsCodec for Executor. If this is not running on Windows this could allow injection" );
+            codec = new WindowsCodec();
+        } else {
+            logger.warning( Logger.SECURITY_SUCCESS, "Using UnixCodec for Executor. If this is not running on Unix this could allow injection" );
+            codec = new UnixCodec();
+        }
     }
 
     /**
      * {@inheritDoc}
      */
     public ExecuteResult executeSystemCommand(File executable, List params) throws ExecutorException {
-    	File workdir = ESAPI.securityConfiguration().getWorkingDirectory();
-    	boolean logParams = false;
-    	boolean redirectErrorStream = false;
-    	return executeSystemCommand( executable, params, workdir, codec, logParams, redirectErrorStream );
+        File workdir = ESAPI.securityConfiguration().getWorkingDirectory();
+        boolean logParams = false;
+        boolean redirectErrorStream = false;
+        return executeSystemCommand( executable, params, workdir, codec, logParams, redirectErrorStream );
     }
 
     /**
@@ -100,18 +100,18 @@ public class DefaultExecutor implements org.owasp.esapi.Executor {
             if (!executable.exists()) {
                 throw new ExecutorException("Execution failure", "No such executable: " + executable);
             }
-            
+
             // executable must use canonical path
             if ( !executable.isAbsolute() ) {
                 throw new ExecutorException("Execution failure", "Attempt to invoke an executable using a non-absolute path: " + executable);
             }
-            
+
             // executable must use canonical path
             if ( !executable.getPath().equals( executable.getCanonicalPath() ) ) {
-            	throw new ExecutorException("Execution failure", "Attempt to invoke an executable using a non-canonical path: " + executable);
-        	}
-            
-            // exact, absolute, canonical path to executable must be listed in ESAPI configuration 
+                throw new ExecutorException("Execution failure", "Attempt to invoke an executable using a non-canonical path: " + executable);
+            }
+
+            // exact, absolute, canonical path to executable must be listed in ESAPI configuration
             List approved = ESAPI.securityConfiguration().getAllowedExecutables();
             if (!approved.contains(executable.getPath())) {
                 throw new ExecutorException("Execution failure", "Attempt to invoke executable that is not listed as an approved executable in ESAPI configuration: " + executable.getPath() + " not listed in " + approved );
@@ -119,22 +119,22 @@ public class DefaultExecutor implements org.owasp.esapi.Executor {
 
             // escape any special characters in the parameters
             for ( int i = 0; i < params.size(); i++ ) {
-            	String param = (String)params.get(i);
-            	params.set( i, ESAPI.encoder().encodeForOS(codec, param));
+                String param = (String)params.get(i);
+                params.set( i, ESAPI.encoder().encodeForOS(codec, param));
             }
-            
+
             // working directory must exist
             if (!workdir.exists()) {
                 throw new ExecutorException("Execution failure", "No such working directory for running executable: " + workdir.getPath());
             }
-            
+
             // set the command into the list and create command array
             params.add(0, executable.getCanonicalPath());
 
             // Legacy - this is how to implement in Java 1.4
             // String[] command = (String[])params.toArray( new String[0] );
             // Process process = Runtime.getRuntime().exec(command, new String[0], workdir);
-            
+
             // The following is host to implement in Java 1.5+
             ProcessBuilder pb = new ProcessBuilder(params);
             Map env = pb.environment();
@@ -143,9 +143,9 @@ public class DefaultExecutor implements org.owasp.esapi.Executor {
             pb.redirectErrorStream(redirectErrorStream);
 
             if ( logParams ) {
-            	logger.debug(Logger.SECURITY_SUCCESS, "Initiating executable: " + executable + " " + params + " in " + workdir);
+                logger.debug(Logger.SECURITY_SUCCESS, "Initiating executable: " + executable + " " + params + " in " + workdir);
             } else {
-            	logger.debug(Logger.SECURITY_SUCCESS, "Initiating executable: " + executable + " [sensitive parameters obscured] in " + workdir);
+                logger.debug(Logger.SECURITY_SUCCESS, "Initiating executable: " + executable + " [sensitive parameters obscured] in " + workdir);
             }
 
             final StringBuilder outputBuffer = new StringBuilder();
@@ -154,37 +154,37 @@ public class DefaultExecutor implements org.owasp.esapi.Executor {
             try {
                 ReadThread errorReader;
                 if (!redirectErrorStream) {
-                	errorReader = new ReadThread(process.getErrorStream(), errorsBuffer);
-                	errorReader.start();
+                    errorReader = new ReadThread(process.getErrorStream(), errorsBuffer);
+                    errorReader.start();
                 } else {
-                	errorReader = null;
+                    errorReader = null;
+                }
+                readStream( process.getInputStream(), outputBuffer );
+                if (errorReader != null) {
+                    errorReader.join();
+                    if (errorReader.exception != null) {
+                        throw errorReader.exception;
+                    }
                 }
-            	readStream( process.getInputStream(), outputBuffer );
-            	if (errorReader != null) {
-            		errorReader.join();
-            		if (errorReader.exception != null) {
-            			throw errorReader.exception;
-            		}
-            	}
-            	process.waitFor();
+                process.waitFor();
             } catch (Throwable e) {
-            	process.destroy();
-            	throw new ExecutorException("Execution failure", "Exception thrown during execution of system command: " + e.getMessage(), e);
+                process.destroy();
+                throw new ExecutorException("Execution failure", "Exception thrown during execution of system command: " + e.getMessage(), e);
             }
 
             String output = outputBuffer.toString();
             String errors = errorsBuffer.toString();
             int exitValue = process.exitValue();
             if ( errors != null && errors.length() > 0 ) {
-            	String logErrors = errors;
-            	final int MAX_LEN = 256;
-            	if (logErrors.length() > MAX_LEN) {
-            		logErrors = logErrors.substring(0, MAX_LEN) + "(truncated at "+MAX_LEN+" characters)";
-            	}
-            	logger.warning( Logger.SECURITY_SUCCESS, "Error during system command: " + logErrors );
+                String logErrors = errors;
+                final int MAX_LEN = 256;
+                if (logErrors.length() > MAX_LEN) {
+                    logErrors = logErrors.substring(0, MAX_LEN) + "(truncated at "+MAX_LEN+" characters)";
+                }
+                logger.warning( Logger.SECURITY_SUCCESS, "Error during system command: " + logErrors );
             }
             if ( exitValue != 0 ) {
-            	logger.warning( Logger.EVENT_FAILURE, "System command exited with non-zero status: " + exitValue );
+                logger.warning( Logger.EVENT_FAILURE, "System command exited with non-zero status: " + exitValue );
             }
 
             logger.debug(Logger.SECURITY_SUCCESS, "System command complete");
@@ -196,38 +196,38 @@ public class DefaultExecutor implements org.owasp.esapi.Executor {
 
     /**
      * readStream reads lines from an input stream and returns all of them in a single string
-     * 
+     *
      * @param is
-     * 			input stream to read from
+     *             input stream to read from
      * @throws IOException
      */
     private static void readStream( InputStream is, StringBuilder sb ) throws IOException {
-	    InputStreamReader isr = new InputStreamReader(is);
-	    BufferedReader br = new BufferedReader(isr);
-	    String line;
-	    while ((line = br.readLine()) != null) {
-	        sb.append(line).append('\n');
-	    }
+        InputStreamReader isr = new InputStreamReader(is);
+        BufferedReader br = new BufferedReader(isr);
+        String line;
+        while ((line = br.readLine()) != null) {
+            sb.append(line).append('\n');
+        }
     }
-    
+
     private static class ReadThread extends Thread {
-    	volatile IOException exception;
-    	private final InputStream stream;
-    	private final StringBuilder buffer;
-
-    	ReadThread(InputStream stream, StringBuilder buffer) {
-    		this.stream = stream;
-    		this.buffer = buffer;
-    	}
-
-    	@Override
-		public void run() {
-    		try {
-    			readStream(stream, buffer);
-    		} catch (IOException e) {
-    			exception = e;
-    		}
-    	}
+        volatile IOException exception;
+        private final InputStream stream;
+        private final StringBuilder buffer;
+
+        ReadThread(InputStream stream, StringBuilder buffer) {
+            this.stream = stream;
+            this.buffer = buffer;
+        }
+
+        @Override
+        public void run() {
+            try {
+                readStream(stream, buffer);
+            } catch (IOException e) {
+                exception = e;
+            }
+        }
 
     }
 
diff --git a/src/main/java/org/owasp/esapi/reference/DefaultHTTPUtilities.java b/src/main/java/org/owasp/esapi/reference/DefaultHTTPUtilities.java
index a9212f2..53fe613 100644
--- a/src/main/java/org/owasp/esapi/reference/DefaultHTTPUtilities.java
+++ b/src/main/java/org/owasp/esapi/reference/DefaultHTTPUtilities.java
@@ -97,7 +97,7 @@ public class DefaultHTTPUtilities implements org.owasp.esapi.HTTPUtilities {
         return instance;
     }
 
-	/**
+    /**
      * Defines the ThreadLocalRequest to store the current request for this thread.
      */
     private class ThreadLocalRequest extends InheritableThreadLocal<HttpServletRequest> {
@@ -107,7 +107,7 @@ public class DefaultHTTPUtilities implements org.owasp.esapi.HTTPUtilities {
         }
 
         public HttpServletRequest initialValue() {
-        	return null;
+            return null;
         }
 
         public void setRequest(HttpServletRequest newRequest) {
@@ -115,7 +115,7 @@ public class DefaultHTTPUtilities implements org.owasp.esapi.HTTPUtilities {
         }
     }
 
-	/**
+    /**
      * Defines the ThreadLocalResponse to store the current response for this thread.
      */
     private class ThreadLocalResponse extends InheritableThreadLocal<HttpServletResponse> {
@@ -125,7 +125,7 @@ public class DefaultHTTPUtilities implements org.owasp.esapi.HTTPUtilities {
         }
 
         public HttpServletResponse initialValue() {
-        	return null;
+            return null;
         }
 
         public void setResponse(HttpServletResponse newResponse) {
@@ -134,10 +134,10 @@ public class DefaultHTTPUtilities implements org.owasp.esapi.HTTPUtilities {
     }
 
     /** The logger. */
-	private final Logger logger = ESAPI.getLogger("HTTPUtilities");
+    private final Logger logger = ESAPI.getLogger("HTTPUtilities");
 
     /** The max bytes. */
-	static final int maxBytes = ESAPI.securityConfiguration().getAllowedFileUploadSize();
+    static final int maxBytes = ESAPI.securityConfiguration().getAllowedFileUploadSize();
 
 
     /*
@@ -147,7 +147,7 @@ public class DefaultHTTPUtilities implements org.owasp.esapi.HTTPUtilities {
      */
     private ThreadLocalRequest currentRequest = new ThreadLocalRequest();
 
-	/*
+    /*
      * The currentResponse ThreadLocal variable is used to make the currentResponse available to any call in any part of an
      * application. This enables API's for actions that require the response to be much simpler. For example, the logout()
      * method in the Authenticator class requires the currentResponse to kill the Session ID cookie.
@@ -156,29 +156,29 @@ public class DefaultHTTPUtilities implements org.owasp.esapi.HTTPUtilities {
 
 
 
-	/**
+    /**
      * No arg constructor.
      */
     public DefaultHTTPUtilities() {
-	}
+    }
 
 
-	/**
-	 * {@inheritDoc}
+    /**
+     * {@inheritDoc}
      * This implementation uses a custom "set-cookie" header rather than Java's
      * cookie interface which doesn't allow the use of HttpOnly. Configure the
      * HttpOnly and Secure settings in ESAPI.properties.
-	 */
-	public void addCookie( Cookie cookie ) {
-		addCookie( getCurrentResponse(), cookie );
+     */
+    public void addCookie( Cookie cookie ) {
+        addCookie( getCurrentResponse(), cookie );
     }
 
     /**
-	 * {@inheritDoc}
+     * {@inheritDoc}
      * This implementation uses a custom "set-cookie" header rather than Java's
      * cookie interface which doesn't allow the use of HttpOnly. Configure the
      * HttpOnly and Secure settings in ESAPI.properties.
-	 */
+     */
     public void addCookie(HttpServletResponse response, Cookie cookie) {
         String name = cookie.getName();
         String value = cookie.getValue();
@@ -195,14 +195,14 @@ public class DefaultHTTPUtilities implements org.owasp.esapi.HTTPUtilities {
 
         // if there are no errors, then set the cookie either with a header or normally
         if (errors.size() == 0) {
-        	if ( ESAPI.securityConfiguration().getForceHttpOnlyCookies() ) {
-	            String header = createCookieHeader(cookieName, cookieValue, maxAge, domain, path, secure);
-	            addHeader(response, "Set-Cookie", header);
-        	} else {
+            if ( ESAPI.securityConfiguration().getForceHttpOnlyCookies() ) {
+                String header = createCookieHeader(cookieName, cookieValue, maxAge, domain, path, secure);
+                addHeader(response, "Set-Cookie", header);
+            } else {
                 // Issue 23 - If the ESAPI Configuration is set to force secure cookies, force the secure flag on the cookie before setting it
                 cookie.setSecure( secure || ESAPI.securityConfiguration().getForceSecureCookies() );
-        		response.addCookie(cookie);
-        	}
+                response.addCookie(cookie);
+            }
             return;
         }
         logger.warning(Logger.SECURITY_FAILURE, "Attempt to add unsafe data to cookie (skip mode). Skipping cookie and continuing.");
@@ -210,32 +210,32 @@ public class DefaultHTTPUtilities implements org.owasp.esapi.HTTPUtilities {
 
 
 
-	/**
-	 * {@inheritDoc}
-	 */
-	public String addCSRFToken(String href) {
-		User user = ESAPI.authenticator().getCurrentUser();
-		if (user.isAnonymous()) {
-			return href;
-		}
+    /**
+     * {@inheritDoc}
+     */
+    public String addCSRFToken(String href) {
+        User user = ESAPI.authenticator().getCurrentUser();
+        if (user.isAnonymous()) {
+            return href;
+        }
 
-		// if there are already parameters append with &, otherwise append with ?
-		String token = CSRF_TOKEN_NAME + "=" + user.getCSRFToken();
-		return href.indexOf( '?') != -1 ? href + "&" + token : href + "?" + token;
-	}
+        // if there are already parameters append with &, otherwise append with ?
+        String token = CSRF_TOKEN_NAME + "=" + user.getCSRFToken();
+        return href.indexOf( '?') != -1 ? href + "&" + token : href + "?" + token;
+    }
 
     /**
-	 * {@inheritDoc}
+     * {@inheritDoc}
      */
     public void addHeader(String name, String value) {
-    	addHeader( getCurrentResponse(), name, value );
+        addHeader( getCurrentResponse(), name, value );
     }
 
     /**
-	 * {@inheritDoc}
+     * {@inheritDoc}
      */
     public void addHeader(HttpServletResponse response, String name, String value) {
-    	SecurityConfiguration sc = ESAPI.securityConfiguration();
+        SecurityConfiguration sc = ESAPI.securityConfiguration();
         try {
             String strippedName = StringUtilities.replaceLinearWhiteSpace(name);
             String strippedValue = StringUtilities.replaceLinearWhiteSpace(value);
@@ -247,109 +247,109 @@ public class DefaultHTTPUtilities implements org.owasp.esapi.HTTPUtilities {
         }
     }
 
-	/**
-	 * {@inheritDoc}
-	 */
-	public void assertSecureChannel() throws AccessControlException {
-    	assertSecureChannel( getCurrentRequest() );
-    }
-
-	/**
-	 * {@inheritDoc}
-	 * 
-	 * This implementation ignores the built-in isSecure() method
-	 * and uses the URL to determine if the request was transmitted over SSL.
-	 * This is because SSL may have been terminated somewhere outside the
-	 * container.
-	 */
-	public void assertSecureChannel(HttpServletRequest request) throws AccessControlException {
-	    if ( request == null ) {
-	    	throw new AccessControlException( "Insecure request received", "HTTP request was null" );
-	    }
-	    StringBuffer sb = request.getRequestURL();
-	    if ( sb == null ) {
-	    	throw new AccessControlException( "Insecure request received", "HTTP request URL was null" );
-	    }
-	    String url = sb.toString();
-	    if ( !url.startsWith( "https" ) ) {
-	    	throw new AccessControlException( "Insecure request received", "HTTP request did not use SSL" );
-	    }
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	public void assertSecureRequest() throws AccessControlException {
-    	assertSecureRequest( getCurrentRequest() );
-    }
-
-	/**
-	 * {@inheritDoc}
-     */
-	public void assertSecureRequest(HttpServletRequest request) throws AccessControlException {
-		assertSecureChannel( request );
-		String receivedMethod = request.getMethod();
-		String requiredMethod = "POST";
-		if ( !receivedMethod.equals( requiredMethod ) ) {
-			throw new AccessControlException( "Insecure request received", "Received request using " + receivedMethod + " when only " + requiredMethod + " is allowed" );
-		}
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	public HttpSession changeSessionIdentifier() throws AuthenticationException {
-    	return changeSessionIdentifier( getCurrentRequest() );
-    }
-
-	/**
-	 * {@inheritDoc}
-     */
-	public HttpSession changeSessionIdentifier(HttpServletRequest request) throws AuthenticationException {
-
-		// get the current session
-		HttpSession oldSession = request.getSession();
-
-		// make a copy of the session content
-		Map<String,Object> temp = new ConcurrentHashMap<String,Object>();
-		Enumeration e = oldSession.getAttributeNames();
-		while (e != null && e.hasMoreElements()) {
-			String name = (String) e.nextElement();
-			Object value = oldSession.getAttribute(name);
-			temp.put(name, value);
-		}
-
-		// kill the old session and create a new one
-		oldSession.invalidate();
-		HttpSession newSession = request.getSession();
-		User user = ESAPI.authenticator().getCurrentUser();
-		user.addSession( newSession );
-		user.removeSession( oldSession );
-
-		// copy back the session content
+    /**
+     * {@inheritDoc}
+     */
+    public void assertSecureChannel() throws AccessControlException {
+        assertSecureChannel( getCurrentRequest() );
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * This implementation ignores the built-in isSecure() method
+     * and uses the URL to determine if the request was transmitted over SSL.
+     * This is because SSL may have been terminated somewhere outside the
+     * container.
+     */
+    public void assertSecureChannel(HttpServletRequest request) throws AccessControlException {
+        if ( request == null ) {
+            throw new AccessControlException( "Insecure request received", "HTTP request was null" );
+        }
+        StringBuffer sb = request.getRequestURL();
+        if ( sb == null ) {
+            throw new AccessControlException( "Insecure request received", "HTTP request URL was null" );
+        }
+        String url = sb.toString();
+        if ( !url.startsWith( "https" ) ) {
+            throw new AccessControlException( "Insecure request received", "HTTP request did not use SSL" );
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void assertSecureRequest() throws AccessControlException {
+        assertSecureRequest( getCurrentRequest() );
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void assertSecureRequest(HttpServletRequest request) throws AccessControlException {
+        assertSecureChannel( request );
+        String receivedMethod = request.getMethod();
+        String requiredMethod = "POST";
+        if ( !receivedMethod.equals( requiredMethod ) ) {
+            throw new AccessControlException( "Insecure request received", "Received request using " + receivedMethod + " when only " + requiredMethod + " is allowed" );
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public HttpSession changeSessionIdentifier() throws AuthenticationException {
+        return changeSessionIdentifier( getCurrentRequest() );
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public HttpSession changeSessionIdentifier(HttpServletRequest request) throws AuthenticationException {
+
+        // get the current session
+        HttpSession oldSession = request.getSession();
+
+        // make a copy of the session content
+        Map<String,Object> temp = new ConcurrentHashMap<String,Object>();
+        Enumeration e = oldSession.getAttributeNames();
+        while (e != null && e.hasMoreElements()) {
+            String name = (String) e.nextElement();
+            Object value = oldSession.getAttribute(name);
+            temp.put(name, value);
+        }
+
+        // kill the old session and create a new one
+        oldSession.invalidate();
+        HttpSession newSession = request.getSession();
+        User user = ESAPI.authenticator().getCurrentUser();
+        user.addSession( newSession );
+        user.removeSession( oldSession );
+
+        // copy back the session content
       for (Map.Entry<String, Object> stringObjectEntry : temp.entrySet())
       {
          newSession.setAttribute(stringObjectEntry.getKey(), stringObjectEntry.getValue());
-		}
-		return newSession;
-	}
+        }
+        return newSession;
+    }
 
-	/**
-	 * {@inheritDoc}
-	 */
+    /**
+     * {@inheritDoc}
+     */
     public void clearCurrent() {
-		currentRequest.set(null);
-		currentResponse.set(null);
-	}
+        currentRequest.set(null);
+        currentResponse.set(null);
+    }
 
-	private String createCookieHeader(String name, String value, int maxAge, String domain, String path, boolean secure) {
+    private String createCookieHeader(String name, String value, int maxAge, String domain, String path, boolean secure) {
         // create the special cookie header instead of creating a Java cookie
         // Set-Cookie:<name>=<value>[; <name>=<value>][; expires=<date>][;
         // domain=<domain_name>][; path=<some_path>][; secure][;HttpOnly]
         String header = name + "=" + value;
-		if (maxAge >= 0) {
-			header += "; Max-Age=" + maxAge;
-		}
+        if (maxAge >= 0) {
+            header += "; Max-Age=" + maxAge;
+        }
         if (domain != null) {
             header += "; Domain=" + domain;
         }
@@ -365,486 +365,486 @@ public class DefaultHTTPUtilities implements org.owasp.esapi.HTTPUtilities {
         return header;
     }
 
-	/**
-	 * {@inheritDoc}
-	 */
-	public String decryptHiddenField(String encrypted) {
-    	try {
-    		return decryptString(encrypted);
-    	} catch( EncryptionException e ) {
-    		throw new IntrusionException("Invalid request","Tampering detected. Hidden field data did not decrypt properly.", e);
-    	}
+    /**
+     * {@inheritDoc}
+     */
+    public String decryptHiddenField(String encrypted) {
+        try {
+            return decryptString(encrypted);
+        } catch( EncryptionException e ) {
+            throw new IntrusionException("Invalid request","Tampering detected. Hidden field data did not decrypt properly.", e);
+        }
     }
 
-	/**
-	 * {@inheritDoc}
-	 */
-	public Map<String,String> decryptQueryString(String encrypted) throws EncryptionException {
+    /**
+     * {@inheritDoc}
+     */
+    public Map<String,String> decryptQueryString(String encrypted) throws EncryptionException {
         String plaintext = decryptString(encrypted);
-		return queryToMap(plaintext);
-	}
+        return queryToMap(plaintext);
+    }
 
-	/**
-	 * {@inheritDoc}
-	 */
-	public Map<String,String> decryptStateFromCookie() throws EncryptionException {
-		return decryptStateFromCookie( getCurrentRequest() );
+    /**
+     * {@inheritDoc}
+     */
+    public Map<String,String> decryptStateFromCookie() throws EncryptionException {
+        return decryptStateFromCookie( getCurrentRequest() );
     }
 
-	/**
-	 * {@inheritDoc}
+    /**
+     * {@inheritDoc}
      *
      * @param request
      */
     public Map<String,String> decryptStateFromCookie(HttpServletRequest request) throws EncryptionException {
-    	try {
-    		String encrypted = getCookie( request, ESAPI_STATE );
-    		if ( encrypted == null ) return new HashMap<String,String>();
-    		String plaintext = decryptString(encrypted);
-    		return queryToMap( plaintext );
-    	} catch( ValidationException e ) {
-        	return null;
-    	}
-    }
-
-	/**
-	 * {@inheritDoc}
-	 */
-	public String encryptHiddenField(String value) throws EncryptionException {
-    	return encryptString(value);
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	public String encryptQueryString(String query) throws EncryptionException {
-	    return encryptString(query);
-	}
-
-	/**
-	 * {@inheritDoc}
+        try {
+            String encrypted = getCookie( request, ESAPI_STATE );
+            if ( encrypted == null ) return new HashMap<String,String>();
+            String plaintext = decryptString(encrypted);
+            return queryToMap( plaintext );
+        } catch( ValidationException e ) {
+            return null;
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public String encryptHiddenField(String value) throws EncryptionException {
+        return encryptString(value);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public String encryptQueryString(String query) throws EncryptionException {
+        return encryptString(query);
+    }
+
+    /**
+     * {@inheritDoc}
      */
     public void encryptStateInCookie(HttpServletResponse response, Map<String,String> cleartext) throws EncryptionException {
-    	StringBuilder sb = new StringBuilder();
-    	Iterator i = cleartext.entrySet().iterator();
-    	while ( i.hasNext() ) {
-    		try {
-	    		Map.Entry entry = (Map.Entry)i.next();
-	    		
-	    		    // What do these need to be URL encoded? They are encrypted!
-	    		String name = ESAPI.encoder().encodeForURL( entry.getKey().toString() );
-	    		String value = ESAPI.encoder().encodeForURL( entry.getValue().toString() );
+        StringBuilder sb = new StringBuilder();
+        Iterator i = cleartext.entrySet().iterator();
+        while ( i.hasNext() ) {
+            try {
+                Map.Entry entry = (Map.Entry)i.next();
+
+                    // What do these need to be URL encoded? They are encrypted!
+                String name = ESAPI.encoder().encodeForURL( entry.getKey().toString() );
+                String value = ESAPI.encoder().encodeForURL( entry.getValue().toString() );
              sb.append(name).append("=").append(value);
-	    		if ( i.hasNext() ) sb.append( "&" );
-    		} catch( EncodingException e ) {
-    			logger.error(Logger.SECURITY_FAILURE, "Problem encrypting state in cookie - skipping entry", e );
-    		}
-    	}
+                if ( i.hasNext() ) sb.append( "&" );
+            } catch( EncodingException e ) {
+                logger.error(Logger.SECURITY_FAILURE, "Problem encrypting state in cookie - skipping entry", e );
+            }
+        }
 
-		String encrypted = encryptString(sb.toString());
+        String encrypted = encryptString(sb.toString());
 
-		if ( encrypted.length() > (MAX_COOKIE_LEN ) ) {
-			logger.error(Logger.SECURITY_FAILURE, "Problem encrypting state in cookie - skipping entry");
-			throw new EncryptionException("Encryption failure", "Encrypted cookie state of " + encrypted.length() + " longer than allowed " + MAX_COOKIE_LEN );
-		}
+        if ( encrypted.length() > (MAX_COOKIE_LEN ) ) {
+            logger.error(Logger.SECURITY_FAILURE, "Problem encrypting state in cookie - skipping entry");
+            throw new EncryptionException("Encryption failure", "Encrypted cookie state of " + encrypted.length() + " longer than allowed " + MAX_COOKIE_LEN );
+        }
 
-    	Cookie cookie = new Cookie( ESAPI_STATE, encrypted );
-    	addCookie( response, cookie );
+        Cookie cookie = new Cookie( ESAPI_STATE, encrypted );
+        addCookie( response, cookie );
     }
 
-	/**
-	 * {@inheritDoc}
-	 */
-	public void encryptStateInCookie( Map<String,String> cleartext ) throws EncryptionException {
-		encryptStateInCookie( getCurrentResponse(), cleartext );
+    /**
+     * {@inheritDoc}
+     */
+    public void encryptStateInCookie( Map<String,String> cleartext ) throws EncryptionException {
+        encryptStateInCookie( getCurrentResponse(), cleartext );
     }
 
 
-	/**
-	 * {@inheritDoc}
-	 */
-	public String getCookie( HttpServletRequest request, String name ) throws ValidationException {
+    /**
+     * {@inheritDoc}
+     */
+    public String getCookie( HttpServletRequest request, String name ) throws ValidationException {
         Cookie c = getFirstCookie( request, name );
         SecurityConfiguration sc = ESAPI.securityConfiguration();
         if ( c == null ) return null;
-		String value = c.getValue();
-		return ESAPI.validator().getValidInput("HTTP cookie value: " + value, value, "HTTPCookieValue", sc.getIntProp("HttpUtilities.MaxHeaderValueSize"), false);
-	}
+        String value = c.getValue();
+        return ESAPI.validator().getValidInput("HTTP cookie value: " + value, value, "HTTPCookieValue", sc.getIntProp("HttpUtilities.MaxHeaderValueSize"), false);
+    }
 
-	/**
-	 * {@inheritDoc}
-	 */
+    /**
+     * {@inheritDoc}
+     */
     public String getCookie( String name ) throws ValidationException {
-    	return getCookie( getCurrentRequest(), name );
+        return getCookie( getCurrentRequest(), name );
     }
 
-	/**
-	 * {@inheritDoc}
-	 */
-	public String getCSRFToken() {
-		User user = ESAPI.authenticator().getCurrentUser();
-		if (user == null) return null;
-		return user.getCSRFToken();
-	}
+    /**
+     * {@inheritDoc}
+     */
+    public String getCSRFToken() {
+        User user = ESAPI.authenticator().getCurrentUser();
+        if (user == null) return null;
+        return user.getCSRFToken();
+    }
 
 
-	/**
-	 * {@inheritDoc}
-	 */
+    /**
+     * {@inheritDoc}
+     */
     public HttpServletRequest getCurrentRequest() {
-    	return currentRequest.getRequest();
+        return currentRequest.getRequest();
     }
 
 
-	/**
-	 * {@inheritDoc}
-	 */
+    /**
+     * {@inheritDoc}
+     */
     public HttpServletResponse getCurrentResponse() {
         return currentResponse.getResponse();
     }
 
-	/**
-	 * {@inheritDoc}
-	 */
+    /**
+     * {@inheritDoc}
+     */
     public List<File> getFileUploads() throws ValidationException {
-    	return getFileUploads( getCurrentRequest(), ESAPI.securityConfiguration().getUploadDirectory(), ESAPI.securityConfiguration().getAllowedFileExtensions() );
+        return getFileUploads( getCurrentRequest(), ESAPI.securityConfiguration().getUploadDirectory(), ESAPI.securityConfiguration().getAllowedFileExtensions() );
     }
 
     /**
-	 * {@inheritDoc}
-	 */
+     * {@inheritDoc}
+     */
     public List<File> getFileUploads(HttpServletRequest request) throws ValidationException {
-    	return getFileUploads(request, ESAPI.securityConfiguration().getUploadDirectory(), ESAPI.securityConfiguration().getAllowedFileExtensions());
+        return getFileUploads(request, ESAPI.securityConfiguration().getUploadDirectory(), ESAPI.securityConfiguration().getAllowedFileExtensions());
     }
 
     /**
-	 * {@inheritDoc}
-	 */
+     * {@inheritDoc}
+     */
     public List<File> getFileUploads(HttpServletRequest request, File finalDir ) throws ValidationException {
-    	return getFileUploads(request, finalDir, ESAPI.securityConfiguration().getAllowedFileExtensions());
+        return getFileUploads(request, finalDir, ESAPI.securityConfiguration().getAllowedFileExtensions());
     }
 
-	/**
-	 * {@inheritDoc}
-	 */
-	public List<File> getFileUploads(HttpServletRequest request, File finalDir, List allowedExtensions) throws ValidationException {
+    /**
+     * {@inheritDoc}
+     */
+    public List<File> getFileUploads(HttpServletRequest request, File finalDir, List allowedExtensions) throws ValidationException {
         File tempDir = ESAPI.securityConfiguration().getUploadTempDirectory();
-		if ( !tempDir.exists() ) {
-		    if ( !tempDir.mkdirs() ) throw new ValidationUploadException( "Upload failed", "Could not create temp directory: " + tempDir.getAbsolutePath() );
-		}
-
-		if( finalDir != null){
-			if ( !finalDir.exists() ) {
-				if ( !finalDir.mkdirs() ) throw new ValidationUploadException( "Upload failed", "Could not create final upload directory: " + finalDir.getAbsolutePath() );
-			}
-		}
-		else {
-			if ( !ESAPI.securityConfiguration().getUploadDirectory().exists()) {
-				if ( !ESAPI.securityConfiguration().getUploadDirectory().mkdirs() ) throw new ValidationUploadException( "Upload failed", "Could not create final upload directory: " + ESAPI.securityConfiguration().getUploadDirectory().getAbsolutePath() );
-			}
-			finalDir = ESAPI.securityConfiguration().getUploadDirectory();
-		}
-
-		List<File> newFiles = new ArrayList<File>();
-		String dfiPrevValue = "false";   // Fail safely in case of Java Security Manager & weird security policy
-		try {
-			dfiPrevValue = System.getProperty(DISKFILEITEM_SERIALIZABLE);
-			System.setProperty(DISKFILEITEM_SERIALIZABLE, "false");
-			final HttpSession session = request.getSession(false);
-			if (!ServletFileUpload.isMultipartContent(request)) {
-				throw new ValidationUploadException("Upload failed", "Not a multipart request");
-			}
-
-			// this factory will store ALL files in the temp directory,
-			// regardless of size
-			DiskFileItemFactory factory = new DiskFileItemFactory(0, tempDir);
-			ServletFileUpload upload = new ServletFileUpload(factory);
-			upload.setSizeMax(maxBytes);
-
-			// Create a progress listener
-			ProgressListener progressListener = new ProgressListener() {
-				private long megaBytes = -1;
-				private long progress = 0;
-
-				public void update(long pBytesRead, long pContentLength, int pItems) {
-					if (pItems == 0)
-						return;
-					long mBytes = pBytesRead / 1000000;
-					if (megaBytes == mBytes)
-						return;
-					megaBytes = mBytes;
-					progress = (long) (((double) pBytesRead / (double) pContentLength) * 100);
-					if ( session != null ) {
-					    session.setAttribute("progress", Long.toString(progress));
-					}
-					// logger.logSuccess(Logger.SECURITY, "   Item " + pItems + " (" + progress + "% of " + pContentLength + " bytes]");
-				}
-			};
-			upload.setProgressListener(progressListener);
-
-			List<FileItem> items = upload.parseRequest(request);
-			for (FileItem item : items)
-			{
-				if (!item.isFormField() && item.getName() != null && !(item.getName().equals("")))
-				{
-					String[] fparts = item.getName().split("[\\/\\\\]");
-					String filename = fparts[fparts.length - 1];
-
-					if (!ESAPI.validator().isValidFileName("upload", filename, allowedExtensions, false))
-					{
-						throw new ValidationUploadException("Upload only simple filenames with the following extensions " + allowedExtensions, "Upload failed isValidFileName check");
-					}
-
-					logger.info(Logger.SECURITY_SUCCESS, "File upload requested: " + filename);
-					File f = new File(finalDir, filename);
-					if (f.exists())
-					{
-						String[] parts = filename.split("\\/.");
-						String extension = "";
-						if (parts.length > 1)
-						{
-							extension = parts[parts.length - 1];
-						}
-						String filenm = filename.substring(0, filename.length() - extension.length());
-						f = File.createTempFile(filenm, "." + extension, finalDir);
-					}
-
-					item.write(f);
-					newFiles.add(f);
-					// delete temporary file
-					item.delete();
-					logger.fatal(Logger.SECURITY_SUCCESS, "File successfully uploaded: " + f);
-					if (session != null)
-					{
-						session.setAttribute("progress", Long.toString(0));
-					}
-				}
-			}
-		} catch (Exception e) {
-			if (e instanceof ValidationUploadException) {
-				throw (ValidationException)e;
-			}
-			throw new ValidationUploadException("Upload failure", "Problem during upload:" + e.getMessage(), e);
-		}
-		finally {
-			if ( dfiPrevValue != null ) {
-				System.setProperty(DISKFILEITEM_SERIALIZABLE, dfiPrevValue);
-			}
-		}
-		return Collections.synchronizedList(newFiles);
-	}
-
-
-
-	/**
+        if ( !tempDir.exists() ) {
+            if ( !tempDir.mkdirs() ) throw new ValidationUploadException( "Upload failed", "Could not create temp directory: " + tempDir.getAbsolutePath() );
+        }
+
+        if( finalDir != null){
+            if ( !finalDir.exists() ) {
+                if ( !finalDir.mkdirs() ) throw new ValidationUploadException( "Upload failed", "Could not create final upload directory: " + finalDir.getAbsolutePath() );
+            }
+        }
+        else {
+            if ( !ESAPI.securityConfiguration().getUploadDirectory().exists()) {
+                if ( !ESAPI.securityConfiguration().getUploadDirectory().mkdirs() ) throw new ValidationUploadException( "Upload failed", "Could not create final upload directory: " + ESAPI.securityConfiguration().getUploadDirectory().getAbsolutePath() );
+            }
+            finalDir = ESAPI.securityConfiguration().getUploadDirectory();
+        }
+
+        List<File> newFiles = new ArrayList<File>();
+        String dfiPrevValue = "false";   // Fail safely in case of Java Security Manager & weird security policy
+        try {
+            dfiPrevValue = System.getProperty(DISKFILEITEM_SERIALIZABLE);
+            System.setProperty(DISKFILEITEM_SERIALIZABLE, "false");
+            final HttpSession session = request.getSession(false);
+            if (!ServletFileUpload.isMultipartContent(request)) {
+                throw new ValidationUploadException("Upload failed", "Not a multipart request");
+            }
+
+            // this factory will store ALL files in the temp directory,
+            // regardless of size
+            DiskFileItemFactory factory = new DiskFileItemFactory(0, tempDir);
+            ServletFileUpload upload = new ServletFileUpload(factory);
+            upload.setSizeMax(maxBytes);
+
+            // Create a progress listener
+            ProgressListener progressListener = new ProgressListener() {
+                private long megaBytes = -1;
+                private long progress = 0;
+
+                public void update(long pBytesRead, long pContentLength, int pItems) {
+                    if (pItems == 0)
+                        return;
+                    long mBytes = pBytesRead / 1000000;
+                    if (megaBytes == mBytes)
+                        return;
+                    megaBytes = mBytes;
+                    progress = (long) (((double) pBytesRead / (double) pContentLength) * 100);
+                    if ( session != null ) {
+                        session.setAttribute("progress", Long.toString(progress));
+                    }
+                    // logger.logSuccess(Logger.SECURITY, "   Item " + pItems + " (" + progress + "% of " + pContentLength + " bytes]");
+                }
+            };
+            upload.setProgressListener(progressListener);
+
+            List<FileItem> items = upload.parseRequest(request);
+            for (FileItem item : items)
+            {
+                if (!item.isFormField() && item.getName() != null && !(item.getName().equals("")))
+                {
+                    String[] fparts = item.getName().split("[\\/\\\\]");
+                    String filename = fparts[fparts.length - 1];
+
+                    if (!ESAPI.validator().isValidFileName("upload", filename, allowedExtensions, false))
+                    {
+                        throw new ValidationUploadException("Upload only simple filenames with the following extensions " + allowedExtensions, "Upload failed isValidFileName check");
+                    }
+
+                    logger.info(Logger.SECURITY_SUCCESS, "File upload requested: " + filename);
+                    File f = new File(finalDir, filename);
+                    if (f.exists())
+                    {
+                        String[] parts = filename.split("\\/.");
+                        String extension = "";
+                        if (parts.length > 1)
+                        {
+                            extension = parts[parts.length - 1];
+                        }
+                        String filenm = filename.substring(0, filename.length() - extension.length());
+                        f = File.createTempFile(filenm, "." + extension, finalDir);
+                    }
+
+                    item.write(f);
+                    newFiles.add(f);
+                    // delete temporary file
+                    item.delete();
+                    logger.fatal(Logger.SECURITY_SUCCESS, "File successfully uploaded: " + f);
+                    if (session != null)
+                    {
+                        session.setAttribute("progress", Long.toString(0));
+                    }
+                }
+            }
+        } catch (Exception e) {
+            if (e instanceof ValidationUploadException) {
+                throw (ValidationException)e;
+            }
+            throw new ValidationUploadException("Upload failure", "Problem during upload:" + e.getMessage(), e);
+        }
+        finally {
+            if ( dfiPrevValue != null ) {
+                System.setProperty(DISKFILEITEM_SERIALIZABLE, dfiPrevValue);
+            }
+        }
+        return Collections.synchronizedList(newFiles);
+    }
+
+
+
+    /**
      * Utility to return the first cookie matching the provided name.
      * @param request
      * @param name
      */
-	private Cookie getFirstCookie(HttpServletRequest request, String name) {
-		Cookie[] cookies = request.getCookies();
-		if (cookies != null) {
+    private Cookie getFirstCookie(HttpServletRequest request, String name) {
+        Cookie[] cookies = request.getCookies();
+        if (cookies != null) {
          for (Cookie cookie : cookies)
          {
             if (cookie.getName().equals(name))
             {
-					return cookie;
-				}
-			}
-		}
-		return null;
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	public String getHeader( HttpServletRequest request, String name ) throws ValidationException {
-		SecurityConfiguration sc = ESAPI.securityConfiguration();
+                    return cookie;
+                }
+            }
+        }
+        return null;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public String getHeader( HttpServletRequest request, String name ) throws ValidationException {
+        SecurityConfiguration sc = ESAPI.securityConfiguration();
         String value = request.getHeader(name);
         return ESAPI.validator().getValidInput("HTTP header value: " + value, value, "HTTPHeaderValue", sc.getIntProp("HttpUtilities.MaxHeaderValueSize"), false);
-	}
+    }
 
 
-	/**
-	 * {@inheritDoc}
-	 */
+    /**
+     * {@inheritDoc}
+     */
     public String getHeader( String name ) throws ValidationException {
-    	return getHeader( getCurrentRequest(), name );
+        return getHeader( getCurrentRequest(), name );
     }
 
 
     /**
-	 * {@inheritDoc}
-	 */
-	public String getParameter( HttpServletRequest request, String name ) throws ValidationException {
-	    String value = request.getParameter(name);
-	    return ESAPI.validator().getValidInput("HTTP parameter value: " + value, value, "HTTPParameterValue", 2000, true);
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
+     * {@inheritDoc}
+     */
+    public String getParameter( HttpServletRequest request, String name ) throws ValidationException {
+        String value = request.getParameter(name);
+        return ESAPI.validator().getValidInput("HTTP parameter value: " + value, value, "HTTPParameterValue", 2000, true);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
     public String getParameter( String name ) throws ValidationException {
-    	return getParameter( getCurrentRequest(), name );
+        return getParameter( getCurrentRequest(), name );
     }
 
-	/**
-	 * {@inheritDoc}
-	 */
+    /**
+     * {@inheritDoc}
+     */
     public void killAllCookies() {
-    	killAllCookies( getCurrentRequest(), getCurrentResponse() );
+        killAllCookies( getCurrentRequest(), getCurrentResponse() );
     }
 
-	/**
-	 * {@inheritDoc}
+    /**
+     * {@inheritDoc}
      *
      * @param request
      * @param response
      */
-	public void killAllCookies(HttpServletRequest request, HttpServletResponse response) {
-		Cookie[] cookies = request.getCookies();
-		if (cookies != null) {
+    public void killAllCookies(HttpServletRequest request, HttpServletResponse response) {
+        Cookie[] cookies = request.getCookies();
+        if (cookies != null) {
          for (Cookie cookie : cookies)
          {
-				killCookie(request, response, cookie.getName());
-			}
-		}
-	}
+                killCookie(request, response, cookie.getName());
+            }
+        }
+    }
 
 
-	/**
-	 * {@inheritDoc}
+    /**
+     * {@inheritDoc}
      *
      * @param request
      * @param response
      * @param name
      */
-	public void killCookie(HttpServletRequest request, HttpServletResponse response, String name) {
-		String path = "/";
-		String domain="";
-		Cookie cookie = getFirstCookie(request, name);
-		if ( cookie != null ) {
-			path = cookie.getPath();
-			domain = cookie.getDomain();
-		}
-		Cookie deleter = new Cookie( name, "deleted" );
-		deleter.setMaxAge( 0 );
-		if ( domain != null ) deleter.setDomain( domain );
-		if ( path != null ) deleter.setPath( path );
-		response.addCookie( deleter );
-	}
-
-
-	/**
-	 * {@inheritDoc}
-	 */
+    public void killCookie(HttpServletRequest request, HttpServletResponse response, String name) {
+        String path = "/";
+        String domain="";
+        Cookie cookie = getFirstCookie(request, name);
+        if ( cookie != null ) {
+            path = cookie.getPath();
+            domain = cookie.getDomain();
+        }
+        Cookie deleter = new Cookie( name, "deleted" );
+        deleter.setMaxAge( 0 );
+        if ( domain != null ) deleter.setDomain( domain );
+        if ( path != null ) deleter.setPath( path );
+        response.addCookie( deleter );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
     public void killCookie( String name ) {
-    	killCookie( getCurrentRequest(), getCurrentResponse(), name );
+        killCookie( getCurrentRequest(), getCurrentResponse(), name );
     }
 
 
-	/**
-	 * {@inheritDoc}
-	 */
+    /**
+     * {@inheritDoc}
+     */
     public void logHTTPRequest() {
-    	logHTTPRequest( getCurrentRequest(), logger, null );
+        logHTTPRequest( getCurrentRequest(), logger, null );
     }
 
-	/**
-	 * {@inheritDoc}
-	 */
+    /**
+     * {@inheritDoc}
+     */
     public void logHTTPRequest(HttpServletRequest request, Logger logger) {
-    	logHTTPRequest( request, logger, null );
-    }
-
-		/**
-		 * Formats an HTTP request into a log suitable string. This implementation logs the remote host IP address (or
-		 * hostname if available), the request method (GET/POST), the URL, and all the querystring and form parameters. All
-		 * the parameters are presented as though they were in the URL even if they were in a form. Any parameters that
-		 * match items in the parameterNamesToObfuscate are shown as eight asterisks.
-		 *
-		 *
-		 * @param request
-		 */
-		public void logHTTPRequest(HttpServletRequest request, Logger logger, List parameterNamesToObfuscate) {
-			StringBuilder params = new StringBuilder();
-		    Iterator i = request.getParameterMap().keySet().iterator();
-		    while (i.hasNext()) {
-		        String key = (String) i.next();
-		        String[] value = request.getParameterMap().get(key);
-		        for (int j = 0; j < value.length; j++) {
+        logHTTPRequest( request, logger, null );
+    }
+
+        /**
+         * Formats an HTTP request into a log suitable string. This implementation logs the remote host IP address (or
+         * hostname if available), the request method (GET/POST), the URL, and all the querystring and form parameters. All
+         * the parameters are presented as though they were in the URL even if they were in a form. Any parameters that
+         * match items in the parameterNamesToObfuscate are shown as eight asterisks.
+         *
+         *
+         * @param request
+         */
+        public void logHTTPRequest(HttpServletRequest request, Logger logger, List parameterNamesToObfuscate) {
+            StringBuilder params = new StringBuilder();
+            Iterator i = request.getParameterMap().keySet().iterator();
+            while (i.hasNext()) {
+                String key = (String) i.next();
+                String[] value = request.getParameterMap().get(key);
+                for (int j = 0; j < value.length; j++) {
                  params.append(key).append("=");
-		            if (parameterNamesToObfuscate != null && parameterNamesToObfuscate.contains(key)) {
-		                params.append("********");
-		            } else {
-		                params.append(value[j]);
-		            }
-		            if (j < value.length - 1) {
-		                params.append("&");
-		            }
-		        }
-		        if (i.hasNext())
-		            params.append("&");
-		    }
-		    Cookie[] cookies = request.getCookies();
-		    if ( cookies != null ) {
+                    if (parameterNamesToObfuscate != null && parameterNamesToObfuscate.contains(key)) {
+                        params.append("********");
+                    } else {
+                        params.append(value[j]);
+                    }
+                    if (j < value.length - 1) {
+                        params.append("&");
+                    }
+                }
+                if (i.hasNext())
+                    params.append("&");
+            }
+            Cookie[] cookies = request.getCookies();
+            if ( cookies != null ) {
              for (Cookie cooky : cookies)
              {
-                if (!cooky.getName().equals(ESAPI.securityConfiguration().getHttpSessionIdName())) 
+                if (!cooky.getName().equals(ESAPI.securityConfiguration().getHttpSessionIdName()))
                 {
                    params.append("+").append(cooky.getName()).append("=").append(cooky.getValue());
-		                    }
-		            }
-		    }
-		    String msg = request.getMethod() + " " + request.getRequestURL() + (params.length() > 0 ? "?" + params : "");
-		    logger.info(Logger.SECURITY_SUCCESS, msg);
-		}
-
-	private Map<String,String> queryToMap(String query) {
-		TreeMap<String,String> map = new TreeMap<String,String>();
-		String[] parts = query.split("&");
+                            }
+                    }
+            }
+            String msg = request.getMethod() + " " + request.getRequestURL() + (params.length() > 0 ? "?" + params : "");
+            logger.info(Logger.SECURITY_SUCCESS, msg);
+        }
+
+    private Map<String,String> queryToMap(String query) {
+        TreeMap<String,String> map = new TreeMap<String,String>();
+        String[] parts = query.split("&");
       for (String part : parts)
       {
          try
          {
             String[] nvpair = part.split("=");
-				String name = ESAPI.encoder().decodeFromURL(nvpair[0]);
-				String value = ESAPI.encoder().decodeFromURL(nvpair[1]);
+                String name = ESAPI.encoder().decodeFromURL(nvpair[0]);
+                String value = ESAPI.encoder().decodeFromURL(nvpair[1]);
             map.put(name, value);
          }
          catch (EncodingException e)
          {
-				// skip the nvpair with the encoding problem - note this is already logged.
-			}
-		}
-		return map;
-	}
-
-	/**
-	 * {@inheritDoc}
-	 *
-	 * This implementation simply checks to make sure that the forward location starts with "WEB-INF" and
-	 * is intended for use in frameworks that forward to JSP files inside the WEB-INF folder.
-	 */
-	public void sendForward(HttpServletRequest request, HttpServletResponse response, String location) throws AccessControlException,ServletException,IOException {
-		if (!location.startsWith("WEB-INF")) {
-			throw new AccessControlException("Forward failed", "Bad forward location: " + location);
-		}
-		RequestDispatcher dispatcher = request.getRequestDispatcher(location);
-		dispatcher.forward( request, response );
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
+                // skip the nvpair with the encoding problem - note this is already logged.
+            }
+        }
+        return map;
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * This implementation simply checks to make sure that the forward location starts with "WEB-INF" and
+     * is intended for use in frameworks that forward to JSP files inside the WEB-INF folder.
+     */
+    public void sendForward(HttpServletRequest request, HttpServletResponse response, String location) throws AccessControlException,ServletException,IOException {
+        if (!location.startsWith("WEB-INF")) {
+            throw new AccessControlException("Forward failed", "Bad forward location: " + location);
+        }
+        RequestDispatcher dispatcher = request.getRequestDispatcher(location);
+        dispatcher.forward( request, response );
+    }
+
+    /**
+     * {@inheritDoc}
+     */
     public void sendForward( String location )  throws AccessControlException,ServletException,IOException {
-    	sendForward( getCurrentRequest(), getCurrentResponse(), location);
+        sendForward( getCurrentRequest(), getCurrentResponse(), location);
     }
 
-	/**
-	 * {@inheritDoc}
-	 *
-	 * This implementation checks against the list of safe redirect locations defined in ESAPI.properties.
+    /**
+     * {@inheritDoc}
+     *
+     * This implementation checks against the list of safe redirect locations defined in ESAPI.properties.
      */
     public void sendRedirect(HttpServletResponse response, String location) throws AccessControlException, IOException {
         if (!ESAPI.validator().isValidRedirectLocation("Redirect", location, false)) {
@@ -854,42 +854,42 @@ public class DefaultHTTPUtilities implements org.owasp.esapi.HTTPUtilities {
         response.sendRedirect(location);
     }
 
-	/**
-	 * {@inheritDoc}
-	 */
+    /**
+     * {@inheritDoc}
+     */
     public void sendRedirect( String location )  throws AccessControlException,IOException {
-    	sendRedirect( getCurrentResponse(), location);
+        sendRedirect( getCurrentResponse(), location);
     }
 
-	/**
-	 * {@inheritDoc}
-	 */
+    /**
+     * {@inheritDoc}
+     */
     public void setContentType() {
-    	setContentType( getCurrentResponse() );
+        setContentType( getCurrentResponse() );
     }
 
 
-	/**
-	 * {@inheritDoc}
-	 */
-	public void setContentType(HttpServletResponse response) {
-		response.setContentType((ESAPI.securityConfiguration()).getResponseContentType());
-	}
+    /**
+     * {@inheritDoc}
+     */
+    public void setContentType(HttpServletResponse response) {
+        response.setContentType((ESAPI.securityConfiguration()).getResponseContentType());
+    }
 
     /**
-	 * {@inheritDoc}
-	 */
+     * {@inheritDoc}
+     */
     public void setCurrentHTTP(HttpServletRequest request, HttpServletResponse response) {
-     	currentRequest.setRequest(request);
+         currentRequest.setRequest(request);
         currentResponse.setResponse(response);
     }
 
     /**
-	 * {@inheritDoc}
+     * {@inheritDoc}
      */
     public void setHeader(HttpServletResponse response, String name, String value) {
         try {
-        	SecurityConfiguration sc = ESAPI.securityConfiguration();
+            SecurityConfiguration sc = ESAPI.securityConfiguration();
             String strippedName = StringUtilities.replaceLinearWhiteSpace(name);
             String strippedValue = StringUtilities.replaceLinearWhiteSpace(value);
             String safeName = ESAPI.validator().getValidInput("setHeader", strippedName, "HTTPHeaderName", sc.getIntProp("HttpUtilities.MaxHeaderNameSize"), false);
@@ -901,145 +901,145 @@ public class DefaultHTTPUtilities implements org.owasp.esapi.HTTPUtilities {
     }
 
 
-	/**
-	 * {@inheritDoc}
-	 */
+    /**
+     * {@inheritDoc}
+     */
     public void setHeader( String name, String value ) {
-    	setHeader( getCurrentResponse(), name, value );
+        setHeader( getCurrentResponse(), name, value );
     }
 
 
     /**
-	 * {@inheritDoc}
-	 */
+     * {@inheritDoc}
+     */
     public void setNoCacheHeaders() {
-    	setNoCacheHeaders( getCurrentResponse() );
+        setNoCacheHeaders( getCurrentResponse() );
     }
 
-	/**
-	 * {@inheritDoc}
+    /**
+     * {@inheritDoc}
      *
      * @param response
      */
-	public void setNoCacheHeaders(HttpServletResponse response) {
-		// HTTP 1.1
-		response.setHeader("Cache-Control", "no-store, no-cache, must-revalidate");
-
-		// HTTP 1.0
-		response.setHeader("Pragma","no-cache");
-		response.setDateHeader("Expires", -1);
-	}
-
-	/**
-	 * {@inheritDoc}
-	 *
-	 * Save the user's remember me data in an encrypted cookie and send it to the user.
-	 * Any old remember me cookie is destroyed first. Setting this cookie will keep the user
-	 * logged in until the maxAge passes, the password is changed, or the cookie is deleted.
-	 * If the cookie exists for the current user, it will automatically be used by ESAPI to
-	 * log the user in, if the data is valid and not expired.
+    public void setNoCacheHeaders(HttpServletResponse response) {
+        // HTTP 1.1
+        response.setHeader("Cache-Control", "no-store, no-cache, must-revalidate");
+
+        // HTTP 1.0
+        response.setHeader("Pragma","no-cache");
+        response.setDateHeader("Expires", -1);
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * Save the user's remember me data in an encrypted cookie and send it to the user.
+     * Any old remember me cookie is destroyed first. Setting this cookie will keep the user
+     * logged in until the maxAge passes, the password is changed, or the cookie is deleted.
+     * If the cookie exists for the current user, it will automatically be used by ESAPI to
+     * log the user in, if the data is valid and not expired.
      *
      * @param request
      * @param response
      */
-	public String setRememberToken( HttpServletRequest request, HttpServletResponse response, String password, int maxAge, String domain, String path ) {
-		User user = ESAPI.authenticator().getCurrentUser();
-		try {
-			killCookie(request, response, REMEMBER_TOKEN_COOKIE_NAME );
-			// seal already contains random data
-			String clearToken = user.getAccountName() + "|" + password;
-			long expiry = ESAPI.encryptor().getRelativeTimeStamp(maxAge * 1000);
-			String cryptToken = ESAPI.encryptor().seal(clearToken, expiry);
-			SecurityConfiguration sg = ESAPI.securityConfiguration();
-			boolean forceSecureCookies = sg.getBooleanProp("HttpUtilities.ForceSecureCookies");
-			boolean forceHttpOnly = sg.getBooleanProp("HttpUtilities.ForceHttpOnlyCookies");
+    public String setRememberToken( HttpServletRequest request, HttpServletResponse response, String password, int maxAge, String domain, String path ) {
+        User user = ESAPI.authenticator().getCurrentUser();
+        try {
+            killCookie(request, response, REMEMBER_TOKEN_COOKIE_NAME );
+            // seal already contains random data
+            String clearToken = user.getAccountName() + "|" + password;
+            long expiry = ESAPI.encryptor().getRelativeTimeStamp(maxAge * 1000);
+            String cryptToken = ESAPI.encryptor().seal(clearToken, expiry);
+            SecurityConfiguration sg = ESAPI.securityConfiguration();
+            boolean forceSecureCookies = sg.getBooleanProp("HttpUtilities.ForceSecureCookies");
+            boolean forceHttpOnly = sg.getBooleanProp("HttpUtilities.ForceHttpOnlyCookies");
 
             // Do NOT URLEncode cryptToken before creating cookie. See Google Issue # 144,
-			// which was marked as "WontFix".
-
-			Cookie cookie = new Cookie( REMEMBER_TOKEN_COOKIE_NAME, cryptToken );
-			cookie.setMaxAge( maxAge );
-			cookie.setDomain( domain );
-			cookie.setPath( path );
-			cookie.setHttpOnly(forceHttpOnly);
-			cookie.setSecure(forceSecureCookies);
-			response.addCookie( cookie );
-			logger.info(Logger.SECURITY_SUCCESS, "Enabled remember me token for " + user.getAccountName() );
-			return cryptToken;
-		} catch( IntegrityException e ) {
-			logger.warning(Logger.SECURITY_FAILURE, "Attempt to set remember me token failed for " + user.getAccountName(), e );
-			return null;
-		}
-	}
-	
-	
-	public String setRememberToken(HttpServletRequest request, HttpServletResponse response, int maxAge, String domain, String path){
-		String rval = "";
-		User user = ESAPI.authenticator().getCurrentUser();
-		
-		try{
-			killCookie(request,response, REMEMBER_TOKEN_COOKIE_NAME);
-			// seal already contains random data
-			String clearToken = user.getAccountName();
-			long expiry = ESAPI.encryptor().getRelativeTimeStamp(maxAge * 1000);
-			String cryptToken = ESAPI.encryptor().seal(clearToken, expiry);
-			SecurityConfiguration sg = ESAPI.securityConfiguration();
-			boolean forceSecureCookies = sg.getBooleanProp("HttpUtilities.ForceSecureCookies");
-			boolean forceHttpOnly = sg.getBooleanProp("HttpUtilities.ForceHttpOnlyCookies");
+            // which was marked as "WontFix".
+
+            Cookie cookie = new Cookie( REMEMBER_TOKEN_COOKIE_NAME, cryptToken );
+            cookie.setMaxAge( maxAge );
+            cookie.setDomain( domain );
+            cookie.setPath( path );
+            cookie.setHttpOnly(forceHttpOnly);
+            cookie.setSecure(forceSecureCookies);
+            response.addCookie( cookie );
+            logger.info(Logger.SECURITY_SUCCESS, "Enabled remember me token for " + user.getAccountName() );
+            return cryptToken;
+        } catch( IntegrityException e ) {
+            logger.warning(Logger.SECURITY_FAILURE, "Attempt to set remember me token failed for " + user.getAccountName(), e );
+            return null;
+        }
+    }
+
+
+    public String setRememberToken(HttpServletRequest request, HttpServletResponse response, int maxAge, String domain, String path){
+        String rval = "";
+        User user = ESAPI.authenticator().getCurrentUser();
+
+        try{
+            killCookie(request,response, REMEMBER_TOKEN_COOKIE_NAME);
+            // seal already contains random data
+            String clearToken = user.getAccountName();
+            long expiry = ESAPI.encryptor().getRelativeTimeStamp(maxAge * 1000);
+            String cryptToken = ESAPI.encryptor().seal(clearToken, expiry);
+            SecurityConfiguration sg = ESAPI.securityConfiguration();
+            boolean forceSecureCookies = sg.getBooleanProp("HttpUtilities.ForceSecureCookies");
+            boolean forceHttpOnly = sg.getBooleanProp("HttpUtilities.ForceHttpOnlyCookies");
             // Do NOT URLEncode cryptToken before creating cookie. See Google Issue # 144,
-			// which was marked as "WontFix".
-
-			Cookie cookie = new Cookie( REMEMBER_TOKEN_COOKIE_NAME, cryptToken );
-			cookie.setMaxAge( maxAge );
-			cookie.setDomain( domain );
-			cookie.setPath( path );
-			cookie.setHttpOnly(forceHttpOnly);
-			cookie.setSecure(forceSecureCookies);
-			response.addCookie( cookie );
-			logger.info(Logger.SECURITY_SUCCESS, "Enabled remember me token for " + user.getAccountName() );
-		} catch( IntegrityException e){
-			logger.warning(Logger.SECURITY_FAILURE, "Attempt to set remember me token failed for " + user.getAccountName(), e );
-			return null;
-		}
-		
-		
-		return rval;
-	}
+            // which was marked as "WontFix".
+
+            Cookie cookie = new Cookie( REMEMBER_TOKEN_COOKIE_NAME, cryptToken );
+            cookie.setMaxAge( maxAge );
+            cookie.setDomain( domain );
+            cookie.setPath( path );
+            cookie.setHttpOnly(forceHttpOnly);
+            cookie.setSecure(forceSecureCookies);
+            response.addCookie( cookie );
+            logger.info(Logger.SECURITY_SUCCESS, "Enabled remember me token for " + user.getAccountName() );
+        } catch( IntegrityException e){
+            logger.warning(Logger.SECURITY_FAILURE, "Attempt to set remember me token failed for " + user.getAccountName(), e );
+            return null;
+        }
+
+
+        return rval;
+    }
 
     /**
-	 * {@inheritDoc}
-	 */
+     * {@inheritDoc}
+     */
     public String setRememberToken( String password, int maxAge, String domain, String path ) {
-    	return setRememberToken( getCurrentRequest(), getCurrentResponse(), password, maxAge, domain, path );
+        return setRememberToken( getCurrentRequest(), getCurrentResponse(), password, maxAge, domain, path );
     }
 
 
     /**
-	 * {@inheritDoc}
-	 */
-	public void verifyCSRFToken() throws IntrusionException {
-    	verifyCSRFToken( getCurrentRequest() );
+     * {@inheritDoc}
+     */
+    public void verifyCSRFToken() throws IntrusionException {
+        verifyCSRFToken( getCurrentRequest() );
     }
 
     /**
-	 * {@inheritDoc}
-	 *
-	 * This implementation uses the CSRF_TOKEN_NAME parameter for the token.
+     * {@inheritDoc}
+     *
+     * This implementation uses the CSRF_TOKEN_NAME parameter for the token.
      *
      * @param request
      */
-	public void verifyCSRFToken(HttpServletRequest request) throws IntrusionException {
-		User user = ESAPI.authenticator().getCurrentUser();
+    public void verifyCSRFToken(HttpServletRequest request) throws IntrusionException {
+        User user = ESAPI.authenticator().getCurrentUser();
 
-		// check if user authenticated with this request - no CSRF protection required
-		if( request.getAttribute(user.getCSRFToken()) != null ) {
-			return;
-		}
-		String token = request.getParameter(CSRF_TOKEN_NAME);
-		if ( !user.getCSRFToken().equals( token ) ) {
-			throw new IntrusionException("Authentication failed", "Possibly forged HTTP request without proper CSRF token detected");
-		}
-	}
+        // check if user authenticated with this request - no CSRF protection required
+        if( request.getAttribute(user.getCSRFToken()) != null ) {
+            return;
+        }
+        String token = request.getParameter(CSRF_TOKEN_NAME);
+        if ( !user.getCSRFToken().equals( token ) ) {
+            throw new IntrusionException("Authentication failed", "Possibly forged HTTP request without proper CSRF token detected");
+        }
+    }
 
     /**
      * {@inheritDoc}
@@ -1074,9 +1074,9 @@ public class DefaultHTTPUtilities implements org.owasp.esapi.HTTPUtilities {
     {
         return (T) request.getAttribute( key );
     }
-    
+
     /////////////////////
-    
+
     /* Helper method to encrypt using new Encryptor encryption methods and
      * return the serialized ciphertext as a hex-encoded string.
      */
@@ -1086,7 +1086,7 @@ public class DefaultHTTPUtilities implements org.owasp.esapi.HTTPUtilities {
         byte[] serializedCiphertext = ct.asPortableSerializedByteArray();
         return Hex.encode(serializedCiphertext, false);
     }
-    
+
     /* Helper method to decrypt a hex-encode serialized ciphertext string and
      * to decrypt it using the new Encryptor decryption methods.
      */
diff --git a/src/main/java/org/owasp/esapi/reference/DefaultIntrusionDetector.java b/src/main/java/org/owasp/esapi/reference/DefaultIntrusionDetector.java
index d7b8f2b..9f9c0e4 100644
--- a/src/main/java/org/owasp/esapi/reference/DefaultIntrusionDetector.java
+++ b/src/main/java/org/owasp/esapi/reference/DefaultIntrusionDetector.java
@@ -1,15 +1,15 @@
 /**
  * OWASP Enterprise Security API (ESAPI)
- * 
+ *
  * This file is part of the Open Web Application Security Project (OWASP)
  * Enterprise Security API (ESAPI) project. For details, please see
  * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
  *
  * Copyright (c) 2007 - The OWASP Foundation
- * 
+ *
  * The ESAPI is published by OWASP under the BSD license. You should read and accept the
  * LICENSE before you use, modify, and/or redistribute this software.
- * 
+ *
  * @author Jeff Williams <a href="http://www.aspectsecurity.com">Aspect Security</a>
  * @created 2007
  */
@@ -39,7 +39,7 @@ import org.owasp.esapi.errors.IntrusionException;
  * user's session, so that it will be properly cleaned up when the session is
  * terminated. State is not otherwise persisted, so attacks that span sessions
  * will not be detectable.
- * 
+ *
  * @author Jeff Williams (jeff.williams .at. aspectsecurity.com) <a
  *         href="http://www.aspectsecurity.com">Aspect Security</a>
  * @since June 1, 2007
@@ -47,38 +47,38 @@ import org.owasp.esapi.errors.IntrusionException;
  */
 public class DefaultIntrusionDetector implements org.owasp.esapi.IntrusionDetector {
 
-	/** The logger. */
-	private final Logger logger = ESAPI.getLogger("IntrusionDetector");
+    /** The logger. */
+    private final Logger logger = ESAPI.getLogger("IntrusionDetector");
 
     public DefaultIntrusionDetector() {
-	}
-	
-	/**
-	 * {@inheritDoc}
+    }
+
+    /**
+     * {@inheritDoc}
      *
      * @param e
      */
-	public void addException(Exception e) {
-		if (ESAPI.securityConfiguration().getDisableIntrusionDetection()) return;
-		
+    public void addException(Exception e) {
+        if (ESAPI.securityConfiguration().getDisableIntrusionDetection()) return;
+
         if ( e instanceof EnterpriseSecurityException ) {
             logger.warning( Logger.SECURITY_FAILURE, ((EnterpriseSecurityException)e).getLogMessage(), e );
         } else {
             logger.warning( Logger.SECURITY_FAILURE, e.getMessage(), e );
         }
 
-        // add the exception to the current user, which may trigger a detector 
-		User user = ESAPI.authenticator().getCurrentUser();
+        // add the exception to the current user, which may trigger a detector
+        User user = ESAPI.authenticator().getCurrentUser();
         String eventName = e.getClass().getName();
 
         if ( e instanceof IntrusionException) {
             return;
         }
-        
+
         // add the exception to the user's store, handle IntrusionException if thrown
-		try {
-			addSecurityEvent(user, eventName);
-		} catch( IntrusionException ex ) {
+        try {
+            addSecurityEvent(user, eventName);
+        } catch( IntrusionException ex ) {
             Threshold quota = ESAPI.securityConfiguration().getQuota(eventName);
             Iterator i = quota.actions.iterator();
             while ( i.hasNext() ) {
@@ -86,18 +86,18 @@ public class DefaultIntrusionDetector implements org.owasp.esapi.IntrusionDetect
                 String message = "User exceeded quota of " + quota.count + " per "+ quota.interval +" seconds for event " + eventName + ". Taking actions " + quota.actions;
                 takeSecurityAction( action, message );
             }
-		}
-	}
+        }
+    }
 
-	/**
-	 * {@inheritDoc}
-	 */
+    /**
+     * {@inheritDoc}
+     */
     public void addEvent(String eventName, String logMessage) throws IntrusionException {
-    	if (ESAPI.securityConfiguration().getDisableIntrusionDetection()) return;
-    	
+        if (ESAPI.securityConfiguration().getDisableIntrusionDetection()) return;
+
         logger.warning( Logger.SECURITY_FAILURE, "Security event " + eventName + " received : " + logMessage );
 
-        // add the event to the current user, which may trigger a detector 
+        // add the event to the current user, which may trigger a detector
         User user = ESAPI.authenticator().getCurrentUser();
         try {
             addSecurityEvent(user, "event." + eventName);
@@ -115,21 +115,21 @@ public class DefaultIntrusionDetector implements org.owasp.esapi.IntrusionDetect
     /**
      * Take a specified security action.  In this implementation, acceptable
      * actions are: log, disable, logout.
-     * 
+     *
      * @param action
-     * 		the action to take (log, disable, logout)
+     *         the action to take (log, disable, logout)
      * @param message
-     * 		the message to log if the action is "log"
+     *         the message to log if the action is "log"
      */
     private void takeSecurityAction( String action, String message ) {
-    	if (ESAPI.securityConfiguration().getDisableIntrusionDetection()) return;
-    	
+        if (ESAPI.securityConfiguration().getDisableIntrusionDetection()) return;
+
         if ( action.equals( "log" ) ) {
             logger.fatal( Logger.SECURITY_FAILURE, "INTRUSION - " + message );
         }
         User user = ESAPI.authenticator().getCurrentUser();
         if (user == User.ANONYMOUS)
-        	return;
+            return;
         if ( action.equals( "disable" ) ) {
             user.disable();
         }
@@ -138,34 +138,34 @@ public class DefaultIntrusionDetector implements org.owasp.esapi.IntrusionDetect
         }
     }
 
-	 /**
-	 * Adds a security event to the user.  These events are used to check that the user has not
-	 * reached the security thresholds set in the properties file.
-	 * 
-	 * @param user
-	 * 			The user that caused the event.
-	 * @param eventName
-	 * 			The name of the event that occurred.
-	 */
-	private void addSecurityEvent(User user, String eventName) {
-		if (ESAPI.securityConfiguration().getDisableIntrusionDetection()) return;
-		
-		if ( user.isAnonymous() ) return;
-		
-		HashMap eventMap = user.getEventMap();
-		
-		// if there is a threshold, then track this event
-		Threshold threshold = ESAPI.securityConfiguration().getQuota( eventName );
-		if ( threshold != null ) {
-			Event event = (Event)eventMap.get( eventName );
-			if ( event == null ) {
-				event = new Event( eventName );
-				eventMap.put( eventName, event );
-			}
-			// increment
-			event.increment(threshold.count, threshold.interval);
-		}
-	}
+     /**
+     * Adds a security event to the user.  These events are used to check that the user has not
+     * reached the security thresholds set in the properties file.
+     *
+     * @param user
+     *             The user that caused the event.
+     * @param eventName
+     *             The name of the event that occurred.
+     */
+    private void addSecurityEvent(User user, String eventName) {
+        if (ESAPI.securityConfiguration().getDisableIntrusionDetection()) return;
+
+        if ( user.isAnonymous() ) return;
+
+        HashMap eventMap = user.getEventMap();
+
+        // if there is a threshold, then track this event
+        Threshold threshold = ESAPI.securityConfiguration().getQuota( eventName );
+        if ( threshold != null ) {
+            Event event = (Event)eventMap.get( eventName );
+            if ( event == null ) {
+                event = new Event( eventName );
+                eventMap.put( eventName, event );
+            }
+            // increment
+            event.increment(threshold.count, threshold.interval);
+        }
+    }
 
     private static class Event {
         public String key;
@@ -175,15 +175,15 @@ public class DefaultIntrusionDetector implements org.owasp.esapi.IntrusionDetect
             this.key = key;
         }
         public void increment(int count, long interval) throws IntrusionException {
-        	if (ESAPI.securityConfiguration().getDisableIntrusionDetection()) return;
-        	
+            if (ESAPI.securityConfiguration().getDisableIntrusionDetection()) return;
+
             Date now = new Date();
             times.add( 0, now );
             while ( times.size() > count ) times.remove( times.size()-1 );
             if ( times.size() == count ) {
                 Date past = (Date)times.get( count-1 );
                 long plong = past.getTime();
-                long nlong = now.getTime(); 
+                long nlong = now.getTime();
                 if ( nlong - plong < interval * 1000 ) {
                     throw new IntrusionException( "Threshold exceeded", "Exceeded threshold for " + key );
                 }
diff --git a/src/main/java/org/owasp/esapi/reference/DefaultRandomizer.java b/src/main/java/org/owasp/esapi/reference/DefaultRandomizer.java
index d7731c5..6ac3b4f 100644
--- a/src/main/java/org/owasp/esapi/reference/DefaultRandomizer.java
+++ b/src/main/java/org/owasp/esapi/reference/DefaultRandomizer.java
@@ -1,15 +1,15 @@
 /**
  * OWASP Enterprise Security API (ESAPI)
- * 
+ *
  * This file is part of the Open Web Application Security Project (OWASP)
  * Enterprise Security API (ESAPI) project. For details, please see
  * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
  *
  * Copyright (c) 2007 - The OWASP Foundation
- * 
+ *
  * The ESAPI is published by OWASP under the BSD license. You should read and accept the
  * LICENSE before you use, modify, and/or redistribute this software.
- * 
+ *
  * @author Jeff Williams <a href="http://www.aspectsecurity.com">Aspect Security</a>
  * @created 2007
  */
@@ -28,7 +28,7 @@ import org.owasp.esapi.errors.EncryptionException;
 /**
  * Reference implementation of the Randomizer interface. This implementation builds on the JCE provider to provide a
  * cryptographically strong source of entropy. The specific algorithm used is configurable in ESAPI.properties.
- * 
+ *
  * @author Jeff Williams (jeff.williams .at. aspectsecurity.com) <a href="http://www.aspectsecurity.com">Aspect Security</a>
  * @since June 1, 2007
  * @see org.owasp.esapi.Randomizer
@@ -65,10 +65,10 @@ public class DefaultRandomizer implements org.owasp.esapi.Randomizer {
     }
 
     /**
-	 * {@inheritDoc}
-	 */
+     * {@inheritDoc}
+     */
     public String getRandomString(int length, char[] characterSet) {
-    	StringBuilder sb = new StringBuilder();
+        StringBuilder sb = new StringBuilder();
         for (int loop = 0; loop < length; loop++) {
             int index = secureRandom.nextInt(characterSet.length);
             sb.append(characterSet[index]);
@@ -78,57 +78,57 @@ public class DefaultRandomizer implements org.owasp.esapi.Randomizer {
     }
 
     /**
-	 * {@inheritDoc}
-	 */
+     * {@inheritDoc}
+     */
     public boolean getRandomBoolean() {
         return secureRandom.nextBoolean();
     }
-    
+
     /**
-	 * {@inheritDoc}
-	 */
+     * {@inheritDoc}
+     */
     public int getRandomInteger(int min, int max) {
         return secureRandom.nextInt(max - min) + min;
     }
-    
+
     /**
-	 * {@inheritDoc}
-	 */
+     * {@inheritDoc}
+     */
     public long getRandomLong() {
-        return secureRandom.nextLong();    
+        return secureRandom.nextLong();
     }
-    
+
     /**
-	 * {@inheritDoc}
-	 */
+     * {@inheritDoc}
+     */
     public float getRandomReal(float min, float max) {
         float factor = max - min;
         return secureRandom.nextFloat() * factor + min;
     }
 
     /**
-	 * {@inheritDoc}
-	 */
+     * {@inheritDoc}
+     */
     public String getRandomFilename(String extension) {
         String fn = getRandomString(12, EncoderConstants.CHAR_ALPHANUMERICS) + "." + extension;
         logger.debug(Logger.SECURITY_SUCCESS, "Generated new random filename: " + fn );
         return fn;
     }
-    
+
     /**
-	 * {@inheritDoc}
-	 */
+     * {@inheritDoc}
+     */
     public String getRandomGUID() throws EncryptionException {
-    	return UUID.randomUUID().toString();
+        return UUID.randomUUID().toString();
     }
-    	
+
     /**
      * {@inheritDoc}
      */
     public byte[] getRandomBytes(int n) {
-    	byte[] result = new byte[ n ];
-    	secureRandom.nextBytes(result);
-    	return result;
+        byte[] result = new byte[ n ];
+        secureRandom.nextBytes(result);
+        return result;
     }
-    	
+
 }
diff --git a/src/main/java/org/owasp/esapi/reference/DefaultSecurityConfiguration.java b/src/main/java/org/owasp/esapi/reference/DefaultSecurityConfiguration.java
index 3e80055..50c4ba4 100644
--- a/src/main/java/org/owasp/esapi/reference/DefaultSecurityConfiguration.java
+++ b/src/main/java/org/owasp/esapi/reference/DefaultSecurityConfiguration.java
@@ -2,7 +2,7 @@
  * OWASP Enterprise Security API (ESAPI)
  *
  * This file is part of the Open Web Application Security Project (OWASP)
- * Enterprise Security API (ESAPI) project. For details, please see
+ * Enterprise Security API (ESAPI) project. For details, please see{
  * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
  *
  * Copyright (c) 2007 - The OWASP Foundation
@@ -36,6 +36,8 @@ import java.util.regex.PatternSyntaxException;
 import org.apache.commons.lang.text.StrTokenizer;
 import org.owasp.esapi.ESAPI;
 import org.owasp.esapi.Logger;
+import org.owasp.esapi.PropNames;   // <== Actual property names moved to here. Eventually we'll do static import.
+import org.owasp.esapi.PropNames.DefaultSearchPath;
 import org.owasp.esapi.SecurityConfiguration;
 import org.owasp.esapi.configuration.EsapiPropertyManager;
 import org.owasp.esapi.errors.ConfigurationException;
@@ -49,7 +51,7 @@ import org.owasp.esapi.errors.ConfigurationException;
  * 2) Inside the System.getProperty( "org.owasp.esapi.resources" ) directory.
  * You can set this on the java command line as follows (for example):
  * <pre>
- * 		java -Dorg.owasp.esapi.resources="C:\temp\resources"
+ *         java -Dorg.owasp.esapi.resources="C:\temp\resources"
  * </pre>
  * You may have to add this to the start-up script that starts your web server. For example, for Tomcat,
  * in the "catalina" script that starts Tomcat, you can set the JAVA_OPTS variable to the {@code -D} string above.
@@ -63,10 +65,17 @@ import org.owasp.esapi.errors.ConfigurationException;
  * keys and passwords, logging locations, error thresholds, and allowed file extensions.
  * <p>
  * WARNING: Do not forget to update ESAPI.properties to change the master key and other security critical settings.
+ * <p>
+ * <b>DEPRECATION WARNING</b>: All of the variables of the type '{@code public static final String}'
+ * are now declared and defined in the {@code org.owasp.esapi.PropNames}. These public fields
+ * representing property names and values in <i>this</i> class <i>will</i> be eventually deleted and
+ * no longer available, so please migrate to the corresponding names in {@code PropNames}. Removal of these
+ * public fields from this class will likely occur sometime in 2Q2024.
  *
  * @author Jeff Williams (jeff.williams .at. aspectsecurity.com) <a href="http://www.aspectsecurity.com">Aspect Security</a>
  * @author Jim Manico (jim .at. manico.net) <a href="http://www.manico.net">Manico.net</a>
- * @author Kevin Wall (kevin.w.wall .at. gmail.com)
+ * @author Kevin W. Wall (kevin.w.wall .at. gmail.com)
+ *
  */
 
 public class DefaultSecurityConfiguration implements SecurityConfiguration {
@@ -82,123 +91,267 @@ public class DefaultSecurityConfiguration implements SecurityConfiguration {
         }
         return instance;
     }
-    
+
     private Properties properties = null;
-    private String cipherXformFromESAPIProp = null;	// New in ESAPI 2.0
-    private String cipherXformCurrent = null;		// New in ESAPI 2.0
-
-	/** The name of the ESAPI property file */
-	public static final String DEFAULT_RESOURCE_FILE = "ESAPI.properties";
-	
-    public static final String REMEMBER_TOKEN_DURATION = "Authenticator.RememberTokenDuration";
-    public static final String IDLE_TIMEOUT_DURATION = "Authenticator.IdleTimeoutDuration";
-    public static final String ABSOLUTE_TIMEOUT_DURATION = "Authenticator.AbsoluteTimeoutDuration";
-    public static final String ALLOWED_LOGIN_ATTEMPTS = "Authenticator.AllowedLoginAttempts";
-    public static final String USERNAME_PARAMETER_NAME = "Authenticator.UsernameParameterName";
-    public static final String PASSWORD_PARAMETER_NAME = "Authenticator.PasswordParameterName";
-    public static final String MAX_OLD_PASSWORD_HASHES = "Authenticator.MaxOldPasswordHashes";
-
-    public static final String ALLOW_MULTIPLE_ENCODING = "Encoder.AllowMultipleEncoding";
-    public static final String ALLOW_MIXED_ENCODING	= "Encoder.AllowMixedEncoding";
-    public static final String CANONICALIZATION_CODECS = "Encoder.DefaultCodecList";
-
-    public static final String DISABLE_INTRUSION_DETECTION  = "IntrusionDetector.Disable";
-    
-    public static final String MASTER_KEY = "Encryptor.MasterKey";
-    public static final String MASTER_SALT = "Encryptor.MasterSalt";
-    public static final String KEY_LENGTH = "Encryptor.EncryptionKeyLength";
-    public static final String ENCRYPTION_ALGORITHM = "Encryptor.EncryptionAlgorithm";
-    public static final String HASH_ALGORITHM = "Encryptor.HashAlgorithm";
-    public static final String HASH_ITERATIONS = "Encryptor.HashIterations";
-    public static final String CHARACTER_ENCODING = "Encryptor.CharacterEncoding";
-    public static final String RANDOM_ALGORITHM = "Encryptor.RandomAlgorithm";
-    public static final String DIGITAL_SIGNATURE_ALGORITHM = "Encryptor.DigitalSignatureAlgorithm";
-    public static final String DIGITAL_SIGNATURE_KEY_LENGTH = "Encryptor.DigitalSignatureKeyLength";
-    			// ==================================//
-    			//		New in ESAPI Java 2.x		 //
-    			// ================================= //
-    public static final String PREFERRED_JCE_PROVIDER = "Encryptor.PreferredJCEProvider";
-    public static final String CIPHER_TRANSFORMATION_IMPLEMENTATION = "Encryptor.CipherTransformation";
-    public static final String CIPHERTEXT_USE_MAC = "Encryptor.CipherText.useMAC";
-    public static final String PLAINTEXT_OVERWRITE = "Encryptor.PlainText.overwrite";
+    private String cipherXformFromESAPIProp = null;    // New in ESAPI 2.0
+    private String cipherXformCurrent = null;          // New in ESAPI 2.0
 
-    @Deprecated
-    public static final String IV_TYPE = "Encryptor.ChooseIVMethod";    // Will be removed in future release.
-
-    public static final String COMBINED_CIPHER_MODES = "Encryptor.cipher_modes.combined_modes";
-    public static final String ADDITIONAL_ALLOWED_CIPHER_MODES = "Encryptor.cipher_modes.additional_allowed";
-    public static final String KDF_PRF_ALG = "Encryptor.KDF.PRF";
-	public static final String PRINT_PROPERTIES_WHEN_LOADED = "ESAPI.printProperties";
-
-    public static final String WORKING_DIRECTORY = "Executor.WorkingDirectory";
-    public static final String APPROVED_EXECUTABLES = "Executor.ApprovedExecutables";
-
-    public static final String FORCE_HTTPONLYSESSION = "HttpUtilities.ForceHttpOnlySession";
-    public static final String FORCE_SECURESESSION = "HttpUtilities.SecureSession";
-    public static final String FORCE_HTTPONLYCOOKIES = "HttpUtilities.ForceHttpOnlyCookies";
-    public static final String FORCE_SECURECOOKIES = "HttpUtilities.ForceSecureCookies";
-	public static final String MAX_HTTP_HEADER_SIZE = "HttpUtilities.MaxHeaderSize";
-    public static final String UPLOAD_DIRECTORY = "HttpUtilities.UploadDir";
-    public static final String UPLOAD_TEMP_DIRECTORY = "HttpUtilities.UploadTempDir";
-    public static final String APPROVED_UPLOAD_EXTENSIONS = "HttpUtilities.ApprovedUploadExtensions";
-    public static final String MAX_UPLOAD_FILE_BYTES = "HttpUtilities.MaxUploadFileBytes";
-    public static final String RESPONSE_CONTENT_TYPE = "HttpUtilities.ResponseContentType";
-    public static final String HTTP_SESSION_ID_NAME = "HttpUtilities.HttpSessionIdName";
-
-    public static final String APPLICATION_NAME = "Logger.ApplicationName";
-    public static final String LOG_ENCODING_REQUIRED = "Logger.LogEncodingRequired";
-    public static final String LOG_APPLICATION_NAME = "Logger.LogApplicationName";
-    public static final String LOG_SERVER_IP = "Logger.LogServerIP";
-    public static final String LOG_USER_INFO = "Logger.UserInfo";
-    public static final String LOG_CLIENT_INFO = "Logger.ClientInfo";
-    public static final String VALIDATION_PROPERTIES = "Validator.ConfigurationFile";
-    public static final String VALIDATION_PROPERTIES_MULTIVALUED = "Validator.ConfigurationFile.MultiValued";
-    public static final String ACCEPT_LENIENT_DATES = "Validator.AcceptLenientDates";
-    public static final String VALIDATOR_HTML_VALIDATION_ACTION = "Validator.HtmlValidationAction";
-	public static final String VALIDATOR_HTML_VALIDATION_CONFIGURATION_FILE = "Validator.HtmlValidationConfigurationFile";
-
-    /**
-     * Special {@code System} property that, if set to {@code true}, will
+    /** The name of the ESAPI property file.
+     *  @deprecated Use same field name, but from {@code org.owasp.esapi.PropNames} instead.
+     */
+    @Deprecated public static final String DEFAULT_RESOURCE_FILE = PropNames.DEFAULT_RESOURCE_FILE;
+
+
+    /** @deprecated Use same field name, but from {@code org.owasp.esapi.PropNames} instead. */
+    @Deprecated public static final String REMEMBER_TOKEN_DURATION = PropNames.REMEMBER_TOKEN_DURATION;
+
+    /** @deprecated Use same field name, but from {@code org.owasp.esapi.PropNames} instead. */
+    @Deprecated public static final String IDLE_TIMEOUT_DURATION = PropNames.IDLE_TIMEOUT_DURATION;
+
+    /** @deprecated Use same field name, but from {@code org.owasp.esapi.PropNames} instead. */
+    @Deprecated public static final String ABSOLUTE_TIMEOUT_DURATION = PropNames.ABSOLUTE_TIMEOUT_DURATION;
+
+    /** @deprecated Use same field name, but from {@code org.owasp.esapi.PropNames} instead. */
+    @Deprecated public static final String ALLOWED_LOGIN_ATTEMPTS = PropNames.ALLOWED_LOGIN_ATTEMPTS;
+
+    /** @deprecated Use same field name, but from {@code org.owasp.esapi.PropNames} instead. */
+    @Deprecated public static final String USERNAME_PARAMETER_NAME = PropNames.USERNAME_PARAMETER_NAME;
+
+    /** @deprecated Use same field name, but from {@code org.owasp.esapi.PropNames} instead. */
+    @Deprecated public static final String PASSWORD_PARAMETER_NAME = PropNames.PASSWORD_PARAMETER_NAME;
+
+    /** @deprecated Use same field name, but from {@code org.owasp.esapi.PropNames} instead. */
+    @Deprecated public static final String MAX_OLD_PASSWORD_HASHES = PropNames.MAX_OLD_PASSWORD_HASHES;
+
+    /** @deprecated Use same field name, but from {@code org.owasp.esapi.PropNames} instead. */
+    @Deprecated public static final String ALLOW_MULTIPLE_ENCODING = PropNames.ALLOW_MULTIPLE_ENCODING;
+
+    /** @deprecated Use same field name, but from {@code org.owasp.esapi.PropNames} instead. */
+    @Deprecated public static final String ALLOW_MIXED_ENCODING    = PropNames.ALLOW_MIXED_ENCODING   ;
+
+    /** @deprecated Use same field name, but from {@code org.owasp.esapi.PropNames} instead. */
+    @Deprecated public static final String CANONICALIZATION_CODECS = PropNames.CANONICALIZATION_CODECS;
+
+    /** @deprecated Use same field name, but from {@code org.owasp.esapi.PropNames} instead. */
+    @Deprecated public static final String DISABLE_INTRUSION_DETECTION  = PropNames.DISABLE_INTRUSION_DETECTION ;
+
+    /** @deprecated Use same field name, but from {@code org.owasp.esapi.PropNames} instead. */
+    @Deprecated public static final String MASTER_KEY = PropNames.MASTER_KEY;
+
+    /** @deprecated Use same field name, but from {@code org.owasp.esapi.PropNames} instead. */
+    @Deprecated public static final String MASTER_SALT = PropNames.MASTER_SALT;
+
+    /** @deprecated Use same field name, but from {@code org.owasp.esapi.PropNames} instead. */
+    @Deprecated public static final String KEY_LENGTH = PropNames.KEY_LENGTH;
+
+    /** @deprecated Use same field name, but from {@code org.owasp.esapi.PropNames} instead. */
+    @Deprecated public static final String ENCRYPTION_ALGORITHM = PropNames.ENCRYPTION_ALGORITHM;
+
+    /** @deprecated Use same field name, but from {@code org.owasp.esapi.PropNames} instead. */
+    @Deprecated public static final String HASH_ALGORITHM = PropNames.HASH_ALGORITHM;
+
+    /** @deprecated Use same field name, but from {@code org.owasp.esapi.PropNames} instead. */
+    @Deprecated public static final String HASH_ITERATIONS = PropNames.HASH_ITERATIONS;
+
+    /** @deprecated Use same field name, but from {@code org.owasp.esapi.PropNames} instead. */
+    @Deprecated public static final String CHARACTER_ENCODING = PropNames.CHARACTER_ENCODING;
+
+    /** @deprecated Use same field name, but from {@code org.owasp.esapi.PropNames} instead. */
+    @Deprecated public static final String RANDOM_ALGORITHM = PropNames.RANDOM_ALGORITHM;
+
+    /** @deprecated Use same field name, but from {@code org.owasp.esapi.PropNames} instead. */
+    @Deprecated public static final String DIGITAL_SIGNATURE_ALGORITHM = PropNames.DIGITAL_SIGNATURE_ALGORITHM;
+
+    /** @deprecated Use same field name, but from {@code org.owasp.esapi.PropNames} instead. */
+    @Deprecated public static final String DIGITAL_SIGNATURE_KEY_LENGTH = PropNames.DIGITAL_SIGNATURE_KEY_LENGTH;
+
+                // ==================================//
+                //        New in ESAPI Java 2.x      //
+                // ================================= //
+    /** @deprecated Use same field name, but from {@code org.owasp.esapi.PropNames} instead. */
+    @Deprecated public static final String PREFERRED_JCE_PROVIDER = PropNames.PREFERRED_JCE_PROVIDER;
+
+    /** @deprecated Use same field name, but from {@code org.owasp.esapi.PropNames} instead. */
+    @Deprecated public static final String CIPHER_TRANSFORMATION_IMPLEMENTATION = PropNames.CIPHER_TRANSFORMATION_IMPLEMENTATION;
+
+    /** @deprecated Use same field name, but from {@code org.owasp.esapi.PropNames} instead. */
+    @Deprecated public static final String CIPHERTEXT_USE_MAC = PropNames.CIPHERTEXT_USE_MAC;
+
+    /** @deprecated Use same field name, but from {@code org.owasp.esapi.PropNames} instead. */
+    @Deprecated public static final String PLAINTEXT_OVERWRITE = PropNames.PLAINTEXT_OVERWRITE;
+
+    @Deprecated public static final String IV_TYPE = PropNames.IV_TYPE;    // Will be removed in future release.
+
+    /** @deprecated Use same field name, but from {@code org.owasp.esapi.PropNames} instead. */
+    @Deprecated public static final String COMBINED_CIPHER_MODES = PropNames.COMBINED_CIPHER_MODES;
+
+    /** @deprecated Use same field name, but from {@code org.owasp.esapi.PropNames} instead. */
+    @Deprecated public static final String ADDITIONAL_ALLOWED_CIPHER_MODES = PropNames.ADDITIONAL_ALLOWED_CIPHER_MODES;
+
+    /** @deprecated Use same field name, but from {@code org.owasp.esapi.PropNames} instead. */
+    @Deprecated public static final String KDF_PRF_ALG = PropNames.KDF_PRF_ALG;
+
+    /** @deprecated Use same field name, but from {@code org.owasp.esapi.PropNames} instead. */
+    @Deprecated public static final String PRINT_PROPERTIES_WHEN_LOADED = PropNames.PRINT_PROPERTIES_WHEN_LOADED;
+
+    /** @deprecated Use same field name, but from {@code org.owasp.esapi.PropNames} instead. */
+    @Deprecated public static final String WORKING_DIRECTORY = PropNames.WORKING_DIRECTORY;
+
+    /** @deprecated Use same field name, but from {@code org.owasp.esapi.PropNames} instead. */
+    @Deprecated public static final String APPROVED_EXECUTABLES = PropNames.APPROVED_EXECUTABLES;
+
+    /** @deprecated Use same field name, but from {@code org.owasp.esapi.PropNames} instead. */
+    @Deprecated public static final String FORCE_HTTPONLYSESSION = PropNames.FORCE_HTTPONLYSESSION;
+
+    /** @deprecated Use same field name, but from {@code org.owasp.esapi.PropNames} instead. */
+    @Deprecated public static final String FORCE_SECURESESSION = PropNames.FORCE_SECURESESSION;
+
+    /** @deprecated Use same field name, but from {@code org.owasp.esapi.PropNames} instead. */
+    @Deprecated public static final String FORCE_HTTPONLYCOOKIES = PropNames.FORCE_HTTPONLYCOOKIES;
+
+    /** @deprecated Use same field name, but from {@code org.owasp.esapi.PropNames} instead. */
+    @Deprecated public static final String FORCE_SECURECOOKIES = PropNames.FORCE_SECURECOOKIES;
+
+    /** @deprecated Use same field name, but from {@code org.owasp.esapi.PropNames} instead. */
+    @Deprecated public static final String MAX_HTTP_HEADER_SIZE = PropNames.MAX_HTTP_HEADER_SIZE;
+
+    /** @deprecated Use same field name, but from {@code org.owasp.esapi.PropNames} instead. */
+    @Deprecated public static final String UPLOAD_DIRECTORY = PropNames.UPLOAD_DIRECTORY;
+
+    /** @deprecated Use same field name, but from {@code org.owasp.esapi.PropNames} instead. */
+    @Deprecated public static final String UPLOAD_TEMP_DIRECTORY = PropNames.UPLOAD_TEMP_DIRECTORY;
+
+    /** @deprecated Use same field name, but from {@code org.owasp.esapi.PropNames} instead. */
+    @Deprecated public static final String APPROVED_UPLOAD_EXTENSIONS = PropNames.APPROVED_UPLOAD_EXTENSIONS;
+
+    /** @deprecated Use same field name, but from {@code org.owasp.esapi.PropNames} instead. */
+    @Deprecated public static final String MAX_UPLOAD_FILE_BYTES = PropNames.MAX_UPLOAD_FILE_BYTES;
+
+    /** @deprecated Use same field name, but from {@code org.owasp.esapi.PropNames} instead. */
+    @Deprecated public static final String RESPONSE_CONTENT_TYPE = PropNames.RESPONSE_CONTENT_TYPE;
+
+    /** @deprecated Use same field name, but from {@code org.owasp.esapi.PropNames} instead. */
+    @Deprecated public static final String HTTP_SESSION_ID_NAME = PropNames.HTTP_SESSION_ID_NAME;
+
+    /** @deprecated Use same field name, but from {@code org.owasp.esapi.PropNames} instead. */
+    @Deprecated public static final String APPLICATION_NAME = PropNames.APPLICATION_NAME;
+
+    /** @deprecated Use same field name, but from {@code org.owasp.esapi.PropNames} instead. */
+    @Deprecated public static final String LOG_ENCODING_REQUIRED = PropNames.LOG_ENCODING_REQUIRED;
+
+    /** @deprecated Use same field name, but from {@code org.owasp.esapi.PropNames} instead. */
+    @Deprecated public static final String LOG_APPLICATION_NAME = PropNames.LOG_APPLICATION_NAME;
+
+    /** @deprecated Use same field name, but from {@code org.owasp.esapi.PropNames} instead. */
+    @Deprecated public static final String LOG_SERVER_IP = PropNames.LOG_SERVER_IP;
+
+    /** @deprecated Use same field name, but from {@code org.owasp.esapi.PropNames} instead. */
+    @Deprecated public static final String LOG_USER_INFO = PropNames.LOG_USER_INFO;
+
+    /** @deprecated Use same field name, but from {@code org.owasp.esapi.PropNames} instead. */
+    @Deprecated public static final String LOG_CLIENT_INFO = PropNames.LOG_CLIENT_INFO;
+
+    /** @deprecated Use same field name, but from {@code org.owasp.esapi.PropNames} instead. */
+    @Deprecated public static final String VALIDATION_PROPERTIES = PropNames.VALIDATION_PROPERTIES;
+
+    /** @deprecated Use same field name, but from {@code org.owasp.esapi.PropNames} instead. */
+    @Deprecated public static final String VALIDATION_PROPERTIES_MULTIVALUED = PropNames.VALIDATION_PROPERTIES_MULTIVALUED;
+
+    /** @deprecated Use same field name, but from {@code org.owasp.esapi.PropNames} instead. */
+    @Deprecated public static final String ACCEPT_LENIENT_DATES = PropNames.ACCEPT_LENIENT_DATES;
+
+    /** @deprecated Use same field name, but from {@code org.owasp.esapi.PropNames} instead. */
+    @Deprecated public static final String VALIDATOR_HTML_VALIDATION_ACTION = PropNames.VALIDATOR_HTML_VALIDATION_ACTION;
+
+    /** @deprecated Use same field name, but from {@code org.owasp.esapi.PropNames} instead. */
+    @Deprecated public static final String VALIDATOR_HTML_VALIDATION_CONFIGURATION_FILE = PropNames.VALIDATOR_HTML_VALIDATION_CONFIGURATION_FILE;
+
+    /**
+     * Special {@code java.lang.System} property that, if set to {@code true}, will
      * disable logging from {@code DefaultSecurityConfiguration.logToStdout()}
      * methods, which is called from various {@code logSpecial()} methods.
      * @see org.owasp.esapi.reference.DefaultSecurityConfiguration#logToStdout(String msg, Throwable t)
+     * @deprecated Use same field name, but from {@code org.owasp.esapi.PropNames} instead.
      */
-    public static final String DISCARD_LOGSPECIAL = "org.owasp.esapi.logSpecial.discard";
+    @Deprecated public static final String DISCARD_LOGSPECIAL = PropNames.DISCARD_LOGSPECIAL;
 
     // We assume that this does not change in the middle of processing the
     // ESAPI.properties files and thus only fetch its value once.
-    private static final String logSpecialValue = System.getProperty(DISCARD_LOGSPECIAL, "false");
+    /** @deprecated Use same field name, but from {@code org.owasp.esapi.PropNames} instead. */
+    @Deprecated private static final String logSpecialValue = System.getProperty( PropNames.DISCARD_LOGSPECIAL, "false" );
 
 
     protected final int MAX_REDIRECT_LOCATION = 1000;
-    
+
+
     /*
      * Implementation Keys
      */
-    public static final String LOG_IMPLEMENTATION = "ESAPI.Logger";
-    public static final String AUTHENTICATION_IMPLEMENTATION = "ESAPI.Authenticator";
-    public static final String ENCODER_IMPLEMENTATION = "ESAPI.Encoder";
-    public static final String ACCESS_CONTROL_IMPLEMENTATION = "ESAPI.AccessControl";
-    public static final String ENCRYPTION_IMPLEMENTATION = "ESAPI.Encryptor";
-    public static final String INTRUSION_DETECTION_IMPLEMENTATION = "ESAPI.IntrusionDetector";
-    public static final String RANDOMIZER_IMPLEMENTATION = "ESAPI.Randomizer";
-	public static final String EXECUTOR_IMPLEMENTATION = "ESAPI.Executor";
-	public static final String VALIDATOR_IMPLEMENTATION = "ESAPI.Validator";
-	public static final String HTTP_UTILITIES_IMPLEMENTATION = "ESAPI.HTTPUtilities";
+
+    /** @deprecated Use same field name, but from {@code org.owasp.esapi.PropNames} instead. */
+    @Deprecated public static final String LOG_IMPLEMENTATION = PropNames.LOG_IMPLEMENTATION;
+
+    /** @deprecated Use same field name, but from {@code org.owasp.esapi.PropNames} instead. */
+    @Deprecated public static final String AUTHENTICATION_IMPLEMENTATION = PropNames.AUTHENTICATION_IMPLEMENTATION;
+
+    /** @deprecated Use same field name, but from {@code org.owasp.esapi.PropNames} instead. */
+    @Deprecated public static final String ENCODER_IMPLEMENTATION = PropNames.ENCODER_IMPLEMENTATION;
+
+    /** @deprecated Use same field name, but from {@code org.owasp.esapi.PropNames} instead. */
+    @Deprecated public static final String ACCESS_CONTROL_IMPLEMENTATION = PropNames.ACCESS_CONTROL_IMPLEMENTATION;
+
+    /** @deprecated Use same field name, but from {@code org.owasp.esapi.PropNames} instead. */
+    @Deprecated public static final String ENCRYPTION_IMPLEMENTATION = PropNames.ENCRYPTION_IMPLEMENTATION;
+
+    /** @deprecated Use same field name, but from {@code org.owasp.esapi.PropNames} instead. */
+    @Deprecated public static final String INTRUSION_DETECTION_IMPLEMENTATION = PropNames.INTRUSION_DETECTION_IMPLEMENTATION;
+
+    /** @deprecated Use same field name, but from {@code org.owasp.esapi.PropNames} instead. */
+    @Deprecated public static final String RANDOMIZER_IMPLEMENTATION = PropNames.RANDOMIZER_IMPLEMENTATION;
+
+    /** @deprecated Use same field name, but from {@code org.owasp.esapi.PropNames} instead. */
+    @Deprecated public static final String EXECUTOR_IMPLEMENTATION = PropNames.EXECUTOR_IMPLEMENTATION;
+
+    /** @deprecated Use same field name, but from {@code org.owasp.esapi.PropNames} instead. */
+    @Deprecated public static final String VALIDATOR_IMPLEMENTATION = PropNames.VALIDATOR_IMPLEMENTATION;
+
+    /** @deprecated Use same field name, but from {@code org.owasp.esapi.PropNames} instead. */
+    @Deprecated public static final String HTTP_UTILITIES_IMPLEMENTATION = PropNames.HTTP_UTILITIES_IMPLEMENTATION;
+
 
     /*
      * Default Implementations
      */
-    public static final String DEFAULT_LOG_IMPLEMENTATION = "org.owasp.esapi.logging.java.JavaLogFactory";
-    public static final String DEFAULT_AUTHENTICATION_IMPLEMENTATION = "org.owasp.esapi.reference.FileBasedAuthenticator";
-    public static final String DEFAULT_ENCODER_IMPLEMENTATION = "org.owasp.esapi.reference.DefaultEncoder";
-    public static final String DEFAULT_ACCESS_CONTROL_IMPLEMENTATION = "org.owasp.esapi.reference.DefaultAccessController";
-    public static final String DEFAULT_ENCRYPTION_IMPLEMENTATION = "org.owasp.esapi.reference.crypto.JavaEncryptor";
-    public static final String DEFAULT_INTRUSION_DETECTION_IMPLEMENTATION = "org.owasp.esapi.reference.DefaultIntrusionDetector";
-    public static final String DEFAULT_RANDOMIZER_IMPLEMENTATION = "org.owasp.esapi.reference.DefaultRandomizer";
-    public static final String DEFAULT_EXECUTOR_IMPLEMENTATION = "org.owasp.esapi.reference.DefaultExecutor";
-    public static final String DEFAULT_HTTP_UTILITIES_IMPLEMENTATION = "org.owasp.esapi.reference.DefaultHTTPUtilities";
-    public static final String DEFAULT_VALIDATOR_IMPLEMENTATION = "org.owasp.esapi.reference.DefaultValidator";
+
+    /** @deprecated Use same field name, but from {@code org.owasp.esapi.PropNames} instead. */
+    @Deprecated public static final String DEFAULT_LOG_IMPLEMENTATION = PropNames.DEFAULT_LOG_IMPLEMENTATION;
+
+    /** @deprecated Use same field name, but from {@code org.owasp.esapi.PropNames} instead. */
+    @Deprecated public static final String DEFAULT_AUTHENTICATION_IMPLEMENTATION = PropNames.DEFAULT_AUTHENTICATION_IMPLEMENTATION;
+
+    /** @deprecated Use same field name, but from {@code org.owasp.esapi.PropNames} instead. */
+    @Deprecated public static final String DEFAULT_ENCODER_IMPLEMENTATION = PropNames.DEFAULT_ENCODER_IMPLEMENTATION;
+
+    /** @deprecated Use same field name, but from {@code org.owasp.esapi.PropNames} instead. */
+    @Deprecated public static final String DEFAULT_ACCESS_CONTROL_IMPLEMENTATION = PropNames.DEFAULT_ACCESS_CONTROL_IMPLEMENTATION;
+
+    /** @deprecated Use same field name, but from {@code org.owasp.esapi.PropNames} instead. */
+    @Deprecated public static final String DEFAULT_ENCRYPTION_IMPLEMENTATION = PropNames.DEFAULT_ENCRYPTION_IMPLEMENTATION;
+
+    /** @deprecated Use same field name, but from {@code org.owasp.esapi.PropNames} instead. */
+    @Deprecated public static final String DEFAULT_INTRUSION_DETECTION_IMPLEMENTATION = PropNames.DEFAULT_INTRUSION_DETECTION_IMPLEMENTATION;
+
+    /** @deprecated Use same field name, but from {@code org.owasp.esapi.PropNames} instead. */
+    @Deprecated public static final String DEFAULT_RANDOMIZER_IMPLEMENTATION = PropNames.DEFAULT_RANDOMIZER_IMPLEMENTATION;
+
+    /** @deprecated Use same field name, but from {@code org.owasp.esapi.PropNames} instead. */
+    @Deprecated public static final String DEFAULT_EXECUTOR_IMPLEMENTATION = PropNames.DEFAULT_EXECUTOR_IMPLEMENTATION;
+
+    /** @deprecated Use same field name, but from {@code org.owasp.esapi.PropNames} instead. */
+    @Deprecated public static final String DEFAULT_HTTP_UTILITIES_IMPLEMENTATION = PropNames.DEFAULT_HTTP_UTILITIES_IMPLEMENTATION;
+
+    /** @deprecated Use same field name, but from {@code org.owasp.esapi.PropNames} instead. */
+    @Deprecated public static final String DEFAULT_VALIDATOR_IMPLEMENTATION = PropNames.DEFAULT_VALIDATOR_IMPLEMENTATION;
 
     private static final Map<String, Pattern> patternCache = new HashMap<String, Pattern>();
 
@@ -208,514 +361,513 @@ public class DefaultSecurityConfiguration implements SecurityConfiguration {
     private static final String userHome = System.getProperty("user.home" );
     /*
      * Absolute path to the customDirectory
-     */	// DISCUSS: Implicit assumption here that there is no SecurityManager installed enforcing the
-        //			prevention of reading system properties. Otherwise this will fail with SecurityException.
+     */    // DISCUSS: Implicit assumption here that there is no SecurityManager installed enforcing the
+        //            prevention of reading system properties. Otherwise this will fail with SecurityException.
     private static String customDirectory = System.getProperty("org.owasp.esapi.resources");
     /*
      * Relative path to the resourceDirectory. Relative to the classpath.
      * Specifically, ClassLoader.getResource(resourceDirectory + filename) will
      * be used to load the file.
      */
-    private String resourceDirectory = ".esapi";	// For backward compatibility (vs. "esapi")
-	private final String resourceFile;
+    private String resourceDirectory = ".esapi";    // For backward compatibility (vs. "esapi")
+    private final String resourceFile;
     private EsapiPropertyManager esapiPropertyManager;
 
-//    private static long lastModified = -1;
 
     /**
-     * Instantiates a new configuration, using the provided property file name
-     * 
+     * Instantiates a new configuration, using the provided property file name.
+     *
      * @param resourceFile The name of the property file to load
      */
     DefaultSecurityConfiguration(String resourceFile) {
-    	this.resourceFile = resourceFile;
-    	// load security configuration
-    	try {
+        this.resourceFile = resourceFile;
+        // load security configuration
+        try {
             this.esapiPropertyManager = new EsapiPropertyManager();
-        	loadConfiguration();
-        	this.setCipherXProperties();
+            loadConfiguration();
+            this.setCipherXProperties();
         } catch( IOException e ) {
-	        logSpecial("Failed to load security configuration", e );
-	        throw new ConfigurationException("Failed to load security configuration", e);
+            logSpecial("Failed to load security configuration", e );
+            throw new ConfigurationException("Failed to load security configuration", e);
         }
     }
-    
+
     /**
      * Instantiates a new configuration with the supplied properties.
-     * 
+     *
      * Warning - if the setResourceDirectory() method is invoked the properties will
      * be re-loaded, replacing the supplied properties.
-     * 
+     *
      * @param properties
      */
     public DefaultSecurityConfiguration(Properties properties) {
-    	resourceFile = DEFAULT_RESOURCE_FILE;
-    	try {
+        resourceFile = DEFAULT_RESOURCE_FILE;
+        try {
             this.esapiPropertyManager = new EsapiPropertyManager();
             // Do NOT call loadConfiguration() here!
         } catch( IOException e ) {
-	        logSpecial("Failed to load security configuration", e );
-	        throw new ConfigurationException("Failed to load security configuration", e);
+            logSpecial("Failed to load security configuration", e );
+            throw new ConfigurationException("Failed to load security configuration", e);
         }
-    	this.properties = properties; 
-    	this.setCipherXProperties();
+        this.properties = properties;
+        this.setCipherXProperties();
     }
-    
+
     /**
      * Instantiates a new configuration.
      */
     public DefaultSecurityConfiguration(){
-    	this(DEFAULT_RESOURCE_FILE);
+        this(DEFAULT_RESOURCE_FILE);
     }
     private void setCipherXProperties() {
-		// TODO: FUTURE: Replace by future CryptoControls class???
-		// See SecurityConfiguration.setCipherTransformation() for
-		// explanation of this.
+        // TODO: FUTURE: Replace by future CryptoControls class???
+        // See SecurityConfiguration.setCipherTransformation() for
+        // explanation of this.
         // (Propose this in a future 2.x release via future email to ESAPI-DEV list.)
-		cipherXformFromESAPIProp =
-			getESAPIProperty(CIPHER_TRANSFORMATION_IMPLEMENTATION,
-							 "AES/CBC/PKCS5Padding");
-		cipherXformCurrent = cipherXformFromESAPIProp;
+        cipherXformFromESAPIProp =
+            getESAPIProperty(CIPHER_TRANSFORMATION_IMPLEMENTATION,
+                             "AES/CBC/PKCS5Padding");
+        cipherXformCurrent = cipherXformFromESAPIProp;
     }
 
     /**
-	 * {@inheritDoc}
-	 */
+     * {@inheritDoc}
+     */
     public String getApplicationName() {
-    	return getESAPIProperty(APPLICATION_NAME, "DefaultName");
+        return getESAPIProperty(APPLICATION_NAME, "DefaultName");
     }
 
     /**
-	 * {@inheritDoc}
-	 */
+     * {@inheritDoc}
+     */
     public String getLogImplementation() {
-    	return getESAPIProperty(LOG_IMPLEMENTATION, DEFAULT_LOG_IMPLEMENTATION);
+        return getESAPIProperty(LOG_IMPLEMENTATION, DEFAULT_LOG_IMPLEMENTATION);
     }
 
     /**
-	 * {@inheritDoc}
-	 */
+     * {@inheritDoc}
+     */
     public String getAuthenticationImplementation() {
-    	return getESAPIProperty(AUTHENTICATION_IMPLEMENTATION, DEFAULT_AUTHENTICATION_IMPLEMENTATION);
+        return getESAPIProperty(AUTHENTICATION_IMPLEMENTATION, DEFAULT_AUTHENTICATION_IMPLEMENTATION);
     }
 
     /**
-	 * {@inheritDoc}
-	 */
+     * {@inheritDoc}
+     */
     public String getEncoderImplementation() {
-    	return getESAPIProperty(ENCODER_IMPLEMENTATION, DEFAULT_ENCODER_IMPLEMENTATION);
+        return getESAPIProperty(ENCODER_IMPLEMENTATION, DEFAULT_ENCODER_IMPLEMENTATION);
     }
 
     /**
-	 * {@inheritDoc}
-	 */
+     * {@inheritDoc}
+     */
     public String getAccessControlImplementation() {
-    	return getESAPIProperty(ACCESS_CONTROL_IMPLEMENTATION, DEFAULT_ACCESS_CONTROL_IMPLEMENTATION);
+        return getESAPIProperty(ACCESS_CONTROL_IMPLEMENTATION, DEFAULT_ACCESS_CONTROL_IMPLEMENTATION);
     }
 
     /**
-	 * {@inheritDoc}
-	 */
+     * {@inheritDoc}
+     */
     public String getEncryptionImplementation() {
-    	return getESAPIProperty(ENCRYPTION_IMPLEMENTATION, DEFAULT_ENCRYPTION_IMPLEMENTATION);
+        return getESAPIProperty(ENCRYPTION_IMPLEMENTATION, DEFAULT_ENCRYPTION_IMPLEMENTATION);
     }
 
     /**
-	 * {@inheritDoc}
-	 */
+     * {@inheritDoc}
+     */
     public String getIntrusionDetectionImplementation() {
-    	return getESAPIProperty(INTRUSION_DETECTION_IMPLEMENTATION, DEFAULT_INTRUSION_DETECTION_IMPLEMENTATION);
+        return getESAPIProperty(INTRUSION_DETECTION_IMPLEMENTATION, DEFAULT_INTRUSION_DETECTION_IMPLEMENTATION);
     }
 
     /**
-	 * {@inheritDoc}
-	 */
+     * {@inheritDoc}
+     */
     public String getRandomizerImplementation() {
-    	return getESAPIProperty(RANDOMIZER_IMPLEMENTATION, DEFAULT_RANDOMIZER_IMPLEMENTATION);
+        return getESAPIProperty(RANDOMIZER_IMPLEMENTATION, DEFAULT_RANDOMIZER_IMPLEMENTATION);
     }
 
     /**
-	 * {@inheritDoc}
-	 */
+     * {@inheritDoc}
+     */
     public String getExecutorImplementation() {
-    	return getESAPIProperty(EXECUTOR_IMPLEMENTATION, DEFAULT_EXECUTOR_IMPLEMENTATION);
+        return getESAPIProperty(EXECUTOR_IMPLEMENTATION, DEFAULT_EXECUTOR_IMPLEMENTATION);
     }
 
     /**
-	 * {@inheritDoc}
-	 */
+     * {@inheritDoc}
+     */
     public String getHTTPUtilitiesImplementation() {
-    	return getESAPIProperty(HTTP_UTILITIES_IMPLEMENTATION, DEFAULT_HTTP_UTILITIES_IMPLEMENTATION);
+        return getESAPIProperty(HTTP_UTILITIES_IMPLEMENTATION, DEFAULT_HTTP_UTILITIES_IMPLEMENTATION);
     }
 
     /**
-	 * {@inheritDoc}
-	 */
+     * {@inheritDoc}
+     */
     public String getValidationImplementation() {
-    	return getESAPIProperty(VALIDATOR_IMPLEMENTATION, DEFAULT_VALIDATOR_IMPLEMENTATION);
+        return getESAPIProperty(VALIDATOR_IMPLEMENTATION, DEFAULT_VALIDATOR_IMPLEMENTATION);
     }
 
 
     /**
-	 * {@inheritDoc}
-	 */
+     * {@inheritDoc}
+     */
     public byte[] getMasterKey() {
-    	byte[] key = getESAPIPropertyEncoded( MASTER_KEY, null );
-    	if ( key == null || key.length == 0 ) {
-    		throw new ConfigurationException("Property '" + MASTER_KEY +
-    							"' missing or empty in ESAPI.properties file.");
+        byte[] key = getESAPIPropertyEncoded( MASTER_KEY, null );
+        if ( key == null || key.length == 0 ) {
+            throw new ConfigurationException("Property '" + MASTER_KEY +
+                                "' missing or empty in ESAPI.properties file.");
     }
-    	return key;
+        return key;
     }
 
     /**
-	 * {@inheritDoc}
-	 */
+     * {@inheritDoc}
+     */
     public void setResourceDirectory( String dir ) {
-    	resourceDirectory = dir;
+        resourceDirectory = dir;
         logSpecial( "Reset resource directory to: " + dir, null );
 
         // reload configuration if necessary
-    	try {
-    		this.loadConfiguration();
-    	} catch( IOException e ) {
-	        logSpecial("Failed to load security configuration from " + dir, e);
-    	}
+        try {
+            this.loadConfiguration();
+        } catch( IOException e ) {
+            logSpecial("Failed to load security configuration from " + dir, e);
+        }
     }
 
     public int getEncryptionKeyLength() {
-    	return getESAPIProperty(KEY_LENGTH, 128 );
+        return getESAPIProperty(KEY_LENGTH, 128 );
     }
 
     /**
-	 * {@inheritDoc}
-	 */
+     * {@inheritDoc}
+     */
     public byte[] getMasterSalt() {
-    	byte[] salt = getESAPIPropertyEncoded( MASTER_SALT, null );
-    	if ( salt == null || salt.length == 0 ) {
-    		throw new ConfigurationException("Property '" + MASTER_SALT +
-    							"' missing or empty in ESAPI.properties file.");
+        byte[] salt = getESAPIPropertyEncoded( MASTER_SALT, null );
+        if ( salt == null || salt.length == 0 ) {
+            throw new ConfigurationException("Property '" + MASTER_SALT +
+                                "' missing or empty in ESAPI.properties file.");
     }
-    	return salt;
+        return salt;
     }
 
     /**
-	 * {@inheritDoc}
-	 */
-	public List<String> getAllowedExecutables() {
-    	String def = "";
+     * {@inheritDoc}
+     */
+    public List<String> getAllowedExecutables() {
+        String def = "";
         String[] exList = getESAPIProperty(APPROVED_EXECUTABLES,def).split(",");
         return Arrays.asList(exList);
     }
 
     /**
-	 * {@inheritDoc}
-	 */
-	public List<String> getAllowedFileExtensions() {
+     * {@inheritDoc}
+     */
+    public List<String> getAllowedFileExtensions() {
         String def = ".pdf,.txt,.jpg,.png";
         String[] extList = getESAPIProperty(APPROVED_UPLOAD_EXTENSIONS,def).split(",");
         return Arrays.asList(extList);
     }
 
     /**
-	 * {@inheritDoc}
-	 */
+     * {@inheritDoc}
+     */
     public int getAllowedFileUploadSize() {
         return getESAPIProperty(MAX_UPLOAD_FILE_BYTES, 5000000);
     }
 
 
     private Properties loadPropertiesFromStream( InputStream is, String name ) throws IOException {
-    	Properties config = new Properties();
+        Properties config = new Properties();
         try {
-	        config.load(is);
-	        logSpecial("Loaded '" + name + "' properties file", null);
+            config.load(is);
+            logSpecial("Loaded '" + name + "' properties file", null);
         } finally {
             if ( is != null ) try { is.close(); } catch( Exception e ) {}
         }
         return config;
     }
 
-	/**
-	 * Load configuration. Never prints properties.
-	 * 
-	 * @throws java.io.IOException
-	 *             if the file is inaccessible
-	 */
-	protected void loadConfiguration() throws IOException {
-		try {
-		    //first attempt file IO loading of properties
-			logSpecial("Attempting to load " + resourceFile + " via file I/O.");
-			properties = loadPropertiesFromStream(getResourceStream(resourceFile), resourceFile);
-			
-		} catch (Exception iae) {
-		    //if file I/O loading fails, attempt classpath based loading next
-		    logSpecial("Loading " + resourceFile + " via file I/O failed. Exception was: " + iae);
-			logSpecial("Attempting to load " + resourceFile + " via the classpath.");
-			try {
-				properties = loadConfigurationFromClasspath(resourceFile);
-			} catch (Exception e) {				
-				logSpecial(resourceFile + " could not be loaded by any means. Fail.", e);
-				throw new ConfigurationException(resourceFile + " could not be loaded by any means. Fail.", e);
-			}			
-		}
-		
-		// if properties loaded properly above, get validation properties and merge them into the main properties
-		if (properties != null) {
-			final Iterator<String> validationPropFileNames;
-			
-			//defaults to single-valued for backwards compatibility
-			final boolean multivalued= getESAPIProperty(VALIDATION_PROPERTIES_MULTIVALUED, false);
-			final String validationPropValue = getESAPIProperty(VALIDATION_PROPERTIES, "validation.properties");
-			
-			if(multivalued){
-				// the following cast warning goes away if the apache commons lib is updated to current version				
-				validationPropFileNames = StrTokenizer.getCSVInstance(validationPropValue);
-			} else {
-				validationPropFileNames = Collections.singletonList(validationPropValue).iterator();
-			}
-			
-			//clear any cached validation patterns so they can be reloaded from validation.properties
-			patternCache.clear();
-			while(validationPropFileNames.hasNext()){
-				String validationPropFileName = validationPropFileNames.next();
-				Properties validationProperties = null;
-				try {
-				    //first attempt file IO loading of properties
-					logSpecial("Attempting to load " + validationPropFileName + " via file I/O.");
-					validationProperties = loadPropertiesFromStream(getResourceStream(validationPropFileName), validationPropFileName);
-					
-				} catch (Exception iae) {
-				    //if file I/O loading fails, attempt classpath based loading next
-				    logSpecial("Loading " + validationPropFileName + " via file I/O failed.");
-					logSpecial("Attempting to load " + validationPropFileName + " via the classpath.");		
-					try {
-						validationProperties = loadConfigurationFromClasspath(validationPropFileName);
-					} catch (Exception e) {				
-						logSpecial(validationPropFileName + " could not be loaded by any means. fail.", e);
-					}			
-				}
-				
-				if (validationProperties != null) {
-			    	Iterator<?> i = validationProperties.keySet().iterator();
-			    	while( i.hasNext() ) {
-			    		String key = (String)i.next();
-			    		String value = validationProperties.getProperty(key);
-			    		properties.put( key, value);
-			    	}
-				}
-				
-		        if ( shouldPrintProperties() ) {
-		    	
-		    	//FIXME - make this chunk configurable
-		    	/*
-		        logSpecial("  ========Master Configuration========", null);
-		        //logSpecial( "  ResourceDirectory: " + DefaultSecurityConfiguration.resourceDirectory );
-		        Iterator j = new TreeSet( properties.keySet() ).iterator();
-		        while (j.hasNext()) {
-		            String key = (String)j.next();
-		            // print out properties, but not sensitive ones like MasterKey and MasterSalt
-		            if ( !key.contains( "Master" ) ) {
-		            		logSpecial("  |   " + key + "=" + properties.get(key), null);
-		        	}
-		        }
-		        */
-		        }   	
-	        }
-		}
-	}	
-	
-	/**
-	 * @param filename
-	 * @return An {@code InputStream} associated with the specified file name as
-	 *         a resource stream.
-	 * @throws IOException
-	 *             If the file cannot be found or opened for reading.
-	 */
-	public InputStream getResourceStream(String filename) throws IOException {
-		if (filename == null) {
-			return null;
-		}
-
-		try {
-			File f = getResourceFile(filename);
-			if (f != null && f.exists()) {
-				return new FileInputStream(f);
-			}
-		} catch (Exception e) {
-		}
-
-		throw new FileNotFoundException();
-	}
-	
-	/**
-	 * {@inheritDoc}
-	 */
-	public File getResourceFile(String filename) {
-		logSpecial("Attempting to load " + filename + " as resource file via file I/O.");
-
-		if (filename == null) {
-			logSpecial("Failed to load properties via FileIO. Filename is null.");
-			return null; // not found.
-		}
-
-		File f = null;
-
-		// first, allow command line overrides. -Dorg.owasp.esapi.resources
-		// directory
-		f = new File(customDirectory, filename);
-		if (customDirectory != null && f.canRead()) {
-			logSpecial("Found in 'org.owasp.esapi.resources' directory: " + f.getAbsolutePath());
-			return f;
-		} else {
-			logSpecial("Not found in 'org.owasp.esapi.resources' directory or file not readable: " + f.getAbsolutePath());
-		}
-
-		// if not found, then try the programmatically set resource directory
-		// (this defaults to SystemResource directory/resourceFile
-		URL fileUrl = ClassLoader.getSystemResource(resourceDirectory + "/" + filename);
+    /**
+     * Load configuration. Never prints properties.
+     *
+     * @throws java.io.IOException
+     *             if the file is inaccessible
+     */
+    protected void loadConfiguration() throws IOException {
+        try {
+            //first attempt file IO loading of properties
+            logSpecial("Attempting to load " + resourceFile + " via file I/O.");
+            properties = loadPropertiesFromStream(getResourceStream(resourceFile), resourceFile);
+        } catch (Exception iae) {
+            //if file I/O loading fails, attempt classpath based loading next
+            logSpecial("Loading " + resourceFile + " via file I/O failed. Exception was: " + iae);
+            logSpecial("Attempting to load " + resourceFile + " via the classpath.");
+            try {
+                properties = loadConfigurationFromClasspath(resourceFile);
+            } catch (Exception e) {
+                logSpecial(resourceFile + " could not be loaded by any means. Fail.", e);
+                throw new ConfigurationException(resourceFile + " could not be loaded by any means. Fail.", e);
+            }
+        }
+
+        // if properties loaded properly above, get validation properties and merge them into the main properties
+        if (properties != null) {
+            final Iterator<String> validationPropFileNames;
+
+            //defaults to single-valued for backwards compatibility
+            final boolean multivalued= getESAPIProperty(VALIDATION_PROPERTIES_MULTIVALUED, false);
+            final String validationPropValue = getESAPIProperty(VALIDATION_PROPERTIES, "validation.properties");
+
+            if(multivalued){
+                // the following cast warning goes away if the apache commons lib is updated to current version
+                validationPropFileNames = StrTokenizer.getCSVInstance(validationPropValue);
+            } else {
+                validationPropFileNames = Collections.singletonList(validationPropValue).iterator();
+            }
+
+            //clear any cached validation patterns so they can be reloaded from validation.properties
+            patternCache.clear();
+            while(validationPropFileNames.hasNext()){
+                String validationPropFileName = validationPropFileNames.next();
+                Properties validationProperties = null;
+                try {
+                    //first attempt file IO loading of properties
+                    logSpecial("Attempting to load " + validationPropFileName + " via file I/O.");
+                    validationProperties = loadPropertiesFromStream(getResourceStream(validationPropFileName), validationPropFileName);
+                } catch (Exception iae) {
+                    //if file I/O loading fails, attempt classpath based loading next
+                    logSpecial("Loading " + validationPropFileName + " via file I/O failed.");
+                    logSpecial("Attempting to load " + validationPropFileName + " via the classpath.");
+                    try {
+                        validationProperties = loadConfigurationFromClasspath(validationPropFileName);
+                    } catch (Exception e) {
+                        logSpecial(validationPropFileName + " could not be loaded by any means. fail.", e);
+                    }
+                }
+
+                if (validationProperties != null) {
+                    Iterator<?> i = validationProperties.keySet().iterator();
+                    while( i.hasNext() ) {
+                        String key = (String)i.next();
+                        String value = validationProperties.getProperty(key);
+                        properties.put( key, value);
+                    }
+                }
+
+                if ( shouldPrintProperties() ) {
+                        // Gotta give them something.
+                    logSpecial("DefaultSecurityConfiguration: The code to print all the properties is currently commented out");
+
+                    //FIXME - make this chunk configurable
+                    /*
+                        logSpecial("  ========Master Configuration========", null);
+                        //logSpecial( "  ResourceDirectory: " + DefaultSecurityConfiguration.resourceDirectory );
+                        Iterator j = new TreeSet( properties.keySet() ).iterator();
+                        while (j.hasNext()) {
+                            String key = (String)j.next();
+                            // print out properties, but not sensitive ones like MasterKey and MasterSalt
+                            if ( !key.contains( "Master" ) ) {
+                                    logSpecial("  |   " + key + "=" + properties.get(key), null);
+                            }
+                        }
+                    */
+                }
+            }
+        }
+    }
+
+    /**
+     * @param filename
+     * @return An {@code InputStream} associated with the specified file name as
+     *         a resource stream.
+     * @throws IOException
+     *             If the file cannot be found or opened for reading.
+     */
+    public InputStream getResourceStream(String filename) throws IOException {
+        if (filename == null) {
+            return null;
+        }
+
+        try {
+            File f = getResourceFile(filename);
+            if (f != null && f.exists()) {
+                return new FileInputStream(f);
+            }
+        } catch (Exception e) {
+        }
+
+        throw new FileNotFoundException();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public File getResourceFile(String filename) {
+        logSpecial("Attempting to load " + filename + " as resource file via file I/O.");
+
+        if (filename == null) {
+            logSpecial("Failed to load properties via FileIO. Filename is null.");
+            return null; // not found.
+        }
+
+        File f = null;
+
+        // first, allow command line overrides. -Dorg.owasp.esapi.resources
+        // directory
+        f = new File(customDirectory, filename);
+        if (customDirectory != null && f.canRead()) {
+            logSpecial("Found in 'org.owasp.esapi.resources' directory: " + f.getAbsolutePath());
+            return f;
+        } else {
+            logSpecial("Not found in 'org.owasp.esapi.resources' directory or file not readable: " + f.getAbsolutePath());
+        }
+
+        // if not found, then try the programmatically set resource directory
+        // (this defaults to SystemResource directory/resourceFile
+        URL fileUrl = ClassLoader.getSystemResource(resourceDirectory + "/" + filename);
         if ( fileUrl == null ) {
             fileUrl = ClassLoader.getSystemResource("esapi/" + filename);
         }
 
-		if (fileUrl != null) {
-			try {
-				String fileLocation = fileUrl.toURI().getPath();
-				f = new File(fileLocation);
-				if (f.exists()) {
-					logSpecial("Found in SystemResource Directory/resourceDirectory: " + f.getAbsolutePath());
-					return f;
-				} else {
-					logSpecial("Not found in SystemResource Directory/resourceDirectory (this should never happen): " + f.getAbsolutePath());
-				}
-			} catch (URISyntaxException e) {
-				logSpecial("Error while converting URL " + fileUrl + " to file path: " + e.getMessage());
-			}
-		} else {
-			logSpecial("Not found in SystemResource Directory/resourceDirectory: " + resourceDirectory + File.separator + filename);
-		}
-
-		// If not found, then try immediately under user's home directory first in
-		//		userHome + "/.esapi"		and secondly under
-		//		userHome + "/esapi"
-		// We look in that order because of backward compatibility issues.
-		String homeDir = userHome;
-		if ( homeDir == null ) {
-			homeDir = "";	// Without this,	homeDir + "/.esapi"	would produce
-							// the string		"null/.esapi"		which surely is not intended.
-		}
-		// First look under ".esapi" (for reasons of backward compatibility).
-		f = new File(homeDir + "/.esapi", filename);
-		if ( f.canRead() ) {
-			logSpecial("[Compatibility] Found in 'user.home' directory: " + f.getAbsolutePath());
-			return f;
-		} else {
-			// Didn't find it under old directory ".esapi" so now look under the "esapi" directory.
-			f = new File(homeDir + "/esapi", filename);
-			if ( f.canRead() ) {
-				logSpecial("Found in 'user.home' directory: " + f.getAbsolutePath());
-				return f;
-			} else {
-				logSpecial("Not found in 'user.home' (" + homeDir + ") directory: " + f.getAbsolutePath());
-			}
-		}
-
-		// return null if not found
-		return null;
-	}
-	
-    /**
-     * Used to load ESAPI.properties from a variety of different classpath locations.
+        if (fileUrl != null) {
+            try {
+                String fileLocation = fileUrl.toURI().getPath();
+                f = new File(fileLocation);
+                if (f.exists()) {
+                    logSpecial("Found in SystemResource Directory/resourceDirectory: " + f.getAbsolutePath());
+                    return f;
+                } else {
+                    logSpecial("Not found in SystemResource Directory/resourceDirectory (this should never happen): " + f.getAbsolutePath());
+                }
+            } catch (URISyntaxException e) {
+                logSpecial("Error while converting URL " + fileUrl + " to file path: " + e.getMessage());
+            }
+        } else {
+            logSpecial("Not found in SystemResource Directory/resourceDirectory: " + resourceDirectory + File.separator + filename);
+        }
+
+        // If not found, then try immediately under user's home directory first in
+        //        userHome + "/.esapi"        and secondly under
+        //        userHome + "/esapi"
+        // We look in that order because of backward compatibility issues.
+        String homeDir = userHome;
+        if ( homeDir == null ) {
+            homeDir = "";    // Without this,    homeDir + "/.esapi"    would produce
+                            // the string        "null/.esapi"        which surely is not intended.
+        }
+        // First look under ".esapi" (for reasons of backward compatibility).
+        f = new File(homeDir + "/.esapi", filename);
+        if ( f.canRead() ) {
+            logSpecial("[Compatibility] Found in 'user.home' directory: " + f.getAbsolutePath());
+            return f;
+        } else {
+            // Didn't find it under old directory ".esapi" so now look under the "esapi" directory.
+            f = new File(homeDir + "/esapi", filename);
+            if ( f.canRead() ) {
+                logSpecial("Found in 'user.home' directory: " + f.getAbsolutePath());
+                return f;
+            } else {
+                logSpecial("Not found in 'user.home' (" + homeDir + ") directory: " + f.getAbsolutePath());
+            }
+        }
+
+        // return null if not found
+        return null;
+    }
+
+    /**
+     * Used to load ESAPI.properties from a variety of different classpath locations. The order is described in the
+     * class overview Javadoc for this class.
      *
      * @param fileName The properties file filename.
      */
-	private Properties loadConfigurationFromClasspath(String fileName) throws IllegalArgumentException {
-		Properties result = null;
-		InputStream in = null;
-
-		ClassLoader[] loaders = new ClassLoader[] {
-				Thread.currentThread().getContextClassLoader(),
-				ClassLoader.getSystemClassLoader(),
-				getClass().getClassLoader() 
-		};
-		String[] classLoaderNames = {
-				"current thread context class loader",
-				"system class loader",
-				"class loader for DefaultSecurityConfiguration class"
-		};
-
-		ClassLoader currentLoader = null;
-		for (int i = 0; i < loaders.length; i++) {
-			if (loaders[i] != null) {
-				currentLoader = loaders[i];
-				try {
-					// try root
-					String currentClasspathSearchLocation = "/ (root)";
+    private Properties loadConfigurationFromClasspath(String fileName) throws IllegalArgumentException {
+        Properties result = null;
+        InputStream in = null;
+
+        ClassLoader[] loaders = new ClassLoader[] {
+                Thread.currentThread().getContextClassLoader(),
+                ClassLoader.getSystemClassLoader(),
+                getClass().getClassLoader()
+        };
+        String[] classLoaderNames = {
+                "current thread context class loader",
+                "system class loader",
+                "class loader for DefaultSecurityConfiguration class"
+        };
+
+        ClassLoader currentLoader = null;
+        for (int i = 0; i < loaders.length; i++) {
+            if (loaders[i] != null) {
+                currentLoader = loaders[i];
+                try {
+                    // try root
+                    String currentClasspathSearchLocation = "/ (root)";
                         // Note: do NOT add '/' anywhere here even though root value is empty string!
                         // Note that since DefaultSearchPath.ROOT.value() is now "" (the empty string),
                         // then this is logically equivalent to what we used to have, which was:
                         //
-						//      in = loaders[i].getResourceAsStream(fileName);
+                        //      in = loaders[i].getResourceAsStream(fileName);
                         //
-					in = loaders[i].getResourceAsStream(DefaultSearchPath.ROOT.value() + fileName);
-					
-					// try resourceDirectory folder
-					if (in == null) {
-						currentClasspathSearchLocation = resourceDirectory + "/";
-						in = currentLoader.getResourceAsStream(DefaultSearchPath.RESOURCE_DIRECTORY.value() + fileName);
-					}
-
-					// try .esapi folder. Look here first for backward compatibility.
-					if (in == null) {
-						currentClasspathSearchLocation = ".esapi/";
-						in = currentLoader.getResourceAsStream(DefaultSearchPath.DOT_ESAPI.value() + fileName);
-					} 
-					
-					// try esapi folder (new directory)
-					if (in == null) {
-						currentClasspathSearchLocation = "esapi/";
-						in = currentLoader.getResourceAsStream(DefaultSearchPath.ESAPI.value() + fileName);
-					} 
-					
-					// try resources folder
-					if (in == null) {
-						currentClasspathSearchLocation = "resources/";
-						in = currentLoader.getResourceAsStream(DefaultSearchPath.RESOURCES.value() + fileName);
-					}
-					
-					// try src/main/resources folder
-					if (in == null) {
-						currentClasspathSearchLocation = "src/main/resources/";
-						in = currentLoader.getResourceAsStream(DefaultSearchPath.SRC_MAIN_RESOURCES.value() + fileName);
-					}
-		
-					// now load the properties
-					if (in != null) {
-						result = new Properties();
-						result.load(in); // Can throw IOException
-						logSpecial("SUCCESSFULLY LOADED " + fileName + " via the CLASSPATH from '" +
-								currentClasspathSearchLocation + "' using " + classLoaderNames[i] + "!");
-						break;	// Outta here since we've found and loaded it.
-					}
-				} catch (Exception e) {
-					result = null;
-		
-				} finally {
-					try {
-						in.close();
-					} catch (Exception e) {
-					}
-				}
-			}
-		}
-
-		if (result == null) {
-			// CHECKME: This is odd...why not ConfigurationException?
-		    throw new IllegalArgumentException("Failed to load " + resourceFile + " as a classloader resource.");
-		}
-
-		return result;
-	}
+                    in = loaders[i].getResourceAsStream(DefaultSearchPath.ROOT.value() + fileName);
+
+                    // try resourceDirectory folder
+                    if (in == null) {
+                        currentClasspathSearchLocation = resourceDirectory + "/";
+                        in = currentLoader.getResourceAsStream(DefaultSearchPath.RESOURCE_DIRECTORY.value() + fileName);
+                    }
+
+                    // try .esapi folder. Look here first for backward compatibility.
+                    if (in == null) {
+                        currentClasspathSearchLocation = ".esapi/";
+                        in = currentLoader.getResourceAsStream(DefaultSearchPath.DOT_ESAPI.value() + fileName);
+                    }
+
+                    // try esapi folder (new directory)
+                    if (in == null) {
+                        currentClasspathSearchLocation = "esapi/";
+                        in = currentLoader.getResourceAsStream(DefaultSearchPath.ESAPI.value() + fileName);
+                    }
+
+                    // try resources folder
+                    if (in == null) {
+                        currentClasspathSearchLocation = "resources/";
+                        in = currentLoader.getResourceAsStream(DefaultSearchPath.RESOURCES.value() + fileName);
+                    }
+
+                    // try src/main/resources folder
+                    if (in == null) {
+                        currentClasspathSearchLocation = "src/main/resources/";
+                        in = currentLoader.getResourceAsStream(DefaultSearchPath.SRC_MAIN_RESOURCES.value() + fileName);
+                    }
+
+                    // now load the properties
+                    if (in != null) {
+                        result = new Properties();
+                        result.load(in); // Can throw IOException
+                        logSpecial("SUCCESSFULLY LOADED " + fileName + " via the CLASSPATH from '" +
+                                currentClasspathSearchLocation + "' using " + classLoaderNames[i] + "!");
+                        break;    // Outta here since we've found and loaded it.
+                    }
+                } catch (Exception e) {
+                    result = null;
+                } finally {
+                    try {
+                        in.close();
+                    } catch (Exception e) {
+                    }
+                }
+            }
+        }
+
+        if (result == null) {
+            // CHECKME: This is odd...why not ConfigurationException?
+            throw new IllegalArgumentException("Failed to load " + resourceFile + " as a classloader resource.");
+        }
+
+        return result;
+    }
 
     /**
      * Log to standard output (i.e., {@code System.out}. This method is
@@ -749,7 +901,7 @@ public class DefaultSecurityConfiguration implements SecurityConfiguration {
                                "; exception message was: " + t);
         }
     }
-    
+
     /**
      * Used to log errors to the console during the loading of the properties file itself. Can't use
      * standard logging in this case, since the Logger may not be initialized yet. Output is sent to
@@ -772,36 +924,36 @@ public class DefaultSecurityConfiguration implements SecurityConfiguration {
      * @param message The message to send to the console.
      */
     private void logSpecial(String message) {
-		logToStdout(message, null);
+        logToStdout(message, null);
     }
     /**
-	 * {@inheritDoc}
-	 */
+     * {@inheritDoc}
+     */
     public String getPasswordParameterName() {
         return getESAPIProperty(PASSWORD_PARAMETER_NAME, "password");
     }
 
     /**
-	 * {@inheritDoc}
-	 */
+     * {@inheritDoc}
+     */
     public String getUsernameParameterName() {
         return getESAPIProperty(USERNAME_PARAMETER_NAME, "username");
     }
 
     /**
-	 * {@inheritDoc}
-	 */
+     * {@inheritDoc}
+     */
     public String getEncryptionAlgorithm() {
         return getESAPIProperty(ENCRYPTION_ALGORITHM, "AES");
     }
 
     /**
-	 * {@inheritDoc}
-	 */
+     * {@inheritDoc}
+     */
     public String getCipherTransformation() {
         // Assertion should be okay here. An NPE is likely at runtime if disabled.
-    	assert cipherXformCurrent != null : "Current cipher transformation is null";
-    	return cipherXformCurrent;
+        assert cipherXformCurrent != null : "Current cipher transformation is null";
+        return cipherXformCurrent;
     }
 
     /**
@@ -825,159 +977,160 @@ public class DefaultSecurityConfiguration implements SecurityConfiguration {
      * {@inheritDoc}
      */
     public boolean useMACforCipherText() {
-    	return getESAPIProperty(CIPHERTEXT_USE_MAC, true);
+        return getESAPIProperty(CIPHERTEXT_USE_MAC, true);
     }
 
     /**
      * {@inheritDoc}
      */
     public boolean overwritePlainText() {
-    	return getESAPIProperty(PLAINTEXT_OVERWRITE, true);
+        return getESAPIProperty(PLAINTEXT_OVERWRITE, true);
     }
-    
+
     /**
-	 * {@inheritDoc}
-	 */
+     * {@inheritDoc}
+     */
     @Deprecated
     public String getIVType() {
-    	String value = getESAPIProperty(IV_TYPE, "random");
-    	if ( value.equalsIgnoreCase("random") ) {
+        String value = getESAPIProperty(IV_TYPE, "random");
+        if ( value.equalsIgnoreCase("random") ) {
             return value;
         } else if ( value.equalsIgnoreCase("fixed") ) {
             logSpecial("WARNING: Property '" + IV_TYPE + "=fixed' is no longer supported AT ALL!!! It had been deprecated since 2.2.0.0 and back then, was announced it would be removed in release 2.3.0.0. It was originally intended to support legacy applications, but is inherently insecure, especially with any streaming mode.");
-    		throw new ConfigurationException("'" + IV_TYPE + "=fixed' is no longer supported AT ALL. It has been deprecated since release 2.2 and has been removed since 2.3.");
-    	} else if ( value.equalsIgnoreCase("specified") ) {
-    		// Originally, this was planned for future implementation where setting
-    		//      Encryptor.ChooseIVMethod=specified
+            throw new ConfigurationException("'" + IV_TYPE + "=fixed' is no longer supported AT ALL. It has been deprecated since release 2.2 and has been removed since 2.3.");
+        } else if ( value.equalsIgnoreCase("specified") ) {
+            // Originally, this was planned for future implementation where setting
+            //      Encryptor.ChooseIVMethod=specified
             // would have allowed a dev to write their own static method to be
             // invoked in a future TBD property, but that is a recipe for
             // disaster. So, it's not going to happen. Ever.
-    		throw new ConfigurationException("Contrary to previous internal comments, '" + IV_TYPE + "=specified' is not going to be supported -- ever.");
-    	} else {
-    		logSpecial("WARNING: '" + value + "' is illegal value for " + IV_TYPE +
-    										 ". Using 'random' for the IV type.");
-    	}
+            throw new ConfigurationException("Contrary to previous internal comments, '" + IV_TYPE + "=specified' is not going to be supported -- ever.");
+        } else {
+            logSpecial("WARNING: '" + value + "' is illegal value for " + IV_TYPE +
+                                             ". Using 'random' for the IV type.");
+        }
         return "random";
     }
 
     /**
-	 * {@inheritDoc}
-	 */
+     * {@inheritDoc}
+     */
     public String getHashAlgorithm() {
         return getESAPIProperty(HASH_ALGORITHM, "SHA-512");
     }
 
     /**
-	 * {@inheritDoc}
-	 */
+     * {@inheritDoc}
+     */
     public int getHashIterations() {
-    	return getESAPIProperty(HASH_ITERATIONS, 1024);
+        return getESAPIProperty(HASH_ITERATIONS, 1024);
     }
 
     /**
      * {@inheritDoc}
      */
-	public String getKDFPseudoRandomFunction() {
-		return getESAPIProperty(KDF_PRF_ALG, "HmacSHA256");  // NSA recommended SHA2 or better.
-	}
+    public String getKDFPseudoRandomFunction() {
+        return getESAPIProperty(KDF_PRF_ALG, "HmacSHA256");  // NSA recommended SHA2 or better.
+    }
 
     /**
-	 * {@inheritDoc}
-	 */
+     * {@inheritDoc}
+     */
     public String getCharacterEncoding() {
         return getESAPIProperty(CHARACTER_ENCODING, "UTF-8");
     }
 
     /**
-	 * {@inheritDoc}
-	 */
-	public boolean getAllowMultipleEncoding() {
-		return getESAPIProperty( ALLOW_MULTIPLE_ENCODING, false );
-	}
+     * {@inheritDoc}
+     */
+    public boolean getAllowMultipleEncoding() {
+        return getESAPIProperty( ALLOW_MULTIPLE_ENCODING, false );
+    }
 
     /**
-	 * {@inheritDoc}
-	 */
-	public boolean getAllowMixedEncoding() {
-		return getESAPIProperty( ALLOW_MIXED_ENCODING, false );
-	}
+     * {@inheritDoc}
+     */
+    public boolean getAllowMixedEncoding() {
+        return getESAPIProperty( ALLOW_MIXED_ENCODING, false );
+    }
 
     /**
-	 * {@inheritDoc}
-	 */
-	public List<String> getDefaultCanonicalizationCodecs() {
-		List<String> def = new ArrayList<String>();
-		def.add( "org.owasp.esapi.codecs.HTMLEntityCodec" );
-		def.add( "org.owasp.esapi.codecs.PercentCodec" );
-		def.add( "org.owasp.esapi.codecs.JavaScriptCodec" );
-		return getESAPIProperty( CANONICALIZATION_CODECS, def );
-	}
+     * {@inheritDoc}
+     */
+    public List<String> getDefaultCanonicalizationCodecs() {
+        List<String> def = new ArrayList<String>();
+        def.add( "org.owasp.esapi.codecs.HTMLEntityCodec" );
+        def.add( "org.owasp.esapi.codecs.PercentCodec" );
+        def.add( "org.owasp.esapi.codecs.JavaScriptCodec" );
+        return getESAPIProperty( CANONICALIZATION_CODECS, def );
+    }
 
     /**
-	 * {@inheritDoc}
-	 */
+     * {@inheritDoc}
+     */
     public String getDigitalSignatureAlgorithm() {
         return getESAPIProperty(DIGITAL_SIGNATURE_ALGORITHM, "SHAwithDSA");
     }
 
     /**
-	 * {@inheritDoc}
-	 */
+     * {@inheritDoc}
+     */
     public int getDigitalSignatureKeyLength() {
         return getESAPIProperty(DIGITAL_SIGNATURE_KEY_LENGTH, 1024);
     }
 
     /**
-	 * {@inheritDoc}
-	 */
+     * {@inheritDoc}
+     */
     public String getRandomAlgorithm() {
         return getESAPIProperty(RANDOM_ALGORITHM, "SHA1PRNG");
     }
 
     /**
-	 * {@inheritDoc}
-	 */
+     * {@inheritDoc}
+     */
     public int getAllowedLoginAttempts() {
         return getESAPIProperty(ALLOWED_LOGIN_ATTEMPTS, 5);
     }
 
     /**
-	 * {@inheritDoc}
-	 */
+     * {@inheritDoc}
+     */
     public int getMaxOldPasswordHashes() {
         return getESAPIProperty(MAX_OLD_PASSWORD_HASHES, 12);
     }
 
     /**
-	 * {@inheritDoc}
-	 */
+     * {@inheritDoc}
+     */
     public File getUploadDirectory() {
-    	String dir = getESAPIProperty( UPLOAD_DIRECTORY, "UploadDir");
-    	return new File( dir );
+        String dir = getESAPIProperty( UPLOAD_DIRECTORY, "UploadDir");
+        return new File( dir );
     }
 
     /**
-	 * {@inheritDoc}
-	 */
+     * {@inheritDoc}
+     */
     public File getUploadTempDirectory() {
-    	String dir = getESAPIProperty(UPLOAD_TEMP_DIRECTORY,
-            System.getProperty("java.io.tmpdir","UploadTempDir"));
-    	return new File( dir );
+        String dir = getESAPIProperty(UPLOAD_TEMP_DIRECTORY,
+                                      System.getProperty("java.io.tmpdir","UploadTempDir")
+                                     );
+        return new File( dir );
     }
-    
+
     /**
-	 * {@inheritDoc}
-	 */
-	public boolean getDisableIntrusionDetection() {
-    	String value = properties.getProperty( DISABLE_INTRUSION_DETECTION );
-    	if ("true".equalsIgnoreCase(value)) return true;
-    	return false;	// Default result
-	}
+     * {@inheritDoc}
+     */
+    public boolean getDisableIntrusionDetection() {
+        String value = properties.getProperty( DISABLE_INTRUSION_DETECTION );
+        if ("true".equalsIgnoreCase(value)) return true;
+        return false;    // Default result
+    }
 
     /**
-	 * {@inheritDoc}
-	 */
-	public Threshold getQuota(String eventName) {
+     * {@inheritDoc}
+     */
+    public Threshold getQuota(String eventName) {
         int count = getESAPIProperty("IntrusionDetector." + eventName + ".count", 0);
         int interval =  getESAPIProperty("IntrusionDetector." + eventName + ".interval", 0);
         List<String> actions = new ArrayList<String>();
@@ -987,254 +1140,254 @@ public class DefaultSecurityConfiguration implements SecurityConfiguration {
             actions = Arrays.asList(actionList);
         }
         if ( count > 0 && interval > 0 && actions.size() > 0 ) {
-        	return new Threshold(eventName, count, interval, actions);
+            return new Threshold(eventName, count, interval, actions);
         }
         return null;
     }
 
     /**
-	 * {@inheritDoc}
-	 */
+     * {@inheritDoc}
+     */
     public boolean getLogEncodingRequired() {
-    	return getESAPIProperty( LOG_ENCODING_REQUIRED, false );
-	}
+        return getESAPIProperty( LOG_ENCODING_REQUIRED, false );
+    }
 
 
     /**
-	 * {@inheritDoc}
-	 */
+     * {@inheritDoc}
+     */
     public boolean getLogApplicationName() {
-    	return getESAPIProperty( LOG_APPLICATION_NAME, true );
-	}
+        return getESAPIProperty( LOG_APPLICATION_NAME, true );
+    }
 
 
     /**
-	 * {@inheritDoc}
-	 */
+     * {@inheritDoc}
+     */
     public boolean getLogServerIP() {
-    	return getESAPIProperty( LOG_SERVER_IP, true );
-	}
+        return getESAPIProperty( LOG_SERVER_IP, true );
+    }
 
     /**
-	 * {@inheritDoc}
-	 */
+     * {@inheritDoc}
+     */
     public boolean getForceHttpOnlySession() {
-    	return getESAPIProperty( FORCE_HTTPONLYSESSION, true );
+        return getESAPIProperty( FORCE_HTTPONLYSESSION, true );
     }
 
     /**
-	 * {@inheritDoc}
-	 */
+     * {@inheritDoc}
+     */
     public boolean getForceSecureSession() {
-    	return getESAPIProperty( FORCE_SECURESESSION, true );
+        return getESAPIProperty( FORCE_SECURESESSION, true );
     }
 
     /**
-	 * {@inheritDoc}
-	 */
+     * {@inheritDoc}
+     */
     public boolean getForceHttpOnlyCookies() {
-    	return getESAPIProperty( FORCE_HTTPONLYCOOKIES, true );
+        return getESAPIProperty( FORCE_HTTPONLYCOOKIES, true );
     }
 
     /**
-	 * {@inheritDoc}
-	 */
+     * {@inheritDoc}
+     */
     public boolean getForceSecureCookies() {
-    	return getESAPIProperty( FORCE_SECURECOOKIES, true );
+        return getESAPIProperty( FORCE_SECURECOOKIES, true );
     }
 
     /**
-	 * {@inheritDoc}
-	 */
-	public int getMaxHttpHeaderSize() {
+     * {@inheritDoc}
+     */
+    public int getMaxHttpHeaderSize() {
         return getESAPIProperty( MAX_HTTP_HEADER_SIZE, 4096);
-	}
+    }
 
     /**
-	 * {@inheritDoc}
-	 */
-	public String getResponseContentType() {
+     * {@inheritDoc}
+     */
+    public String getResponseContentType() {
         return getESAPIProperty( RESPONSE_CONTENT_TYPE, "text/html; charset=UTF-8" );
     }
 
-	/**
-	 * {@inheritDoc}
-	 */
-	public String getHttpSessionIdName() {
+    /**
+     * {@inheritDoc}
+     */
+    public String getHttpSessionIdName() {
         return getESAPIProperty( HTTP_SESSION_ID_NAME, "JSESSIONID" );
     }
-	
-	/**
-	 * {@inheritDoc}
-	 */
+
+    /**
+     * {@inheritDoc}
+     */
     public long getRememberTokenDuration() {
         int days = getESAPIProperty( REMEMBER_TOKEN_DURATION, 14 );
         return (long) (1000 * 60 * 60 * 24 * days);
     }
 
     /**
-	 * {@inheritDoc}
-	 */
-	public int getSessionIdleTimeoutLength() {
+     * {@inheritDoc}
+     */
+    public int getSessionIdleTimeoutLength() {
         int minutes = getESAPIProperty( IDLE_TIMEOUT_DURATION, 20 );
         return 1000 * 60 * minutes;
-	}
+    }
 
-	/**
-	 * {@inheritDoc}
-	 */
-	public int getSessionAbsoluteTimeoutLength() {
+    /**
+     * {@inheritDoc}
+     */
+    public int getSessionAbsoluteTimeoutLength() {
         int minutes = getESAPIProperty(ABSOLUTE_TIMEOUT_DURATION, 20 );
         return 1000 * 60 * minutes;
-	}
+    }
 
    /**
     * getValidationPattern returns a single pattern based upon key
     *
     *  @param key
-    *  			validation pattern name you'd like
+    *              validation pattern name you'd like
     *  @return
-    *  			if key exists, the associated validation pattern, null otherwise
-	*/
+    *              if key exists, the associated validation pattern, null otherwise
+    */
     public Pattern getValidationPattern( String key ) {
-    	String value = getESAPIProperty( "Validator." + key, "" );
-    	// check cache
-    	Pattern p = patternCache.get( value );
-    	if ( p != null ) return p;
+        String value = getESAPIProperty( "Validator." + key, "" );
+        // check cache
+        Pattern p = patternCache.get( value );
+        if ( p != null ) return p;
 
-    	// compile a new pattern
-    	if ( value == null || value.equals( "" ) ) return null;
-    	try {
-    		Pattern q = Pattern.compile(value);
-    		patternCache.put( value, q );
-    		return q;
-    	} catch ( PatternSyntaxException e ) {
-    		logSpecial( "SecurityConfiguration for " + key + " not a valid regex in ESAPI.properties. Returning null", null );
-    		return null;
-    	}
+        // compile a new pattern
+        if ( value == null || value.equals( "" ) ) return null;
+        try {
+            Pattern q = Pattern.compile(value);
+            patternCache.put( value, q );
+            return q;
+        } catch ( PatternSyntaxException e ) {
+            logSpecial( "SecurityConfiguration for " + key + " not a valid regex in ESAPI.properties. Returning null", null );
+            return null;
+        }
     }
 
     /**
      * getWorkingDirectory returns the default directory where processes will be executed
      * by the Executor.
      */
-	public File getWorkingDirectory() {
-		String dir = getESAPIProperty( WORKING_DIRECTORY, System.getProperty( "user.dir") );
-		if ( dir != null ) {
-			return new File( dir );
-		}
-		return null;
-	}
-	
-	/**
-	 * {@inheritDoc}
-	 */
-	public String getPreferredJCEProvider() {
-	    return properties.getProperty(PREFERRED_JCE_PROVIDER); // No default!
-	}  
-
-	/**
-	 * {@inheritDoc}
-	 */
-	public List<String> getCombinedCipherModes()
-	{
-	    List<String> empty = new ArrayList<String>();     // Default is empty list
-	    return getESAPIProperty(COMBINED_CIPHER_MODES, empty);
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	public List<String> getAdditionalAllowedCipherModes()
-	{
-	    List<String> empty = new ArrayList<String>();     // Default is empty list
-	    return getESAPIProperty(ADDITIONAL_ALLOWED_CIPHER_MODES, empty);
-	}
-	
-	/**
-	 * {@inheritDoc}
-	 */
-	public boolean getLenientDatesAccepted() {
-		return getESAPIProperty( ACCEPT_LENIENT_DATES, false);
-	}
-
-	protected String getESAPIProperty( String key, String def ) {
-		String value = properties.getProperty(key);
-		if ( value == null ) {
-    		logSpecial( "SecurityConfiguration for " + key + " not found in ESAPI.properties. Using default: " + def, null );
-    		return def;
-		}
-		return value;
-	}
-
-	protected boolean getESAPIProperty( String key, boolean def ) {
-		String property = properties.getProperty(key);
-		if ( property == null ) {
-    		logSpecial( "SecurityConfiguration for " + key + " not found in ESAPI.properties. Using default: " + def, null );
-    		return def;
-		}
-		if ( property.equalsIgnoreCase("true") || property.equalsIgnoreCase("yes" ) ) {
-			return true;
-		}
-		if ( property.equalsIgnoreCase("false") || property.equalsIgnoreCase( "no" ) ) {
-			return false;
-		}
-		logSpecial( "SecurityConfiguration for " + key + " not either \"true\" or \"false\" in ESAPI.properties. Using default: " + def, null );
-		return def;
-	}
-
-	protected byte[] getESAPIPropertyEncoded( String key, byte[] def ) {
-		String property = properties.getProperty(key);
-		if ( property == null ) {
-    		logSpecial( "SecurityConfiguration for " + key + " not found in ESAPI.properties. Using default: " + def, null );
-    		return def;
-		}
+    public File getWorkingDirectory() {
+        String dir = getESAPIProperty( WORKING_DIRECTORY, System.getProperty( "user.dir") );
+        if ( dir != null ) {
+            return new File( dir );
+        }
+        return null;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public String getPreferredJCEProvider() {
+        return properties.getProperty(PREFERRED_JCE_PROVIDER); // No default!
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public List<String> getCombinedCipherModes()
+    {
+        List<String> empty = new ArrayList<String>();     // Default is empty list
+        return getESAPIProperty(COMBINED_CIPHER_MODES, empty);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public List<String> getAdditionalAllowedCipherModes()
+    {
+        List<String> empty = new ArrayList<String>();     // Default is empty list
+        return getESAPIProperty(ADDITIONAL_ALLOWED_CIPHER_MODES, empty);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean getLenientDatesAccepted() {
+        return getESAPIProperty( ACCEPT_LENIENT_DATES, false);
+    }
+
+    protected String getESAPIProperty( String key, String def ) {
+        String value = properties.getProperty(key);
+        if ( value == null ) {
+            logSpecial( "SecurityConfiguration for " + key + " not found in ESAPI.properties. Using default: " + def, null );
+            return def;
+        }
+        return value;
+    }
+
+    protected boolean getESAPIProperty( String key, boolean def ) {
+        String property = properties.getProperty(key);
+        if ( property == null ) {
+            logSpecial( "SecurityConfiguration for " + key + " not found in ESAPI.properties. Using default: " + def, null );
+            return def;
+        }
+        if ( property.equalsIgnoreCase("true") || property.equalsIgnoreCase("yes" ) ) {
+            return true;
+        }
+        if ( property.equalsIgnoreCase("false") || property.equalsIgnoreCase( "no" ) ) {
+            return false;
+        }
+        logSpecial( "SecurityConfiguration for " + key + " not either \"true\" or \"false\" in ESAPI.properties. Using default: " + def, null );
+        return def;
+    }
+
+    protected byte[] getESAPIPropertyEncoded( String key, byte[] def ) {
+        String property = properties.getProperty(key);
+        if ( property == null ) {
+            logSpecial( "SecurityConfiguration for " + key + " not found in ESAPI.properties. Using default: " + def, null );
+            return def;
+        }
         try {
             return ESAPI.encoder().decodeFromBase64(property);
         } catch( IOException e ) {
-    		logSpecial( "SecurityConfiguration for " + key + " not properly Base64 encoded in ESAPI.properties. Using default: " + def, null );
+            logSpecial( "SecurityConfiguration for " + key + " not properly Base64 encoded in ESAPI.properties. Using default: " + def, null );
             return null;
         }
-	}
-
-	protected int getESAPIProperty( String key, int def ) {
-		String property = properties.getProperty(key);
-		if ( property == null ) {
-    		logSpecial( "SecurityConfiguration for " + key + " not found in ESAPI.properties. Using default: " + def, null );
-    		return def;
-		}
-		try {
+    }
+
+    protected int getESAPIProperty( String key, int def ) {
+        String property = properties.getProperty(key);
+        if ( property == null ) {
+            logSpecial( "SecurityConfiguration for " + key + " not found in ESAPI.properties. Using default: " + def, null );
+            return def;
+        }
+        try {
             return Integer.parseInt( property );
-		} catch( NumberFormatException e ) {
-    		logSpecial( "SecurityConfiguration for " + key + " not an integer in ESAPI.properties. Using default: " + def, null );
-			return def;
-		}
-	}
+        } catch( NumberFormatException e ) {
+            logSpecial( "SecurityConfiguration for " + key + " not an integer in ESAPI.properties. Using default: " + def, null );
+            return def;
+        }
+    }
 
-	/**
+    /**
      * Returns a {@code List} representing the parsed, comma-separated property.
-     * 
-	 * @param key  The specified property name
-	 * @param def  A default value for the property name to return if the property
-	 *             is not set.
-	 * @return A list of strings.
-	 */
-	protected List<String> getESAPIProperty( String key, List<String> def ) {
-	    String property = properties.getProperty( key );
-	    if ( property == null ) {
-	        logSpecial( "SecurityConfiguration for " + key + " not found in ESAPI.properties. Using default: " + def, null );
-	        return def;
-	    }
-	    String[] parts = property.split(",");
-	    return Arrays.asList( parts );
-	}
+     *
+     * @param key  The specified property name
+     * @param def  A default value for the property name to return if the property
+     *             is not set.
+     * @return A list of strings.
+     */
+    protected List<String> getESAPIProperty( String key, List<String> def ) {
+        String property = properties.getProperty( key );
+        if ( property == null ) {
+            logSpecial( "SecurityConfiguration for " + key + " not found in ESAPI.properties. Using default: " + def, null );
+            return def;
+        }
+        String[] parts = property.split(",");
+        return Arrays.asList( parts );
+    }
 
     /**
      * {@inheritDoc}
      * Looks for property in three configuration files in following order:
-     * 1.) In file defined as org.owasp.esapi.opsteam system property 
-     * 2.) In file defined as org.owasp.esapi.devteam system property 
-     * 3.) In ESAPI.properties* 
+     * 1.) In file defined as org.owasp.esapi.opsteam system property
+     * 2.) In file defined as org.owasp.esapi.devteam system property
+     * 3.) In ESAPI.properties
      */
     @Override
     public int getIntProp(String propertyName) throws ConfigurationException {
@@ -1254,8 +1407,8 @@ public class DefaultSecurityConfiguration implements SecurityConfiguration {
     /**
      * {@inheritDoc}
      * Looks for property in three configuration files in following order:
-     * 1.) In file defined as org.owasp.esapi.opsteam system property 
-     * 2.) In file defined as org.owasp.esapi.devteam system property 
+     * 1.) In file defined as org.owasp.esapi.opsteam system property
+     * 2.) In file defined as org.owasp.esapi.devteam system property
      * 3.) In ESAPI.properties
      */
     @Override
@@ -1277,10 +1430,10 @@ public class DefaultSecurityConfiguration implements SecurityConfiguration {
     }
 
     /**
-     * {@inheritDoc}  
+     * {@inheritDoc}
      * Looks for property in three configuration files in following order:
-     * 1.) In file defined as org.owasp.esapi.opsteam system property 
-     * 2.) In file defined as org.owasp.esapi.devteam system property 
+     * 1.) In file defined as org.owasp.esapi.opsteam system property
+     * 2.) In file defined as org.owasp.esapi.devteam system property
      * 3.) In ESAPI.properties
      */
     @Override
@@ -1326,29 +1479,9 @@ public class DefaultSecurityConfiguration implements SecurityConfiguration {
 
     protected boolean shouldPrintProperties() {
         return getESAPIProperty(PRINT_PROPERTIES_WHEN_LOADED, false);
-	}
+    }
 
     protected Properties getESAPIProperties() {
         return properties;
     }
-    
-    public enum DefaultSearchPath {
-    	
-    	RESOURCE_DIRECTORY("resourceDirectory/"),
-    	SRC_MAIN_RESOURCES("src/main/resources/"),
-    	ROOT(""),
-    	DOT_ESAPI(".esapi/"),
-    	ESAPI("esapi/"),
-    	RESOURCES("resources/");
-    	
-    	private final String path;
-    	
-    	private DefaultSearchPath(String s){
-    		this.path = s;
-    	}
-    	
-    	public String value(){
-    		return path;
-    	}
-    }
 }
diff --git a/src/main/java/org/owasp/esapi/reference/DefaultUser.java b/src/main/java/org/owasp/esapi/reference/DefaultUser.java
index a0553ce..c906542 100644
--- a/src/main/java/org/owasp/esapi/reference/DefaultUser.java
+++ b/src/main/java/org/owasp/esapi/reference/DefaultUser.java
@@ -1,15 +1,15 @@
 /**
  * OWASP Enterprise Security API (ESAPI)
- * 
+ *
  * This file is part of the Open Web Application Security Project (OWASP)
  * Enterprise Security API (ESAPI) project. For details, please see
  * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
  *
  * Copyright (c) 2007 - The OWASP Foundation
- * 
+ *
  * The ESAPI is published by OWASP under the BSD license. You should read and accept the
  * LICENSE before you use, modify, and/or redistribute this software.
- * 
+ *
  * @author Jeff Williams <a href="http://www.aspectsecurity.com">Aspect Security</a>
  * @created 2007
  */
@@ -32,7 +32,7 @@ import java.util.Collections;
 import java.util.HashMap;
 /**
  * Reference implementation of the User interface. This implementation is serialized into a flat file in a simple format.
- * 
+ *
  * @author Jeff Williams (jeff.williams .at. aspectsecurity.com) <a href="http://www.aspectsecurity.com">Aspect Security</a>
  * @author Chris Schmidt (chrisisbeef .at. gmail.com) <a href="http://www.digital-ritual.com">Digital Ritual Software</a>
  * @since June 1, 2007
@@ -40,569 +40,569 @@ import java.util.HashMap;
  */
 public class DefaultUser implements User, Serializable {
 
-	/** The Constant serialVersionUID. */
-	private static final long serialVersionUID = 1L;
+    /** The Constant serialVersionUID. */
+    private static final long serialVersionUID = 1L;
+
+    /** The idle timeout length specified in the ESAPI config file. */
+    private static final int IDLE_TIMEOUT_LENGTH = ESAPI.securityConfiguration().getSessionIdleTimeoutLength();
+
+    /** The absolute timeout length specified in the ESAPI config file. */
+    private static final int ABSOLUTE_TIMEOUT_LENGTH = ESAPI.securityConfiguration().getSessionAbsoluteTimeoutLength();
+
+    /** The logger used by the class. */
+    private transient final Logger logger = ESAPI.getLogger("DefaultUser");
 
-	/** The idle timeout length specified in the ESAPI config file. */
-	private static final int IDLE_TIMEOUT_LENGTH = ESAPI.securityConfiguration().getSessionIdleTimeoutLength();
-	
-	/** The absolute timeout length specified in the ESAPI config file. */
-	private static final int ABSOLUTE_TIMEOUT_LENGTH = ESAPI.securityConfiguration().getSessionAbsoluteTimeoutLength();
-	
-	/** The logger used by the class. */
-	private transient final Logger logger = ESAPI.getLogger("DefaultUser");
-    
-	/** This user's account id. */
-	long accountId = 0;
+    /** This user's account id. */
+    long accountId = 0;
 
-	/** This user's account name. */
-	private String accountName = "";
+    /** This user's account name. */
+    private String accountName = "";
 
-	/** This user's screen name (account name alias). */
-	private String screenName = "";
+    /** This user's screen name (account name alias). */
+    private String screenName = "";
 
-	/** This user's CSRF token. */
-	private String csrfToken = resetCSRFToken();
+    /** This user's CSRF token. */
+    private String csrfToken = resetCSRFToken();
 
-	/** This user's assigned roles. */
-	private Set<String> roles = new HashSet<String>();
+    /** This user's assigned roles. */
+    private Set<String> roles = new HashSet<String>();
 
-	/** Whether this user's account is locked. */
-	private boolean locked = false;
+    /** Whether this user's account is locked. */
+    private boolean locked = false;
 
-	/** Whether this user is logged in. */
-	private boolean loggedIn = true;
+    /** Whether this user is logged in. */
+    private boolean loggedIn = true;
 
     /** Whether this user's account is enabled. */
-	private boolean enabled = false;
+    private boolean enabled = false;
 
     /** The last host address used by this user. */
     private String lastHostAddress;
 
-	/** The last password change time for this user. */
-	private Date lastPasswordChangeTime = new Date(0);
-
-	/** The last login time for this user. */
-	private Date lastLoginTime = new Date(0);
-
-	/** The last failed login time for this user. */
-	private Date lastFailedLoginTime = new Date(0);
-	
-	/** The expiration date/time for this user's account. */
-	private Date expirationTime = new Date(Long.MAX_VALUE);
-
-	/** The sessions this user is associated with */
-	private transient Set<HttpSession> sessions = new HashSet<HttpSession>();
-	
-	/** The event map for this User */ 
-	private transient HashMap eventMap = new HashMap();
-	
-	/* A flag to indicate that the password must be changed before the account can be used. */
-	// private boolean requiresPasswordChange = true;
-	
-	/** The failed login count for this user's account. */
-	private int failedLoginCount = 0;
-	
-	/** This user's Locale. */
-	private Locale locale;
-    
+    /** The last password change time for this user. */
+    private Date lastPasswordChangeTime = new Date(0);
+
+    /** The last login time for this user. */
+    private Date lastLoginTime = new Date(0);
+
+    /** The last failed login time for this user. */
+    private Date lastFailedLoginTime = new Date(0);
+
+    /** The expiration date/time for this user's account. */
+    private Date expirationTime = new Date(Long.MAX_VALUE);
+
+    /** The sessions this user is associated with */
+    private transient Set<HttpSession> sessions = new HashSet<HttpSession>();
+
+    /** The event map for this User */
+    private transient HashMap eventMap = new HashMap();
+
+    /* A flag to indicate that the password must be changed before the account can be used. */
+    // private boolean requiresPasswordChange = true;
+
+    /** The failed login count for this user's account. */
+    private int failedLoginCount = 0;
+
+    /** This user's Locale. */
+    private Locale locale;
+
     private static final int MAX_ROLE_LENGTH = 250;
-    
-	/**
-	 * Instantiates a new user.
-	 *
-	 * @param accountName
-	 * 		The name of this user's account.
-	 */
-	public DefaultUser(String accountName) {
-		this.accountName = accountName.toLowerCase();
-		while( true ) {
-			long id = Math.abs( ESAPI.randomizer().getRandomLong() );
-			if ( ESAPI.authenticator().getUser( id ) == null && id != 0 ) {
-				this.accountId = id;
-				break;
-			}
-		}
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	public void addRole(String role) throws AuthenticationException {
-		String roleName = role.toLowerCase();
-		if ( ESAPI.validator().isValidInput("addRole", roleName, "RoleName", MAX_ROLE_LENGTH, false) ) {
-			roles.add(roleName);
-			logger.info(Logger.SECURITY_SUCCESS, "Role " + roleName + " added to " + getAccountName() );
-		} else {
-			throw new AuthenticationAccountsException( "Add role failed", "Attempt to add invalid role " + roleName + " to " + getAccountName() );
-		}
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	public void addRoles(Set<String> newRoles) throws AuthenticationException {
+
+    /**
+     * Instantiates a new user.
+     *
+     * @param accountName
+     *         The name of this user's account.
+     */
+    public DefaultUser(String accountName) {
+        this.accountName = accountName.toLowerCase();
+        while( true ) {
+            long id = Math.abs( ESAPI.randomizer().getRandomLong() );
+            if ( ESAPI.authenticator().getUser( id ) == null && id != 0 ) {
+                this.accountId = id;
+                break;
+            }
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void addRole(String role) throws AuthenticationException {
+        String roleName = role.toLowerCase();
+        if ( ESAPI.validator().isValidInput("addRole", roleName, "RoleName", MAX_ROLE_LENGTH, false) ) {
+            roles.add(roleName);
+            logger.info(Logger.SECURITY_SUCCESS, "Role " + roleName + " added to " + getAccountName() );
+        } else {
+            throw new AuthenticationAccountsException( "Add role failed", "Attempt to add invalid role " + roleName + " to " + getAccountName() );
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void addRoles(Set<String> newRoles) throws AuthenticationException {
         for (String newRole : newRoles)
         {
             addRole(newRole);
-		}
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	public void changePassword(String oldPassword, String newPassword1, String newPassword2) throws AuthenticationException, EncryptionException {
-		ESAPI.authenticator().changePassword(this, oldPassword, newPassword1, newPassword2);
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	public void disable() {
-		enabled = false;
-		logger.info( Logger.SECURITY_SUCCESS, "Account disabled: " + getAccountName() );
-	}
-	
-	/**
-	 * {@inheritDoc}
-	 */
-	public void enable() {
-		this.enabled = true;
-		logger.info( Logger.SECURITY_SUCCESS, "Account enabled: " + getAccountName() );
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void changePassword(String oldPassword, String newPassword1, String newPassword2) throws AuthenticationException, EncryptionException {
+        ESAPI.authenticator().changePassword(this, oldPassword, newPassword1, newPassword2);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void disable() {
+        enabled = false;
+        logger.info( Logger.SECURITY_SUCCESS, "Account disabled: " + getAccountName() );
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void enable() {
+        this.enabled = true;
+        logger.info( Logger.SECURITY_SUCCESS, "Account enabled: " + getAccountName() );
+    }
+
+    /**
+     * {@inheritDoc}
+     */
     public long getAccountId() {
         return accountId;
     }
 
-	/**
-	 * {@inheritDoc}
-	 */
-	public String getAccountName() {
-		return accountName;
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	public String getCSRFToken() {
-		return csrfToken;
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	public Date getExpirationTime() {
-		return (Date)expirationTime.clone();
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	public int getFailedLoginCount() {
-		return failedLoginCount;
-	}
-	
-	/**
-	 * Set the failed login count
-	 * 
-	 * @param count
-	 * 			the number of failed logins
-	 */
-	void setFailedLoginCount(int count) {
-		failedLoginCount = count;
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	public Date getLastFailedLoginTime() {
-		return (Date)lastFailedLoginTime.clone();
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	public String getLastHostAddress() {
-		if ( lastHostAddress == null ) {
-			return "unknown";
-		}
+    /**
+     * {@inheritDoc}
+     */
+    public String getAccountName() {
+        return accountName;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public String getCSRFToken() {
+        return csrfToken;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public Date getExpirationTime() {
+        return (Date)expirationTime.clone();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public int getFailedLoginCount() {
+        return failedLoginCount;
+    }
+
+    /**
+     * Set the failed login count
+     *
+     * @param count
+     *             the number of failed logins
+     */
+    void setFailedLoginCount(int count) {
+        failedLoginCount = count;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public Date getLastFailedLoginTime() {
+        return (Date)lastFailedLoginTime.clone();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public String getLastHostAddress() {
+        if ( lastHostAddress == null ) {
+            return "unknown";
+        }
         return lastHostAddress;
     }
 
-	/**
-	 * {@inheritDoc}
-	 */
-	public Date getLastLoginTime() {
-		return (Date)lastLoginTime.clone();
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	public Date getLastPasswordChangeTime() {
-		return (Date)lastPasswordChangeTime.clone();
-	}
-
-	/**
-	 * {@inheritDoc}
-     */
-	public String getName() {
-		return this.getAccountName();
-	}
-	
-	/**
-	 * {@inheritDoc}
-	 */
-	public Set<String> getRoles() {
-		return Collections.unmodifiableSet(roles);
-	}
-	
-	/**
-	 * {@inheritDoc}
-	 */
-	public String getScreenName() {
-		return screenName;
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
+    /**
+     * {@inheritDoc}
+     */
+    public Date getLastLoginTime() {
+        return (Date)lastLoginTime.clone();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public Date getLastPasswordChangeTime() {
+        return (Date)lastPasswordChangeTime.clone();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public String getName() {
+        return this.getAccountName();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public Set<String> getRoles() {
+        return Collections.unmodifiableSet(roles);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public String getScreenName() {
+        return screenName;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
     public void addSession( HttpSession s ) {
         sessions.add( s );
     }
-    
-	/**
-	 * {@inheritDoc}
-	 */
+
+    /**
+     * {@inheritDoc}
+     */
     public void removeSession( HttpSession s ) {
         sessions.remove( s );
     }
-    
-	/**
-	 * {@inheritDoc}
-     */
-	public Set getSessions() {
-	    return sessions;
-	}
-	
-	/**
-	 * {@inheritDoc}
-	 */
-	public void incrementFailedLoginCount() {
-		failedLoginCount++;
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	public boolean isAnonymous() {
-		// User cannot be anonymous, since we have a special User.ANONYMOUS instance
-		// for the anonymous user
-		return false;
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	public boolean isEnabled() {
-		return enabled;
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	public boolean isExpired() {
-		return getExpirationTime().before( new Date() );
-
-		// If expiration should happen automatically or based on lastPasswordChangeTime?
-		//		long from = lastPasswordChangeTime.getTime();
-		//		long to = new Date().getTime();
-		//		double difference = to - from;
-		//		long days = Math.round((difference / (1000 * 60 * 60 * 24)));
-		//		return days > 60;
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	public boolean isInRole(String role) {
-		return roles.contains(role.toLowerCase());
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	public boolean isLocked() {
-		return locked;
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	public boolean isLoggedIn() {
-		return loggedIn;
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	public boolean isSessionAbsoluteTimeout() {
-		HttpSession session = ESAPI.httpUtilities().getCurrentRequest().getSession(false);
-		if ( session == null ) return true;
-		Date deadline = new Date( session.getCreationTime() + ABSOLUTE_TIMEOUT_LENGTH);
-		Date now = new Date();
-		return now.after(deadline);
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	public boolean isSessionTimeout() {
-		HttpSession session = ESAPI.httpUtilities().getCurrentRequest().getSession(false);
-		if ( session == null ) return true;
-		Date deadline = new Date( session.getLastAccessedTime() + IDLE_TIMEOUT_LENGTH);
-		Date now = new Date();
-		return now.after(deadline);
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	public void lock() {
-		this.locked = true;
-		logger.info(Logger.SECURITY_SUCCESS, "Account locked: " + getAccountName() );
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	public void loginWithPassword(String password) throws AuthenticationException {
-		if ( password == null || password.equals("") ) {
-			setLastFailedLoginTime(new Date());
-			incrementFailedLoginCount();
-			throw new AuthenticationLoginException( "Login failed", "Missing password: " + accountName  );
-		}
-		
-		// don't let disabled users log in
-		if ( !isEnabled() ) {
-			setLastFailedLoginTime(new Date());
-			incrementFailedLoginCount();
-			throw new AuthenticationLoginException("Login failed", "Disabled user attempt to login: " + accountName );
-		}
-		
-		// don't let locked users log in
-		if ( isLocked() ) {
-			setLastFailedLoginTime(new Date());
-			incrementFailedLoginCount();
-			throw new AuthenticationLoginException("Login failed", "Locked user attempt to login: " + accountName );
-		}
-		
-		// don't let expired users log in
-		if ( isExpired() ) {
-			setLastFailedLoginTime(new Date());
-			incrementFailedLoginCount();
-			throw new AuthenticationLoginException("Login failed", "Expired user attempt to login: " + accountName );
-		}
-		
-		logout();
-
-		if ( verifyPassword( password ) ) {
-			loggedIn = true;
-			ESAPI.httpUtilities().changeSessionIdentifier( ESAPI.currentRequest() );
-			ESAPI.authenticator().setCurrentUser(this);
-			setLastLoginTime(new Date());
+
+    /**
+     * {@inheritDoc}
+     */
+    public Set getSessions() {
+        return sessions;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void incrementFailedLoginCount() {
+        failedLoginCount++;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isAnonymous() {
+        // User cannot be anonymous, since we have a special User.ANONYMOUS instance
+        // for the anonymous user
+        return false;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isEnabled() {
+        return enabled;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isExpired() {
+        return getExpirationTime().before( new Date() );
+
+        // If expiration should happen automatically or based on lastPasswordChangeTime?
+        //        long from = lastPasswordChangeTime.getTime();
+        //        long to = new Date().getTime();
+        //        double difference = to - from;
+        //        long days = Math.round((difference / (1000 * 60 * 60 * 24)));
+        //        return days > 60;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isInRole(String role) {
+        return roles.contains(role.toLowerCase());
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isLocked() {
+        return locked;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isLoggedIn() {
+        return loggedIn;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isSessionAbsoluteTimeout() {
+        HttpSession session = ESAPI.httpUtilities().getCurrentRequest().getSession(false);
+        if ( session == null ) return true;
+        Date deadline = new Date( session.getCreationTime() + ABSOLUTE_TIMEOUT_LENGTH);
+        Date now = new Date();
+        return now.after(deadline);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isSessionTimeout() {
+        HttpSession session = ESAPI.httpUtilities().getCurrentRequest().getSession(false);
+        if ( session == null ) return true;
+        Date deadline = new Date( session.getLastAccessedTime() + IDLE_TIMEOUT_LENGTH);
+        Date now = new Date();
+        return now.after(deadline);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void lock() {
+        this.locked = true;
+        logger.info(Logger.SECURITY_SUCCESS, "Account locked: " + getAccountName() );
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void loginWithPassword(String password) throws AuthenticationException {
+        if ( password == null || password.equals("") ) {
+            setLastFailedLoginTime(new Date());
+            incrementFailedLoginCount();
+            throw new AuthenticationLoginException( "Login failed", "Missing password: " + accountName  );
+        }
+
+        // don't let disabled users log in
+        if ( !isEnabled() ) {
+            setLastFailedLoginTime(new Date());
+            incrementFailedLoginCount();
+            throw new AuthenticationLoginException("Login failed", "Disabled user attempt to login: " + accountName );
+        }
+
+        // don't let locked users log in
+        if ( isLocked() ) {
+            setLastFailedLoginTime(new Date());
+            incrementFailedLoginCount();
+            throw new AuthenticationLoginException("Login failed", "Locked user attempt to login: " + accountName );
+        }
+
+        // don't let expired users log in
+        if ( isExpired() ) {
+            setLastFailedLoginTime(new Date());
+            incrementFailedLoginCount();
+            throw new AuthenticationLoginException("Login failed", "Expired user attempt to login: " + accountName );
+        }
+
+        logout();
+
+        if ( verifyPassword( password ) ) {
+            loggedIn = true;
+            ESAPI.httpUtilities().changeSessionIdentifier( ESAPI.currentRequest() );
+            ESAPI.authenticator().setCurrentUser(this);
+            setLastLoginTime(new Date());
             setLastHostAddress( ESAPI.httpUtilities().getCurrentRequest().getRemoteAddr() );
-			logger.trace(Logger.SECURITY_SUCCESS, "User logged in: " + accountName );
-		} else {
-			loggedIn = false;
-			setLastFailedLoginTime(new Date());
-			incrementFailedLoginCount();
-			if (getFailedLoginCount() >= ESAPI.securityConfiguration().getAllowedLoginAttempts()) {
-				lock();
-			}
-			throw new AuthenticationLoginException("Login failed", "Incorrect password provided for " + getAccountName() );
-		}
-	}
- 
-
-	/**
-	 * {@inheritDoc}
-	 */
-	public void logout() {
-		ESAPI.httpUtilities().killCookie( ESAPI.currentRequest(), ESAPI.currentResponse(), HTTPUtilities.REMEMBER_TOKEN_COOKIE_NAME );
-		
-		HttpSession session = ESAPI.currentRequest().getSession(false);
-		if (session != null) {
+            logger.trace(Logger.SECURITY_SUCCESS, "User logged in: " + accountName );
+        } else {
+            loggedIn = false;
+            setLastFailedLoginTime(new Date());
+            incrementFailedLoginCount();
+            if (getFailedLoginCount() >= ESAPI.securityConfiguration().getAllowedLoginAttempts()) {
+                lock();
+            }
+            throw new AuthenticationLoginException("Login failed", "Incorrect password provided for " + getAccountName() );
+        }
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void logout() {
+        ESAPI.httpUtilities().killCookie( ESAPI.currentRequest(), ESAPI.currentResponse(), HTTPUtilities.REMEMBER_TOKEN_COOKIE_NAME );
+
+        HttpSession session = ESAPI.currentRequest().getSession(false);
+        if (session != null) {
             removeSession(session);
-			session.invalidate();
-		}
-		ESAPI.httpUtilities().killCookie(ESAPI.currentRequest(), ESAPI.currentResponse(), ESAPI.securityConfiguration().getHttpSessionIdName());
-		loggedIn = false;
-		logger.info(Logger.SECURITY_SUCCESS, "Logout successful" );
-		ESAPI.authenticator().setCurrentUser(User.ANONYMOUS);
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	public void removeRole(String role) {
-		roles.remove(role.toLowerCase());
-		logger.trace(Logger.SECURITY_SUCCESS, "Role " + role + " removed from " + getAccountName() );
-	}
-
-	/**
-	 * {@inheritDoc}
-	 * 
-	 * In this implementation, we have chosen to use a random token that is
-	 * stored in the User object. Note that it is possible to avoid the use of
-	 * server side state by using either the hash of the users's session id or
-	 * an encrypted token that includes a timestamp and the user's IP address.
-	 * user's IP address. A relatively short 8 character string has been chosen
-	 * because this token will appear in all links and forms.
-	 * 
-	 * @return the string
-	 */
-	public String resetCSRFToken() {
-		// user.csrfToken = ESAPI.encryptor().hash( session.getId(),user.name );
-		// user.csrfToken = ESAPI.encryptor().encrypt( address + ":" + ESAPI.encryptor().getTimeStamp();
-		csrfToken = ESAPI.randomizer().getRandomString(8, EncoderConstants.CHAR_ALPHANUMERICS);
-		return csrfToken;
-	}
-
-	/**
-	 * Sets the account id for this user's account.
-	 */
-	private void setAccountId(long accountId) {
-		this.accountId = accountId;
-	}
-	
-	
-	/**
-	 * {@inheritDoc}
-	 */
-	public void setAccountName(String accountName) {
-		String old = getAccountName();
-		this.accountName = accountName.toLowerCase();
-		if (old != null) {
-			if ( old.equals( "" ) ) {
-				old = "[nothing]";
-			}
-			logger.info(Logger.SECURITY_SUCCESS, "Account name changed from " + old + " to " + getAccountName() );
-		}
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	public void setExpirationTime(Date expirationTime) {
-		this.expirationTime = new Date( expirationTime.getTime() );
-		logger.info(Logger.SECURITY_SUCCESS, "Account expiration time set to " + expirationTime + " for " + getAccountName() );
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	public void setLastFailedLoginTime(Date lastFailedLoginTime) {
-		this.lastFailedLoginTime = lastFailedLoginTime;
-		logger.info(Logger.SECURITY_SUCCESS, "Set last failed login time to " + lastFailedLoginTime + " for " + getAccountName() );
-	}
-	
-	/**
-	 * {@inheritDoc}
-	 */
-	public void setLastHostAddress(String remoteHost) throws AuthenticationHostException
+            session.invalidate();
+        }
+        ESAPI.httpUtilities().killCookie(ESAPI.currentRequest(), ESAPI.currentResponse(), ESAPI.securityConfiguration().getHttpSessionIdName());
+        loggedIn = false;
+        logger.info(Logger.SECURITY_SUCCESS, "Logout successful" );
+        ESAPI.authenticator().setCurrentUser(User.ANONYMOUS);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void removeRole(String role) {
+        roles.remove(role.toLowerCase());
+        logger.trace(Logger.SECURITY_SUCCESS, "Role " + role + " removed from " + getAccountName() );
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * In this implementation, we have chosen to use a random token that is
+     * stored in the User object. Note that it is possible to avoid the use of
+     * server side state by using either the hash of the users's session id or
+     * an encrypted token that includes a timestamp and the user's IP address.
+     * user's IP address. A relatively short 8 character string has been chosen
+     * because this token will appear in all links and forms.
+     *
+     * @return the string
+     */
+    public String resetCSRFToken() {
+        // user.csrfToken = ESAPI.encryptor().hash( session.getId(),user.name );
+        // user.csrfToken = ESAPI.encryptor().encrypt( address + ":" + ESAPI.encryptor().getTimeStamp();
+        csrfToken = ESAPI.randomizer().getRandomString(8, EncoderConstants.CHAR_ALPHANUMERICS);
+        return csrfToken;
+    }
+
+    /**
+     * Sets the account id for this user's account.
+     */
+    private void setAccountId(long accountId) {
+        this.accountId = accountId;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void setAccountName(String accountName) {
+        String old = getAccountName();
+        this.accountName = accountName.toLowerCase();
+        if (old != null) {
+            if ( old.equals( "" ) ) {
+                old = "[nothing]";
+            }
+            logger.info(Logger.SECURITY_SUCCESS, "Account name changed from " + old + " to " + getAccountName() );
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void setExpirationTime(Date expirationTime) {
+        this.expirationTime = new Date( expirationTime.getTime() );
+        logger.info(Logger.SECURITY_SUCCESS, "Account expiration time set to " + expirationTime + " for " + getAccountName() );
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void setLastFailedLoginTime(Date lastFailedLoginTime) {
+        this.lastFailedLoginTime = lastFailedLoginTime;
+        logger.info(Logger.SECURITY_SUCCESS, "Set last failed login time to " + lastFailedLoginTime + " for " + getAccountName() );
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void setLastHostAddress(String remoteHost) throws AuthenticationHostException
     {
-		if ( lastHostAddress != null && !lastHostAddress.equals(remoteHost)) {
-        	// returning remote address not remote hostname to prevent DNS lookup
-			throw new AuthenticationHostException("Host change", "User session just jumped from " + lastHostAddress + " to " + remoteHost );
-		}
-		lastHostAddress = remoteHost;
-    }
-
-	/**
-	 * {@inheritDoc}
-	 */
-	public void setLastLoginTime(Date lastLoginTime) {
-		this.lastLoginTime = lastLoginTime;
-		logger.info(Logger.SECURITY_SUCCESS, "Set last successful login time to " + lastLoginTime + " for " + getAccountName() );
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	public void setLastPasswordChangeTime(Date lastPasswordChangeTime) {
-		this.lastPasswordChangeTime = lastPasswordChangeTime;
-		logger.info(Logger.SECURITY_SUCCESS, "Set last password change time to " + lastPasswordChangeTime + " for " + getAccountName() );
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	public void setRoles(Set<String> roles) throws AuthenticationException {
-		this.roles = new HashSet<String>();
-		addRoles(roles);
-		logger.info(Logger.SECURITY_SUCCESS, "Adding roles " + roles + " to " + getAccountName() );
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	public void setScreenName(String screenName) {
-		this.screenName = screenName;
-		logger.info(Logger.SECURITY_SUCCESS, "ScreenName changed to " + screenName + " for " + getAccountName() );
-	}
-
-	/**
-	 * {@inheritDoc}
-     */
-	public String toString() {
-		return "USER:" + accountName;
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	public void unlock() {
-		this.locked = false;
-		this.failedLoginCount = 0;
-		logger.info( Logger.SECURITY_SUCCESS, "Account unlocked: " + getAccountName() );
-	}
-	
-	/**
-	 * {@inheritDoc}
-	 */
-	public boolean verifyPassword(String password) {
-		return ESAPI.authenticator().verifyPassword(this, password);
-	}
-    
+        if ( lastHostAddress != null && !lastHostAddress.equals(remoteHost)) {
+            // returning remote address not remote hostname to prevent DNS lookup
+            throw new AuthenticationHostException("Host change", "User session just jumped from " + lastHostAddress + " to " + remoteHost );
+        }
+        lastHostAddress = remoteHost;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void setLastLoginTime(Date lastLoginTime) {
+        this.lastLoginTime = lastLoginTime;
+        logger.info(Logger.SECURITY_SUCCESS, "Set last successful login time to " + lastLoginTime + " for " + getAccountName() );
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void setLastPasswordChangeTime(Date lastPasswordChangeTime) {
+        this.lastPasswordChangeTime = lastPasswordChangeTime;
+        logger.info(Logger.SECURITY_SUCCESS, "Set last password change time to " + lastPasswordChangeTime + " for " + getAccountName() );
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void setRoles(Set<String> roles) throws AuthenticationException {
+        this.roles = new HashSet<String>();
+        addRoles(roles);
+        logger.info(Logger.SECURITY_SUCCESS, "Adding roles " + roles + " to " + getAccountName() );
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void setScreenName(String screenName) {
+        this.screenName = screenName;
+        logger.info(Logger.SECURITY_SUCCESS, "ScreenName changed to " + screenName + " for " + getAccountName() );
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public String toString() {
+        return "USER:" + accountName;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void unlock() {
+        this.locked = false;
+        this.failedLoginCount = 0;
+        logger.info( Logger.SECURITY_SUCCESS, "Account unlocked: " + getAccountName() );
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean verifyPassword(String password) {
+        return ESAPI.authenticator().verifyPassword(this, password);
+    }
+
     /**
      * Override clone and make final to prevent duplicate user objects.
      * @return Nothing, as clone() is not supported for this class. A CloneNotSupportedException is always thrown for this class.
      * @throws java.lang.CloneNotSupportedException
      */
     public final Object clone() throws java.lang.CloneNotSupportedException {
-    	  throw new java.lang.CloneNotSupportedException();
-    }
-	/**
-	 * @return the locale
-	 */
-	public Locale getLocale() {
-		return locale;
-	}
-
-	/**
-	 * @param locale the locale to set
-	 */
-	public void setLocale(Locale locale) {
-		this.locale = locale;
-	}
-    
+          throw new java.lang.CloneNotSupportedException();
+    }
+    /**
+     * @return the locale
+     */
+    public Locale getLocale() {
+        return locale;
+    }
+
+    /**
+     * @param locale the locale to set
+     */
+    public void setLocale(Locale locale) {
+        this.locale = locale;
+    }
+
     public HashMap getEventMap() {
-    	return eventMap;
+        return eventMap;
     }
-    
+
 }
diff --git a/src/main/java/org/owasp/esapi/reference/DefaultValidator.java b/src/main/java/org/owasp/esapi/reference/DefaultValidator.java
index 0699a52..6dd3728 100644
--- a/src/main/java/org/owasp/esapi/reference/DefaultValidator.java
+++ b/src/main/java/org/owasp/esapi/reference/DefaultValidator.java
@@ -54,20 +54,49 @@ import org.owasp.esapi.reference.validation.NumberValidationRule;
 import org.owasp.esapi.reference.validation.StringValidationRule;
 
 /**
- * Reference implementation of the Validator interface. This implementation
- * relies on the ESAPI Encoder, Java Pattern (regex), Date,
+ * Reference implementation of the {@code Validator} interface. This implementation
+ * relies on the ESAPI {@code Encoder}, {@link java.util.regex.Pattern},
+ * {@link java.util.Date},
  * and several other classes to provide basic validation functions. This library
- * has a heavy emphasis on whitelist validation and canonicalization.
+ * has a heavy emphasis on allow-list validation and canonicalization.
+ * <p>
+ * <b>A Note about Canonicalization</b>:
+ * The behaviors of objects of this class are largely driven by how the
+ * associated {@code Encoder} is created and passed to one of this
+ * class' constructors. Specifically, what {@link org.owasp.esapi.codecs.Codec}
+ * types are referenced by the {@link org.owasp.esapi.Encoder} instance
+ * associated with this particular {@code DefaultValidator} instance. In places
+ * where the default {@code Encoder} instance is used, the behavior is driven
+ * by three ESAPI properties as defined in the <b>ESAPI.properties</b> file.
+ * These property names and their default values (as delivered in ESAPI's
+ * "configuration" jar) are as follows:
+ * <pre>
+ * Encoder.AllowMultipleEncoding=false
+ * Encoder.AllowMixedEncoding=false
+ * Encoder.DefaultCodecList=HTMLEntityCodec,PercentCodec,JavaScriptCodec
+ * </pre>
+ * In places where canonicalization is checked, multiple
+ * encoding (the first property, which refers to encoding in the <i>same</i> manner
+ * more than once) or mixed encoding (the second property, which refers to
+ * encoding using multiple <i>different</i> encoding mechanisms) are generally
+ * considered attacks unless these respective property values are set to
+ * "true".
+ * </p><p>
+ * Note that changing any of these three properties may affect the behavior as
+ * documented in this class' methods.
+ * </p>
  *
  * @author Jeff Williams (jeff.williams .at. aspectsecurity.com) <a href="http://www.aspectsecurity.com">Aspect Security</a>
  * @author Jim Manico (jim@manico.net) <a href="http://www.manico.net">Manico.net</a>
- * @author Matt Seil (mseil .at. acm.org) 
+ * @author Matt Seil (mseil .at. acm.org)
  *
  * @since June 1, 2007
  * @see org.owasp.esapi.Validator
+ * @see org.owasp.esapi.Encoder
+ * @see org.owasp.esapi.Encoder#canonicalize(String,boolean,boolean)
  */
 public class DefaultValidator implements org.owasp.esapi.Validator {
-	private static Logger logger = ESAPI.log();
+    private static Logger logger = ESAPI.log();
     private static volatile Validator instance = null;
 
     public static Validator getInstance() {
@@ -81,1182 +110,1306 @@ public class DefaultValidator implements org.owasp.esapi.Validator {
         return instance;
     }
 
-	/** A map of validation rules */
-	private Map<String, ValidationRule> rules = new HashMap<String, ValidationRule>();
+    /** A map of validation rules */
+    private Map<String, ValidationRule> rules = new HashMap<String, ValidationRule>();
 
-	/** The encoder to use for canonicalization */
-	private Encoder encoder = null;
+    /** The encoder to use for canonicalization */
+    private Encoder encoder = null;
 
-	/** The encoder to use for file system */
-	private static Validator fileValidator = null;
+    /** The encoder to use for file system */
+    private static Validator fileValidator = null;
 
-	/** Initialize file validator with an appropriate set of codecs */
-	static {
-		List<String> list = new ArrayList<String>();
-		list.add( "HTMLEntityCodec" );
-		list.add( "PercentCodec" );
-		Encoder fileEncoder = new DefaultEncoder( list );
-		fileValidator = new DefaultValidator( fileEncoder );
-	}
+    /* Initialize file validator with an appropriate set of codecs */
+    static {
+        List<String> list = new ArrayList<String>();
+        list.add( "HTMLEntityCodec" );
+        list.add( "PercentCodec" );
+        Encoder fileEncoder = new DefaultEncoder( list );
+        fileValidator = new DefaultValidator( fileEncoder );
+    }
+
+
+    /**
+     * Default constructor uses the ESAPI standard encoder for canonicalization.
+     * This uses an {@code Encoder} created based on the {@code Codec}s
+     * specified by the value of the {@code Encoder.DefaultCodecList} ESAPI
+     * property as defined in your <b>ESAPI.properties</b> file.
+     */
+    public DefaultValidator() {
+        this.encoder = ESAPI.encoder();
+    }
+
+    /**
+     * Construct a new DefaultValidator that will use the specified
+     * {@code Encoder} for canonicalization.
+     * @param encoder The specially constructed ESAPI {@code Encoder} instance
+     *                that uses a custom list of {@code Codec}s for
+     *                canonicalization purposes. See
+     *                {@link org.owasp.esapi.Encoder#canonicalize(String,boolean,boolean)}
+     *                for an example of how to create a custom {@code Encoder}.
+     */
+    public DefaultValidator( Encoder encoder ) {
+        this.encoder = encoder;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void addRule(ValidationRule rule ) {
+        rules.put( rule.getTypeName(), rule );
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public ValidationRule getRule(String name ) {
+        return rules.get( name );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     * <p>
+     * Double encoding is treated as an attack.
+     * The canonicalization behavior is controlled by the instance's associated ESAPI
+     * {@code Encoder} and generally driven through the ESAPI property
+     * {@code Encoder.DefaultCodecList} specified in the <b>ESAPI.properties</b>
+     * file. See the class level documentation section "<b>A Note about Canonicalization</b>"
+     * for additional details.
+     */
+    @Override
+    public boolean isValidInput(String context, String input, String type, int maxLength, boolean allowNull) throws IntrusionException  {
+        return isValidInput(context, input, type, maxLength, allowNull, true);
+    }
+
+    /**
+     * {@inheritDoc}
+     * <p>
+     * Double encoding is treated as an attack.
+     * The canonicalization behavior is controlled by the instance's associated ESAPI
+     * {@code Encoder} and generally driven through the ESAPI property
+     * {@code Encoder.DefaultCodecList} specified in the <b>ESAPI.properties</b>
+     * file. See the class level documentation section "<b>A Note about Canonicalization</b>"
+     * for additional details.
+     */
+    @Override
+    public boolean isValidInput(String context, String input, String type, int maxLength, boolean allowNull, ValidationErrorList errors)  {
+        return isValidInput(context, input, type, maxLength, allowNull, true, errors);
+    }
+
+    /**
+     * {@inheritDoc}
+     * <p>
+     * Double encoding is treated as an attack.
+     * The canonicalization behavior is controlled by the instance's associated ESAPI
+     * {@code Encoder} and generally driven through the ESAPI property
+     * {@code Encoder.DefaultCodecList} specified in the <b>ESAPI.properties</b>
+     * file. See the class level documentation section "<b>A Note about Canonicalization</b>"
+     * for additional details.
+     * <p>
+     * This implementation does not throw {@link IntrusionException}.
+     */
+    @Override
+    public boolean isValidInput(String context, String input, String type, int maxLength, boolean allowNull, boolean canonicalize) {
+        try {
+            getValidInput( context, input, type, maxLength, allowNull, canonicalize);
+            return true;
+        } catch( Exception e ) {
+            return false;
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     * <p>
+     * Double encoding is treated as an attack.
+     * The canonicalization behavior is controlled by the instance's associated ESAPI
+     * {@code Encoder} and generally driven through the ESAPI property
+     * {@code Encoder.DefaultCodecList} specified in the <b>ESAPI.properties</b>
+     * file. See the class level documentation section "<b>A Note about Canonicalization</b>"
+     * for additional details.
+     */
+    @Override
+    public boolean isValidInput(String context, String input, String type, int maxLength, boolean allowNull, boolean canonicalize, ValidationErrorList errors) throws IntrusionException  {
+        try {
+            getValidInput( context, input, type, maxLength, allowNull, canonicalize);
+            return true;
+        } catch( ValidationException e ) {
+            errors.addError( context, e );
+            return false;
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     * <p>
+     * Double encoding is treated as an attack.
+     * The canonicalization behavior is controlled by the instance's associated ESAPI
+     * {@code Encoder} and generally driven through the ESAPI property
+     * {@code Encoder.DefaultCodecList} specified in the <b>ESAPI.properties</b>
+     * file. See the class level documentation section "<b>A Note about Canonicalization</b>"
+     * for additional details.
+     */
+    @Override
+    public String getValidInput(String context, String input, String type, int maxLength, boolean allowNull) throws ValidationException {
+        return getValidInput(context, input, type, maxLength, allowNull, true);
+    }
+
+    /**
+     * {@inheritDoc}
+     * <p>
+     * Double encoding is treated as an attack.
+     * The canonicalization behavior is controlled by the instance's associated ESAPI
+     * {@code Encoder} and generally driven through the ESAPI property
+     * {@code Encoder.DefaultCodecList} specified in the <b>ESAPI.properties</b>
+     * file. See the class level documentation section "<b>A Note about Canonicalization</b>"
+     * for additional details.
+     */
+    @Override
+    public String getValidInput(String context, String input, String type, int maxLength, boolean allowNull, boolean canonicalize) throws ValidationException {
+        StringValidationRule rvr = new StringValidationRule( type, encoder );
+        Pattern p = ESAPI.securityConfiguration().getValidationPattern( type );
+        if ( p != null ) {
+            rvr.addWhitelistPattern( p );
+        } else {
+            // Issue 232 - Specify requested type in exception message - CS
+            throw new IllegalArgumentException("The selected type [" + type + "] was not set via the ESAPI validation configuration");
+        }
+        rvr.setMaximumLength(maxLength);
+        rvr.setAllowNull(allowNull);
+        rvr.setCanonicalize(canonicalize);
+        return rvr.getValid(context, input);
+    }
+
+    /**
+     * {@inheritDoc}
+     * <p>
+     * Double encoding is treated as an attack.
+     * The canonicalization behavior is controlled by the instance's associated ESAPI
+     * {@code Encoder} and generally driven through the ESAPI property
+     * {@code Encoder.DefaultCodecList} specified in the <b>ESAPI.properties</b>
+     * file. See the class level documentation section "<b>A Note about Canonicalization</b>"
+     * for additional details.
+     */
+    @Override
+    public String getValidInput(String context, String input, String type, int maxLength, boolean allowNull, ValidationErrorList errors) throws IntrusionException {
+        return getValidInput(context, input, type, maxLength, allowNull, true, errors);
+    }
+
+    /**
+     * {@inheritDoc}
+     * <p>
+     * Double encoding is treated as an attack.
+     * The canonicalization behavior is controlled by the instance's associated ESAPI
+     * {@code Encoder} and generally driven through the ESAPI property
+     * {@code Encoder.DefaultCodecList} specified in the <b>ESAPI.properties</b>
+     * file. See the class level documentation section "<b>A Note about Canonicalization</b>"
+     * for additional details.
+     */
+    @Override
+    public String getValidInput(String context, String input, String type, int maxLength, boolean allowNull, boolean canonicalize, ValidationErrorList errors) throws IntrusionException {
+        try {
+            return getValidInput(context,  input,  type,  maxLength,  allowNull, canonicalize);
+        } catch (ValidationException e) {
+            errors.addError(context, e);
+        }
+
+        return "";
+    }
+
+    /**
+     * {@inheritDoc}
+     * <p>
+     * This implementation does not throw {@link IntrusionException}.
+     */
+    @Override
+    public boolean isValidDate(String context, String input, DateFormat format, boolean allowNull) {
+        try {
+            getValidDate( context, input, format, allowNull);
+            return true;
+        } catch( Exception e ) {
+            return false;
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public boolean isValidDate(String context, String input, DateFormat format, boolean allowNull, ValidationErrorList errors) throws IntrusionException {
+        getValidDate( context, input, format, allowNull, errors);
+        return errors.isEmpty();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public Date getValidDate(String context, String input, DateFormat format, boolean allowNull) throws ValidationException, IntrusionException {
+
+        ValidationErrorList vel = new ValidationErrorList();
+        Date validDate =  getValidDate(context, input, format, allowNull, vel);
+
+        if (vel.isEmpty()) {
+            return validDate;
+        }
+
+        throw vel.errors().get(0);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public Date getValidDate(String context, String input, DateFormat format, boolean allowNull, ValidationErrorList errors) throws IntrusionException {
+        DateValidationRule dvr = new DateValidationRule( "SimpleDate", encoder, format);
+        dvr.setAllowNull(allowNull);
+        Date safeDate = dvr.sanitize(context, input, errors);
+        if (!errors.isEmpty()) {
+            safeDate = null;
+        }
+        // error has been added to list, so return null
+        return safeDate;
+    }
+
+    /**
+     * {@inheritDoc}
+     * <p>
+     * This implementation does not throw {@link IntrusionException}.
+     */
+    @Override
+    public boolean isValidSafeHTML(String context, String input, int maxLength, boolean allowNull) {
+        try {
+            getValidSafeHTML( context, input, maxLength, allowNull);
+            return true;
+        } catch( Exception e ) {
+            return false;
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public boolean isValidSafeHTML(String context, String input, int maxLength, boolean allowNull, ValidationErrorList errors) throws IntrusionException {
+        try {
+            getValidSafeHTML( context, input, maxLength, allowNull);
+            return true;
+        } catch( ValidationException e ) {
+            errors.addError(context, e);
+            return false;
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     * <p>
+     * This implementation relies on the <a href="https://owasp.org/www-project-antisamy/">OWASP AntiSamy project</a>.
+     */
+    @Override
+    public String getValidSafeHTML(String context, String input, int maxLength, boolean allowNull ) throws ValidationException, IntrusionException {
+        HTMLValidationRule hvr = new HTMLValidationRule( "safehtml", encoder );
+        hvr.setMaximumLength(maxLength);
+        hvr.setAllowNull(allowNull);
+        return hvr.getValid(context, input);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public String getValidSafeHTML(String context, String input, int maxLength, boolean allowNull, ValidationErrorList errors) throws IntrusionException {
+        try {
+            return getValidSafeHTML(context, input, maxLength, allowNull);
+        } catch (ValidationException e) {
+            errors.addError(context, e);
+        }
+
+        return "";
+    }
+
+    /**
+     * {@inheritDoc}
+     * <p>
+     * This implementation does not throw {@link IntrusionException}.
+     */
+    @Override
+    public boolean isValidCreditCard(String context, String input, boolean allowNull) {
+        try {
+            getValidCreditCard( context, input, allowNull);
+            return true;
+        } catch( Exception e ) {
+            return false;
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public boolean isValidCreditCard(String context, String input, boolean allowNull, ValidationErrorList errors) throws IntrusionException {
+        try {
+            getValidCreditCard( context, input, allowNull);
+            return true;
+        } catch( ValidationException e ) {
+            errors.addError(context, e);
+            return false;
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public String getValidCreditCard(String context, String input, boolean allowNull) throws ValidationException, IntrusionException {
+        CreditCardValidationRule ccvr = new CreditCardValidationRule( "creditcard", encoder );
+        ccvr.setAllowNull(allowNull);
+        return ccvr.getValid(context, input);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public String getValidCreditCard(String context, String input, boolean allowNull, ValidationErrorList errors) throws IntrusionException {
+        try {
+            return getValidCreditCard(context, input, allowNull);
+        } catch (ValidationException e) {
+            errors.addError(context, e);
+        }
+
+        return "";
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * <p><b>Note:</b> On platforms that support symlinks, this function will fail canonicalization if directorypath
+     * is a symlink. For example, on MacOS X, /etc is actually /private/etc. If you mean to use /etc, use its real
+     * path (/private/etc), not the symlink (/etc).</p>
+     * <p>
+     * This implementation does not throw {@link IntrusionException}.
+     */
+    @Override
+    public boolean isValidDirectoryPath(String context, String input, File parent, boolean allowNull) {
+        try {
+            getValidDirectoryPath( context, input, parent, allowNull);
+            return true;
+        } catch( Exception e ) {
+            return false;
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * <p><b>Note:</b> On platforms that support symlinks, this function will fail canonicalization if directorypath
+     * is a symlink. For example, on MacOS X, /etc is actually /private/etc. If you mean to use /etc, use its real
+     * path (/private/etc), not the symlink (/etc).</p>
+     */
+    @Override
+    public boolean isValidDirectoryPath(String context, String input, File parent, boolean allowNull, ValidationErrorList errors) throws IntrusionException {
+        try {
+            getValidDirectoryPath( context, input, parent, allowNull);
+            return true;
+        } catch( ValidationException e ) {
+            errors.addError(context, e);
+            return false;
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * <p><b>Note:</b> On platforms that support symlinks, this function will fail canonicalization if directorypath
+     * is a symlink. For example, on MacOS X, /etc is actually /private/etc. If you mean to use /etc, use its real
+     * path (/private/etc), not the symlink (/etc).</p>
+     */
+    @Override
+    public String getValidDirectoryPath(String context, String input, File parent, boolean allowNull) throws ValidationException, IntrusionException {
+        try {
+            if (isEmpty(input)) {
+                if (allowNull) {
+                    return null;
+                }
+                throw new ValidationException( context + ": Input directory path required", "Input directory path required: context=" + context + ", input=" + input, context );
+            }
+
+            File dir = new File( input );
+
+            // check dir exists and parent exists and dir is inside parent
+            if ( !dir.exists() ) {
+                throw new ValidationException( context + ": Invalid directory name", "Invalid directory, does not exist: context=" + context + ", input=" + input );
+            }
+            if ( !dir.isDirectory() ) {
+                throw new ValidationException( context + ": Invalid directory name", "Invalid directory, not a directory: context=" + context + ", input=" + input );
+            }
+            if ( !parent.exists() ) {
+                throw new ValidationException( context + ": Invalid directory name", "Invalid directory, specified parent does not exist: context=" + context + ", input=" + input + ", parent=" + parent );
+            }
+            if ( !parent.isDirectory() ) {
+                throw new ValidationException( context + ": Invalid directory name", "Invalid directory, specified parent is not a directory: context=" + context + ", input=" + input + ", parent=" + parent );
+            }
+            if ( !dir.getCanonicalFile().toPath().startsWith( parent.getCanonicalFile().toPath() ) ) { // Fixes GHSL-2022-008
+                throw new ValidationException( context + ": Invalid directory name", "Invalid directory, not inside specified parent: context=" + context + ", input=" + input + ", parent=" + parent );
+            }
+
+            // check canonical form matches input
+            String canonicalPath = dir.getCanonicalPath();
+            String canonical = fileValidator.getValidInput( context, canonicalPath, "DirectoryName", 255, false);
+            if ( !canonical.equals( input ) ) {
+                throw new ValidationException( context + ": Invalid directory name", "Invalid directory name does not match the canonical path: context=" + context + ", input=" + input + ", canonical=" + canonical, context );
+            }
+            return canonical;
+        } catch (Exception e) {
+            throw new ValidationException( context + ": Invalid directory name", "Failure to validate directory path: context=" + context + ", input=" + input, e, context );
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * <p><b>Note:</b> On platforms that support symlinks, this function will fail canonicalization if directorypath
+     * is a symlink. For example, on MacOS X, /etc is actually /private/etc. If you mean to use /etc, use its real
+     * path (/private/etc), not the symlink (/etc).</p>
+     */
+    @Override
+    public String getValidDirectoryPath(String context, String input, File parent, boolean allowNull, ValidationErrorList errors) throws IntrusionException {
+
+        try {
+            return getValidDirectoryPath(context, input, parent, allowNull);
+        } catch (ValidationException e) {
+            errors.addError(context, e);
+        }
+
+        return "";
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public boolean isValidFileName(String context, String input, boolean allowNull) throws IntrusionException {
+        return isValidFileName( context, input, ESAPI.securityConfiguration().getAllowedFileExtensions(), allowNull );
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public boolean isValidFileName(String context, String input, boolean allowNull, ValidationErrorList errors) throws IntrusionException {
+        return isValidFileName( context, input, ESAPI.securityConfiguration().getAllowedFileExtensions(), allowNull, errors );
+    }
+
+    /**
+     * {@inheritDoc}
+     * <p>
+     * This implementation does not throw {@link IntrusionException}.
+     */
+    @Override
+    public boolean isValidFileName(String context, String input, List<String> allowedExtensions, boolean allowNull) {
+        try {
+            getValidFileName( context, input, allowedExtensions, allowNull);
+            return true;
+        } catch( Exception e ) {
+            return false;
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public boolean isValidFileName(String context, String input, List<String> allowedExtensions, boolean allowNull, ValidationErrorList errors) throws IntrusionException {
+        try {
+            getValidFileName( context, input, allowedExtensions, allowNull);
+            return true;
+        } catch( ValidationException e ) {
+            errors.addError(context, e);
+            return false;
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public String getValidFileName(String context, String input, List<String> allowedExtensions, boolean allowNull) throws ValidationException, IntrusionException {
+        if ((allowedExtensions == null) || (allowedExtensions.isEmpty())) {
+            throw new ValidationException( "Internal Error", "getValidFileName called with an empty or null list of allowed Extensions, therefore no files can be uploaded" );
+        }
+
+        String canonical = "";
+        // detect path manipulation
+        try {
+            if (isEmpty(input)) {
+                if (allowNull) {
+                    return null;
+                }
+                throw new ValidationException( context + ": Input file name required", "Input required: context=" + context + ", input=" + input, context );
+            }
+
+            // do basic validation
+            canonical = new File(input).getCanonicalFile().getName();
+            getValidInput( context, input, "FileName", 255, true );
+
+            File f = new File(canonical);
+            String c = f.getCanonicalPath();
+            String cpath = c.substring(c.lastIndexOf(File.separator) + 1);
+
+
+            // the path is valid if the input matches the canonical path
+            if (!input.equals(cpath)) {
+                throw new ValidationException( context + ": Invalid file name", "Invalid directory name does not match the canonical path: context=" + context + ", input=" + input + ", canonical=" + canonical, context );
+            }
+
+        } catch (IOException e) {
+            throw new ValidationException( context + ": Invalid file name", "Invalid file name does not exist: context=" + context + ", canonical=" + canonical, e, context );
+        }
+
+        // verify extensions
+        Iterator<String> i = allowedExtensions.iterator();
+        while (i.hasNext()) {
+            String ext = i.next();
+            if (input.toLowerCase().endsWith(ext.toLowerCase())) {
+                return canonical;
+            }
+        }
+        throw new ValidationException( context + ": Invalid file name does not have valid extension ( "+allowedExtensions+")", "Invalid file name does not have valid extension ( "+allowedExtensions+"): context=" + context+", input=" + input, context );
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public String getValidFileName(String context, String input, List<String> allowedParameters, boolean allowNull, ValidationErrorList errors) throws IntrusionException {
+        try {
+            return getValidFileName(context, input, allowedParameters, allowNull);
+        } catch (ValidationException e) {
+            errors.addError(context, e);
+        }
+
+        return "";
+    }
+
+    /**
+     * {@inheritDoc}
+     * <p>
+     * This implementation does not throw {@link IntrusionException}.
+     */
+    @Override
+    public boolean isValidNumber(String context, String input, long minValue, long maxValue, boolean allowNull) {
+        try {
+            getValidNumber(context, input, minValue, maxValue, allowNull);
+            return true;
+        } catch( Exception e ) {
+            return false;
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public boolean isValidNumber(String context, String input, long minValue, long maxValue, boolean allowNull, ValidationErrorList errors) throws IntrusionException {
+        try {
+            getValidNumber(context, input, minValue, maxValue, allowNull);
+            return true;
+        } catch( ValidationException e ) {
+            errors.addError(context, e);
+            return false;
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public Double getValidNumber(String context, String input, long minValue, long maxValue, boolean allowNull) throws ValidationException, IntrusionException {
+        Double minDoubleValue = new Double(minValue);
+        Double maxDoubleValue = new Double(maxValue);
+        return getValidDouble(context, input, minDoubleValue.doubleValue(), maxDoubleValue.doubleValue(), allowNull);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public Double getValidNumber(String context, String input, long minValue, long maxValue, boolean allowNull, ValidationErrorList errors) throws IntrusionException {
+        try {
+            return getValidNumber(context, input, minValue, maxValue, allowNull);
+        } catch (ValidationException e) {
+            errors.addError(context, e);
+        }
+
+        return null;
+    }
+
+    /**
+     * {@inheritDoc}
+     * <p>
+     * This implementation does not throw {@link IntrusionException}.
+     */
+    @Override
+    public boolean isValidDouble(String context, String input, double minValue, double maxValue, boolean allowNull) {
+        try {
+            getValidDouble( context, input, minValue, maxValue, allowNull );
+            return true;
+        } catch( Exception e ) {
+            return false;
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public boolean isValidDouble(String context, String input, double minValue, double maxValue, boolean allowNull, ValidationErrorList errors) throws IntrusionException {
+        try {
+            getValidDouble( context, input, minValue, maxValue, allowNull );
+            return true;
+        } catch( ValidationException e ) {
+            errors.addError(context, e);
+            return false;
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public Double getValidDouble(String context, String input, double minValue, double maxValue, boolean allowNull) throws ValidationException, IntrusionException {
+        NumberValidationRule nvr = new NumberValidationRule( "number", encoder, minValue, maxValue );
+        nvr.setAllowNull(allowNull);
+        return nvr.getValid(context, input);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public Double getValidDouble(String context, String input, double minValue, double maxValue, boolean allowNull, ValidationErrorList errors) throws IntrusionException {
+        try {
+            return getValidDouble(context, input, minValue, maxValue, allowNull);
+        } catch (ValidationException e) {
+            errors.addError(context, e);
+        }
 
+        return new Double(Double.NaN);
+    }
 
-	/**
-	 * Default constructor uses the ESAPI standard encoder for canonicalization.
-	 */
-	public DefaultValidator() {
-	    this.encoder = ESAPI.encoder();
-	}
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public boolean isValidInteger(String context, String input, int minValue, int maxValue, boolean allowNull) throws IntrusionException {
+        try {
+            getValidInteger( context, input, minValue, maxValue, allowNull);
+            return true;
+        } catch( ValidationException e ) {
+            return false;
+        }
+    }
 
-	/**
-	 * Construct a new DefaultValidator that will use the specified
-	 * Encoder for canonicalization.
-     *
-     * @param encoder
-     */
-	public DefaultValidator( Encoder encoder ) {
-	    this.encoder = encoder;
-	}
-
-
-	/**
-	 * Add a validation rule to the registry using the "type name" of the rule as the key.
-	 */
-	public void addRule( ValidationRule rule ) {
-		rules.put( rule.getTypeName(), rule );
-	}
-
-	/**
-	 * Get a validation rule from the registry with the "type name" of the rule as the key.
-	 */
-	public ValidationRule getRule( String name ) {
-		return rules.get( name );
-	}
-
-
-	/**
-	 * Returns true if data received from browser is valid. Double encoding is treated as an attack. The
-	 * default encoder supports html encoding, URL encoding, and javascript escaping. Input is canonicalized
-	 * by default before validation.
-	 *
-	 * @param context A descriptive name for the field to validate. This is used for error facing validation messages and element identification.
-	 * @param input The actual user input data to validate.
-	 * @param type The regular expression name while maps to the actual regular expression from "ESAPI.properties".
-	 * @param maxLength The maximum post-canonicalized String length allowed.
-	 * @param allowNull If allowNull is true then a input that is NULL or an empty string will be legal. If allowNull is false then NULL or an empty String will throw a ValidationException.
-	 * @return The canonicalized user input.
-	 * @throws IntrusionException
-	 */
-	public boolean isValidInput(String context, String input, String type, int maxLength, boolean allowNull) throws IntrusionException  {
-		return isValidInput(context, input, type, maxLength, allowNull, true);
-	}
-
-        public boolean isValidInput(String context, String input, String type, int maxLength, boolean allowNull, ValidationErrorList errors) throws IntrusionException  {
-		return isValidInput(context, input, type, maxLength, allowNull, true, errors);
-	}
-
-	public boolean isValidInput(String context, String input, String type, int maxLength, boolean allowNull, boolean canonicalize) throws IntrusionException  {
-		try {
-			getValidInput( context, input, type, maxLength, allowNull, canonicalize);
-			return true;
-		} catch( Exception e ) {
-			return false;
-		}
-	}
-
-        public boolean isValidInput(String context, String input, String type, int maxLength, boolean allowNull, boolean canonicalize, ValidationErrorList errors) throws IntrusionException  {
-		try {
-			getValidInput( context, input, type, maxLength, allowNull, canonicalize);
-			return true;
-		} catch( ValidationException e ) {
-			errors.addError( context, e );
-			return false;
-		}
-	}
-
-	/**
-	 * Validates data received from the browser and returns a safe version.
-	 * Double encoding is treated as an attack. The default encoder supports
-	 * html encoding, URL encoding, and javascript escaping. Input is
-	 * canonicalized by default before validation.
-	 *
-	 * @param context A descriptive name for the field to validate. This is used for error facing validation messages and element identification.
-	 * @param input The actual user input data to validate.
-	 * @param type The regular expression name which maps to the actual regular expression from "ESAPI.properties".
-	 * @param maxLength The maximum post-canonicalized String length allowed.
-	 * @param allowNull If allowNull is true then a input that is NULL or an empty string will be legal. If allowNull is false then NULL or an empty String will throw a ValidationException.
-	 * @return The canonicalized user input.
-	 * @throws ValidationException
-	 * @throws IntrusionException
-	 */
-	public String getValidInput(String context, String input, String type, int maxLength, boolean allowNull) throws ValidationException {
-		return getValidInput(context, input, type, maxLength, allowNull, true);
-	}
-
-	/**
-	 * Validates data received from the browser and returns a safe version. Only
-	 * URL encoding is supported. Double encoding is treated as an attack.
-	 *
-	 * @param context A descriptive name for the field to validate. This is used for error facing validation messages and element identification.
-	 * @param input The actual user input data to validate.
-	 * @param type The regular expression name which maps to the actual regular expression in the ESAPI validation configuration file
-	 * @param maxLength The maximum String length allowed. If input is canonicalized per the canonicalize argument, then maxLength must be verified after canonicalization
-     * @param allowNull If allowNull is true then a input that is NULL or an empty string will be legal. If allowNull is false then NULL or an empty String will throw a ValidationException.
-	 * @param canonicalize If canonicalize is true then input will be canonicalized before validation
-	 * @return The user input, may be canonicalized if canonicalize argument is true
-	 * @throws ValidationException
-	 * @throws IntrusionException
-	 */
-	public String getValidInput(String context, String input, String type, int maxLength, boolean allowNull, boolean canonicalize) throws ValidationException {
-		StringValidationRule rvr = new StringValidationRule( type, encoder );
-		Pattern p = ESAPI.securityConfiguration().getValidationPattern( type );
-		if ( p != null ) {
-			rvr.addWhitelistPattern( p );
-		} else {
-            // Issue 232 - Specify requested type in exception message - CS
-			throw new IllegalArgumentException("The selected type [" + type + "] was not set via the ESAPI validation configuration");
-		}
-		rvr.setMaximumLength(maxLength);
-		rvr.setAllowNull(allowNull);
-		rvr.setCanonicalize(canonicalize);
-		return rvr.getValid(context, input);
-	}
-
-	/**
-	 * Validates data received from the browser and returns a safe version. Only
-	 * URL encoding is supported. Double encoding is treated as an attack. Input
-	 * is canonicalized by default before validation.
-	 *
-	 * @param context A descriptive name for the field to validate. This is used for error facing validation messages and element identification.
-	 * @param input The actual user input data to validate.
-	 * @param type The regular expression name while maps to the actual regular expression from "ESAPI.properties".
-	 * @param maxLength The maximum String length allowed. If input is canonicalized per the canonicalize argument, then maxLength must be verified after canonicalization
-	 * @param allowNull If allowNull is true then a input that is NULL or an empty string will be legal. If allowNull is false then NULL or an empty String will throw a ValidationException.
-	 * @param errors If ValidationException is thrown, then add to error list instead of throwing out to caller
-	 * @return The canonicalized user input.
-	 * @throws IntrusionException
-	 */
-	public String getValidInput(String context, String input, String type, int maxLength, boolean allowNull, ValidationErrorList errors) throws IntrusionException {
-		return getValidInput(context, input, type, maxLength, allowNull, true, errors);
-	}
-
-	/**
-	 * Validates data received from the browser and returns a safe version. Only
-	 * URL encoding is supported. Double encoding is treated as an attack.
-	 *
-	 * @param context A descriptive name for the field to validate. This is used for error facing validation messages and element identification.
-	 * @param input The actual user input data to validate.
-	 * @param type The regular expression name while maps to the actual regular expression from "ESAPI.properties".
-	 * @param maxLength The maximum post-canonicalized String length allowed
-	 * @param allowNull If allowNull is true then a input that is NULL or an empty string will be legal. If allowNull is false then NULL or an empty String will throw a ValidationException.
-	 * @param canonicalize If canonicalize is true then input will be canonicalized before validation
-	 * @param errors If ValidationException is thrown, then add to error list instead of throwing out to caller
-	 * @return The user input, may be canonicalized if canonicalize argument is true
-	 * @throws IntrusionException
-	 */
-	public String getValidInput(String context, String input, String type, int maxLength, boolean allowNull, boolean canonicalize, ValidationErrorList errors) throws IntrusionException {
-		try {
-			return getValidInput(context,  input,  type,  maxLength,  allowNull, canonicalize);
-		} catch (ValidationException e) {
-			errors.addError(context, e);
-		}
-
-		return "";
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	public boolean isValidDate(String context, String input, DateFormat format, boolean allowNull) throws IntrusionException {
-		try {
-			getValidDate( context, input, format, allowNull);
-			return true;
-		} catch( Exception e ) {
-			return false;
-		}
-	}
-
-        /**
-	 * {@inheritDoc}
-	 */
-	public boolean isValidDate(String context, String input, DateFormat format, boolean allowNull, ValidationErrorList errors) throws IntrusionException {
-	    getValidDate( context, input, format, allowNull, errors);
-	    return errors.isEmpty();
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	public Date getValidDate(String context, String input, DateFormat format, boolean allowNull) throws ValidationException, IntrusionException {
-		
-		ValidationErrorList vel = new ValidationErrorList();
-		Date validDate =  getValidDate(context, input, format, allowNull, vel);
-		
-		if (vel.isEmpty()) {
-		    return validDate;
-		}
-		
-		throw vel.errors().get(0);
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	public Date getValidDate(String context, String input, DateFormat format, boolean allowNull, ValidationErrorList errors) throws IntrusionException {
-	    Date safeDate = null;
-	    DateValidationRule dvr = new DateValidationRule( "SimpleDate", encoder, format);
-	    dvr.setAllowNull(allowNull);
-	    safeDate = dvr.sanitize(context, input, errors);
-	    if (!errors.isEmpty()) {
-	        safeDate = null;
-	    }
-	    // error has been added to list, so return null
-	    return safeDate;
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	public boolean isValidSafeHTML(String context, String input, int maxLength, boolean allowNull) throws IntrusionException {
-		try {
-			getValidSafeHTML( context, input, maxLength, allowNull);
-			return true;
-		} catch( Exception e ) {
-			return false;
-		}
-	}
-
-        /**
-	 * {@inheritDoc}
-	 */
-	public boolean isValidSafeHTML(String context, String input, int maxLength, boolean allowNull, ValidationErrorList errors) throws IntrusionException {
-		try {
-			getValidSafeHTML( context, input, maxLength, allowNull);
-			return true;
-		} catch( ValidationException e ) {
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public boolean isValidInteger(String context, String input, int minValue, int maxValue, boolean allowNull, ValidationErrorList errors) throws IntrusionException {
+        try {
+            getValidInteger( context, input, minValue, maxValue, allowNull);
+            return true;
+        } catch( ValidationException e ) {
             errors.addError(context, e);
-			return false;
-		}
-	}
-
-	/**
-	 * {@inheritDoc}
-	 *
-	 * This implementation relies on the OWASP AntiSamy project.
-	 */
-	public String getValidSafeHTML( String context, String input, int maxLength, boolean allowNull ) throws ValidationException, IntrusionException {
-		HTMLValidationRule hvr = new HTMLValidationRule( "safehtml", encoder );
-		hvr.setMaximumLength(maxLength);
-		hvr.setAllowNull(allowNull);
-		return hvr.getValid(context, input);
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	public String getValidSafeHTML(String context, String input, int maxLength, boolean allowNull, ValidationErrorList errors) throws IntrusionException {
-		try {
-			return getValidSafeHTML(context, input, maxLength, allowNull);
-		} catch (ValidationException e) {
-			errors.addError(context, e);
-		}
-
-		return "";
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	public boolean isValidCreditCard(String context, String input, boolean allowNull) throws IntrusionException {
-		try {
-			getValidCreditCard( context, input, allowNull);
-			return true;
-		} catch( Exception e ) {
-			return false;
-		}
-	}
-
-        /**
-	 * {@inheritDoc}
-	 */
-	public boolean isValidCreditCard(String context, String input, boolean allowNull, ValidationErrorList errors) throws IntrusionException {
-		try {
-			getValidCreditCard( context, input, allowNull);
-			return true;
-		} catch( ValidationException e ) {
+            return false;
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public Integer getValidInteger(String context, String input, int minValue, int maxValue, boolean allowNull) throws ValidationException, IntrusionException {
+        IntegerValidationRule ivr = new IntegerValidationRule( "number", encoder, minValue, maxValue );
+        ivr.setAllowNull(allowNull);
+        return ivr.getValid(context, input);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public Integer getValidInteger(String context, String input, int minValue, int maxValue, boolean allowNull, ValidationErrorList errors) throws IntrusionException {
+        try {
+            return getValidInteger(context, input, minValue, maxValue, allowNull);
+        } catch (ValidationException e) {
             errors.addError(context, e);
-			return false;
-		}
-	}
-	/**
-	 * {@inheritDoc}
-	 */
-	public String getValidCreditCard(String context, String input, boolean allowNull) throws ValidationException, IntrusionException {
-		CreditCardValidationRule ccvr = new CreditCardValidationRule( "creditcard", encoder );
-		ccvr.setAllowNull(allowNull);
-		return ccvr.getValid(context, input);
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	public String getValidCreditCard(String context, String input, boolean allowNull, ValidationErrorList errors) throws IntrusionException {
-		try {
-			return getValidCreditCard(context, input, allowNull);
-		} catch (ValidationException e) {
-			errors.addError(context, e);
-		}
-
-		return "";
-	}
-
-	/**
-	 * {@inheritDoc}
-	 *
-	 * <p><b>Note:</b> On platforms that support symlinks, this function will fail canonicalization if directorypath
-	 * is a symlink. For example, on MacOS X, /etc is actually /private/etc. If you mean to use /etc, use its real
-	 * path (/private/etc), not the symlink (/etc).</p>
-	 */
-	public boolean isValidDirectoryPath(String context, String input, File parent, boolean allowNull) throws IntrusionException {
-		try {
-			getValidDirectoryPath( context, input, parent, allowNull);
-			return true;
-		} catch( Exception e ) {
-			return false;
-		}
-	}
-
-        /**
-	 * {@inheritDoc}
-	 *
-	 * <p><b>Note:</b> On platforms that support symlinks, this function will fail canonicalization if directorypath
-	 * is a symlink. For example, on MacOS X, /etc is actually /private/etc. If you mean to use /etc, use its real
-	 * path (/private/etc), not the symlink (/etc).</p>
-	 */
-	public boolean isValidDirectoryPath(String context, String input, File parent, boolean allowNull, ValidationErrorList errors) throws IntrusionException {
-		try {
-			getValidDirectoryPath( context, input, parent, allowNull);
-			return true;
-		} catch( ValidationException e ) {
+        }
+        // error has been added to list, so return original input
+        return null;
+    }
+
+    /**
+     * {@inheritDoc}
+     * <p>
+     * This implementation does not throw {@link IntrusionException}.
+     */
+    @Override
+    public boolean isValidFileContent(String context, byte[] input, int maxBytes, boolean allowNull) {
+        try {
+            getValidFileContent( context, input, maxBytes, allowNull);
+            return true;
+        } catch( Exception e ) {
+            return false;
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public boolean isValidFileContent(String context, byte[] input, int maxBytes, boolean allowNull, ValidationErrorList errors) throws IntrusionException {
+        try {
+            getValidFileContent( context, input, maxBytes, allowNull);
+            return true;
+        } catch( ValidationException e ) {
             errors.addError(context, e);
-			return false;
-		}
-	}
-	/**
-	 * {@inheritDoc}
-	 */
-	public String getValidDirectoryPath(String context, String input, File parent, boolean allowNull) throws ValidationException, IntrusionException {
-		try {
-			if (isEmpty(input)) {
-				if (allowNull) return null;
-       			throw new ValidationException( context + ": Input directory path required", "Input directory path required: context=" + context + ", input=" + input, context );
-			}
-
-			File dir = new File( input );
-
-			// check dir exists and parent exists and dir is inside parent
-			if ( !dir.exists() ) {
-				throw new ValidationException( context + ": Invalid directory name", "Invalid directory, does not exist: context=" + context + ", input=" + input );
-			}
-			if ( !dir.isDirectory() ) {
-				throw new ValidationException( context + ": Invalid directory name", "Invalid directory, not a directory: context=" + context + ", input=" + input );
-			}
-			if ( !parent.exists() ) {
-				throw new ValidationException( context + ": Invalid directory name", "Invalid directory, specified parent does not exist: context=" + context + ", input=" + input + ", parent=" + parent );
-			}
-			if ( !parent.isDirectory() ) {
-				throw new ValidationException( context + ": Invalid directory name", "Invalid directory, specified parent is not a directory: context=" + context + ", input=" + input + ", parent=" + parent );
-			}
-			if ( !dir.getCanonicalFile().toPath().startsWith( parent.getCanonicalFile().toPath() ) ) { // Fixes GHSL-2022-008
-				throw new ValidationException( context + ": Invalid directory name", "Invalid directory, not inside specified parent: context=" + context + ", input=" + input + ", parent=" + parent );
-			}
-
-			// check canonical form matches input
-			String canonicalPath = dir.getCanonicalPath();
-			String canonical = fileValidator.getValidInput( context, canonicalPath, "DirectoryName", 255, false);
-			if ( !canonical.equals( input ) ) {
-				throw new ValidationException( context + ": Invalid directory name", "Invalid directory name does not match the canonical path: context=" + context + ", input=" + input + ", canonical=" + canonical, context );
-			}
-			return canonical;
-		} catch (Exception e) {
-			throw new ValidationException( context + ": Invalid directory name", "Failure to validate directory path: context=" + context + ", input=" + input, e, context );
-		}
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	public String getValidDirectoryPath(String context, String input, File parent, boolean allowNull, ValidationErrorList errors) throws IntrusionException {
-
-		try {
-			return getValidDirectoryPath(context, input, parent, allowNull);
-		} catch (ValidationException e) {
-			errors.addError(context, e);
-		}
-
-		return "";
-	}
-
-
-	/**
-	 * {@inheritDoc}
-	 */
-	public boolean isValidFileName(String context, String input, boolean allowNull) throws IntrusionException {
-		return isValidFileName( context, input, ESAPI.securityConfiguration().getAllowedFileExtensions(), allowNull );
-	}
-
-        /**
-	 * {@inheritDoc}
-	 */
-	public boolean isValidFileName(String context, String input, boolean allowNull, ValidationErrorList errors) throws IntrusionException {
-		return isValidFileName( context, input, ESAPI.securityConfiguration().getAllowedFileExtensions(), allowNull, errors );
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	public boolean isValidFileName(String context, String input, List<String> allowedExtensions, boolean allowNull) throws IntrusionException {
-		try {
-			getValidFileName( context, input, allowedExtensions, allowNull);
-			return true;
-		} catch( Exception e ) {
-			return false;
-		}
-	}
-
-        /**
-	 * {@inheritDoc}
-	 */
-	public boolean isValidFileName(String context, String input, List<String> allowedExtensions, boolean allowNull, ValidationErrorList errors) throws IntrusionException {
-		try {
-			getValidFileName( context, input, allowedExtensions, allowNull);
-			return true;
-		} catch( ValidationException e ) {
+            return false;
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public byte[] getValidFileContent(String context, byte[] input, int maxBytes, boolean allowNull) throws ValidationException, IntrusionException {
+        if (isEmpty(input)) {
+            if (allowNull) {
+                return null;
+            }
+            throw new ValidationException( context + ": Input required", "Input required: context=" + context + ", input=" + Arrays.toString(input), context );
+        }
+
+        long esapiMaxBytes = ESAPI.securityConfiguration().getAllowedFileUploadSize();
+        if (input.length > esapiMaxBytes ) throw new ValidationException( context + ": Invalid file content can not exceed " + esapiMaxBytes + " bytes", "Exceeded ESAPI max length", context );
+        if (input.length > maxBytes ) throw new ValidationException( context + ": Invalid file content can not exceed " + maxBytes + " bytes", "Exceeded maxBytes ( " + input.length + ")", context );
+
+        return input;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public byte[] getValidFileContent(String context, byte[] input, int maxBytes, boolean allowNull, ValidationErrorList errors) throws IntrusionException {
+        try {
+            return getValidFileContent(context, input, maxBytes, allowNull);
+        } catch (ValidationException e) {
             errors.addError(context, e);
-			return false;
-		}
-	}
-	/**
-	 * {@inheritDoc}
-	 */
-	public String getValidFileName(String context, String input, List<String> allowedExtensions, boolean allowNull) throws ValidationException, IntrusionException {
-		if ((allowedExtensions == null) || (allowedExtensions.isEmpty())) {
-			throw new ValidationException( "Internal Error", "getValidFileName called with an empty or null list of allowed Extensions, therefore no files can be uploaded" );
-		}
-
-		String canonical = "";
-		// detect path manipulation
-		try {
-			if (isEmpty(input)) {
-				if (allowNull) return null;
-	   			throw new ValidationException( context + ": Input file name required", "Input required: context=" + context + ", input=" + input, context );
-			}
-
-			// do basic validation
-	        canonical = new File(input).getCanonicalFile().getName();
-	        getValidInput( context, input, "FileName", 255, true );
-
-			File f = new File(canonical);
-			String c = f.getCanonicalPath();
-			String cpath = c.substring(c.lastIndexOf(File.separator) + 1);
-
-
-			// the path is valid if the input matches the canonical path
-			if (!input.equals(cpath)) {
-				throw new ValidationException( context + ": Invalid file name", "Invalid directory name does not match the canonical path: context=" + context + ", input=" + input + ", canonical=" + canonical, context );
-			}
-
-		} catch (IOException e) {
-			throw new ValidationException( context + ": Invalid file name", "Invalid file name does not exist: context=" + context + ", canonical=" + canonical, e, context );
-		}
-
-		// verify extensions
-		Iterator<String> i = allowedExtensions.iterator();
-		while (i.hasNext()) {
-			String ext = i.next();
-			if (input.toLowerCase().endsWith(ext.toLowerCase())) {
-				return canonical;
-			}
-		}
-		throw new ValidationException( context + ": Invalid file name does not have valid extension ( "+allowedExtensions+")", "Invalid file name does not have valid extension ( "+allowedExtensions+"): context=" + context+", input=" + input, context );
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	public String getValidFileName(String context, String input, List<String> allowedParameters, boolean allowNull, ValidationErrorList errors) throws IntrusionException {
-		try {
-			return getValidFileName(context, input, allowedParameters, allowNull);
-		} catch (ValidationException e) {
-			errors.addError(context, e);
-		}
-
-		return "";
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	public boolean isValidNumber(String context, String input, long minValue, long maxValue, boolean allowNull) throws IntrusionException {
-		try {
-			getValidNumber(context, input, minValue, maxValue, allowNull);
-			return true;
-		} catch( Exception e ) {
-			return false;
-		}
-	}
-
-        /**
-	 * {@inheritDoc}
-	 */
-	public boolean isValidNumber(String context, String input, long minValue, long maxValue, boolean allowNull, ValidationErrorList errors) throws IntrusionException {
-		try {
-			getValidNumber(context, input, minValue, maxValue, allowNull);
-			return true;
-		} catch( ValidationException e ) {
+        }
+        // return empty byte array on error
+        return new byte[0];
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * <p><b>Note:</b> On platforms that support symlinks, this function will fail canonicalization if directorypath
+     * is a symlink. For example, on MacOS X, /etc is actually /private/etc. If you mean to use /etc, use its real
+     * path (/private/etc), not the symlink (/etc).</p>
+     */
+    @Override
+    public boolean isValidFileUpload(String context, String directorypath, String filename, File parent, byte[] content, int maxBytes, boolean allowNull) throws IntrusionException {
+        return( isValidFileName( context, filename, allowNull ) &&
+                isValidDirectoryPath( context, directorypath, parent, allowNull ) &&
+                isValidFileContent( context, content, maxBytes, allowNull ) );
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * <p><b>Note:</b> On platforms that support symlinks, this function will fail canonicalization if directorypath
+     * is a symlink. For example, on MacOS X, /etc is actually /private/etc. If you mean to use /etc, use its real
+     * path (/private/etc), not the symlink (/etc).</p>
+     */
+    @Override
+    public boolean isValidFileUpload(String context, String directorypath, String filename, File parent, byte[] content, int maxBytes, boolean allowNull, ValidationErrorList errors) throws IntrusionException {
+        return( isValidFileName( context, filename, allowNull, errors ) &&
+                isValidDirectoryPath( context, directorypath, parent, allowNull, errors ) &&
+                isValidFileContent( context, content, maxBytes, allowNull, errors ) );
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void assertValidFileUpload(String context, String directorypath, String filename, File parent, byte[] content, int maxBytes, List<String> allowedExtensions, boolean allowNull) throws ValidationException, IntrusionException {
+        getValidFileName( context, filename, allowedExtensions, allowNull );
+        getValidDirectoryPath( context, directorypath, parent, allowNull );
+        getValidFileContent( context, content, maxBytes, allowNull );
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void assertValidFileUpload(String context, String filepath, String filename, File parent, byte[] content, int maxBytes, List<String> allowedExtensions, boolean allowNull, ValidationErrorList errors)
+        throws IntrusionException {
+        try {
+            assertValidFileUpload(context, filepath, filename, parent, content, maxBytes, allowedExtensions, allowNull);
+        } catch (ValidationException e) {
             errors.addError(context, e);
-			return false;
-		}
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	public Double getValidNumber(String context, String input, long minValue, long maxValue, boolean allowNull) throws ValidationException, IntrusionException {
-		Double minDoubleValue = new Double(minValue);
-		Double maxDoubleValue = new Double(maxValue);
-		return getValidDouble(context, input, minDoubleValue.doubleValue(), maxDoubleValue.doubleValue(), allowNull);
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	public Double getValidNumber(String context, String input, long minValue, long maxValue, boolean allowNull, ValidationErrorList errors) throws IntrusionException {
-		try {
-			return getValidNumber(context, input, minValue, maxValue, allowNull);
-		} catch (ValidationException e) {
-			errors.addError(context, e);
-		}
-
-		return null;
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	public boolean isValidDouble(String context, String input, double minValue, double maxValue, boolean allowNull) throws IntrusionException {
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     * <p>
+     * This implementation does not throw {@link IntrusionException}.
+     */
+    @Override
+    public boolean isValidListItem(String context, String input, List<String> list) {
         try {
-            getValidDouble( context, input, minValue, maxValue, allowNull );
+            getValidListItem( context, input, list);
             return true;
         } catch( Exception e ) {
             return false;
         }
-	}
+    }
 
-        /**
-	 * {@inheritDoc}
-	 */
-	public boolean isValidDouble(String context, String input, double minValue, double maxValue, boolean allowNull, ValidationErrorList errors) throws IntrusionException {
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public boolean isValidListItem(String context, String input, List<String> list, ValidationErrorList errors) {
         try {
-            getValidDouble( context, input, minValue, maxValue, allowNull );
+            getValidListItem( context, input, list);
             return true;
         } catch( ValidationException e ) {
             errors.addError(context, e);
             return false;
         }
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	public Double getValidDouble(String context, String input, double minValue, double maxValue, boolean allowNull) throws ValidationException, IntrusionException {
-		NumberValidationRule nvr = new NumberValidationRule( "number", encoder, minValue, maxValue );
-		nvr.setAllowNull(allowNull);
-		return nvr.getValid(context, input);
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	public Double getValidDouble(String context, String input, double minValue, double maxValue, boolean allowNull, ValidationErrorList errors) throws IntrusionException {
-		try {
-			return getValidDouble(context, input, minValue, maxValue, allowNull);
-		} catch (ValidationException e) {
-			errors.addError(context, e);
-		}
-
-		return new Double(Double.NaN);
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	public boolean isValidInteger(String context, String input, int minValue, int maxValue, boolean allowNull) throws IntrusionException {
-		try {
-			getValidInteger( context, input, minValue, maxValue, allowNull);
-			return true;
-		} catch( ValidationException e ) {
-			return false;
-		}
-	}
-
-        /**
-	 * {@inheritDoc}
-	 */
-	public boolean isValidInteger(String context, String input, int minValue, int maxValue, boolean allowNull, ValidationErrorList errors) throws IntrusionException {
-		try {
-			getValidInteger( context, input, minValue, maxValue, allowNull);
-			return true;
-		} catch( ValidationException e ) {
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public String getValidListItem(String context, String input, List<String> list) throws ValidationException, IntrusionException {
+        if (list.contains(input)) return input;
+        throw new ValidationException( context + ": Invalid list item", "Invalid list item: context=" + context + ", input=" + input, context );
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public String getValidListItem(String context, String input, List<String> list, ValidationErrorList errors) throws IntrusionException {
+        try {
+            return getValidListItem(context, input, list);
+        } catch (ValidationException e) {
             errors.addError(context, e);
-			return false;
-		}
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	public Integer getValidInteger(String context, String input, int minValue, int maxValue, boolean allowNull) throws ValidationException, IntrusionException {
-		IntegerValidationRule ivr = new IntegerValidationRule( "number", encoder, minValue, maxValue );
-		ivr.setAllowNull(allowNull);
-		return ivr.getValid(context, input);
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	public Integer getValidInteger(String context, String input, int minValue, int maxValue, boolean allowNull, ValidationErrorList errors) throws IntrusionException {
-		try {
-			return getValidInteger(context, input, minValue, maxValue, allowNull);
-		} catch (ValidationException e) {
-			errors.addError(context, e);
-		}
-		// error has been added to list, so return original input
-		return null;
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	public boolean isValidFileContent(String context, byte[] input, int maxBytes, boolean allowNull) throws IntrusionException {
-		try {
-			getValidFileContent( context, input, maxBytes, allowNull);
-			return true;
-		} catch( Exception e ) {
-			return false;
-		}
-	}
-
-        /**
-	 * {@inheritDoc}
-	 */
-	public boolean isValidFileContent(String context, byte[] input, int maxBytes, boolean allowNull, ValidationErrorList errors) throws IntrusionException {
-		try {
-			getValidFileContent( context, input, maxBytes, allowNull);
-			return true;
-		} catch( ValidationException e ) {
+        }
+        // error has been added to list, so return original input
+        return input;
+    }
+
+    /**
+     * {@inheritDoc}
+     * <p>
+     * This implementation does not throw {@link IntrusionException}.
+     */
+    @Override
+    public boolean isValidHTTPRequestParameterSet(String context, HttpServletRequest request, Set<String> requiredNames, Set<String> optionalNames) {
+        try {
+            assertValidHTTPRequestParameterSet( context, request, requiredNames, optionalNames);
+            return true;
+        } catch( Exception e ) {
+            return false;
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public boolean isValidHTTPRequestParameterSet(String context, HttpServletRequest request, Set<String> requiredNames, Set<String> optionalNames, ValidationErrorList errors) {
+        try {
+            assertValidHTTPRequestParameterSet( context, request, requiredNames, optionalNames);
+            return true;
+        } catch( ValidationException e ) {
             errors.addError(context, e);
-			return false;
-		}
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	public byte[] getValidFileContent(String context, byte[] input, int maxBytes, boolean allowNull) throws ValidationException, IntrusionException {
-		if (isEmpty(input)) {
-			if (allowNull) return null;
-   			throw new ValidationException( context + ": Input required", "Input required: context=" + context + ", input=" + Arrays.toString(input), context );
-		}
-
-		long esapiMaxBytes = ESAPI.securityConfiguration().getAllowedFileUploadSize();
-		if (input.length > esapiMaxBytes ) throw new ValidationException( context + ": Invalid file content can not exceed " + esapiMaxBytes + " bytes", "Exceeded ESAPI max length", context );
-		if (input.length > maxBytes ) throw new ValidationException( context + ": Invalid file content can not exceed " + maxBytes + " bytes", "Exceeded maxBytes ( " + input.length + ")", context );
-
-		return input;
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	public byte[] getValidFileContent(String context, byte[] input, int maxBytes, boolean allowNull, ValidationErrorList errors) throws IntrusionException {
-		try {
-			return getValidFileContent(context, input, maxBytes, allowNull);
-		} catch (ValidationException e) {
-			errors.addError(context, e);
-		}
-		// return empty byte array on error
-		return new byte[0];
-	}
-
-	/**
-	 * {@inheritDoc}
-	 *
-	 * <p><b>Note:</b> On platforms that support symlinks, this function will fail canonicalization if directorypath
-	 * is a symlink. For example, on MacOS X, /etc is actually /private/etc. If you mean to use /etc, use its real
-	 * path (/private/etc), not the symlink (/etc).</p>
-     */
-	public boolean isValidFileUpload(String context, String directorypath, String filename, File parent, byte[] content, int maxBytes, boolean allowNull) throws IntrusionException {
-		return( isValidFileName( context, filename, allowNull ) &&
-				isValidDirectoryPath( context, directorypath, parent, allowNull ) &&
-				isValidFileContent( context, content, maxBytes, allowNull ) );
-	}
-
-        /**
-	 * {@inheritDoc}
-	 *
-	 * <p><b>Note:</b> On platforms that support symlinks, this function will fail canonicalization if directorypath
-	 * is a symlink. For example, on MacOS X, /etc is actually /private/etc. If you mean to use /etc, use its real
-	 * path (/private/etc), not the symlink (/etc).</p>
-     */
-	public boolean isValidFileUpload(String context, String directorypath, String filename, File parent, byte[] content, int maxBytes, boolean allowNull, ValidationErrorList errors) throws IntrusionException {
-		return( isValidFileName( context, filename, allowNull, errors ) &&
-				isValidDirectoryPath( context, directorypath, parent, allowNull, errors ) &&
-				isValidFileContent( context, content, maxBytes, allowNull, errors ) );
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	public void assertValidFileUpload(String context, String directorypath, String filename, File parent, byte[] content, int maxBytes, List<String> allowedExtensions, boolean allowNull) throws ValidationException, IntrusionException {
-		getValidFileName( context, filename, allowedExtensions, allowNull );
-		getValidDirectoryPath( context, directorypath, parent, allowNull );
-		getValidFileContent( context, content, maxBytes, allowNull );
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	public void assertValidFileUpload(String context, String filepath, String filename, File parent, byte[] content, int maxBytes, List<String> allowedExtensions, boolean allowNull, ValidationErrorList errors)
-		throws IntrusionException {
-		try {
-			assertValidFileUpload(context, filepath, filename, parent, content, maxBytes, allowedExtensions, allowNull);
-		} catch (ValidationException e) {
-			errors.addError(context, e);
-		}
-	}
-
-	 /**
-	 * {@inheritDoc}
-	 *
-	 * Returns true if input is a valid list item.
-	 */
-	public boolean isValidListItem(String context, String input, List<String> list) {
-		try {
-			getValidListItem( context, input, list);
-			return true;
-		} catch( Exception e ) {
-			return false;
-		}
-	}
-
-        /**
-	 * {@inheritDoc}
-	 *
-	 * Returns true if input is a valid list item.
-	 */
-	public boolean isValidListItem(String context, String input, List<String> list, ValidationErrorList errors) {
-		try {
-			getValidListItem( context, input, list);
-			return true;
-		} catch( ValidationException e ) {
+            return false;
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void assertValidHTTPRequestParameterSet(String context, HttpServletRequest request, Set<String> required, Set<String> optional) throws ValidationException, IntrusionException {
+        Set<String> actualNames = request.getParameterMap().keySet();
+
+        // verify ALL required parameters are present
+        Set<String> missing = new HashSet<String>(required);
+        missing.removeAll(actualNames);
+        if (missing.size() > 0) {
+            throw new ValidationException( context + ": Invalid HTTP request missing parameters", "Invalid HTTP request missing parameters " + missing + ": context=" + context, context );
+        }
+
+        // verify ONLY optional + required parameters are present
+        Set<String> extra = new HashSet<String>(actualNames);
+        extra.removeAll(required);
+        extra.removeAll(optional);
+        if (extra.size() > 0) {
+            throw new ValidationException( context + ": Invalid HTTP request extra parameters " + extra, "Invalid HTTP request extra parameters " + extra + ": context=" + context, context );
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void assertValidHTTPRequestParameterSet(String context, HttpServletRequest request, Set<String> required, Set<String> optional, ValidationErrorList errors) throws IntrusionException {
+        try {
+            assertValidHTTPRequestParameterSet(context, request, required, optional);
+        } catch (ValidationException e) {
             errors.addError(context, e);
-			return false;
-		}
-	}
-
-	/**
-	 * Returns the list item that exactly matches the canonicalized input. Invalid or non-matching input
-	 * will generate a descriptive ValidationException, and input that is clearly an attack
-	 * will generate a descriptive IntrusionException.
-	 */
-	public String getValidListItem(String context, String input, List<String> list) throws ValidationException, IntrusionException {
-		if (list.contains(input)) return input;
-		throw new ValidationException( context + ": Invalid list item", "Invalid list item: context=" + context + ", input=" + input, context );
-	}
-
-
-	/**
-	 * ValidationErrorList variant of getValidListItem
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     * <p>
+     * Checks that all bytes are valid ASCII characters (between 33 and 126 inclusive).
+     * This implementation does no decoding.
+     * <p>
+     * This implementation does not throw {@link IntrusionException}.
      *
-     * @param errors
-     */
-	public String getValidListItem(String context, String input, List<String> list, ValidationErrorList errors) throws IntrusionException {
-		try {
-			return getValidListItem(context, input, list);
-		} catch (ValidationException e) {
-			errors.addError(context, e);
-		}
-		// error has been added to list, so return original input
-		return input;
-	}
-
-	 /**
-	 * {@inheritDoc}
-     */
-	public boolean isValidHTTPRequestParameterSet(String context, HttpServletRequest request, Set<String> requiredNames, Set<String> optionalNames) {
-		try {
-			assertValidHTTPRequestParameterSet( context, request, requiredNames, optionalNames);
-			return true;
-		} catch( Exception e ) {
-			return false;
-		}
-	}
-
-         /**
-	 * {@inheritDoc}
-     */
-	public boolean isValidHTTPRequestParameterSet(String context, HttpServletRequest request, Set<String> requiredNames, Set<String> optionalNames, ValidationErrorList errors) {
-		try {
-			assertValidHTTPRequestParameterSet( context, request, requiredNames, optionalNames);
-			return true;
-		} catch( ValidationException e ) {
-            errors.addError(context, e);
-			return false;
-		}
-	}
-
-	/**
-	 * Validates that the parameters in the current request contain all required parameters and only optional ones in
-	 * addition. Invalid input will generate a descriptive ValidationException, and input that is clearly an attack
-	 * will generate a descriptive IntrusionException.
-	 *
-	 * Uses current HTTPRequest
-	 */
-	public void assertValidHTTPRequestParameterSet(String context, HttpServletRequest request, Set<String> required, Set<String> optional) throws ValidationException, IntrusionException {
-		Set<String> actualNames = request.getParameterMap().keySet();
-
-		// verify ALL required parameters are present
-		Set<String> missing = new HashSet<String>(required);
-		missing.removeAll(actualNames);
-		if (missing.size() > 0) {
-			throw new ValidationException( context + ": Invalid HTTP request missing parameters", "Invalid HTTP request missing parameters " + missing + ": context=" + context, context );
-		}
-
-		// verify ONLY optional + required parameters are present
-		Set<String> extra = new HashSet<String>(actualNames);
-		extra.removeAll(required);
-		extra.removeAll(optional);
-		if (extra.size() > 0) {
-			throw new ValidationException( context + ": Invalid HTTP request extra parameters " + extra, "Invalid HTTP request extra parameters " + extra + ": context=" + context, context );
-		}
-	}
-
-	/**
-	 * ValidationErrorList variant of assertIsValidHTTPRequestParameterSet
+     * @see <a href="https://en.wikipedia.org/wiki/ASCII">Wikipedia - ASCII</a>
+     */
+    @Override
+    public boolean isValidPrintable(String context, char[] input, int maxLength, boolean allowNull) {
+        try {
+            getValidPrintable( context, input, maxLength, allowNull);
+            return true;
+        } catch( Exception e ) {
+            return false;
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     * <p>
+     * Checks that all bytes are valid ASCII characters (between 33 and 126
+     * inclusive). This implementation does no decoding.
      *
-	 * Uses current HTTPRequest saved in ESAPI Authenticator
-     * @param errors
+     * @see <a href="https://en.wikipedia.org/wiki/ASCII">Wikipedia - ASCII</a>
      */
-	public void assertValidHTTPRequestParameterSet(String context, HttpServletRequest request, Set<String> required, Set<String> optional, ValidationErrorList errors) throws IntrusionException {
-		try {
-			assertValidHTTPRequestParameterSet(context, request, required, optional);
-		} catch (ValidationException e) {
-			errors.addError(context, e);
-		}
-	}
+    @Override
+    public boolean isValidPrintable(String context, char[] input, int maxLength, boolean allowNull, ValidationErrorList errors) throws IntrusionException {
+        try {
+            getValidPrintable( context, input, maxLength, allowNull);
+            return true;
+        } catch( ValidationException e ) {
+            errors.addError(context, e);
+            return false;
+        }
+    }
 
-	/**
+    /**
      * {@inheritDoc}
+     * <p>
+     * Input is valid if it only contains printable ASCII characters (33-126 inclusive).
      *
-	 * Checks that all bytes are valid ASCII characters (between 33 and 126
-	 * inclusive). This implementation does no decoding. http://en.wikipedia.org/wiki/ASCII.
-	 */
-	public boolean isValidPrintable(String context, char[] input, int maxLength, boolean allowNull) throws IntrusionException {
-		try {
-			getValidPrintable( context, input, maxLength, allowNull);
-			return true;
-		} catch( Exception e ) {
-			return false;
-		}
-	}
-
-        /**
+     * @see <a href="https://en.wikipedia.org/wiki/ASCII">Wikipedia - ASCII</a>
+     */
+    @Override
+    public char[] getValidPrintable(String context, char[] input, int maxLength, boolean allowNull) throws ValidationException, IntrusionException {
+        if (isEmpty(input)) {
+            if (allowNull) {
+                return null;
+            }
+            throw new ValidationException(context + ": Input bytes required", "Input bytes required: HTTP request is null", context );
+        }
+
+        if (input.length > maxLength) {
+            throw new ValidationException(context + ": Input bytes can not exceed " + maxLength + " bytes", "Input exceeds maximum allowed length of " + maxLength + " by " + (input.length-maxLength) + " bytes: context=" + context + ", input=" + new String( input ), context);
+        }
+
+        for (int i = 0; i < input.length; i++) {
+            if (input[i] <= 0x20 || input[i] >= 0x7E ) {
+                throw new ValidationException(context + ": Invalid input bytes: context=" + context, "Invalid non-ASCII input bytes, context=" + context + ", input=" + new String( input ), context);
+            }
+        }
+        return input;
+    }
+
+    /**
      * {@inheritDoc}
+     * <p>
+     * Input is valid if it only contains printable ASCII characters (33-126 inclusive).
      *
-	 * Checks that all bytes are valid ASCII characters (between 33 and 126
-	 * inclusive). This implementation does no decoding. http://en.wikipedia.org/wiki/ASCII.
-	 */
-	public boolean isValidPrintable(String context, char[] input, int maxLength, boolean allowNull, ValidationErrorList errors) throws IntrusionException {
-		try {
-			getValidPrintable( context, input, maxLength, allowNull);
-			return true;
-		} catch( ValidationException e ) {
+     * @see <a href="https://en.wikipedia.org/wiki/ASCII">Wikipedia - ASCII</a>
+     */
+    @Override
+    public char[] getValidPrintable(String context, char[] input, int maxLength, boolean allowNull, ValidationErrorList errors)
+        throws IntrusionException {
+
+        try {
+            return getValidPrintable(context, input, maxLength, allowNull);
+        } catch (ValidationException e) {
             errors.addError(context, e);
-			return false;
-		}
-	}
+        }
+        // error has been added to list, so return original input
+        return input;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     * <p>
+     * Returns true if input is valid printable ASCII characters (33-126 inclusive).
+     * <p>
+     * This implementation does not throw {@link IntrusionException}.
+     *
+     * @see <a href="https://en.wikipedia.org/wiki/ASCII">Wikipedia - ASCII</a>
+     */
+    @Override
+    public boolean isValidPrintable(String context, String input, int maxLength, boolean allowNull) {
+        try {
+            getValidPrintable( context, input, maxLength, allowNull);
+            return true;
+        } catch( Exception e ) {
+            return false;
+        }
+    }
 
-	/**
-	 * Returns canonicalized and validated printable characters as a byte array. Invalid input will generate a descriptive ValidationException, and input that is clearly an attack
-	 * will generate a descriptive IntrusionException.
+    /**
+     * {@inheritDoc}
      *
-     * @throws IntrusionException
-     */
-	public char[] getValidPrintable(String context, char[] input, int maxLength, boolean allowNull) throws ValidationException, IntrusionException {
-		if (isEmpty(input)) {
-			if (allowNull) return null;
-   			throw new ValidationException(context + ": Input bytes required", "Input bytes required: HTTP request is null", context );
-		}
-
-		if (input.length > maxLength) {
-			throw new ValidationException(context + ": Input bytes can not exceed " + maxLength + " bytes", "Input exceeds maximum allowed length of " + maxLength + " by " + (input.length-maxLength) + " bytes: context=" + context + ", input=" + new String( input ), context);
-		}
-
-		for (int i = 0; i < input.length; i++) {
-			if (input[i] <= 0x20 || input[i] >= 0x7E ) {
-				throw new ValidationException(context + ": Invalid input bytes: context=" + context, "Invalid non-ASCII input bytes, context=" + context + ", input=" + new String( input ), context);
-			}
-		}
-		return input;
-	}
-
-	/**
-	 * ValidationErrorList variant of getValidPrintable
+     * Returns true if input is valid printable ASCII characters (33-126 inclusive).
      *
-     * @param errors
-     */
-	public char[] getValidPrintable(String context, char[] input,int maxLength, boolean allowNull, ValidationErrorList errors)
-		throws IntrusionException {
-
-		try {
-			return getValidPrintable(context, input, maxLength, allowNull);
-		} catch (ValidationException e) {
-			errors.addError(context, e);
-		}
-		// error has been added to list, so return original input
-		return input;
-	}
-
-
-	 /**
-	 * {@inheritDoc}
-	 *
-	 * Returns true if input is valid printable ASCII characters (32-126).
-	 */
-	public boolean isValidPrintable(String context, String input, int maxLength, boolean allowNull) throws IntrusionException {
-		try {
-			getValidPrintable( context, input, maxLength, allowNull);
-			return true;
-		} catch( Exception e ) {
-			return false;
-		}
-	}
-
-        /**
-	 * {@inheritDoc}
-	 *
-	 * Returns true if input is valid printable ASCII characters (32-126).
-	 */
-	public boolean isValidPrintable(String context, String input, int maxLength, boolean allowNull, ValidationErrorList errors) throws IntrusionException {
-		try {
-			getValidPrintable( context, input, maxLength, allowNull);
-			return true;
-		} catch( ValidationException e ) {
+     * @see <a href="https://en.wikipedia.org/wiki/ASCII">Wikipedia - ASCII</a>
+     */
+    @Override
+    public boolean isValidPrintable(String context, String input, int maxLength, boolean allowNull, ValidationErrorList errors) throws IntrusionException {
+        try {
+            getValidPrintable( context, input, maxLength, allowNull);
+            return true;
+        } catch( ValidationException e ) {
             errors.addError(context, e);
-			return false;
-		}
-	}
+            return false;
+        }
+    }
 
-	/**
-	 * Returns canonicalized and validated printable characters as a String. Invalid input will generate a descriptive ValidationException, and input that is clearly an attack
-	 * will generate a descriptive IntrusionException.
+    /**
+     * {@inheritDoc}
+     * <p>
+     * Input is valid if it only contains printable ASCII characters (33-126 inclusive).
      *
-     * @throws IntrusionException
-     */
-	public String getValidPrintable(String context, String input, int maxLength, boolean allowNull) throws ValidationException, IntrusionException {
-		try {
-    		String canonical = encoder.canonicalize(input);
-    		return new String( getValidPrintable( context, canonical.toCharArray(), maxLength, allowNull) );
-	    //TODO - changed this to base Exception since we no longer need EncodingException
-    	//TODO - this is a bit lame: we need to re-think this function.
-		} catch (Exception e) {
-	        throw new ValidationException( context + ": Invalid printable input", "Invalid encoding of printable input, context=" + context + ", input=" + input, e, context);
-	    }
-	}
-
-	/**
-	 * ValidationErrorList variant of getValidPrintable
+     * @see <a href="https://en.wikipedia.org/wiki/ASCII">Wikipedia - ASCII</a>
+     */
+    @Override
+    public String getValidPrintable(String context, String input, int maxLength, boolean allowNull) throws ValidationException {
+        try {
+            String canonical = encoder.canonicalize(input);
+            return new String( getValidPrintable( context, canonical.toCharArray(), maxLength, allowNull) );
+        //TODO - changed this to base Exception since we no longer need EncodingException
+        //TODO - this is a bit lame: we need to re-think this function.
+        } catch (Exception e) {
+            throw new ValidationException( context + ": Invalid printable input", "Invalid encoding of printable input, context=" + context + ", input=" + input, e, context);
+        }
+    }
+
+    /**
+     * {@inheritDoc}
      *
-     * @param errors
-     */
-	public String getValidPrintable(String context, String input,int maxLength, boolean allowNull, ValidationErrorList errors) throws IntrusionException {
-		try {
-			return getValidPrintable(context, input, maxLength, allowNull);
-		} catch (ValidationException e) {
-			errors.addError(context, e);
-		}
-		// error has been added to list, so return original input
-		return input;
-	}
-
-
-	/**
-	 * Returns true if input is a valid redirect location.
-	 */
-	public boolean isValidRedirectLocation(String context, String input, boolean allowNull) throws IntrusionException {
-		SecurityConfiguration sc = ESAPI.securityConfiguration();
-		return ESAPI.validator().isValidInput( context, input, "Redirect", sc.getIntProp("HttpUtilities.maxRedirectLength"), allowNull);
-	}
-
-        /**
-	 * Returns true if input is a valid redirect location.
-	 */
-	public boolean isValidRedirectLocation(String context, String input, boolean allowNull, ValidationErrorList errors) throws IntrusionException {
-		SecurityConfiguration sc = ESAPI.securityConfiguration();
-		return ESAPI.validator().isValidInput( context, input, "Redirect", sc.getIntProp("HttpUtilities.maxRedirectLength"), allowNull, errors);
-	}
-
-
-	/**
-	 * Returns a canonicalized and validated redirect location as a String. Invalid input will generate a descriptive ValidationException, and input that is clearly an attack
-	 * will generate a descriptive IntrusionException.
-	 */
-	public String getValidRedirectLocation(String context, String input, boolean allowNull) throws ValidationException, IntrusionException {
-		SecurityConfiguration sc = ESAPI.securityConfiguration();
-		return ESAPI.validator().getValidInput( context, input, "Redirect", sc.getIntProp("HttpUtilities.maxRedirectLength"), allowNull);
-	}
-
-	/**
-	 * ValidationErrorList variant of getValidRedirectLocation
+     * Input is valid if it only contains printable ASCII characters (33-126 inclusive).
      *
-     * @param errors
+     * @see <a href="https://en.wikipedia.org/wiki/ASCII">Wikipedia - ASCII</a>
+     */
+    @Override
+    public String getValidPrintable(String context, String input, int maxLength, boolean allowNull, ValidationErrorList errors) throws IntrusionException {
+        try {
+            return getValidPrintable(context, input, maxLength, allowNull);
+        } catch (ValidationException e) {
+            errors.addError(context, e);
+        }
+        // error has been added to list, so return original input
+        return input;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public boolean isValidRedirectLocation(String context, String input, boolean allowNull) throws IntrusionException {
+        SecurityConfiguration sc = ESAPI.securityConfiguration();
+        return ESAPI.validator().isValidInput( context, input, "Redirect", sc.getIntProp("HttpUtilities.maxRedirectLength"), allowNull);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public boolean isValidRedirectLocation(String context, String input, boolean allowNull, ValidationErrorList errors) throws IntrusionException {
+        SecurityConfiguration sc = ESAPI.securityConfiguration();
+        return ESAPI.validator().isValidInput( context, input, "Redirect", sc.getIntProp("HttpUtilities.maxRedirectLength"), allowNull, errors);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public String getValidRedirectLocation(String context, String input, boolean allowNull) throws ValidationException, IntrusionException {
+        SecurityConfiguration sc = ESAPI.securityConfiguration();
+        return ESAPI.validator().getValidInput( context, input, "Redirect", sc.getIntProp("HttpUtilities.maxRedirectLength"), allowNull);
+    }
+
+    /**
+     * {@inheritDoc}
      */
-	public String getValidRedirectLocation(String context, String input, boolean allowNull, ValidationErrorList errors) throws IntrusionException {
-		try {
-			return getValidRedirectLocation(context, input, allowNull);
-		} catch (ValidationException e) {
-			errors.addError(context, e);
-		}
-		// error has been added to list, so return original input
-		return input;
-	}
+    @Override
+    public String getValidRedirectLocation(String context, String input, boolean allowNull, ValidationErrorList errors) throws IntrusionException {
+        try {
+            return getValidRedirectLocation(context, input, allowNull);
+        } catch (ValidationException e) {
+            errors.addError(context, e);
+        }
+        // error has been added to list, so return original input
+        return input;
+    }
 
-	/**
+    /**
      * {@inheritDoc}
+     * <p>
+     * This implementation reads until a newline or the specified number of
+     * characters.
+     */
+    @Override
+    public String safeReadLine(InputStream in, int max) throws ValidationException {
+        if (max <= 0) {
+            throw new ValidationAvailabilityException( "Invalid input", "Invalid readline. Must read a positive number of bytes from the stream");
+        }
+
+        StringBuilder sb = new StringBuilder();
+        int count = 0;
+        int c;
+
+        try {
+            while (true) {
+                c = in.read();
+                if ( c == -1 ) {
+                    if (sb.length() == 0) {
+                        return null;
+                    }
+                    break;
+                }
+                if (c == '\n' || c == '\r') {
+                    break;
+                }
+                count++;
+                if (count > max) {
+                    throw new ValidationAvailabilityException( "Invalid input", "Invalid readLine. Read more than maximum characters allowed (" + max + ")");
+                }
+                sb.append((char) c);
+            }
+            return sb.toString();
+        } catch (IOException e) {
+            throw new ValidationAvailabilityException( "Invalid input", "Invalid readLine. Problem reading from input stream", e);
+        }
+    }
+
+    /**
+     * Helper function to check if a String is empty
+     *
+     * @param input string input value
+     * @return boolean response if input is empty or not
+     */
+    private final boolean isEmpty(String input) {
+        return (input==null || input.trim().length() == 0);
+    }
+
+    /**
+     * Helper function to check if a byte array is empty
      *
-	 * This implementation reads until a newline or the specified number of
-	 * characters.
+     * @param input string input value
+     * @return boolean response if input is empty or not
+     */
+    private final boolean isEmpty(byte[] input) {
+        return (input==null || input.length == 0);
+    }
+
+
+    /**
+     * Helper function to check if a char array is empty
      *
-     * @param in
-     * @param max
-     */
-	public String safeReadLine(InputStream in, int max) throws ValidationException {
-		if (max <= 0) {
-			throw new ValidationAvailabilityException( "Invalid input", "Invalid readline. Must read a positive number of bytes from the stream");
-		}
-
-		StringBuilder sb = new StringBuilder();
-		int count = 0;
-		int c;
-
-		try {
-			while (true) {
-				c = in.read();
-				if ( c == -1 ) {
-					if (sb.length() == 0) {
-						return null;
-					}
-					break;
-				}
-				if (c == '\n' || c == '\r') {
-					break;
-				}
-				count++;
-				if (count > max) {
-					throw new ValidationAvailabilityException( "Invalid input", "Invalid readLine. Read more than maximum characters allowed (" + max + ")");
-				}
-				sb.append((char) c);
-			}
-			return sb.toString();
-		} catch (IOException e) {
-			throw new ValidationAvailabilityException( "Invalid input", "Invalid readLine. Problem reading from input stream", e);
-		}
-	}
-
-	/**
-	 * Helper function to check if a String is empty
-	 *
-	 * @param input string input value
-	 * @return boolean response if input is empty or not
-	 */
-	private final boolean isEmpty(String input) {
-		return (input==null || input.trim().length() == 0);
-	}
-
-	/**
-	 * Helper function to check if a byte array is empty
-	 *
-	 * @param input string input value
-	 * @return boolean response if input is empty or not
-	 */
-	private final boolean isEmpty(byte[] input) {
-		return (input==null || input.length == 0);
-	}
-
-
-	/**
-	 * Helper function to check if a char array is empty
-	 *
-	 * @param input string input value
-	 * @return boolean response if input is empty or not
-	 */
-	private final boolean isEmpty(char[] input) {
-		return (input==null || input.length == 0);
-	}
-	
-	/**
-	 * {@inheritDoc}
-	 */
-	public boolean isValidURI(String context, String input, boolean allowNull) {
-		boolean isValid = false;
-		boolean inputIsNullOrEmpty = input == null || "".equals(input);
-		Encoder encoder = ESAPI.encoder();
-		try{
-			URI compliantURI = null == input ? new URI("") :  this.getRfcCompliantURI(input);
-			if(null != compliantURI && input != null){
-				String canonicalizedURI = encoder.getCanonicalizedURI(compliantURI);
-				//if getCanonicalizedURI doesn't throw an IntrusionException, then the URI contains no mixed or 
-				//double-encoding attacks.  
-				logger.debug(Logger.SECURITY_SUCCESS, "We did not detect any mixed or multiple encoding in the uri:[" + input + "]");
-				Validator v = ESAPI.validator();
-				//This part will use the regex from validation.properties.  This regex should be super-simple, and 
-				//used mainly to restrict certain parts of a URL.  
-				Pattern p = ESAPI.securityConfiguration().getValidationPattern( "URL" );
-				if(p != null){
-					//We're doing this instead of using the normal validator API, because it will canonicalize the input again
-					//and if the URI has any queries that also happen to match HTML entities, like &para;
-					//it will cease conforming to the regex we now specify for a URL.
-					isValid = p.matcher(canonicalizedURI).matches();
-				}else{
-					logger.error(Logger.EVENT_FAILURE, "Invalid regex pulled from configuration.  Check the regex for URL and correct.");
-				}
-			}else{
-				if(allowNull && inputIsNullOrEmpty ){
-					isValid = true;
-				}
-			}
-			
-		}catch (IntrusionException e){
-			logger.error(Logger.SECURITY_FAILURE, e.getMessage());
-			isValid = false;
-		} catch (URISyntaxException e) {
-			logger.error(Logger.EVENT_FAILURE, e.getMessage());
-		}
-		
-		
-		return isValid;
-	}
-	
-	/**
-	 * {@inheritDoc}
-	 */
-	public URI getRfcCompliantURI(String input){
-		URI rval = null;
-		try {
-			rval = new URI(input);
-		} catch (URISyntaxException e) {
-			logger.error(Logger.EVENT_FAILURE, e.getMessage());
-		}
-		return rval;
-	}
+     * @param input string input value
+     * @return boolean response if input is empty or not
+     */
+    private final boolean isEmpty(char[] input) {
+        return (input==null || input.length == 0);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public boolean isValidURI(String context, String input, boolean allowNull) {
+        boolean isValid = false;
+        boolean inputIsNullOrEmpty = input == null || "".equals(input);
+        Encoder encoder = ESAPI.encoder();
+        try{
+            URI compliantURI = null == input ? new URI("") :  this.getRfcCompliantURI(input);
+            if(null != compliantURI && input != null){
+                String canonicalizedURI = encoder.getCanonicalizedURI(compliantURI);
+                //if getCanonicalizedURI doesn't throw an IntrusionException, then the URI contains no mixed or
+                //double-encoding attacks.
+                logger.debug(Logger.SECURITY_SUCCESS, "We did not detect any mixed or multiple encoding in the uri:[" + input + "]");
+                Validator v = ESAPI.validator();
+                //This part will use the regex from validation.properties.  This regex should be super-simple, and
+                //used mainly to restrict certain parts of a URL.
+                Pattern p = ESAPI.securityConfiguration().getValidationPattern( "URL" );
+                if(p != null){
+                    //We're doing this instead of using the normal validator API, because it will canonicalize the input again
+                    //and if the URI has any queries that also happen to match HTML entities, like &para;
+                    //it will cease conforming to the regex we now specify for a URL.
+                    isValid = p.matcher(canonicalizedURI).matches();
+                }else{
+                    logger.error(Logger.EVENT_FAILURE, "Invalid regex pulled from configuration.  Check the regex for URL and correct.");
+                }
+            }else{
+                if(allowNull && inputIsNullOrEmpty ){
+                    isValid = true;
+                }
+            }
+
+        }catch (IntrusionException e){
+            logger.error(Logger.SECURITY_FAILURE, e.getMessage());
+            isValid = false;
+        } catch (URISyntaxException e) {
+            logger.error(Logger.EVENT_FAILURE, e.getMessage());
+        }
+
+
+        return isValid;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public URI getRfcCompliantURI(String input){
+        URI rval = null;
+        try {
+            rval = new URI(input);
+        } catch (URISyntaxException e) {
+            logger.error(Logger.EVENT_FAILURE, e.getMessage());
+        }
+        return rval;
+    }
 }
diff --git a/src/main/java/org/owasp/esapi/reference/FileBasedAuthenticator.java b/src/main/java/org/owasp/esapi/reference/FileBasedAuthenticator.java
index 77d2a88..111e3f8 100644
--- a/src/main/java/org/owasp/esapi/reference/FileBasedAuthenticator.java
+++ b/src/main/java/org/owasp/esapi/reference/FileBasedAuthenticator.java
@@ -231,7 +231,7 @@ public class FileBasedAuthenticator extends AbstractAuthenticator {
      *
      */
     private FileBasedAuthenticator() {
-    	super();
+        super();
     }
 
 
@@ -252,9 +252,9 @@ public class FileBasedAuthenticator extends AbstractAuthenticator {
         if (password1 == null) {
             throw new AuthenticationCredentialsException("Invalid account name", "Attempt to create account " + accountName + " with a null password");
         }
-        
+
         DefaultUser user = new DefaultUser(accountName);
-        
+
         verifyPasswordStrength(null, password1, user);
 
         if (!password1.equals(password2)) {
@@ -389,7 +389,7 @@ public class FileBasedAuthenticator extends AbstractAuthenticator {
         return null;
     }
 
- 
+
 
     /**
      * {@inheritDoc}
@@ -663,10 +663,10 @@ public class FileBasedAuthenticator extends AbstractAuthenticator {
             sb.append(s).append(",");
         }
         if ( c.size() > 0) {
-        	return sb.toString().substring(0, sb.length() - 1);
+            return sb.toString().substring(0, sb.length() - 1);
         }
         return "";
-        
+
     }
 
     /**
@@ -741,13 +741,13 @@ public class FileBasedAuthenticator extends AbstractAuthenticator {
         if (strength < 16) {
             throw new AuthenticationCredentialsException("Invalid password", "New password is not long and complex enough");
         }
-        
+
         String accountName = user.getAccountName();
-        
+
         //jtm - 11/3/2010 - fix for bug http://code.google.com/p/owasp-esapi-java/issues/detail?id=108
         if (accountName.equalsIgnoreCase(newPassword)) {
-        	//password can't be account name
-        	throw new AuthenticationCredentialsException("Invalid password", "Password matches account name, irrespective of case");
+            //password can't be account name
+            throw new AuthenticationCredentialsException("Invalid password", "Password matches account name, irrespective of case");
         }
     }
 
diff --git a/src/main/java/org/owasp/esapi/reference/IntegerAccessReferenceMap.java b/src/main/java/org/owasp/esapi/reference/IntegerAccessReferenceMap.java
index 6f01e1f..24ff9d6 100644
--- a/src/main/java/org/owasp/esapi/reference/IntegerAccessReferenceMap.java
+++ b/src/main/java/org/owasp/esapi/reference/IntegerAccessReferenceMap.java
@@ -1,15 +1,15 @@
 /**
  * OWASP Enterprise Security API (ESAPI)
- * 
+ *
  * This file is part of the Open Web Application Security Project (OWASP)
  * Enterprise Security API (ESAPI) project. For details, please see
  * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
  *
  * Copyright (c) 2007 - The OWASP Foundation
- * 
+ *
  * The ESAPI is published by OWASP under the BSD license. You should read and accept the
  * LICENSE before you use, modify, and/or redistribute this software.
- * 
+ *
  * @author Jeff Williams <a href="http://www.aspectsecurity.com">Aspect Security</a>
  * @created 2007
  */
@@ -20,7 +20,7 @@ import java.util.Set;
 /**
  * Reference implementation of the AccessReferenceMap interface. This
  * implementation generates integers for indirect references.
- * 
+ *
  * @author Jeff Williams (jeff.williams@aspectsecurity.com)
  * @author Chris Schmidt (chrisisbeef@gmail.com)
  * @since June 1, 2007
@@ -28,53 +28,53 @@ import java.util.Set;
  */
 public class IntegerAccessReferenceMap extends AbstractAccessReferenceMap<String> {
 
-	private static final long serialVersionUID = 5311769278372489771L;
+    private static final long serialVersionUID = 5311769278372489771L;
 
-	int count = 1;
+    int count = 1;
 
-	/**
-	 * TODO Javadoc
-	 */
-	public IntegerAccessReferenceMap()
-	{
-	}
+    /**
+     * TODO Javadoc
+     */
+    public IntegerAccessReferenceMap()
+    {
+    }
 
-	/**
-	 * TODO Javadoc
-	 */
-	public IntegerAccessReferenceMap(int initialSize)
-	{
-		super(initialSize);
-	}
+    /**
+     * TODO Javadoc
+     */
+    public IntegerAccessReferenceMap(int initialSize)
+    {
+        super(initialSize);
+    }
 
-	/**
-	 * TODO Javadoc
-	 */
-	public IntegerAccessReferenceMap(Set<Object> directReferences)
-	{
-		super(directReferences.size());
-		update(directReferences);
-	}
+    /**
+     * TODO Javadoc
+     */
+    public IntegerAccessReferenceMap(Set<Object> directReferences)
+    {
+        super(directReferences.size());
+        update(directReferences);
+    }
 
-	/**
-	 * TODO Javadoc
-	 */
-	public IntegerAccessReferenceMap(Set<Object> directReferences, int initialSize)
-	{
-		super(initialSize);
-		update(directReferences);
-	}
+    /**
+     * TODO Javadoc
+     */
+    public IntegerAccessReferenceMap(Set<Object> directReferences, int initialSize)
+    {
+        super(initialSize);
+        update(directReferences);
+    }
 
-	/**
+    /**
      * {@inheritDoc}
-	 * Note: this is final as redefinition by subclasses
-	 * can lead to use before initialization issues as
-	 * {@link #IntegerAccessReferenceMap(Set)} and
-	 * {@link #IntegerAccessReferenceMap(Set,int)} both call it
-	 * internally.
-	 */
-	protected final synchronized String getUniqueReference() {
-		return "" + count++;  // returns a string version of the counter
-	}
+     * Note: this is final as redefinition by subclasses
+     * can lead to use before initialization issues as
+     * {@link #IntegerAccessReferenceMap(Set)} and
+     * {@link #IntegerAccessReferenceMap(Set,int)} both call it
+     * internally.
+     */
+    protected final synchronized String getUniqueReference() {
+        return "" + count++;  // returns a string version of the counter
+    }
 
 }
diff --git a/src/main/java/org/owasp/esapi/reference/accesscontrol/AlwaysFalseACR.java b/src/main/java/org/owasp/esapi/reference/accesscontrol/AlwaysFalseACR.java
index af22587..bd25ab8 100644
--- a/src/main/java/org/owasp/esapi/reference/accesscontrol/AlwaysFalseACR.java
+++ b/src/main/java/org/owasp/esapi/reference/accesscontrol/AlwaysFalseACR.java
@@ -2,8 +2,8 @@ package org.owasp.esapi.reference.accesscontrol;
 
 public class AlwaysFalseACR extends BaseACR<Object, Object> {
 
-//	@Override
-	public boolean isAuthorized(Object runtimeParameter) {
-		return false;
-	}
+//    @Override
+    public boolean isAuthorized(Object runtimeParameter) {
+        return false;
+    }
 }
diff --git a/src/main/java/org/owasp/esapi/reference/accesscontrol/AlwaysTrueACR.java b/src/main/java/org/owasp/esapi/reference/accesscontrol/AlwaysTrueACR.java
index 0c0c9de..a132722 100644
--- a/src/main/java/org/owasp/esapi/reference/accesscontrol/AlwaysTrueACR.java
+++ b/src/main/java/org/owasp/esapi/reference/accesscontrol/AlwaysTrueACR.java
@@ -1,9 +1,9 @@
 package org.owasp.esapi.reference.accesscontrol;
 
 public class AlwaysTrueACR extends BaseACR<Object, Object> {
-	
-//	@Override
-	public boolean isAuthorized(Object runtimeParameter) {
-		return true;
-	}
+
+//    @Override
+    public boolean isAuthorized(Object runtimeParameter) {
+        return true;
+    }
 }
diff --git a/src/main/java/org/owasp/esapi/reference/accesscontrol/BaseACR.java b/src/main/java/org/owasp/esapi/reference/accesscontrol/BaseACR.java
index f169902..1e307a7 100644
--- a/src/main/java/org/owasp/esapi/reference/accesscontrol/BaseACR.java
+++ b/src/main/java/org/owasp/esapi/reference/accesscontrol/BaseACR.java
@@ -4,15 +4,15 @@ import org.owasp.esapi.AccessControlRule;
 
 abstract public class BaseACR<P, R> implements AccessControlRule<P, R> {
 
-	protected P policyParameters;
-	
-//	@Override
-	public void setPolicyParameters(P policyParameter) {
-		this.policyParameters = policyParameter;
-	}
-	
-//	@Override
-	public P getPolicyParameters() {
-		return policyParameters;
-	}
+    protected P policyParameters;
+
+//    @Override
+    public void setPolicyParameters(P policyParameter) {
+        this.policyParameters = policyParameter;
+    }
+
+//    @Override
+    public P getPolicyParameters() {
+        return policyParameters;
+    }
 }
diff --git a/src/main/java/org/owasp/esapi/reference/accesscontrol/DelegatingACR.java b/src/main/java/org/owasp/esapi/reference/accesscontrol/DelegatingACR.java
index 65cb0eb..eaa3579 100644
--- a/src/main/java/org/owasp/esapi/reference/accesscontrol/DelegatingACR.java
+++ b/src/main/java/org/owasp/esapi/reference/accesscontrol/DelegatingACR.java
@@ -9,92 +9,92 @@ import java.util.Arrays;
 import org.apache.commons.collections4.iterators.ArrayListIterator;
 
 public class DelegatingACR extends BaseACR<DynaBeanACRParameter, Object[]> {
-	protected Method delegateMethod;
-	protected Object delegateInstance;
-	
-	@Override
-	public void setPolicyParameters(DynaBeanACRParameter policyParameter) {
-		String delegateClassName = policyParameter.getString("delegateClass", "").trim();
-		String methodName = policyParameter.getString("delegateMethod", "").trim();
-		String[] parameterClassNames = policyParameter.getStringArray("parameterClasses");
+    protected Method delegateMethod;
+    protected Object delegateInstance;
 
-		//Convert the classNames into Classes and get the delegate method.
-		Class delegateClass = getClass(delegateClassName, "delegate");
-		Class parameterClasses[] = getParameters(parameterClassNames);
-		try {
-			this.delegateMethod = delegateClass.getMethod(methodName, parameterClasses);
-		} catch (SecurityException e) {
-			throw new IllegalArgumentException(e.getMessage() + 
-					" delegateClass.delegateMethod(parameterClasses): \"" +  
-					delegateClassName + "." + methodName + "(" + Arrays.toString(parameterClassNames) +
-					")\" must be public.", e);
-		} catch (NoSuchMethodException e) {
-			throw new IllegalArgumentException(e.getMessage() + 
-					" delegateClass.delegateMethod(parameterClasses): \"" +  
-					delegateClassName + "." + methodName + "(" + Arrays.toString(parameterClassNames) +
-					")\" does not exist.", e);
-		}
-	
-		//static methods do not need a delegateInstance. Non-static methods do.
-		if(!Modifier.isStatic(this.delegateMethod.getModifiers())) {
-			try {
-				this.delegateInstance = delegateClass.newInstance();
-			} catch (InstantiationException ex) {
-				throw new IllegalArgumentException( 
-						" Delegate class \"" + delegateClassName + 
-						"\" must be concrete, because method " +
-					    delegateClassName + "." + methodName + "(" + Arrays.toString(parameterClassNames) +
-						") is not static.", ex);
-			} catch (IllegalAccessException ex) {
-				new IllegalArgumentException( 
-						" Delegate class \"" + delegateClassName + 
-						"\" must must have a zero-argument constructor, because " +
-						"method delegateClass.delegateMethod(parameterClasses): \"" +  
-					    delegateClassName + "." + methodName + "(" + Arrays.toString(parameterClassNames) +
-						")\" is not static.", ex);
-			}	
-		} else {
-			this.delegateInstance = null;
-		}
-	}
-	/**
-	 * Convert an array of fully qualified class names into an array of Class objects
-	 * @param parameterClassNames
-	 * @return The Class objects found that match the specified class names provided.
-	 */
-	protected final Class[] getParameters(String[] parameterClassNames) {
-		if (parameterClassNames == null) {
-			return new Class[0];
-		}
-		Vector<Class> classes = new Vector<Class>();
-		Iterator<String> classNames = new ArrayListIterator(parameterClassNames);
-		while(classNames.hasNext()) {
-			classes.add(getClass(classNames.next(), "parameter"));
-		}
-		return classes.toArray(new Class[classes.size()]);
-	}
-	/**
-	 * Convert a single fully qualified class name into a Class object
-	 * @param className
-	 * @param purpose
-	 * @return The Class matching the specified name, if it exists.
-	 */
-	protected final Class getClass(String className, String purpose) {
-		try {
-	        Class theClass = Class.forName(className);
-	        return theClass;
-	    } catch ( ClassNotFoundException ex ) {
-			throw new IllegalArgumentException(ex.getMessage() + 
-					" " + purpose + " Class " + className + 
-					" must be in the classpath", ex);
-	    } 
-	}
-	/**
-	 * Delegates to the method specified in setPolicyParameters
-	 */
-	public boolean isAuthorized(Object[] runtimeParameters) throws Exception {
-		return ((Boolean)delegateMethod.invoke(delegateInstance, runtimeParameters)).booleanValue();
-	}
+    @Override
+    public void setPolicyParameters(DynaBeanACRParameter policyParameter) {
+        String delegateClassName = policyParameter.getString("delegateClass", "").trim();
+        String methodName = policyParameter.getString("delegateMethod", "").trim();
+        String[] parameterClassNames = policyParameter.getStringArray("parameterClasses");
+
+        //Convert the classNames into Classes and get the delegate method.
+        Class delegateClass = getClass(delegateClassName, "delegate");
+        Class parameterClasses[] = getParameters(parameterClassNames);
+        try {
+            this.delegateMethod = delegateClass.getMethod(methodName, parameterClasses);
+        } catch (SecurityException e) {
+            throw new IllegalArgumentException(e.getMessage() +
+                    " delegateClass.delegateMethod(parameterClasses): \"" +
+                    delegateClassName + "." + methodName + "(" + Arrays.toString(parameterClassNames) +
+                    ")\" must be public.", e);
+        } catch (NoSuchMethodException e) {
+            throw new IllegalArgumentException(e.getMessage() +
+                    " delegateClass.delegateMethod(parameterClasses): \"" +
+                    delegateClassName + "." + methodName + "(" + Arrays.toString(parameterClassNames) +
+                    ")\" does not exist.", e);
+        }
+
+        //static methods do not need a delegateInstance. Non-static methods do.
+        if(!Modifier.isStatic(this.delegateMethod.getModifiers())) {
+            try {
+                this.delegateInstance = delegateClass.newInstance();
+            } catch (InstantiationException ex) {
+                throw new IllegalArgumentException(
+                        " Delegate class \"" + delegateClassName +
+                        "\" must be concrete, because method " +
+                        delegateClassName + "." + methodName + "(" + Arrays.toString(parameterClassNames) +
+                        ") is not static.", ex);
+            } catch (IllegalAccessException ex) {
+                new IllegalArgumentException(
+                        " Delegate class \"" + delegateClassName +
+                        "\" must must have a zero-argument constructor, because " +
+                        "method delegateClass.delegateMethod(parameterClasses): \"" +
+                        delegateClassName + "." + methodName + "(" + Arrays.toString(parameterClassNames) +
+                        ")\" is not static.", ex);
+            }
+        } else {
+            this.delegateInstance = null;
+        }
+    }
+    /**
+     * Convert an array of fully qualified class names into an array of Class objects
+     * @param parameterClassNames
+     * @return The Class objects found that match the specified class names provided.
+     */
+    protected final Class[] getParameters(String[] parameterClassNames) {
+        if (parameterClassNames == null) {
+            return new Class[0];
+        }
+        Vector<Class> classes = new Vector<Class>();
+        Iterator<String> classNames = new ArrayListIterator(parameterClassNames);
+        while(classNames.hasNext()) {
+            classes.add(getClass(classNames.next(), "parameter"));
+        }
+        return classes.toArray(new Class[classes.size()]);
+    }
+    /**
+     * Convert a single fully qualified class name into a Class object
+     * @param className
+     * @param purpose
+     * @return The Class matching the specified name, if it exists.
+     */
+    protected final Class getClass(String className, String purpose) {
+        try {
+            Class theClass = Class.forName(className);
+            return theClass;
+        } catch ( ClassNotFoundException ex ) {
+            throw new IllegalArgumentException(ex.getMessage() +
+                    " " + purpose + " Class " + className +
+                    " must be in the classpath", ex);
+        }
+    }
+    /**
+     * Delegates to the method specified in setPolicyParameters
+     */
+    public boolean isAuthorized(Object[] runtimeParameters) throws Exception {
+        return ((Boolean)delegateMethod.invoke(delegateInstance, runtimeParameters)).booleanValue();
+    }
 }
 
 
diff --git a/src/main/java/org/owasp/esapi/reference/accesscontrol/DynaBeanACRParameter.java b/src/main/java/org/owasp/esapi/reference/accesscontrol/DynaBeanACRParameter.java
index 9f12417..c0d29f3 100644
--- a/src/main/java/org/owasp/esapi/reference/accesscontrol/DynaBeanACRParameter.java
+++ b/src/main/java/org/owasp/esapi/reference/accesscontrol/DynaBeanACRParameter.java
@@ -9,188 +9,188 @@ import org.apache.commons.beanutils.LazyDynaMap;
 import org.owasp.esapi.reference.accesscontrol.policyloader.PolicyParameters;
 
 /**
- * A DynaBean comes from the apache bean utils. It is basically a 
- * convenient way to dynamically assign getters and setters. Essentially, 
+ * A DynaBean comes from the apache bean utils. It is basically a
+ * convenient way to dynamically assign getters and setters. Essentially,
  * the way we use DynaBean is a HashMap that can be set to read only.
  * @author Mike H. Fauzy
  */
 public class DynaBeanACRParameter implements PolicyParameters {
-	protected LazyDynaMap policyProperties;
-	
-	public DynaBeanACRParameter() {
-		policyProperties = new LazyDynaMap();
-	}
-	
-	/* (non-Javadoc)
-	 * @see org.owasp.esapi.reference.accesscontrol.policyloader.PolicyParameters#get(java.lang.String)
-	 */
-	public Object get(String key) {
-		return policyProperties.get(key);
-	}
-	/**
-	 * Convenience method to avoid common casts.
-	 * @param key
-	 * @return The true/false value of the specified key. False if not found.
-	 */
-	public boolean getBoolean(String key) {
-		return ((Boolean)get(key)).booleanValue();
-	}
-	/**
-	 * Convenience method to avoid common casts.
-	 * @param key
-	 * @return The byte value of the specified key.
-	 */
-	public byte getByte(String key) {
-		return ((Byte)get(key)).byteValue();
-	}
-	/**
-	 * Convenience method to avoid common casts.
-	 * @param key
-	 * @return The char value of the specified key.
-	 */
-	public char getChar(String key) {
-		return ((Character)get(key)).charValue();
-	}
-	/**
-	 * Convenience method to avoid common casts.
-	 * @param key
-	 * @return The int value of the specified key.
-	 */
-	public int getInt(String key) {
-		return ((Integer)get(key)).intValue();
-	}
-	/**
-	 * Convenience method to avoid common casts.
-	 * @param key
-	 * @return The long value of the specified key.
-	 */
-	public long getLong(String key) {
-		return ((Long)get(key)).longValue();
-	}
-	/**
-	 * Convenience method to avoid common casts.
-	 * @param key
-	 * @return The float value of the specified key.
-	 */
-	public float getFloat(String key) {
-		return ((Float)get(key)).floatValue();
-	}
-	/**
-	 * Convenience method to avoid common casts.
-	 * @param key
-	 * @return The double value of the specified key.
-	 */
-	public double getDouble(String key) {
-		return ((Double)get(key)).doubleValue();
-	}
-	/**
-	 * Convenience method to avoid common casts.
-	 * @param key
-	 * @return The BigDecimal value of the specified key.
-	 */
-	public BigDecimal getBigDecimal(String key) {
-		return (BigDecimal)get(key);
-	}
-	/**
-	 * Convenience method to avoid common casts.
-	 * @param key
-	 * @return The BigInteger value of the specified key.
-	 */
-	public BigInteger getBigInteger(String key) {
-		return (BigInteger)get(key);
-	}
-	/**
-	 * Convenience method to avoid common casts.
-	 * @param key
-	 * @return The Date value of the specified key.
-	 */
-	public Date getDate(String key) {
-		return (Date)get(key);
-	}
-	
-	/**
-	 * Convenience method to avoid common casts. Note that the time object
-	 * is the same as a date object
-	 * @param key
-	 * @return The Date value of the specified key.
-	 */
-	public Date getTime(String key) {
-		return (Date)get(key);
-	}
-	
-	/**
-	 * Convenience method to avoid common casts.
-	 * @param key
-	 * @return The String value of the specified key. null if the key is not defined.
-	 */
-	public String getString(String key) {
-		return (String)get(key);
-	}
-	
-	/**
-	 * Convenience method to avoid common casts.
-	 * @param key
-	 * @return The String value of the specified key. If the key is not defined, the default value is returned instead.
-	 */
-	public String getString(String key, String defaultValue) {
-		return (String)get(key) == null ? defaultValue : (String)get(key);
-	}
-	
-	/**
-	 * Convenience method to avoid common casts.
-	 * @param key
-	 * @return The String[] value of the specified key.
-	 */
-	public String[] getStringArray(String key) {
-		return (String[])get(key);
-	}
-	
-	/**
-	 * Convenience method to avoid common casts.
-	 * @param key
-	 * @return The value of the specified key, returned generically as an Object. 
-	 */
-	public Object getObject(String key) {
-		return get(key);
-	}	
+    protected LazyDynaMap policyProperties;
 
-	/* (non-Javadoc)
-	 * @see org.owasp.esapi.reference.accesscontrol.policyloader.PolicyParameters#set(java.lang.String, java.lang.Object)
-	 */
-	public void set(String key, Object value) throws IllegalArgumentException {
-		policyProperties.set(key, value);
-	}
-	/* (non-Javadoc)
-	 * @see org.owasp.esapi.reference.accesscontrol.policyloader.PolicyParameters#put(java.lang.String, java.lang.Object)
-	 */
-	public void put(String key, Object value) throws IllegalArgumentException {
-		set(key, value);
-	}
-	
-	/**
-	 * This makes the map itself read only, but the mutability of objects 
-	 * that this map contains is not affected. Specifically, properties 
-	 * cannot be added or removed and the reference cannot be changed to 
-	 * a different object, but this does not change whether the values that the 
-	 * object contains can be changed. 
-	 */
-	public void lock() {
-		policyProperties.setRestricted(true);
-	}
-	
-	public String toString() {
-		StringBuilder sb = new StringBuilder();
-		Iterator keys = policyProperties.getMap().keySet().iterator();
-		String currentKey;
-		while(keys.hasNext()) {
-			currentKey = (String)keys.next();
-			sb.append(currentKey);
-			sb.append("=");
-			sb.append(policyProperties.get(currentKey));
-			if(keys.hasNext()) {
-				sb.append(",");
-			}
-		}
-		return sb.toString();
-	}
+    public DynaBeanACRParameter() {
+        policyProperties = new LazyDynaMap();
+    }
+
+    /* (non-Javadoc)
+     * @see org.owasp.esapi.reference.accesscontrol.policyloader.PolicyParameters#get(java.lang.String)
+     */
+    public Object get(String key) {
+        return policyProperties.get(key);
+    }
+    /**
+     * Convenience method to avoid common casts.
+     * @param key
+     * @return The true/false value of the specified key. False if not found.
+     */
+    public boolean getBoolean(String key) {
+        return ((Boolean)get(key)).booleanValue();
+    }
+    /**
+     * Convenience method to avoid common casts.
+     * @param key
+     * @return The byte value of the specified key.
+     */
+    public byte getByte(String key) {
+        return ((Byte)get(key)).byteValue();
+    }
+    /**
+     * Convenience method to avoid common casts.
+     * @param key
+     * @return The char value of the specified key.
+     */
+    public char getChar(String key) {
+        return ((Character)get(key)).charValue();
+    }
+    /**
+     * Convenience method to avoid common casts.
+     * @param key
+     * @return The int value of the specified key.
+     */
+    public int getInt(String key) {
+        return ((Integer)get(key)).intValue();
+    }
+    /**
+     * Convenience method to avoid common casts.
+     * @param key
+     * @return The long value of the specified key.
+     */
+    public long getLong(String key) {
+        return ((Long)get(key)).longValue();
+    }
+    /**
+     * Convenience method to avoid common casts.
+     * @param key
+     * @return The float value of the specified key.
+     */
+    public float getFloat(String key) {
+        return ((Float)get(key)).floatValue();
+    }
+    /**
+     * Convenience method to avoid common casts.
+     * @param key
+     * @return The double value of the specified key.
+     */
+    public double getDouble(String key) {
+        return ((Double)get(key)).doubleValue();
+    }
+    /**
+     * Convenience method to avoid common casts.
+     * @param key
+     * @return The BigDecimal value of the specified key.
+     */
+    public BigDecimal getBigDecimal(String key) {
+        return (BigDecimal)get(key);
+    }
+    /**
+     * Convenience method to avoid common casts.
+     * @param key
+     * @return The BigInteger value of the specified key.
+     */
+    public BigInteger getBigInteger(String key) {
+        return (BigInteger)get(key);
+    }
+    /**
+     * Convenience method to avoid common casts.
+     * @param key
+     * @return The Date value of the specified key.
+     */
+    public Date getDate(String key) {
+        return (Date)get(key);
+    }
+
+    /**
+     * Convenience method to avoid common casts. Note that the time object
+     * is the same as a date object
+     * @param key
+     * @return The Date value of the specified key.
+     */
+    public Date getTime(String key) {
+        return (Date)get(key);
+    }
+
+    /**
+     * Convenience method to avoid common casts.
+     * @param key
+     * @return The String value of the specified key. null if the key is not defined.
+     */
+    public String getString(String key) {
+        return (String)get(key);
+    }
+
+    /**
+     * Convenience method to avoid common casts.
+     * @param key
+     * @return The String value of the specified key. If the key is not defined, the default value is returned instead.
+     */
+    public String getString(String key, String defaultValue) {
+        return (String)get(key) == null ? defaultValue : (String)get(key);
+    }
+
+    /**
+     * Convenience method to avoid common casts.
+     * @param key
+     * @return The String[] value of the specified key.
+     */
+    public String[] getStringArray(String key) {
+        return (String[])get(key);
+    }
+
+    /**
+     * Convenience method to avoid common casts.
+     * @param key
+     * @return The value of the specified key, returned generically as an Object.
+     */
+    public Object getObject(String key) {
+        return get(key);
+    }
+
+    /* (non-Javadoc)
+     * @see org.owasp.esapi.reference.accesscontrol.policyloader.PolicyParameters#set(java.lang.String, java.lang.Object)
+     */
+    public void set(String key, Object value) throws IllegalArgumentException {
+        policyProperties.set(key, value);
+    }
+    /* (non-Javadoc)
+     * @see org.owasp.esapi.reference.accesscontrol.policyloader.PolicyParameters#put(java.lang.String, java.lang.Object)
+     */
+    public void put(String key, Object value) throws IllegalArgumentException {
+        set(key, value);
+    }
+
+    /**
+     * This makes the map itself read only, but the mutability of objects
+     * that this map contains is not affected. Specifically, properties
+     * cannot be added or removed and the reference cannot be changed to
+     * a different object, but this does not change whether the values that the
+     * object contains can be changed.
+     */
+    public void lock() {
+        policyProperties.setRestricted(true);
+    }
+
+    public String toString() {
+        StringBuilder sb = new StringBuilder();
+        Iterator keys = policyProperties.getMap().keySet().iterator();
+        String currentKey;
+        while(keys.hasNext()) {
+            currentKey = (String)keys.next();
+            sb.append(currentKey);
+            sb.append("=");
+            sb.append(policyProperties.get(currentKey));
+            if(keys.hasNext()) {
+                sb.append(",");
+            }
+        }
+        return sb.toString();
+    }
 }
diff --git a/src/main/java/org/owasp/esapi/reference/accesscontrol/EchoRuntimeParameterACR.java b/src/main/java/org/owasp/esapi/reference/accesscontrol/EchoRuntimeParameterACR.java
index b330077..2bafc38 100644
--- a/src/main/java/org/owasp/esapi/reference/accesscontrol/EchoRuntimeParameterACR.java
+++ b/src/main/java/org/owasp/esapi/reference/accesscontrol/EchoRuntimeParameterACR.java
@@ -2,12 +2,12 @@ package org.owasp.esapi.reference.accesscontrol;
 
 public class EchoRuntimeParameterACR extends BaseACR<Object, Boolean>{
 
-	/**
-	 * Returns true iff runtimeParameter is a Boolean true.
-	 * throws ClassCastException if runtimeParameter is not a Boolean.
-	 */
-	public boolean isAuthorized(Boolean runtimeParameter) throws ClassCastException{
-		return runtimeParameter.booleanValue();
-	}
+    /**
+     * Returns true iff runtimeParameter is a Boolean true.
+     * throws ClassCastException if runtimeParameter is not a Boolean.
+     */
+    public boolean isAuthorized(Boolean runtimeParameter) throws ClassCastException{
+        return runtimeParameter.booleanValue();
+    }
 
 }
\ No newline at end of file
diff --git a/src/main/java/org/owasp/esapi/reference/accesscontrol/ExperimentalAccessController.java b/src/main/java/org/owasp/esapi/reference/accesscontrol/ExperimentalAccessController.java
index 34936c7..0b1e4cf 100644
--- a/src/main/java/org/owasp/esapi/reference/accesscontrol/ExperimentalAccessController.java
+++ b/src/main/java/org/owasp/esapi/reference/accesscontrol/ExperimentalAccessController.java
@@ -11,184 +11,184 @@ import org.owasp.esapi.reference.accesscontrol.policyloader.ACRPolicyFileLoader;
 import org.owasp.esapi.reference.accesscontrol.policyloader.PolicyDTO;
 
 public class ExperimentalAccessController implements AccessController {
-	private Map ruleMap;
-
-	protected final Logger logger = ESAPI.getLogger("DefaultAccessController");
-	
-	public ExperimentalAccessController(Map ruleMap) {
-		this.ruleMap = ruleMap;	
-	}
-	public ExperimentalAccessController() throws AccessControlException {
-		ACRPolicyFileLoader policyDescriptor = new ACRPolicyFileLoader();
-		PolicyDTO policyDTO = policyDescriptor.load();		
-		ruleMap = policyDTO.getAccessControlRules();
-	}
-	
-	public boolean isAuthorized(Object key, Object runtimeParameter) {
-		try {
-			AccessControlRule rule = (AccessControlRule)ruleMap.get(key);
-			if(rule == null) {
-				throw new AccessControlException("Access Denied",
-						"AccessControlRule was not found for key: " + key); 
-			}
-			if(logger.isDebugEnabled()){ logger.debug(Logger.EVENT_SUCCESS, "Evaluating Authorization Rule \"" + key + "\" Using class: " + rule.getClass().getCanonicalName()); }
-			return rule.isAuthorized(runtimeParameter);
-		} catch(Exception e) {
-			try {
-				//Log the exception by throwing and then catching it.
-				//TODO figure out what which string goes where.		
-				throw new AccessControlException("Access Denied",
-					"An unhandled Exception was " +
-					"caught, so access is denied.",  
-					e);	
-			} catch(AccessControlException ace) {
-				//the exception was just logged. There's nothing left to do.
-			}
-			return false; //fail closed
-		}
-	}
-
-	public void assertAuthorized(Object key, Object runtimeParameter)
-		throws AccessControlException {
-		boolean isAuthorized = false;
-		try {
-			AccessControlRule rule = (AccessControlRule)ruleMap.get(key);
-			if(rule == null) {
-				throw new AccessControlException("Access Denied", 
-						"AccessControlRule was not found for key: " + key); 
-			}
-			if(logger.isDebugEnabled()){ logger.debug(Logger.EVENT_SUCCESS, "Asserting Authorization Rule \"" + key + "\" Using class: " + rule.getClass().getCanonicalName()); }
-			isAuthorized = rule.isAuthorized(runtimeParameter);
-		} catch(Exception e) {
-			//TODO figure out what which string goes where.		
-			throw new AccessControlException("Access Denied", "An unhandled Exception was " +
-					"caught, so access is denied." +
-					"AccessControlException.",
-					e);
-		}
-		if(!isAuthorized) {
-			throw new AccessControlException("Access Denied", 
-					"Access Denied for key: " + key + 
-					" runtimeParameter: " + runtimeParameter);
-		}
-	}
-	
-	/**** Below this line is legacy support ****/
-	
-	/**
-	 * @param action
-	 * @param data
-	 * @throws AccessControlException
-	 * @see org.owasp.esapi.reference.accesscontrol.FileBasedACRs#isAuthorizedForData(java.lang.String, java.lang.Object)
-	 * @deprecated
-	 */
+    private Map ruleMap;
+
+    protected final Logger logger = ESAPI.getLogger("DefaultAccessController");
+
+    public ExperimentalAccessController(Map ruleMap) {
+        this.ruleMap = ruleMap;
+    }
+    public ExperimentalAccessController() throws AccessControlException {
+        ACRPolicyFileLoader policyDescriptor = new ACRPolicyFileLoader();
+        PolicyDTO policyDTO = policyDescriptor.load();
+        ruleMap = policyDTO.getAccessControlRules();
+    }
+
+    public boolean isAuthorized(Object key, Object runtimeParameter) {
+        try {
+            AccessControlRule rule = (AccessControlRule)ruleMap.get(key);
+            if(rule == null) {
+                throw new AccessControlException("Access Denied",
+                        "AccessControlRule was not found for key: " + key);
+            }
+            if(logger.isDebugEnabled()){ logger.debug(Logger.EVENT_SUCCESS, "Evaluating Authorization Rule \"" + key + "\" Using class: " + rule.getClass().getCanonicalName()); }
+            return rule.isAuthorized(runtimeParameter);
+        } catch(Exception e) {
+            try {
+                //Log the exception by throwing and then catching it.
+                //TODO figure out what which string goes where.
+                throw new AccessControlException("Access Denied",
+                    "An unhandled Exception was " +
+                    "caught, so access is denied.",
+                    e);
+            } catch(AccessControlException ace) {
+                //the exception was just logged. There's nothing left to do.
+            }
+            return false; //fail closed
+        }
+    }
+
+    public void assertAuthorized(Object key, Object runtimeParameter)
+        throws AccessControlException {
+        boolean isAuthorized = false;
+        try {
+            AccessControlRule rule = (AccessControlRule)ruleMap.get(key);
+            if(rule == null) {
+                throw new AccessControlException("Access Denied",
+                        "AccessControlRule was not found for key: " + key);
+            }
+            if(logger.isDebugEnabled()){ logger.debug(Logger.EVENT_SUCCESS, "Asserting Authorization Rule \"" + key + "\" Using class: " + rule.getClass().getCanonicalName()); }
+            isAuthorized = rule.isAuthorized(runtimeParameter);
+        } catch(Exception e) {
+            //TODO figure out what which string goes where.
+            throw new AccessControlException("Access Denied", "An unhandled Exception was " +
+                    "caught, so access is denied." +
+                    "AccessControlException.",
+                    e);
+        }
+        if(!isAuthorized) {
+            throw new AccessControlException("Access Denied",
+                    "Access Denied for key: " + key +
+                    " runtimeParameter: " + runtimeParameter);
+        }
+    }
+
+    /**** Below this line is legacy support ****/
+
+    /**
+     * @param action
+     * @param data
+     * @throws AccessControlException
+     * @see org.owasp.esapi.reference.accesscontrol.FileBasedACRs#isAuthorizedForData(java.lang.String, java.lang.Object)
+     * @deprecated
+     */
     @Deprecated
-	public void assertAuthorizedForData(String action, Object data)
-			throws AccessControlException {
-		this.assertAuthorized("AC 1.0 Data", new Object[] {action, data});
-	}
-
-	/**
-	 * @param filepath
-	 * @throws AccessControlException
-	 * @see org.owasp.esapi.reference.accesscontrol.FileBasedACRs#isAuthorizedForFile(java.lang.String)
-	 * @deprecated
-	 */
+    public void assertAuthorizedForData(String action, Object data)
+            throws AccessControlException {
+        this.assertAuthorized("AC 1.0 Data", new Object[] {action, data});
+    }
+
+    /**
+     * @param filepath
+     * @throws AccessControlException
+     * @see org.owasp.esapi.reference.accesscontrol.FileBasedACRs#isAuthorizedForFile(java.lang.String)
+     * @deprecated
+     */
     @Deprecated
-	public void assertAuthorizedForFile(String filepath)
-			throws AccessControlException {
-		this.assertAuthorized("AC 1.0 File", new Object[] {filepath});
-	}
-
-	/**
-	 * @param functionName
-	 * @throws AccessControlException
-	 * @see org.owasp.esapi.reference.accesscontrol.FileBasedACRs#isAuthorizedForFunction(java.lang.String)
-	 * @deprecated
-	 */
+    public void assertAuthorizedForFile(String filepath)
+            throws AccessControlException {
+        this.assertAuthorized("AC 1.0 File", new Object[] {filepath});
+    }
+
+    /**
+     * @param functionName
+     * @throws AccessControlException
+     * @see org.owasp.esapi.reference.accesscontrol.FileBasedACRs#isAuthorizedForFunction(java.lang.String)
+     * @deprecated
+     */
     @Deprecated
-	public void assertAuthorizedForFunction(String functionName)
-			throws AccessControlException {
-		this.assertAuthorized("AC 1.0 Function", new Object[] {functionName});
-	}
-
-	/**
-	 * @param serviceName
-	 * @throws AccessControlException
-	 * @see org.owasp.esapi.reference.accesscontrol.FileBasedACRs#isAuthorizedForService(java.lang.String)
-	 * @deprecated
-	 */
+    public void assertAuthorizedForFunction(String functionName)
+            throws AccessControlException {
+        this.assertAuthorized("AC 1.0 Function", new Object[] {functionName});
+    }
+
+    /**
+     * @param serviceName
+     * @throws AccessControlException
+     * @see org.owasp.esapi.reference.accesscontrol.FileBasedACRs#isAuthorizedForService(java.lang.String)
+     * @deprecated
+     */
     @Deprecated
-	public void assertAuthorizedForService(String serviceName)
-			throws AccessControlException {
-		this.assertAuthorized("AC 1.0 Service", new Object[] {serviceName});
-	}
-
-	/**
-	 * @param url
-	 * @throws AccessControlException
-	 * @see org.owasp.esapi.reference.accesscontrol.FileBasedACRs#isAuthorizedForURL(java.lang.String)
-	 * @deprecated
-	 */
+    public void assertAuthorizedForService(String serviceName)
+            throws AccessControlException {
+        this.assertAuthorized("AC 1.0 Service", new Object[] {serviceName});
+    }
+
+    /**
+     * @param url
+     * @throws AccessControlException
+     * @see org.owasp.esapi.reference.accesscontrol.FileBasedACRs#isAuthorizedForURL(java.lang.String)
+     * @deprecated
+     */
     @Deprecated
-	public void assertAuthorizedForURL(String url)
-			throws AccessControlException {
-		this.assertAuthorized("AC 1.0 URL", new Object[] {url});
-	}
-
-	/**
-	 * @param action
-	 * @param data
-	 * @return {@code true} if access is permitted; {@code false} otherwise.
-	 * @see org.owasp.esapi.reference.accesscontrol.FileBasedACRs#isAuthorizedForData(java.lang.String, java.lang.Object)
-	 * @deprecated
-	 */
+    public void assertAuthorizedForURL(String url)
+            throws AccessControlException {
+        this.assertAuthorized("AC 1.0 URL", new Object[] {url});
+    }
+
+    /**
+     * @param action
+     * @param data
+     * @return {@code true} if access is permitted; {@code false} otherwise.
+     * @see org.owasp.esapi.reference.accesscontrol.FileBasedACRs#isAuthorizedForData(java.lang.String, java.lang.Object)
+     * @deprecated
+     */
     @Deprecated
-	public boolean isAuthorizedForData(String action, Object data) {
-		return this.isAuthorized("AC 1.0 Data", new Object[] {action, data});
-	}
+    public boolean isAuthorizedForData(String action, Object data) {
+        return this.isAuthorized("AC 1.0 Data", new Object[] {action, data});
+    }
 
-	/**
-	 * @param filepath
+    /**
+     * @param filepath
      * @return {@code true} if access is permitted; {@code false} otherwise.
-	 * @see org.owasp.esapi.reference.accesscontrol.FileBasedACRs#isAuthorizedForFile(java.lang.String)
-	 * @deprecated
-	 */
+     * @see org.owasp.esapi.reference.accesscontrol.FileBasedACRs#isAuthorizedForFile(java.lang.String)
+     * @deprecated
+     */
     @Deprecated
-	public boolean isAuthorizedForFile(String filepath) {
-		return this.isAuthorized("AC 1.0 File", new Object[] {filepath});
-	}
+    public boolean isAuthorizedForFile(String filepath) {
+        return this.isAuthorized("AC 1.0 File", new Object[] {filepath});
+    }
 
-	/**
-	 * @param functionName
+    /**
+     * @param functionName
      * @return {@code true} if access is permitted; {@code false} otherwise.
-	 * @see org.owasp.esapi.reference.accesscontrol.FileBasedACRs#isAuthorizedForFunction(java.lang.String)
-	 * @deprecated
-	 */
+     * @see org.owasp.esapi.reference.accesscontrol.FileBasedACRs#isAuthorizedForFunction(java.lang.String)
+     * @deprecated
+     */
     @Deprecated
-	public boolean isAuthorizedForFunction(String functionName) {
-		return this.isAuthorized("AC 1.0 Function", new Object[] {functionName});
-	}
+    public boolean isAuthorizedForFunction(String functionName) {
+        return this.isAuthorized("AC 1.0 Function", new Object[] {functionName});
+    }
 
-	/**
-	 * @param serviceName
+    /**
+     * @param serviceName
      * @return {@code true} if access is permitted; {@code false} otherwise.
-	 * @see org.owasp.esapi.reference.accesscontrol.FileBasedACRs#isAuthorizedForService(java.lang.String)
-	 * @deprecated
-	 */
+     * @see org.owasp.esapi.reference.accesscontrol.FileBasedACRs#isAuthorizedForService(java.lang.String)
+     * @deprecated
+     */
     @Deprecated
-	public boolean isAuthorizedForService(String serviceName) {
-		return this.isAuthorized("AC 1.0 Service", new Object[] {serviceName});
-	}
+    public boolean isAuthorizedForService(String serviceName) {
+        return this.isAuthorized("AC 1.0 Service", new Object[] {serviceName});
+    }
 
-	/**
-	 * @param url
+    /**
+     * @param url
      * @return {@code true} if access is permitted; {@code false} otherwise.
-	 * @see org.owasp.esapi.reference.accesscontrol.FileBasedACRs#isAuthorizedForURL(java.lang.String)
-	 * @deprecated
-	 */
+     * @see org.owasp.esapi.reference.accesscontrol.FileBasedACRs#isAuthorizedForURL(java.lang.String)
+     * @deprecated
+     */
     @Deprecated
-	public boolean isAuthorizedForURL(String url) {
-		return this.isAuthorized("AC 1.0 URL", new Object[] {url});
-	}
+    public boolean isAuthorizedForURL(String url) {
+        return this.isAuthorized("AC 1.0 URL", new Object[] {url});
+    }
 }
diff --git a/src/main/java/org/owasp/esapi/reference/accesscontrol/FileBasedACRs.java b/src/main/java/org/owasp/esapi/reference/accesscontrol/FileBasedACRs.java
index 0e2d8fe..2e19304 100644
--- a/src/main/java/org/owasp/esapi/reference/accesscontrol/FileBasedACRs.java
+++ b/src/main/java/org/owasp/esapi/reference/accesscontrol/FileBasedACRs.java
@@ -1,15 +1,15 @@
 /**
  * OWASP Enterprise Security API (ESAPI)
- * 
+ *
  * This file is part of the Open Web Application Security Project (OWASP)
  * Enterprise Security API (ESAPI) project. For details, please see
  * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
  *
  * Copyright (c) 2007 - The OWASP Foundation
- * 
+ *
  * The ESAPI is published by OWASP under the BSD license. You should read and accept the
  * LICENSE before you use, modify, and/or redistribute this software.
- * 
+ *
  * @author Mike Fauzy <a href="http://www.aspectsecurity.com">Aspect Security</a>
  * @author Jeff Williams <a href="http://www.aspectsecurity.com">Aspect Security</a>
  * @created 2007
@@ -37,7 +37,7 @@ import org.owasp.esapi.errors.IntrusionException;
 // CHECKME: If this exists for backward compatibility, should this
 //          class be deprecated??? If so, mark it using annotation.
 /**
- * This class exists for backwards compatibility with the AccessController 1.0 
+ * This class exists for backwards compatibility with the AccessController 1.0
  * reference implementation.
  *
  * This reference implementation uses a simple model for specifying a set of
@@ -78,7 +78,7 @@ import org.owasp.esapi.errors.IntrusionException;
  * the AccessController interface. These files are located in the ESAPI
  * resources directory as specified when the JVM was started. The use of a
  * default deny rule is STRONGLY recommended. The file format is as follows:
- * 
+ *
  * <pre>
  * path          | role,role   | allow/deny | comment
  * ------------------------------------------------------------------------------------
@@ -86,7 +86,7 @@ import org.owasp.esapi.errors.IntrusionException;
  * /admin        | admin       | allow      | only admin role can access /admin
  * /             | any         | deny       | default deny rule
  * </pre>
- * 
+ *
  * To find the matching rules, this implementation follows the general approach
  * used in Java EE when matching HTTP requests to servlets in web.xml. The four
  * mapping rules are used in the following order:
@@ -97,463 +97,463 @@ import org.owasp.esapi.errors.IntrusionException;
  * <li>extension match, beginning *., e.g. *.css</li>
  * <li>default rule, specified by the single character pattern /</li>
  * </ul>
- * 
+ *
  * @author Mike Fauzy (mike.fauzy@aspectsecurity.com)
  * @author Jeff Williams (jeff.williams@aspectsecurity.com)
  * @since June 1, 2007
  */
 public class FileBasedACRs {
 
-	/** The url map. */
-	private Map urlMap = new HashMap();
+    /** The url map. */
+    private Map urlMap = new HashMap();
 
-	/** The function map. */
-	private Map functionMap = new HashMap();
+    /** The function map. */
+    private Map functionMap = new HashMap();
 
-	/** The data map. */
-	private Map dataMap = new HashMap();
+    /** The data map. */
+    private Map dataMap = new HashMap();
 
-	/** The file map. */
-	private Map fileMap = new HashMap();
+    /** The file map. */
+    private Map fileMap = new HashMap();
 
-	/** The service map. */
-	private Map serviceMap = new HashMap();
+    /** The service map. */
+    private Map serviceMap = new HashMap();
 
-	/** A rule containing "deny". */
-	private Rule deny = new Rule();
+    /** A rule containing "deny". */
+    private Rule deny = new Rule();
 
-	/** The logger. */
-	private Logger logger = ESAPI.getLogger("FileBasedACRs");
+    /** The logger. */
+    private Logger logger = ESAPI.getLogger("FileBasedACRs");
 
     /**
-	* Check if URL is authorized.
-	* @param url The URL tested for authorization
-	* @return {@code true} if access is allowed, {@code false} otherwise.
-	*/
+    * Check if URL is authorized.
+    * @param url The URL tested for authorization
+    * @return {@code true} if access is allowed, {@code false} otherwise.
+    */
     public boolean isAuthorizedForURL(String url) {
-		if (urlMap==null || urlMap.isEmpty()) {
-			urlMap = loadRules("URLAccessRules.txt");
-		}
-		return matchRule(urlMap, url);
-	}
+        if (urlMap==null || urlMap.isEmpty()) {
+            urlMap = loadRules("URLAccessRules.txt");
+        }
+        return matchRule(urlMap, url);
+    }
 
     /**
-	* TODO Javadoc
-	*/
+    * TODO Javadoc
+    */
     public boolean isAuthorizedForFunction(String functionName) throws AccessControlException {
-    	if (functionMap==null || functionMap.isEmpty()) {
-			functionMap = loadRules("FunctionAccessRules.txt");
-		}
-		return matchRule(functionMap, functionName);
-	}
-  
+        if (functionMap==null || functionMap.isEmpty()) {
+            functionMap = loadRules("FunctionAccessRules.txt");
+        }
+        return matchRule(functionMap, functionName);
+    }
+
     /**
-	* TODO Javadoc
-	*/
+    * TODO Javadoc
+    */
     public boolean isAuthorizedForData(String action, Object data) throws AccessControlException{
-    	if (dataMap==null || dataMap.isEmpty()) {
-			dataMap = loadDataRules("DataAccessRules.txt");
-    	}		
-    	return matchRule(dataMap, (Class)data, action);    	
+        if (dataMap==null || dataMap.isEmpty()) {
+            dataMap = loadDataRules("DataAccessRules.txt");
+        }
+        return matchRule(dataMap, (Class)data, action);
     }
-    
+
     /**
-	* TODO Javadoc
-	*/
+    * TODO Javadoc
+    */
     public boolean isAuthorizedForFile(String filepath) throws AccessControlException {
-		if (fileMap==null || fileMap.isEmpty()) {
-			fileMap = loadRules("FileAccessRules.txt");
-		}
-		return matchRule(fileMap, filepath.replaceAll("\\\\","/"));
-	}
+        if (fileMap==null || fileMap.isEmpty()) {
+            fileMap = loadRules("FileAccessRules.txt");
+        }
+        return matchRule(fileMap, filepath.replaceAll("\\\\","/"));
+    }
+
+    /**
+    * TODO Javadoc
+    */
+    public boolean isAuthorizedForService(String serviceName) throws AccessControlException {
+        if (serviceMap==null || serviceMap.isEmpty()) {
+            serviceMap = loadRules("ServiceAccessRules.txt");
+        }
+        return matchRule(serviceMap, serviceName);
+    }
+
+    /**
+     * Checks to see if the current user has access to the specified data, File, Object, etc.
+     * If the User has access, as specified by the map parameter, this method returns true.  If the
+     * User does not have access or an exception is thrown, false is returned.
+     *
+     * @param map
+     *       the map containing access rules
+     * @param path
+     *       the path of the requested File, URL, Object, etc.
+     *
+     * @return
+     *         true, if the user has access, false otherwise
+     *
+     */
+    private boolean matchRule(Map map, String path) {
+        // get users roles
+        User user = ESAPI.authenticator().getCurrentUser();
+        Set roles = user.getRoles();
+        // search for the first rule that matches the path and rules
+        Rule rule = searchForRule(map, roles, path);
+        return rule.allow;
+    }
 
     /**
-	* TODO Javadoc
-	*/
-    public boolean isAuthorizedForService(String serviceName) throws AccessControlException {    	
-		if (serviceMap==null || serviceMap.isEmpty()) {
-			serviceMap = loadRules("ServiceAccessRules.txt");
-		}
-		return matchRule(serviceMap, serviceName);
-	}
-
-	/**
-	 * Checks to see if the current user has access to the specified data, File, Object, etc.
-	 * If the User has access, as specified by the map parameter, this method returns true.  If the 
-	 * User does not have access or an exception is thrown, false is returned.
-	 * 
-	 * @param map
-	 *       the map containing access rules
-	 * @param path
-	 *       the path of the requested File, URL, Object, etc.
-	 * 
-	 * @return 
-	 * 		true, if the user has access, false otherwise
-	 * 
-	 */
-	private boolean matchRule(Map map, String path) {
-		// get users roles
-		User user = ESAPI.authenticator().getCurrentUser();
-		Set roles = user.getRoles();
-		// search for the first rule that matches the path and rules
-		Rule rule = searchForRule(map, roles, path);
-		return rule.allow;
-	}
-	
-	/**
-	 * Checks to see if the current user has access to the specified Class and action.
-	 * If the User has access, as specified by the map parameter, this method returns true.
+     * Checks to see if the current user has access to the specified Class and action.
+     * If the User has access, as specified by the map parameter, this method returns true.
      * If the User does not have access or an exception is thrown, false is returned.
-	 * 
-	 * @param map
-	 *       the map containing access rules
-	 * @param clazz
-	 *       the Class being requested for access
-	 * @param action
-	 * 		 the action the User has asked to perform
-	 * @return 
-	 * 		true, if the user has access, false otherwise
-	 * 
-	 */
-	private boolean matchRule(Map map, Class clazz, String action) {
-		// get users roles
-		User user = ESAPI.authenticator().getCurrentUser();
-		Set roles = user.getRoles();
-		// search for the first rule that matches the path and rules
-		Rule rule = searchForRule(map, roles, clazz, action);
-		return rule != null;
-	}
-
-	/**
-	 * Search for rule. Four mapping rules are used in order: - exact match,
-	 * e.g. /access/login - longest path prefix match, beginning / and ending
-	 * /*, e.g. /access/* or /* - extension match, beginning *., e.g. *.css -
-	 * default servlet, specified by the single character pattern /
-	 * 
-	 * @param map
-	 *       the map containing access rules
-	 * @param roles
-	 *       the roles of the User being checked for access
-	 * @param path
-	 *       the File, URL, Object, etc. being checked for access
-	 * 
-	 * @return 
-	 *       the rule stating whether to allow or deny access
-	 * 
-	 */
-	private Rule searchForRule(Map map, Set roles, String path) {
-		String canonical = ESAPI.encoder().canonicalize(path);
-
-		String part = canonical;
+     *
+     * @param map
+     *       the map containing access rules
+     * @param clazz
+     *       the Class being requested for access
+     * @param action
+     *          the action the User has asked to perform
+     * @return
+     *         true, if the user has access, false otherwise
+     *
+     */
+    private boolean matchRule(Map map, Class clazz, String action) {
+        // get users roles
+        User user = ESAPI.authenticator().getCurrentUser();
+        Set roles = user.getRoles();
+        // search for the first rule that matches the path and rules
+        Rule rule = searchForRule(map, roles, clazz, action);
+        return rule != null;
+    }
+
+    /**
+     * Search for rule. Four mapping rules are used in order: - exact match,
+     * e.g. /access/login - longest path prefix match, beginning / and ending
+     * /*, e.g. /access/* or /* - extension match, beginning *., e.g. *.css -
+     * default servlet, specified by the single character pattern /
+     *
+     * @param map
+     *       the map containing access rules
+     * @param roles
+     *       the roles of the User being checked for access
+     * @param path
+     *       the File, URL, Object, etc. being checked for access
+     *
+     * @return
+     *       the rule stating whether to allow or deny access
+     *
+     */
+    private Rule searchForRule(Map map, Set roles, String path) {
+        String canonical = ESAPI.encoder().canonicalize(path);
+
+        String part = canonical;
         if ( part == null ) {
             part = "";
         }
-        
-		while (part.endsWith("/")) {
-			part = part.substring(0, part.length() - 1);
-		}
-
-		if (part.indexOf("..") != -1) {
-			throw new IntrusionException("Attempt to manipulate access control path", "Attempt to manipulate access control path: " + path );
-		}
-		
-		// extract extension if any
-		String extension = "";
-		int extIndex = part.lastIndexOf(".");
-		if (extIndex != -1) {
-			extension = part.substring(extIndex + 1);
-		}
-
-		// Check for exact match - ignore any ending slash
-		Rule rule = (Rule) map.get(part);
-
-		// Check for ending with /*
-		if (rule == null)
-			rule = (Rule) map.get(part + "/*");
-
-		// Check for matching extension rule *.ext
-		if (rule == null)
-			rule = (Rule) map.get("*." + extension);
-
-		// if rule found and user's roles match rules' roles, return the rule
-		if (rule != null && overlap(rule.roles, roles))
-			return rule;
-
-		// rule hasn't been found - if there are no more parts, return a deny
-		int slash = part.lastIndexOf('/');
-		if ( slash == -1 ) {
-			return deny;
-		}
-		
-		// if there are more parts, strip off the last part and recurse
-		part = part.substring(0, part.lastIndexOf('/'));
-		
-		// return default deny
-		if (part.length() <= 1) {
-			return deny;
-		}
-		
-		return searchForRule(map, roles, part);
-	}
-	
-	/**
-	 * Search for rule. Searches the specified access map to see if any of the roles specified have 
-	 * access to perform the specified action on the specified Class.
-	 * 
-	 * @param map
-	 *      the map containing access rules
-	 * @param roles
-	 *      the roles used to determine access level
-	 * @param clazz
-	 *      the Class being requested for access
-	 * @param action
-	 * 		the action the User has asked to perform
-	 * 
-	 * @return 
-	 * 		the rule that allows the specified roles access to perform the requested action on the specified Class, or null if access is not granted
-	 * 
-	 */
-	private Rule searchForRule(Map map, Set roles, Class clazz, String action) {
-
-		// Check for exact match - ignore any ending slash
-		Rule rule = (Rule) map.get(clazz);
-		if( ( rule != null ) && ( overlap(rule.actions, action) ) && ( overlap(rule.roles, roles) )){
-			return rule;
-		}
-		return null;
-	}
-
-	/**
-	 * Return true if there is overlap between the two sets.  This method merely checks to see if 
-	 * ruleRoles contains any of the roles listed in userRoles.
-	 * 
-	 * @param ruleRoles
-	 *      the rule roles
-	 * @param userRoles
-	 *      the user roles
-	 * 
-	 * @return 
-	 * 		true, if any roles exist in both Sets.  False otherwise.
-	 */
-	private boolean overlap(Set ruleRoles, Set userRoles) {
-		if (ruleRoles.contains("any")) {
-			return true;
-		}
-		Iterator i = userRoles.iterator();
-		while (i.hasNext()) {
-			String role = (String) i.next();
-			if (ruleRoles.contains(role)) {
-				return true;
-			}
-		}
-		return false;
-	}
-	
-	/**
-	 * This method merely checks to see if ruleActions contains the action requested.
-	 * 
-	 * @param ruleActions
-	 *      actions listed for a rule
-	 * @param action
-	 *      the action requested that will be searched for in ruleActions
-	 * 
-	 * @return 
-	 * 		true, if any action exists in ruleActions.  False otherwise.
-	 */
-	private boolean overlap( List ruleActions, String action){
-		if( ruleActions.contains(action) )
-			return true;
-		return false;
-	}
-		
-	/**
-	 * Checks that the roles passed in contain only letters, numbers, and underscores.  Also checks that
-	 * roles are no more than 10 characters long.  If a role does not pass validation, it is not included in the 
-	 * list of roles returned by this method.  A log warning is also generated for any invalid roles.
-	 * 
-	 * @param roles
-	 * 		roles to validate according to criteria started above
-	 * @return
-	 * 		a List of roles that are valid according to the criteria stated above.
-	 * 
-	 */
-	private List validateRoles(List roles){
-		List ret = new ArrayList();	
-		for(int x = 0; x < roles.size(); x++){
-			String canonical = ESAPI.encoder().canonicalize(((String)roles.get(x)).trim());
-
-			if(!ESAPI.validator().isValidInput("Validating user roles in FileBasedAccessController", canonical, "RoleName", 20, false)) {
-				logger.warning( Logger.SECURITY_FAILURE, "Role: " + ((String)roles.get(x)).trim() + " is invalid, so was not added to the list of roles for this Rule.");
-			} else { 
-				ret.add(canonical.trim());
-			}
-		}
-		return ret;
-	}
-	
-	/**
-	 * Loads access rules by storing them in a hashmap.  This method begins reading the File specified by
-	 * the ruleset parameter, ignoring any lines that begin with '#' characters as comments.  Sections of the access rules file
-	 * are split by the pipe character ('|').  The method loads all paths, replacing '\' characters with '/' for uniformity then loads
-	 * the list of comma separated roles. The roles are validated to be sure they are within a 
-	 * length and character set, specified in the validateRoles(String) method.  Then the permissions are stored for each item in the rules list.
-	 * If the word "allow" appears on the line, the specified roles are granted access to the data - otherwise, they will be denied access.
-	 * 
-	 * Each path may only appear once in the access rules file.  Any entry, after the first, containing the same path will be logged and ignored. 
-	 *  
-	 * @param ruleset
-	 *      the name of the data that contains access rules
-	 * 
-	 * @return 
-	 * 		a hash map containing the ruleset
-	 */
-	private Map loadRules(String ruleset) {
-		ruleset = "fbac-policies/" + ruleset;
-		Map map = new HashMap();
-		InputStream is = null;
-		try {
-			is = ESAPI.securityConfiguration().getResourceStream(ruleset);
-			String line = "";
-			while ((line = ESAPI.validator().safeReadLine(is, 500)) != null) {
-				if (line.length() > 0 && line.charAt(0) != '#') {
-					Rule rule = new Rule();
-					String[] parts = line.split("\\|");
-					// fix Windows paths
-					rule.path = parts[0].trim().replaceAll("\\\\", "/");
-					
-					List roles = commaSplit(parts[1].trim().toLowerCase());
-					roles = validateRoles(roles);
-					for(int x = 0; x < roles.size(); x++)
-						rule.roles.add(((String)roles.get(x)).trim());
-					
-					String action = parts[2].trim();
-					rule.allow = action.equalsIgnoreCase("allow");
-					if (map.containsKey(rule.path)) {
-						logger.warning( Logger.SECURITY_FAILURE, "Problem in access control file. Duplicate rule ignored: " + rule);
-					} else {
-						map.put(rule.path, rule);
-					}
-				}
-			}
-		} catch (Exception e) {
-			logger.warning( Logger.SECURITY_FAILURE, "Problem in access control file: " + ruleset, e );
-		} finally {
-			try {
-				if (is != null) {
-					is.close();
-				}
-			} catch (IOException e) {
-				logger.warning(Logger.SECURITY_FAILURE, "Failure closing access control file: " + ruleset, e);
-			}
-		}
-		return map;
-	}
-	
-	/**
-	 * Loads access rules by storing them in a hashmap.  This method begins reading the File specified by
-	 * the ruleset parameter, ignoring any lines that begin with '#' characters as comments.  Sections of the access rules file
-	 * are split by the pipe character ('|').  The method then loads all Classes, loads the list of comma separated roles, then the list of comma separated actions.  
-	 * The roles are validated to be sure they are within a length and character set, specified in the validateRoles(String) method.  
-	 * 
-	 * Each path may only appear once in the access rules file.  Any entry, after the first, containing the same path will be logged and ignored. 
-	 *  
-	 * @param ruleset
-	 *      the name of the data that contains access rules
-	 * 
-	 * @return 
-	 * 		a hash map containing the ruleset
-	 */
-	private Map loadDataRules(String ruleset) {
-		Map map = new HashMap();
-		InputStream is = null;
-
-		try {
-			ruleset = "fbac-policies/" + ruleset;
-			is = ESAPI.securityConfiguration().getResourceStream(ruleset);
-			String line = "";
-			while ((line = ESAPI.validator().safeReadLine(is, 500)) != null) {
-				if (line.length() > 0 && line.charAt(0) != '#') {
-					Rule rule = new Rule();
-					String[] parts = line.split("\\|");
-					rule.clazz = Class.forName(parts[0].trim());
-					
-					List roles = commaSplit(parts[1].trim().toLowerCase());
-					roles = validateRoles(roles);
-					for(int x = 0; x < roles.size(); x++)
-						rule.roles.add(((String)roles.get(x)).trim());
-					
-					List action = commaSplit(parts[2].trim().toLowerCase());
-					for(int x = 0; x < action.size(); x++)
-						rule.actions.add(((String) action.get(x)).trim());
-					
-					if (map.containsKey(rule.path)) {
-						logger.warning( Logger.SECURITY_FAILURE, "Problem in access control file. Duplicate rule ignored: " + rule);
-					} else {
-						map.put(rule.clazz, rule);		
-					}
-				}
-			}
-		} catch (Exception e) {
-			logger.warning( Logger.SECURITY_FAILURE, "Problem in access control file : " + ruleset, e );
-		} finally {
-			
-			try {
-				if (is != null) {
-					is.close();
-				}
-			} catch (IOException e) {
-				logger.warning(Logger.SECURITY_FAILURE, "Failure closing access control file : " + ruleset, e);
-			}
-		}
-		return map;
-	}
-
-	/**
-	 * This method splits a String by the ',' and returns the result as a List.
-	 * 
-	 * @param input
-	 * 		the String to split by ','
-	 * @return
-	 * 		a List where each entry was on either side of a ',' in the original String
-	 */
-	private List commaSplit(String input){
-		String[] array = input.split(",");
-		return Arrays.asList(array);
-	}
-	
-	/**
-	 * The Class Rule.
-	 */
-	private class Rule {
-
-		
-		protected String path = "";
-
-		
-		protected Set roles = new HashSet();
-
-		
-		protected boolean allow = false;
-		
-		
-		protected Class clazz = null;
-		
-		
-		protected List actions = new ArrayList();
-
-		/**
-		 * 
-		 * Creates a new Rule object.
-		 */
-		protected Rule() {
-			// to replace synthetic accessor method
-		}
-
-		/**
-	     * {@inheritDoc}
-		 */
-		public String toString() {
-			return "URL:" + path + " | " + roles + " | " + (allow ? "allow" : "deny");
-		}
-	}
+
+        while (part.endsWith("/")) {
+            part = part.substring(0, part.length() - 1);
+        }
+
+        if (part.indexOf("..") != -1) {
+            throw new IntrusionException("Attempt to manipulate access control path", "Attempt to manipulate access control path: " + path );
+        }
+
+        // extract extension if any
+        String extension = "";
+        int extIndex = part.lastIndexOf(".");
+        if (extIndex != -1) {
+            extension = part.substring(extIndex + 1);
+        }
+
+        // Check for exact match - ignore any ending slash
+        Rule rule = (Rule) map.get(part);
+
+        // Check for ending with /*
+        if (rule == null)
+            rule = (Rule) map.get(part + "/*");
+
+        // Check for matching extension rule *.ext
+        if (rule == null)
+            rule = (Rule) map.get("*." + extension);
+
+        // if rule found and user's roles match rules' roles, return the rule
+        if (rule != null && overlap(rule.roles, roles))
+            return rule;
+
+        // rule hasn't been found - if there are no more parts, return a deny
+        int slash = part.lastIndexOf('/');
+        if ( slash == -1 ) {
+            return deny;
+        }
+
+        // if there are more parts, strip off the last part and recurse
+        part = part.substring(0, part.lastIndexOf('/'));
+
+        // return default deny
+        if (part.length() <= 1) {
+            return deny;
+        }
+
+        return searchForRule(map, roles, part);
+    }
+
+    /**
+     * Search for rule. Searches the specified access map to see if any of the roles specified have
+     * access to perform the specified action on the specified Class.
+     *
+     * @param map
+     *      the map containing access rules
+     * @param roles
+     *      the roles used to determine access level
+     * @param clazz
+     *      the Class being requested for access
+     * @param action
+     *         the action the User has asked to perform
+     *
+     * @return
+     *         the rule that allows the specified roles access to perform the requested action on the specified Class, or null if access is not granted
+     *
+     */
+    private Rule searchForRule(Map map, Set roles, Class clazz, String action) {
+
+        // Check for exact match - ignore any ending slash
+        Rule rule = (Rule) map.get(clazz);
+        if( ( rule != null ) && ( overlap(rule.actions, action) ) && ( overlap(rule.roles, roles) )){
+            return rule;
+        }
+        return null;
+    }
+
+    /**
+     * Return true if there is overlap between the two sets.  This method merely checks to see if
+     * ruleRoles contains any of the roles listed in userRoles.
+     *
+     * @param ruleRoles
+     *      the rule roles
+     * @param userRoles
+     *      the user roles
+     *
+     * @return
+     *         true, if any roles exist in both Sets.  False otherwise.
+     */
+    private boolean overlap(Set ruleRoles, Set userRoles) {
+        if (ruleRoles.contains("any")) {
+            return true;
+        }
+        Iterator i = userRoles.iterator();
+        while (i.hasNext()) {
+            String role = (String) i.next();
+            if (ruleRoles.contains(role)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * This method merely checks to see if ruleActions contains the action requested.
+     *
+     * @param ruleActions
+     *      actions listed for a rule
+     * @param action
+     *      the action requested that will be searched for in ruleActions
+     *
+     * @return
+     *         true, if any action exists in ruleActions.  False otherwise.
+     */
+    private boolean overlap( List ruleActions, String action){
+        if( ruleActions.contains(action) )
+            return true;
+        return false;
+    }
+
+    /**
+     * Checks that the roles passed in contain only letters, numbers, and underscores.  Also checks that
+     * roles are no more than 10 characters long.  If a role does not pass validation, it is not included in the
+     * list of roles returned by this method.  A log warning is also generated for any invalid roles.
+     *
+     * @param roles
+     *         roles to validate according to criteria started above
+     * @return
+     *         a List of roles that are valid according to the criteria stated above.
+     *
+     */
+    private List validateRoles(List roles){
+        List ret = new ArrayList();
+        for(int x = 0; x < roles.size(); x++){
+            String canonical = ESAPI.encoder().canonicalize(((String)roles.get(x)).trim());
+
+            if(!ESAPI.validator().isValidInput("Validating user roles in FileBasedAccessController", canonical, "RoleName", 20, false)) {
+                logger.warning( Logger.SECURITY_FAILURE, "Role: " + ((String)roles.get(x)).trim() + " is invalid, so was not added to the list of roles for this Rule.");
+            } else {
+                ret.add(canonical.trim());
+            }
+        }
+        return ret;
+    }
+
+    /**
+     * Loads access rules by storing them in a hashmap.  This method begins reading the File specified by
+     * the ruleset parameter, ignoring any lines that begin with '#' characters as comments.  Sections of the access rules file
+     * are split by the pipe character ('|').  The method loads all paths, replacing '\' characters with '/' for uniformity then loads
+     * the list of comma separated roles. The roles are validated to be sure they are within a
+     * length and character set, specified in the validateRoles(String) method.  Then the permissions are stored for each item in the rules list.
+     * If the word "allow" appears on the line, the specified roles are granted access to the data - otherwise, they will be denied access.
+     *
+     * Each path may only appear once in the access rules file.  Any entry, after the first, containing the same path will be logged and ignored.
+     *
+     * @param ruleset
+     *      the name of the data that contains access rules
+     *
+     * @return
+     *         a hash map containing the ruleset
+     */
+    private Map loadRules(String ruleset) {
+        ruleset = "fbac-policies/" + ruleset;
+        Map map = new HashMap();
+        InputStream is = null;
+        try {
+            is = ESAPI.securityConfiguration().getResourceStream(ruleset);
+            String line = "";
+            while ((line = ESAPI.validator().safeReadLine(is, 500)) != null) {
+                if (line.length() > 0 && line.charAt(0) != '#') {
+                    Rule rule = new Rule();
+                    String[] parts = line.split("\\|");
+                    // fix Windows paths
+                    rule.path = parts[0].trim().replaceAll("\\\\", "/");
+
+                    List roles = commaSplit(parts[1].trim().toLowerCase());
+                    roles = validateRoles(roles);
+                    for(int x = 0; x < roles.size(); x++)
+                        rule.roles.add(((String)roles.get(x)).trim());
+
+                    String action = parts[2].trim();
+                    rule.allow = action.equalsIgnoreCase("allow");
+                    if (map.containsKey(rule.path)) {
+                        logger.warning( Logger.SECURITY_FAILURE, "Problem in access control file. Duplicate rule ignored: " + rule);
+                    } else {
+                        map.put(rule.path, rule);
+                    }
+                }
+            }
+        } catch (Exception e) {
+            logger.warning( Logger.SECURITY_FAILURE, "Problem in access control file: " + ruleset, e );
+        } finally {
+            try {
+                if (is != null) {
+                    is.close();
+                }
+            } catch (IOException e) {
+                logger.warning(Logger.SECURITY_FAILURE, "Failure closing access control file: " + ruleset, e);
+            }
+        }
+        return map;
+    }
+
+    /**
+     * Loads access rules by storing them in a hashmap.  This method begins reading the File specified by
+     * the ruleset parameter, ignoring any lines that begin with '#' characters as comments.  Sections of the access rules file
+     * are split by the pipe character ('|').  The method then loads all Classes, loads the list of comma separated roles, then the list of comma separated actions.
+     * The roles are validated to be sure they are within a length and character set, specified in the validateRoles(String) method.
+     *
+     * Each path may only appear once in the access rules file.  Any entry, after the first, containing the same path will be logged and ignored.
+     *
+     * @param ruleset
+     *      the name of the data that contains access rules
+     *
+     * @return
+     *         a hash map containing the ruleset
+     */
+    private Map loadDataRules(String ruleset) {
+        Map map = new HashMap();
+        InputStream is = null;
+
+        try {
+            ruleset = "fbac-policies/" + ruleset;
+            is = ESAPI.securityConfiguration().getResourceStream(ruleset);
+            String line = "";
+            while ((line = ESAPI.validator().safeReadLine(is, 500)) != null) {
+                if (line.length() > 0 && line.charAt(0) != '#') {
+                    Rule rule = new Rule();
+                    String[] parts = line.split("\\|");
+                    rule.clazz = Class.forName(parts[0].trim());
+
+                    List roles = commaSplit(parts[1].trim().toLowerCase());
+                    roles = validateRoles(roles);
+                    for(int x = 0; x < roles.size(); x++)
+                        rule.roles.add(((String)roles.get(x)).trim());
+
+                    List action = commaSplit(parts[2].trim().toLowerCase());
+                    for(int x = 0; x < action.size(); x++)
+                        rule.actions.add(((String) action.get(x)).trim());
+
+                    if (map.containsKey(rule.path)) {
+                        logger.warning( Logger.SECURITY_FAILURE, "Problem in access control file. Duplicate rule ignored: " + rule);
+                    } else {
+                        map.put(rule.clazz, rule);
+                    }
+                }
+            }
+        } catch (Exception e) {
+            logger.warning( Logger.SECURITY_FAILURE, "Problem in access control file : " + ruleset, e );
+        } finally {
+
+            try {
+                if (is != null) {
+                    is.close();
+                }
+            } catch (IOException e) {
+                logger.warning(Logger.SECURITY_FAILURE, "Failure closing access control file : " + ruleset, e);
+            }
+        }
+        return map;
+    }
+
+    /**
+     * This method splits a String by the ',' and returns the result as a List.
+     *
+     * @param input
+     *         the String to split by ','
+     * @return
+     *         a List where each entry was on either side of a ',' in the original String
+     */
+    private List commaSplit(String input){
+        String[] array = input.split(",");
+        return Arrays.asList(array);
+    }
+
+    /**
+     * The Class Rule.
+     */
+    private class Rule {
+
+
+        protected String path = "";
+
+
+        protected Set roles = new HashSet();
+
+
+        protected boolean allow = false;
+
+
+        protected Class clazz = null;
+
+
+        protected List actions = new ArrayList();
+
+        /**
+         *
+         * Creates a new Rule object.
+         */
+        protected Rule() {
+            // to replace synthetic accessor method
+        }
+
+        /**
+         * {@inheritDoc}
+         */
+        public String toString() {
+            return "URL:" + path + " | " + roles + " | " + (allow ? "allow" : "deny");
+        }
+    }
 }
diff --git a/src/main/java/org/owasp/esapi/reference/accesscontrol/policyloader/ACRParameterLoader.java b/src/main/java/org/owasp/esapi/reference/accesscontrol/policyloader/ACRParameterLoader.java
index c445661..a0ae77f 100644
--- a/src/main/java/org/owasp/esapi/reference/accesscontrol/policyloader/ACRParameterLoader.java
+++ b/src/main/java/org/owasp/esapi/reference/accesscontrol/policyloader/ACRParameterLoader.java
@@ -4,6 +4,6 @@ import org.apache.commons.configuration.XMLConfiguration;
 
 
 public interface ACRParameterLoader <T> {
-	public abstract T getParameters(XMLConfiguration config, int currentRule)
-		throws java.lang.Exception; //TODO this exception could be more specific
+    public abstract T getParameters(XMLConfiguration config, int currentRule)
+        throws java.lang.Exception; //TODO this exception could be more specific
 }
diff --git a/src/main/java/org/owasp/esapi/reference/accesscontrol/policyloader/ACRParameterLoaderHelper.java b/src/main/java/org/owasp/esapi/reference/accesscontrol/policyloader/ACRParameterLoaderHelper.java
index 22be7f0..d0846fc 100644
--- a/src/main/java/org/owasp/esapi/reference/accesscontrol/policyloader/ACRParameterLoaderHelper.java
+++ b/src/main/java/org/owasp/esapi/reference/accesscontrol/policyloader/ACRParameterLoaderHelper.java
@@ -3,44 +3,44 @@ package org.owasp.esapi.reference.accesscontrol.policyloader;
 import org.apache.commons.configuration.XMLConfiguration;
 
 final public class ACRParameterLoaderHelper {
-	
-	public static Object getParameterValue(XMLConfiguration config, int currentRule, int currentParameter, String parameterType) throws Exception {
-		String key = "AccessControlRules.AccessControlRule(" + 
-			currentRule + ").Parameters.Parameter(" + currentParameter + ")[@value]";
-		Object parameterValue;
-		if("String".equalsIgnoreCase(parameterType)) {
-			parameterValue = config.getString(key);
-		} else if("StringArray".equalsIgnoreCase(parameterType)) {
-			parameterValue = config.getStringArray(key);
-		} else if("Boolean".equalsIgnoreCase(parameterType)){ 
-			parameterValue = config.getBoolean(key);
-		} else if("Byte".equalsIgnoreCase(parameterType)){ 
-			parameterValue = config.getByte(key);
-		} else if("Int".equalsIgnoreCase(parameterType)){ 
-			parameterValue = config.getInt(key);
-		} else if("Long".equalsIgnoreCase(parameterType)){ 
-			parameterValue = config.getLong(key);
-		} else if("Float".equalsIgnoreCase(parameterType)){ 
-			parameterValue = config.getFloat(key);
-		} else if("Double".equalsIgnoreCase(parameterType)){ 
-			parameterValue = config.getDouble(key);
-		} else if("BigDecimal".equalsIgnoreCase(parameterType)){ 
-			parameterValue = config.getBigDecimal(key);
-		} else if("BigInteger".equalsIgnoreCase(parameterType)){ 
-			parameterValue = config.getBigInteger(key);
-		} else if("Date".equalsIgnoreCase(parameterType)){
-			parameterValue = java.text.DateFormat.getDateInstance().parse(config.getString(key));
-		} else if("Time".equalsIgnoreCase(parameterType)){
-			java.text.SimpleDateFormat sdf = new java.text.SimpleDateFormat("h:mm a");
-			parameterValue = sdf.parseObject(config.getString(key)); 
-//			parameterValue = java.text.DateFormat.getTimeInstance().parse(config.getString(key));
-		}		
-		//add timestamp. check for other stuff.
-		else {
-			throw new IllegalArgumentException("Unable to load the key \"" + key 
-					+ "\", because " + "the type \"" + parameterType + 
-					"\" was not recognized." );
-		}
-		return parameterValue;
-	}	
+
+    public static Object getParameterValue(XMLConfiguration config, int currentRule, int currentParameter, String parameterType) throws Exception {
+        String key = "AccessControlRules.AccessControlRule(" +
+            currentRule + ").Parameters.Parameter(" + currentParameter + ")[@value]";
+        Object parameterValue;
+        if("String".equalsIgnoreCase(parameterType)) {
+            parameterValue = config.getString(key);
+        } else if("StringArray".equalsIgnoreCase(parameterType)) {
+            parameterValue = config.getStringArray(key);
+        } else if("Boolean".equalsIgnoreCase(parameterType)){
+            parameterValue = config.getBoolean(key);
+        } else if("Byte".equalsIgnoreCase(parameterType)){
+            parameterValue = config.getByte(key);
+        } else if("Int".equalsIgnoreCase(parameterType)){
+            parameterValue = config.getInt(key);
+        } else if("Long".equalsIgnoreCase(parameterType)){
+            parameterValue = config.getLong(key);
+        } else if("Float".equalsIgnoreCase(parameterType)){
+            parameterValue = config.getFloat(key);
+        } else if("Double".equalsIgnoreCase(parameterType)){
+            parameterValue = config.getDouble(key);
+        } else if("BigDecimal".equalsIgnoreCase(parameterType)){
+            parameterValue = config.getBigDecimal(key);
+        } else if("BigInteger".equalsIgnoreCase(parameterType)){
+            parameterValue = config.getBigInteger(key);
+        } else if("Date".equalsIgnoreCase(parameterType)){
+            parameterValue = java.text.DateFormat.getDateInstance().parse(config.getString(key));
+        } else if("Time".equalsIgnoreCase(parameterType)){
+            java.text.SimpleDateFormat sdf = new java.text.SimpleDateFormat("h:mm a");
+            parameterValue = sdf.parseObject(config.getString(key));
+//            parameterValue = java.text.DateFormat.getTimeInstance().parse(config.getString(key));
+        }
+        //add timestamp. check for other stuff.
+        else {
+            throw new IllegalArgumentException("Unable to load the key \"" + key
+                    + "\", because " + "the type \"" + parameterType +
+                    "\" was not recognized." );
+        }
+        return parameterValue;
+    }
 }
diff --git a/src/main/java/org/owasp/esapi/reference/accesscontrol/policyloader/ACRPolicyFileLoader.java b/src/main/java/org/owasp/esapi/reference/accesscontrol/policyloader/ACRPolicyFileLoader.java
index 17f0aa0..9a7f595 100644
--- a/src/main/java/org/owasp/esapi/reference/accesscontrol/policyloader/ACRPolicyFileLoader.java
+++ b/src/main/java/org/owasp/esapi/reference/accesscontrol/policyloader/ACRPolicyFileLoader.java
@@ -10,90 +10,90 @@ import org.owasp.esapi.Logger;
 import org.owasp.esapi.errors.AccessControlException;
 
 final public class ACRPolicyFileLoader {
-	protected final Logger logger = ESAPI.getLogger("ACRPolicyFileLoader");
-	
-	public PolicyDTO load() throws AccessControlException {
-		PolicyDTO policyDTO = new PolicyDTO();
-		XMLConfiguration config;
-		File file = ESAPI.securityConfiguration().getResourceFile("ESAPI-AccessControlPolicy.xml"); 
-		try
-		{
-		    config = new XMLConfiguration(file);		    
-		}
-		catch(ConfigurationException cex)
-		{
-			if(file == null) {
-				throw new AccessControlException("Unable to load configuration file for the following: " + "ESAPI-AccessControlPolicy.xml", "", cex);
-			}
-		    throw new AccessControlException("Unable to load configuration file from the following location: " + file.getAbsolutePath(), "", cex);
-		} 
+    protected final Logger logger = ESAPI.getLogger("ACRPolicyFileLoader");
 
-		Object property = config.getProperty("AccessControlRules.AccessControlRule[@name]");
-		logger.info(Logger.EVENT_SUCCESS, "Loading Property: " + property);
-		int numberOfRules = 0;
-		if(property instanceof Collection) {
-			numberOfRules = ((Collection)property).size();
-		} //implied else property == null -> return new PolicyDTO
-				 
-		String ruleName = "";
-		String ruleClass = "";
-		Object rulePolicyParameter = null;
-		int currentRule = 0;
-	    try {	    	
-	    	logger.info(Logger.EVENT_SUCCESS, "Number of rules: " + numberOfRules);
-			for(currentRule = 0; currentRule < numberOfRules; currentRule++) {
-				logger.trace(Logger.EVENT_SUCCESS, "----");
-				ruleName = config.getString("AccessControlRules.AccessControlRule(" + currentRule + ")[@name]");
-				logger.trace(Logger.EVENT_SUCCESS, "Rule name: " + ruleName);
-				ruleClass = config.getString("AccessControlRules.AccessControlRule(" + currentRule + ")[@class]");
-				logger.trace(Logger.EVENT_SUCCESS, "Rule Class: " + ruleClass);
-				rulePolicyParameter = getPolicyParameter(config, currentRule);
-				logger.trace(Logger.EVENT_SUCCESS, "rulePolicyParameters: " + rulePolicyParameter);
-				policyDTO.addAccessControlRule(
-						ruleName,
-						ruleClass,
-						rulePolicyParameter);		    	
-			}
-			logger.info(Logger.EVENT_SUCCESS, "policyDTO loaded: " + policyDTO);
-		} catch (Exception e) {
-			throw new AccessControlException("Unable to load AccessControlRule parameter. " + 
-					" Rule number: " + currentRule + 
-					" Probably: Rule.name: " + ruleName +
-					" Probably: Rule.class: " + ruleClass +
-					e.getMessage(), "", e);
-		}
-		return policyDTO;
-	}
+    public PolicyDTO load() throws AccessControlException {
+        PolicyDTO policyDTO = new PolicyDTO();
+        XMLConfiguration config;
+        File file = ESAPI.securityConfiguration().getResourceFile("ESAPI-AccessControlPolicy.xml");
+        try
+        {
+            config = new XMLConfiguration(file);
+        }
+        catch(ConfigurationException cex)
+        {
+            if(file == null) {
+                throw new AccessControlException("Unable to load configuration file for the following: " + "ESAPI-AccessControlPolicy.xml", "", cex);
+            }
+            throw new AccessControlException("Unable to load configuration file from the following location: " + file.getAbsolutePath(), "", cex);
+        }
 
-	protected Object getPolicyParameter(XMLConfiguration config, int currentRule)
-		throws ClassNotFoundException, IllegalAccessException, InstantiationException, Exception {
-		//If there aren't any properties: short circuit and return null.
-//		Properties tempParameters = config.getProperties("AccessControlRules.AccessControlRule(" + currentRule + ").Parameters.Parameter[@name]");
-		Object property = config.getProperty("AccessControlRules.AccessControlRule(" + currentRule + ").Parameters.Parameter[@name]");
-		if(property == null) {
-			return null;
-		}
-		
-		int numberOfProperties = 0;		
-		if(property instanceof Collection) {
-			numberOfProperties = ((Collection)property).size(); 
-		} else {
-			numberOfProperties = 1;
-		}
-		logger.info(Logger.EVENT_SUCCESS, "Number of properties: " + numberOfProperties);
-		
-		if(numberOfProperties < 1) {
-			return null;
-		}
-		String parametersLoaderClassName = config.getString("AccessControlRules.AccessControlRule(" + currentRule + ").Parameters[@parametersLoader]");
-		if("".equals(parametersLoaderClassName) || parametersLoaderClassName == null) {
-			//this default should have a properties file override option
-			parametersLoaderClassName = "org.owasp.esapi.reference.accesscontrol.policyloader.DynaBeanACRParameterLoader";
-		}
-		logger.info(Logger.EVENT_SUCCESS, "Parameters Loader:" + parametersLoaderClassName);
-		ACRParameterLoader acrParamaterLoader = 
-			(ACRParameterLoader)
-			Class.forName(parametersLoaderClassName).newInstance();
-		return acrParamaterLoader.getParameters(config, currentRule);		
-	}
+        Object property = config.getProperty("AccessControlRules.AccessControlRule[@name]");
+        logger.info(Logger.EVENT_SUCCESS, "Loading Property: " + property);
+        int numberOfRules = 0;
+        if(property instanceof Collection) {
+            numberOfRules = ((Collection)property).size();
+        } //implied else property == null -> return new PolicyDTO
+
+        String ruleName = "";
+        String ruleClass = "";
+        Object rulePolicyParameter = null;
+        int currentRule = 0;
+        try {
+            logger.info(Logger.EVENT_SUCCESS, "Number of rules: " + numberOfRules);
+            for(currentRule = 0; currentRule < numberOfRules; currentRule++) {
+                logger.trace(Logger.EVENT_SUCCESS, "----");
+                ruleName = config.getString("AccessControlRules.AccessControlRule(" + currentRule + ")[@name]");
+                logger.trace(Logger.EVENT_SUCCESS, "Rule name: " + ruleName);
+                ruleClass = config.getString("AccessControlRules.AccessControlRule(" + currentRule + ")[@class]");
+                logger.trace(Logger.EVENT_SUCCESS, "Rule Class: " + ruleClass);
+                rulePolicyParameter = getPolicyParameter(config, currentRule);
+                logger.trace(Logger.EVENT_SUCCESS, "rulePolicyParameters: " + rulePolicyParameter);
+                policyDTO.addAccessControlRule(
+                        ruleName,
+                        ruleClass,
+                        rulePolicyParameter);
+            }
+            logger.info(Logger.EVENT_SUCCESS, "policyDTO loaded: " + policyDTO);
+        } catch (Exception e) {
+            throw new AccessControlException("Unable to load AccessControlRule parameter. " +
+                    " Rule number: " + currentRule +
+                    " Probably: Rule.name: " + ruleName +
+                    " Probably: Rule.class: " + ruleClass +
+                    e.getMessage(), "", e);
+        }
+        return policyDTO;
+    }
+
+    protected Object getPolicyParameter(XMLConfiguration config, int currentRule)
+        throws ClassNotFoundException, IllegalAccessException, InstantiationException, Exception {
+        //If there aren't any properties: short circuit and return null.
+//        Properties tempParameters = config.getProperties("AccessControlRules.AccessControlRule(" + currentRule + ").Parameters.Parameter[@name]");
+        Object property = config.getProperty("AccessControlRules.AccessControlRule(" + currentRule + ").Parameters.Parameter[@name]");
+        if(property == null) {
+            return null;
+        }
+
+        int numberOfProperties = 0;
+        if(property instanceof Collection) {
+            numberOfProperties = ((Collection)property).size();
+        } else {
+            numberOfProperties = 1;
+        }
+        logger.info(Logger.EVENT_SUCCESS, "Number of properties: " + numberOfProperties);
+
+        if(numberOfProperties < 1) {
+            return null;
+        }
+        String parametersLoaderClassName = config.getString("AccessControlRules.AccessControlRule(" + currentRule + ").Parameters[@parametersLoader]");
+        if("".equals(parametersLoaderClassName) || parametersLoaderClassName == null) {
+            //this default should have a properties file override option
+            parametersLoaderClassName = "org.owasp.esapi.reference.accesscontrol.policyloader.DynaBeanACRParameterLoader";
+        }
+        logger.info(Logger.EVENT_SUCCESS, "Parameters Loader:" + parametersLoaderClassName);
+        ACRParameterLoader acrParamaterLoader =
+            (ACRParameterLoader)
+            Class.forName(parametersLoaderClassName).newInstance();
+        return acrParamaterLoader.getParameters(config, currentRule);
+    }
 }
\ No newline at end of file
diff --git a/src/main/java/org/owasp/esapi/reference/accesscontrol/policyloader/DynaBeanACRParameterLoader.java b/src/main/java/org/owasp/esapi/reference/accesscontrol/policyloader/DynaBeanACRParameterLoader.java
index d57b488..1417462 100644
--- a/src/main/java/org/owasp/esapi/reference/accesscontrol/policyloader/DynaBeanACRParameterLoader.java
+++ b/src/main/java/org/owasp/esapi/reference/accesscontrol/policyloader/DynaBeanACRParameterLoader.java
@@ -7,24 +7,24 @@ import org.owasp.esapi.reference.accesscontrol.DynaBeanACRParameter;
 
 import static org.owasp.esapi.reference.accesscontrol.policyloader.ACRParameterLoaderHelper.getParameterValue;
 
-final public class DynaBeanACRParameterLoader  
-	implements ACRParameterLoader<DynaBeanACRParameter> {
-	
-	Logger logger = ESAPI.getLogger(this.getClass());
-	
-//	@Override
-	public DynaBeanACRParameter getParameters(XMLConfiguration config, int currentRule) throws java.lang.Exception { //TODO reduce the exception
-		DynaBeanACRParameter policyParameter = new DynaBeanACRParameter();
-		int numberOfParameters = config.getList("AccessControlRules.AccessControlRule(" + currentRule + ").Parameters.Parameter[@name]").size();
-		for(int currentParameter = 0; currentParameter < numberOfParameters; currentParameter++) {
-			String parameterName = config.getString("AccessControlRules.AccessControlRule(" + currentRule + ").Parameters.Parameter(" + currentParameter + ")[@name]");
-			String parameterType = config.getString("AccessControlRules.AccessControlRule(" + currentRule + ").Parameters.Parameter(" + currentParameter + ")[@type]");
-			Object parameterValue = getParameterValue(config, currentRule, currentParameter, parameterType);
-			policyParameter.set(parameterName, parameterValue);
-		}
-		policyParameter.lock(); //This line makes the policyParameter read only. 
-		logger.info(Logger.SECURITY_SUCCESS, "Loaded " + numberOfParameters + 
-				" parameters: " + policyParameter.toString());
-		return policyParameter;
-	}
+final public class DynaBeanACRParameterLoader
+    implements ACRParameterLoader<DynaBeanACRParameter> {
+
+    Logger logger = ESAPI.getLogger(this.getClass());
+
+//    @Override
+    public DynaBeanACRParameter getParameters(XMLConfiguration config, int currentRule) throws java.lang.Exception { //TODO reduce the exception
+        DynaBeanACRParameter policyParameter = new DynaBeanACRParameter();
+        int numberOfParameters = config.getList("AccessControlRules.AccessControlRule(" + currentRule + ").Parameters.Parameter[@name]").size();
+        for(int currentParameter = 0; currentParameter < numberOfParameters; currentParameter++) {
+            String parameterName = config.getString("AccessControlRules.AccessControlRule(" + currentRule + ").Parameters.Parameter(" + currentParameter + ")[@name]");
+            String parameterType = config.getString("AccessControlRules.AccessControlRule(" + currentRule + ").Parameters.Parameter(" + currentParameter + ")[@type]");
+            Object parameterValue = getParameterValue(config, currentRule, currentParameter, parameterType);
+            policyParameter.set(parameterName, parameterValue);
+        }
+        policyParameter.lock(); //This line makes the policyParameter read only.
+        logger.info(Logger.SECURITY_SUCCESS, "Loaded " + numberOfParameters +
+                " parameters: " + policyParameter.toString());
+        return policyParameter;
+    }
 }
diff --git a/src/main/java/org/owasp/esapi/reference/accesscontrol/policyloader/EchoDynaBeanPolicyParameterACR.java b/src/main/java/org/owasp/esapi/reference/accesscontrol/policyloader/EchoDynaBeanPolicyParameterACR.java
index b89aaae..f30919c 100644
--- a/src/main/java/org/owasp/esapi/reference/accesscontrol/policyloader/EchoDynaBeanPolicyParameterACR.java
+++ b/src/main/java/org/owasp/esapi/reference/accesscontrol/policyloader/EchoDynaBeanPolicyParameterACR.java
@@ -5,11 +5,11 @@ import org.owasp.esapi.reference.accesscontrol.DynaBeanACRParameter;
 
 //public class EchoDynaBeanPolicyParameterACR extends BaseDynaBeanACR {
 public class EchoDynaBeanPolicyParameterACR extends BaseACR<DynaBeanACRParameter, Object> {
-	/**
-	 * Returns true if runtimeParameter is a Boolean true.
-	 * throws ClassCastException if runtimeParameter is not a Boolean.
-	 */
-	public boolean isAuthorized(Object runtimeParameter) throws ClassCastException{		
-		return getPolicyParameters().getBoolean("isTrue");
-	}
+    /**
+     * Returns true if runtimeParameter is a Boolean true.
+     * throws ClassCastException if runtimeParameter is not a Boolean.
+     */
+    public boolean isAuthorized(Object runtimeParameter) throws ClassCastException{
+        return getPolicyParameters().getBoolean("isTrue");
+    }
 }
\ No newline at end of file
diff --git a/src/main/java/org/owasp/esapi/reference/accesscontrol/policyloader/PolicyDTO.java b/src/main/java/org/owasp/esapi/reference/accesscontrol/policyloader/PolicyDTO.java
index cfb1e27..7be9915 100644
--- a/src/main/java/org/owasp/esapi/reference/accesscontrol/policyloader/PolicyDTO.java
+++ b/src/main/java/org/owasp/esapi/reference/accesscontrol/policyloader/PolicyDTO.java
@@ -13,43 +13,43 @@ import org.owasp.esapi.errors.AccessControlException;
  *
  */
 final public class PolicyDTO {
-	private Map accessControlRules;
-
-	public PolicyDTO() {
-		this.accessControlRules = new HashMap();
-	}
-	
-	public Map getAccessControlRules() {
-		return accessControlRules;
-	}
-
-	public void addAccessControlRule(String key, String accessControlRuleClassName,
-			Object policyParameter) throws AccessControlException {
-		if (accessControlRules.get(key) != null) {
-			throw new AccessControlException("Duplicate keys are not allowed. "
-					+ "Key: " + key, "");
-		}
-		Constructor accessControlRuleConstructor;
-		try {
-			
-			
-			Class accessControlRuleClass = Class.forName(accessControlRuleClassName, false, this.getClass().getClassLoader());
-			accessControlRuleConstructor = accessControlRuleClass
-					.getConstructor();
-			AccessControlRule accessControlRule = 
-				(AccessControlRule) accessControlRuleConstructor
-					.newInstance();
-			accessControlRule.setPolicyParameters(policyParameter);
-			accessControlRules.put(key, accessControlRule);
-		} catch (Exception e) {
-			throw new AccessControlException(
-					"Unable to create Access Control Rule for key: \"" + key
-							+ "\" with policyParameters: \"" + policyParameter + "\"",
-					"", 
-					e);
-		}
-	}
-	public String toString() {
-		return accessControlRules.toString();
-	}
+    private Map accessControlRules;
+
+    public PolicyDTO() {
+        this.accessControlRules = new HashMap();
+    }
+
+    public Map getAccessControlRules() {
+        return accessControlRules;
+    }
+
+    public void addAccessControlRule(String key, String accessControlRuleClassName,
+            Object policyParameter) throws AccessControlException {
+        if (accessControlRules.get(key) != null) {
+            throw new AccessControlException("Duplicate keys are not allowed. "
+                    + "Key: " + key, "");
+        }
+        Constructor accessControlRuleConstructor;
+        try {
+
+
+            Class accessControlRuleClass = Class.forName(accessControlRuleClassName, false, this.getClass().getClassLoader());
+            accessControlRuleConstructor = accessControlRuleClass
+                    .getConstructor();
+            AccessControlRule accessControlRule =
+                (AccessControlRule) accessControlRuleConstructor
+                    .newInstance();
+            accessControlRule.setPolicyParameters(policyParameter);
+            accessControlRules.put(key, accessControlRule);
+        } catch (Exception e) {
+            throw new AccessControlException(
+                    "Unable to create Access Control Rule for key: \"" + key
+                            + "\" with policyParameters: \"" + policyParameter + "\"",
+                    "",
+                    e);
+        }
+    }
+    public String toString() {
+        return accessControlRules.toString();
+    }
 }
diff --git a/src/main/java/org/owasp/esapi/reference/accesscontrol/policyloader/PolicyParameters.java b/src/main/java/org/owasp/esapi/reference/accesscontrol/policyloader/PolicyParameters.java
index 9b0d5d4..65175f8 100644
--- a/src/main/java/org/owasp/esapi/reference/accesscontrol/policyloader/PolicyParameters.java
+++ b/src/main/java/org/owasp/esapi/reference/accesscontrol/policyloader/PolicyParameters.java
@@ -2,41 +2,41 @@ package org.owasp.esapi.reference.accesscontrol.policyloader;
 
 public interface PolicyParameters {
 
-	/**
-	 * Follows the contract for java.util.Map;
-	 * @param key
-	 * @return The Object referred to by this key, if it exists.
-	 * @see java.util.Map
-	 */
-	public abstract Object get(String key);
+    /**
+     * Follows the contract for java.util.Map;
+     * @param key
+     * @return The Object referred to by this key, if it exists.
+     * @see java.util.Map
+     */
+    public abstract Object get(String key);
 
-	/**
-	 * This works just like a Map, except it will throw an exception if lock()
-	 * has been called. 
-	 * @param key
-	 * @param value
-	 * @throws IllegalArgumentException if this DynaBeanACRParameter instance 
-	 * has already been locked.
-	 */
-	public abstract void set(String key, Object value)
-			throws IllegalArgumentException;
+    /**
+     * This works just like a Map, except it will throw an exception if lock()
+     * has been called.
+     * @param key
+     * @param value
+     * @throws IllegalArgumentException if this DynaBeanACRParameter instance
+     * has already been locked.
+     */
+    public abstract void set(String key, Object value)
+            throws IllegalArgumentException;
 
-	/**
-	 * This is a convenience method for developers that prefer to think of this
-	 * as a map instead of being bean-like. 
-	 * 
-	 * @see #set(String, Object)
-	 */
-	public abstract void put(String key, Object value)
-			throws IllegalArgumentException;
+    /**
+     * This is a convenience method for developers that prefer to think of this
+     * as a map instead of being bean-like.
+     *
+     * @see #set(String, Object)
+     */
+    public abstract void put(String key, Object value)
+            throws IllegalArgumentException;
+
+    /**
+     * This makes the map itself read only, but the mutability of objects
+     * that this map contains is not affected. Specifically, properties
+     * cannot be added or removed and the reference cannot be changed to
+     * a different object, but this does not change whether the values that the
+     * object contains can be changed.
+     */
+    public abstract void lock();
 
-	/**
-	 * This makes the map itself read only, but the mutability of objects 
-	 * that this map contains is not affected. Specifically, properties 
-	 * cannot be added or removed and the reference cannot be changed to 
-	 * a different object, but this does not change whether the values that the 
-	 * object contains can be changed.
-	 */
-	public abstract void lock();
-	
 }
\ No newline at end of file
diff --git a/src/main/java/org/owasp/esapi/reference/crypto/DefaultEncryptedProperties.java b/src/main/java/org/owasp/esapi/reference/crypto/DefaultEncryptedProperties.java
index af7b524..3970889 100644
--- a/src/main/java/org/owasp/esapi/reference/crypto/DefaultEncryptedProperties.java
+++ b/src/main/java/org/owasp/esapi/reference/crypto/DefaultEncryptedProperties.java
@@ -1,15 +1,15 @@
 /**
  * OWASP Enterprise Security API (ESAPI)
- * 
+ *
  * This file is part of the Open Web Application Security Project (OWASP)
  * Enterprise Security API (ESAPI) project. For details, please see
  * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
  *
  * Copyright (c) 2007 - The OWASP Foundation
- * 
+ *
  * The ESAPI is published by OWASP under the BSD license. You should read and accept the
  * LICENSE before you use, modify, and/or redistribute this software.
- * 
+ *
  * @author Jeff Williams <a href="http://www.aspectsecurity.com">Aspect Security</a>
  * @created 2007
  */
@@ -43,7 +43,7 @@ import org.owasp.esapi.errors.EncryptionException;
  * encrypted properties file. A better approach would be to allow unencrypted
  * properties in the file and to encrypt them the first time the file is
  * accessed.
- * 
+ *
  * @author Jeff Williams (jeff.williams .at. aspectsecurity.com) <a
  *         href="http://www.aspectsecurity.com">Aspect Security</a>
  * @author kevin.w.wall@gmail.com
@@ -53,164 +53,164 @@ import org.owasp.esapi.errors.EncryptionException;
  */
 public class DefaultEncryptedProperties implements org.owasp.esapi.EncryptedProperties {
 
-	/** The properties. */
-	private final Properties properties = new Properties();
-
-	/** The logger. */
-	private final Logger logger = ESAPI.getLogger("EncryptedProperties");
-
-	/**
-	 * Instantiates a new encrypted properties.
-	 */
-	public DefaultEncryptedProperties() {
-		// hidden
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	public synchronized String getProperty(String key) throws EncryptionException {
-	    String[] errorMsgs = new String[] {
-	            ": failed decoding from base64",
-	            ": failed to deserialize properly",
-	            ": failed to decrypt properly"
-	        };
-
-	    int progressMark = 0;
-	    try {
-	        String encryptedValue = properties.getProperty(key);
-
-	        if(encryptedValue==null)
-	            return null;
-
-	        progressMark = 0;
-	        byte[] serializedCiphertext   = ESAPI.encoder().decodeFromBase64(encryptedValue);
-	        progressMark++;
-	        CipherText restoredCipherText = CipherText.fromPortableSerializedBytes(serializedCiphertext);
-	        progressMark++;
-	        PlainText plaintext           = ESAPI.encryptor().decrypt(restoredCipherText);
-	        
-	        return plaintext.toString();
-	    } catch (Exception e) {
-	        throw new EncryptionException("Property retrieval failure",
-	                                      "Couldn't retrieve encrypted property for property " + key +
-	                                      errorMsgs[progressMark], e);
-	    }
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	public synchronized String setProperty(String key, String value) throws EncryptionException {
-	    String[] errorMsgs = new String[] {
-	            ": failed to encrypt properly",
-	            ": failed to serialize correctly",
-	            ": failed to base64-encode properly",
-	            ": failed to set base64-encoded value as property. Illegal key name?"
-	    };
-
-	    int progressMark = 0;
-	    try {
-	        if ( key == null ) {
-	            throw new NullPointerException("Property name may not be null.");
-	        }
-	        if ( value == null ) {
-	            throw new NullPointerException("Property value may not be null.");
-	        }
-	        // NOTE: Not backward compatible w/ ESAPI 1.4.
-	        PlainText pt = new PlainText(value);
-	        CipherText ct = ESAPI.encryptor().encrypt(pt);
-	        progressMark++;
-	        byte[] serializedCiphertext = ct.asPortableSerializedByteArray();
-	        progressMark++;
-	        String b64str = ESAPI.encoder().encodeForBase64(serializedCiphertext, false);
-	        progressMark++;
-	        String encryptedValue = (String)properties.setProperty(key, b64str);
-	        progressMark++;
-	        return encryptedValue;
-	    } catch (Exception e) {
-	        throw new EncryptionException("Property setting failure",
-	                                      "Couldn't set encrypted property " + key +
-	                                      errorMsgs[progressMark], e);
-	    }
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	public Set<?> keySet() {
-		return properties.keySet();
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	public void load(InputStream in) throws IOException {
-		properties.load(in);
-		logger.trace(Logger.SECURITY_SUCCESS, "Encrypted properties loaded successfully");
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	public void store(OutputStream out, String comments) throws IOException {
-		properties.store(out, comments);
-	}
-
-	/**
-	 * Loads encrypted properties file based on the location passed in args then prompts the 
-	 * user to input key-value pairs.  When the user enters a null or blank key, the values 
-	 * are stored to the properties file.
-	 * 
-	 * @param args
-	 *            the location of the properties file to load and write to
-	 * 
-	 * @throws Exception
-	 *             Any exception thrown
-	 * @deprecated Use {@code EncryptedPropertiesUtils} instead, which allows creating, reading,
-	 *			   and writing encrypted properties. {@code main} method will be removed in a
-     *			   future release.
-	 */
+    /** The properties. */
+    private final Properties properties = new Properties();
+
+    /** The logger. */
+    private final Logger logger = ESAPI.getLogger("EncryptedProperties");
+
+    /**
+     * Instantiates a new encrypted properties.
+     */
+    public DefaultEncryptedProperties() {
+        // hidden
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public synchronized String getProperty(String key) throws EncryptionException {
+        String[] errorMsgs = new String[] {
+                ": failed decoding from base64",
+                ": failed to deserialize properly",
+                ": failed to decrypt properly"
+            };
+
+        int progressMark = 0;
+        try {
+            String encryptedValue = properties.getProperty(key);
+
+            if(encryptedValue==null)
+                return null;
+
+            progressMark = 0;
+            byte[] serializedCiphertext   = ESAPI.encoder().decodeFromBase64(encryptedValue);
+            progressMark++;
+            CipherText restoredCipherText = CipherText.fromPortableSerializedBytes(serializedCiphertext);
+            progressMark++;
+            PlainText plaintext           = ESAPI.encryptor().decrypt(restoredCipherText);
+
+            return plaintext.toString();
+        } catch (Exception e) {
+            throw new EncryptionException("Property retrieval failure",
+                                          "Couldn't retrieve encrypted property for property " + key +
+                                          errorMsgs[progressMark], e);
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public synchronized String setProperty(String key, String value) throws EncryptionException {
+        String[] errorMsgs = new String[] {
+                ": failed to encrypt properly",
+                ": failed to serialize correctly",
+                ": failed to base64-encode properly",
+                ": failed to set base64-encoded value as property. Illegal key name?"
+        };
+
+        int progressMark = 0;
+        try {
+            if ( key == null ) {
+                throw new NullPointerException("Property name may not be null.");
+            }
+            if ( value == null ) {
+                throw new NullPointerException("Property value may not be null.");
+            }
+            // NOTE: Not backward compatible w/ ESAPI 1.4.
+            PlainText pt = new PlainText(value);
+            CipherText ct = ESAPI.encryptor().encrypt(pt);
+            progressMark++;
+            byte[] serializedCiphertext = ct.asPortableSerializedByteArray();
+            progressMark++;
+            String b64str = ESAPI.encoder().encodeForBase64(serializedCiphertext, false);
+            progressMark++;
+            String encryptedValue = (String)properties.setProperty(key, b64str);
+            progressMark++;
+            return encryptedValue;
+        } catch (Exception e) {
+            throw new EncryptionException("Property setting failure",
+                                          "Couldn't set encrypted property " + key +
+                                          errorMsgs[progressMark], e);
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public Set<?> keySet() {
+        return properties.keySet();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void load(InputStream in) throws IOException {
+        properties.load(in);
+        logger.trace(Logger.SECURITY_SUCCESS, "Encrypted properties loaded successfully");
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void store(OutputStream out, String comments) throws IOException {
+        properties.store(out, comments);
+    }
+
+    /**
+     * Loads encrypted properties file based on the location passed in args then prompts the
+     * user to input key-value pairs.  When the user enters a null or blank key, the values
+     * are stored to the properties file.
+     *
+     * @param args
+     *            the location of the properties file to load and write to
+     *
+     * @throws Exception
+     *             Any exception thrown
+     * @deprecated Use {@code EncryptedPropertiesUtils} instead, which allows creating, reading,
+     *               and writing encrypted properties. {@code main} method will be removed in a
+     *               future release.
+     */
     @Deprecated
-	public static void main(String[] args) throws Exception {
-		File f = new File(args[0]);
-		ESAPI.getLogger( "EncryptedProperties.main" ).debug(Logger.SECURITY_SUCCESS, "Loading encrypted properties from " + f.getAbsolutePath() );
-		if ( !f.exists() ) throw new IOException( "Properties file not found: " + f.getAbsolutePath() );
-		ESAPI.getLogger( "EncryptedProperties.main" ).debug(Logger.SECURITY_SUCCESS, "Encrypted properties found in " + f.getAbsolutePath() );
-		DefaultEncryptedProperties ep = new DefaultEncryptedProperties();
-
-		FileInputStream in = null;
-		FileOutputStream out = null;
-		try {
-    		in = new FileInputStream(f);
+    public static void main(String[] args) throws Exception {
+        File f = new File(args[0]);
+        ESAPI.getLogger( "EncryptedProperties.main" ).debug(Logger.SECURITY_SUCCESS, "Loading encrypted properties from " + f.getAbsolutePath() );
+        if ( !f.exists() ) throw new IOException( "Properties file not found: " + f.getAbsolutePath() );
+        ESAPI.getLogger( "EncryptedProperties.main" ).debug(Logger.SECURITY_SUCCESS, "Encrypted properties found in " + f.getAbsolutePath() );
+        DefaultEncryptedProperties ep = new DefaultEncryptedProperties();
+
+        FileInputStream in = null;
+        FileOutputStream out = null;
+        try {
+            in = new FileInputStream(f);
             out = new FileOutputStream(f);
 
-            ep.load(in);   
-    		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
-    		String key = null;
-    		do {
-    			System.out.print("Enter key: ");
-    			key = br.readLine();
-    			System.out.print("Enter value: ");
-    			String value = br.readLine();
-    			if (key != null && key.length() > 0 && value != null && value.length() > 0) {
-    				ep.setProperty(key, value);
-    			}
-    		} while (key != null && key.length() > 0);
-    		ep.store(out, "Encrypted Properties File");
-		} finally {
-		    // FindBugs and PMD both complain about these next lines, that they may
-		    // ignore thrown exceptions. Really!!! That's the whole point.
-    		try { if ( in != null ) in.close(); } catch( Exception e ) {}
-    		try { if ( out != null ) out.close(); } catch( Exception e ) {}
-		}
-		
-		Iterator<?> i = ep.keySet().iterator();
-		while (i.hasNext()) {
-			String k = (String) i.next();
-			String value = ep.getProperty(k);
-			System.out.println("   " + k + "=" + value);
-		}
-	}
+            ep.load(in);
+            BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
+            String key = null;
+            do {
+                System.out.print("Enter key: ");
+                key = br.readLine();
+                System.out.print("Enter value: ");
+                String value = br.readLine();
+                if (key != null && key.length() > 0 && value != null && value.length() > 0) {
+                    ep.setProperty(key, value);
+                }
+            } while (key != null && key.length() > 0);
+            ep.store(out, "Encrypted Properties File");
+        } finally {
+            // FindBugs and PMD both complain about these next lines, that they may
+            // ignore thrown exceptions. Really!!! That's the whole point.
+            try { if ( in != null ) in.close(); } catch( Exception e ) {}
+            try { if ( out != null ) out.close(); } catch( Exception e ) {}
+        }
+
+        Iterator<?> i = ep.keySet().iterator();
+        while (i.hasNext()) {
+            String k = (String) i.next();
+            String value = ep.getProperty(k);
+            System.out.println("   " + k + "=" + value);
+        }
+    }
 
 }
diff --git a/src/main/java/org/owasp/esapi/reference/crypto/EncryptedPropertiesUtils.java b/src/main/java/org/owasp/esapi/reference/crypto/EncryptedPropertiesUtils.java
index cb1d512..dee385f 100644
--- a/src/main/java/org/owasp/esapi/reference/crypto/EncryptedPropertiesUtils.java
+++ b/src/main/java/org/owasp/esapi/reference/crypto/EncryptedPropertiesUtils.java
@@ -17,8 +17,8 @@ import org.owasp.esapi.EncryptedProperties;
  * <p>
  * Usage:<br/>
  * <code>
- *    java org.owasp.esapi.reference.crypto.EncryptedPropertiesUtils [--in file] [--out file] 
- *			[--in-encrypted true|false] [--verbose true|false]
+ *    java org.owasp.esapi.reference.crypto.EncryptedPropertiesUtils [--in file] [--out file]
+ *            [--in-encrypted true|false] [--verbose true|false]
  * </code>
  * <p>
  * Command line parameters:<br/>
@@ -36,177 +36,177 @@ import org.owasp.esapi.EncryptedProperties;
  */
 public class EncryptedPropertiesUtils {
 
-	/**
-	 * Loads encrypted or plaintext properties file based on the location passed in args
-	 * then prompts the user to input key-value pairs.  When the user enters a null or
-	 * blank key, the values are stored to the properties file.
-	 *
-	 * @throws Exception Any exception thrown
-	 */
-	public static void main(String[] args) throws Exception {
-
-		//command line options
-		String inFile = null;
-		String outFile = null;
-		boolean inFileEncrypted = true;
-		boolean verbose = false;
-
-		//parse command line params
-		for (int i = 0; i < args.length; i = i + 2) {
-			String paramType = args[i];
-
-			if ("--in".equals(paramType) && args.length >= i + 1) {
-				inFile = args[i + 1];
-
-			} else if ("--out".equals(paramType) && args.length >= i + 1) {
-				outFile = args[i + 1];
-
-			} else if ("--in-encrypted".equals(paramType) && args.length >= i + 1) {
-				inFileEncrypted = Boolean.valueOf(args[i + 1]);
-
-			} else if ("--verbose".equals(paramType) && args.length >= i + 1) {
-				verbose = Boolean.valueOf(args[i + 1]);
-			}
-
-		}
-
-		if (outFile == null) {
-			outFile = inFile; //if no output file is specified we will overwrite the input file
-		}
-		if (outFile == null) {
-			//no input or output file specified. Can't continue.
-			System.out.println("You must specify an input file or output file");
-			System.exit(1);
-		}
-
-		//load in existing properties from a file
-		Properties props = loadProperties(inFile, inFileEncrypted);
-
-		//read user input and add keys and values to the property file
-		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
-		String key = null;
-		do {
-			System.out.print("Enter key: ");
-			key = br.readLine();
-
-			if (props.containsKey(key)) {
-				System.out.print("Key already exists. Replace? ");
-				String confirm = br.readLine();
-				if (!("y".equals(confirm) || "yes".equals(confirm))) {
-					continue;
-				}
-			}
-
-			System.out.print("Enter value: ");
-			String value = br.readLine();
-
-			addProperty(props, key, value);
-
-		} while (key != null && key.length() > 0);
-
-		//save output file
-		storeProperties(outFile, props,
-				"Encrypted Properties File generated by org.owasp.esapi.reference.crypto.EncryptedPropertiesUtils");
-
-		System.out.println("Encrypted Properties file output to " + outFile);
-
-		if (verbose) {
-			for (Object oKey : props.keySet()) {
-				String sKey = (String) oKey;
-				String value = props.getProperty(sKey);
-				System.out.println("   " + sKey + "=" + value);
-			}
-		}
-
-	}
-
-	/**
-	 * Loads a Properties file from a filename. If the filename is unspecified
-	 * or the file could not be found, a new Properties is returned.
-	 *
-	 * @param inFile Filename to load Properties from.
-	 * @param inFileEncrypted If true, the input file is assumed to be already encrypted. Default true.
-	 * @return Either the loaded Properties object or a new one if the file could not be found.
-	 * @throws IOException
-	 */
-	public static Properties loadProperties(String inFile, Boolean inFileEncrypted) throws IOException {
-
-		if (inFileEncrypted == null) inFileEncrypted = true;
-
-		Properties props;
-
-		if (inFile != null) {
-
-			File f = new File(inFile);
-			if (!f.exists()) {
-				System.out.println("Input properties file not found. Creating new.");
-				props = new ReferenceEncryptedProperties();
-
-			} else {
-				String encrypted = inFileEncrypted ? "Encrypted" : "Plaintext";
-				System.out.println(encrypted + " properties found in " + f.getAbsolutePath());
-
-				Properties inProperties;
-				if (inFileEncrypted) {
-					inProperties = new ReferenceEncryptedProperties();
-				} else {
-					inProperties = new Properties();
-				}
-
-				InputStream in = null;
-				try {
-					in = new FileInputStream(f);
-					inProperties.load(in);
-				} finally {
-					try {
-						if (in != null) in.close(); //quietly close the InputStream
-					} catch (Exception e) {}
-				}
-
-				//Use the existing properties
-				props = new ReferenceEncryptedProperties(inProperties);
-			}
-		} else {
-			System.out.println("Input properties file not found. Creating new.");
-			props = new ReferenceEncryptedProperties();
-		}
-
-		return props;
-	}
-
-	/**
-	 * Stores a Properties object to a file.
-	 *
-	 * @param outFile Filename to store to
-	 * @param props Properties to store
-	 * @param message A message to add to the comments in the stored file
-	 * @throws Exception
-	 */
-	public static void storeProperties(String outFile, Properties props, String message) throws Exception {
-		OutputStream out = null;
-		try {
-			out = new FileOutputStream(new File(outFile));
-			props.store(out, message);
-		} finally {
-			try {
-				if (out != null) out.close();  //quietly close OutputStream
-			} catch (Exception e) {}
-		}
-	}
-
-	/**
-	 * Adds a new key-value property to the passed Properties object
-	 *
-	 * @param props The Properties object to add to
-	 * @param key The key to add
-	 * @param value The value to set
-	 * @return The previous value of the property, or null if it is newly added.
-	 */
-	public static Object addProperty(Properties props, String key, String value) {
-		if (props != null && key != null && key.length() > 0 && value != null && value.length() > 0) {
-			return props.setProperty(key, value);
-		}
-		return null;
-	}
-	
+    /**
+     * Loads encrypted or plaintext properties file based on the location passed in args
+     * then prompts the user to input key-value pairs.  When the user enters a null or
+     * blank key, the values are stored to the properties file.
+     *
+     * @throws Exception Any exception thrown
+     */
+    public static void main(String[] args) throws Exception {
+
+        //command line options
+        String inFile = null;
+        String outFile = null;
+        boolean inFileEncrypted = true;
+        boolean verbose = false;
+
+        //parse command line params
+        for (int i = 0; i < args.length; i = i + 2) {
+            String paramType = args[i];
+
+            if ("--in".equals(paramType) && args.length >= i + 1) {
+                inFile = args[i + 1];
+
+            } else if ("--out".equals(paramType) && args.length >= i + 1) {
+                outFile = args[i + 1];
+
+            } else if ("--in-encrypted".equals(paramType) && args.length >= i + 1) {
+                inFileEncrypted = Boolean.valueOf(args[i + 1]);
+
+            } else if ("--verbose".equals(paramType) && args.length >= i + 1) {
+                verbose = Boolean.valueOf(args[i + 1]);
+            }
+
+        }
+
+        if (outFile == null) {
+            outFile = inFile; //if no output file is specified we will overwrite the input file
+        }
+        if (outFile == null) {
+            //no input or output file specified. Can't continue.
+            System.out.println("You must specify an input file or output file");
+            System.exit(1);
+        }
+
+        //load in existing properties from a file
+        Properties props = loadProperties(inFile, inFileEncrypted);
+
+        //read user input and add keys and values to the property file
+        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
+        String key = null;
+        do {
+            System.out.print("Enter key: ");
+            key = br.readLine();
+
+            if (props.containsKey(key)) {
+                System.out.print("Key already exists. Replace? ");
+                String confirm = br.readLine();
+                if (!("y".equals(confirm) || "yes".equals(confirm))) {
+                    continue;
+                }
+            }
+
+            System.out.print("Enter value: ");
+            String value = br.readLine();
+
+            addProperty(props, key, value);
+
+        } while (key != null && key.length() > 0);
+
+        //save output file
+        storeProperties(outFile, props,
+                "Encrypted Properties File generated by org.owasp.esapi.reference.crypto.EncryptedPropertiesUtils");
+
+        System.out.println("Encrypted Properties file output to " + outFile);
+
+        if (verbose) {
+            for (Object oKey : props.keySet()) {
+                String sKey = (String) oKey;
+                String value = props.getProperty(sKey);
+                System.out.println("   " + sKey + "=" + value);
+            }
+        }
+
+    }
+
+    /**
+     * Loads a Properties file from a filename. If the filename is unspecified
+     * or the file could not be found, a new Properties is returned.
+     *
+     * @param inFile Filename to load Properties from.
+     * @param inFileEncrypted If true, the input file is assumed to be already encrypted. Default true.
+     * @return Either the loaded Properties object or a new one if the file could not be found.
+     * @throws IOException
+     */
+    public static Properties loadProperties(String inFile, Boolean inFileEncrypted) throws IOException {
+
+        if (inFileEncrypted == null) inFileEncrypted = true;
+
+        Properties props;
+
+        if (inFile != null) {
+
+            File f = new File(inFile);
+            if (!f.exists()) {
+                System.out.println("Input properties file not found. Creating new.");
+                props = new ReferenceEncryptedProperties();
+
+            } else {
+                String encrypted = inFileEncrypted ? "Encrypted" : "Plaintext";
+                System.out.println(encrypted + " properties found in " + f.getAbsolutePath());
+
+                Properties inProperties;
+                if (inFileEncrypted) {
+                    inProperties = new ReferenceEncryptedProperties();
+                } else {
+                    inProperties = new Properties();
+                }
+
+                InputStream in = null;
+                try {
+                    in = new FileInputStream(f);
+                    inProperties.load(in);
+                } finally {
+                    try {
+                        if (in != null) in.close(); //quietly close the InputStream
+                    } catch (Exception e) {}
+                }
+
+                //Use the existing properties
+                props = new ReferenceEncryptedProperties(inProperties);
+            }
+        } else {
+            System.out.println("Input properties file not found. Creating new.");
+            props = new ReferenceEncryptedProperties();
+        }
+
+        return props;
+    }
+
+    /**
+     * Stores a Properties object to a file.
+     *
+     * @param outFile Filename to store to
+     * @param props Properties to store
+     * @param message A message to add to the comments in the stored file
+     * @throws Exception
+     */
+    public static void storeProperties(String outFile, Properties props, String message) throws Exception {
+        OutputStream out = null;
+        try {
+            out = new FileOutputStream(new File(outFile));
+            props.store(out, message);
+        } finally {
+            try {
+                if (out != null) out.close();  //quietly close OutputStream
+            } catch (Exception e) {}
+        }
+    }
+
+    /**
+     * Adds a new key-value property to the passed Properties object
+     *
+     * @param props The Properties object to add to
+     * @param key The key to add
+     * @param value The value to set
+     * @return The previous value of the property, or null if it is newly added.
+     */
+    public static Object addProperty(Properties props, String key, String value) {
+        if (props != null && key != null && key.length() > 0 && value != null && value.length() > 0) {
+            return props.setProperty(key, value);
+        }
+        return null;
+    }
+
 }
diff --git a/src/main/java/org/owasp/esapi/reference/crypto/ReferenceEncryptedProperties.java b/src/main/java/org/owasp/esapi/reference/crypto/ReferenceEncryptedProperties.java
index 0d35b25..1137a5f 100644
--- a/src/main/java/org/owasp/esapi/reference/crypto/ReferenceEncryptedProperties.java
+++ b/src/main/java/org/owasp/esapi/reference/crypto/ReferenceEncryptedProperties.java
@@ -55,239 +55,239 @@ import org.owasp.esapi.errors.EncryptionRuntimeException;
  */
 public class ReferenceEncryptedProperties extends java.util.Properties implements EncryptedProperties {
 
-	/**
-	 * serverVersionUID; use format of YYYYMMDD.
-	 */
-	private static final long serialVersionUID = 20120718L;
-
-	/** The logger. */
-	private final Logger logger = ESAPI.getLogger(this.getClass());
-
-	private static final String[] GET_ERROR_MESSAGES = new String[]{
-		": failed decoding from base64",
-		": failed to deserialize properly",
-		": failed to decrypt properly"
-	};
-
-	private static final String[] SET_ERROR_MESSAGES = new String[]{
-		": failed to encrypt properly",
-		": failed to serialize correctly",
-		": failed to base64-encode properly",
-		": failed to set base64-encoded value as property. Illegal key name?"
-	};
-
-	/**
-	 * Instantiates a new encrypted properties.
-	 */
-	public ReferenceEncryptedProperties() {
-		super();
-	}
-
-	public ReferenceEncryptedProperties(Properties defaults) {
-		super();
-
-		for (Object oKey : defaults.keySet()) {
-			String key		= (oKey instanceof String) ? (String)oKey : oKey.toString();
-			String value	= defaults.getProperty(key);
-
-			this.setProperty(key, value);
-		}
-	}
-
-	/**
-	 * {@inheritDoc}
-	 *
-	 * @throws EncryptionRuntimeException Thrown if decryption fails.
-	 */
-	@Override
-	public synchronized String getProperty(String key) throws EncryptionRuntimeException {
-	    int progressMark = 0;
-	    try {
-	        String encryptedValue = super.getProperty(key);
-
-	        if(encryptedValue==null)
-	            return null;
-
-	        progressMark = 0;
-	        byte[] serializedCiphertext   = ESAPI.encoder().decodeFromBase64(encryptedValue);
-	        progressMark++;
-	        CipherText restoredCipherText = CipherText.fromPortableSerializedBytes(serializedCiphertext);
-	        progressMark++;
-	        PlainText plaintext           = ESAPI.encryptor().decrypt(restoredCipherText);
-
-	        return plaintext.toString();
-		} catch (Exception e) {
-			throw new EncryptionRuntimeException("Property retrieval failure",
-					                             "Couldn't retrieve encrypted property for property " + key +
-												 GET_ERROR_MESSAGES[progressMark], e);
-	    }
-	}
-
-	/**
-	 * {@inheritDoc}
-	 *
-	 * @throws EncryptionRuntimeException Thrown if decryption fails.
-	 */
-	@Override
-	public synchronized String getProperty(String key, String defaultValue) throws EncryptionRuntimeException {
-		String value = getProperty(key);
-
-		if (value == null) return defaultValue;
-
-		return value;
-	}
-
-	/**
-	 * {@inheritDoc}
-	 *
-	 * @throws EncryptionRuntimeException Thrown if encryption fails.
-	 */
-	@Override
-	public synchronized String setProperty(String key, String value) throws EncryptionRuntimeException {
-	    int progressMark = 0;
-	    try {
-	        if ( key == null ) {
-	            throw new NullPointerException("Property name may not be null.");
-	        }
-	        if ( value == null ) {
-	            throw new NullPointerException("Property value may not be null.");
-	        }
-	        // NOTE: Not backward compatible w/ ESAPI 1.4.
-	        PlainText pt = new PlainText(value);
-	        CipherText ct = ESAPI.encryptor().encrypt(pt);
-	        progressMark++;
-	        byte[] serializedCiphertext = ct.asPortableSerializedByteArray();
-	        progressMark++;
-	        String b64str = ESAPI.encoder().encodeForBase64(serializedCiphertext, false);
-	        progressMark++;
-	        return (String)super.put(key, b64str);
-	    } catch (Exception e) {
-	        throw new EncryptionRuntimeException("Property setting failure",
-	                                      "Couldn't set encrypted property " + key +
-	                                      SET_ERROR_MESSAGES[progressMark], e);
-	    }
-	}
-
-	/**
-	 * {@inheritDoc}
-	 * @throws IOException Thrown if input stream invalid or does not
-	 * 					   correspond to Java properties file format.
-	 */
-	@Override
-	public void load(InputStream in) throws IOException {
-		super.load(in);
-		logger.trace(Logger.SECURITY_SUCCESS, "Encrypted properties loaded successfully");
-	}
-
-	/**
-	 * {@inheritDoc}
-	 *
-	 * For JDK 1.5 compatibility, this method has been overridden convert the Reader
-	 * into an InputStream and call the superclass constructor.
-	 * 
-	 * @throws IOException Thrown if {@code Reader} input stream invalid or does not
-	 * 					   correspond to Java properties file format.
-	 */
-	public void load(Reader in) throws IOException {
-
-		if (in == null) return;
-
-		//read from the reader into a StringBuffer
-		char[] cbuf				= new char[65536];
-		BufferedReader buff		= new BufferedReader(in);
-		StringBuilder contents	= new StringBuilder();
-
-		int read_this_time = 0;
-		while (read_this_time != -1) {
-			read_this_time = buff.read(cbuf, 0, 65536);
-			if (read_this_time > 0) contents.append(cbuf, 0, read_this_time);
-		}
-
-		//create a new InputStream from the StringBuffer
-		InputStream is = new ByteArrayInputStream(contents.toString().getBytes());
-
-		super.load(is);
-		logger.trace(Logger.SECURITY_SUCCESS, "Encrypted properties loaded successfully");
-	}
-
-	/**
-	 * This method has been overridden to throw an {@code UnsupportedOperationException}
-	 */
-	@Override
-	public void list(PrintStream out) {
-		throw new UnsupportedOperationException("This method has been removed for security.");
-	}
-
-	/**
-	 * This method has been overridden to throw an {@code UnsupportedOperationException}
-	 */
-	@Override
-	public void list(PrintWriter out) {
-		throw new UnsupportedOperationException("This method has been removed for security.");
-	}
-
-	/**
-	 * This method has been overridden to throw an {@code UnsupportedOperationException}
-	 */
-	@SuppressWarnings({ "unchecked", "rawtypes" })
-	@Override
-	public Collection values() {
-		throw new UnsupportedOperationException("This method has been removed for security.");
-	}
-
-	/**
-	 * This method has been overridden to throw an {@code UnsupportedOperationException}
-	 */
-	@SuppressWarnings({ "unchecked", "rawtypes" })
-	@Override
-	public Set entrySet() {
-		throw new UnsupportedOperationException("This method has been removed for security.");
-	}
-
-	/**
-	 * This method has been overridden to throw an {@code UnsupportedOperationException}
-	 */
-	@SuppressWarnings({ "unchecked", "rawtypes" })
-	@Override
-	public Enumeration elements() {
-		throw new UnsupportedOperationException("This method has been removed for security.");
-	}
-
-	/**
-	 * This method has been overridden to only accept Strings for key and value, and to encrypt
-	 * those Strings before storing them. Outside classes should always use {@code setProperty}
-	 * to add values to the Properties map. If an outside class does erroneously call this method 
-	 * with non-String parameters an {@code IllegalArgumentException} will be thrown.
-	 *
-	 * @param key	A String key to add
-	 * @param value A String value to add
-	 * @return		The old value associated with the specified key, or {@code null}
-     *				if the key did not exist.
-	 */
-	@Override
-	public synchronized Object put(Object key, Object value) {
-		//if java.util.Properties is calling this method, just forward to the implementation in
-		//the superclass (java.util.Hashtable)
-		Throwable t = new Throwable();
-		for (StackTraceElement trace : t.getStackTrace()) {
-			if ("java.util.Properties".equals(trace.getClassName()) ) return super.put(key, value);
-		}
-
-		//otherwise, if both arguments are Strings, encrypt and store them
-		if (key instanceof String && value instanceof String) return setProperty((String)key, (String)value);
-
-		//other Object types are not allowed
-		throw new IllegalArgumentException("This method has been overridden to only accept Strings for key and value.");
-	}
-
-	/**
-	 * This method has been overridden to not print out the keys and values stored in this properties file.
-	 *
-	 * @return The minimal String representation of this class, as per java.lang.Object.
-	 */
-	@Override
-	public String toString() {
-		return getClass().getName() + "@" + Integer.toHexString(hashCode());
-	}
+    /**
+     * serverVersionUID; use format of YYYYMMDD.
+     */
+    private static final long serialVersionUID = 20120718L;
+
+    /** The logger. */
+    private final Logger logger = ESAPI.getLogger(this.getClass());
+
+    private static final String[] GET_ERROR_MESSAGES = new String[]{
+        ": failed decoding from base64",
+        ": failed to deserialize properly",
+        ": failed to decrypt properly"
+    };
+
+    private static final String[] SET_ERROR_MESSAGES = new String[]{
+        ": failed to encrypt properly",
+        ": failed to serialize correctly",
+        ": failed to base64-encode properly",
+        ": failed to set base64-encoded value as property. Illegal key name?"
+    };
+
+    /**
+     * Instantiates a new encrypted properties.
+     */
+    public ReferenceEncryptedProperties() {
+        super();
+    }
+
+    public ReferenceEncryptedProperties(Properties defaults) {
+        super();
+
+        for (Object oKey : defaults.keySet()) {
+            String key        = (oKey instanceof String) ? (String)oKey : oKey.toString();
+            String value    = defaults.getProperty(key);
+
+            this.setProperty(key, value);
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * @throws EncryptionRuntimeException Thrown if decryption fails.
+     */
+    @Override
+    public synchronized String getProperty(String key) throws EncryptionRuntimeException {
+        int progressMark = 0;
+        try {
+            String encryptedValue = super.getProperty(key);
+
+            if(encryptedValue==null)
+                return null;
+
+            progressMark = 0;
+            byte[] serializedCiphertext   = ESAPI.encoder().decodeFromBase64(encryptedValue);
+            progressMark++;
+            CipherText restoredCipherText = CipherText.fromPortableSerializedBytes(serializedCiphertext);
+            progressMark++;
+            PlainText plaintext           = ESAPI.encryptor().decrypt(restoredCipherText);
+
+            return plaintext.toString();
+        } catch (Exception e) {
+            throw new EncryptionRuntimeException("Property retrieval failure",
+                                                 "Couldn't retrieve encrypted property for property " + key +
+                                                 GET_ERROR_MESSAGES[progressMark], e);
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * @throws EncryptionRuntimeException Thrown if decryption fails.
+     */
+    @Override
+    public synchronized String getProperty(String key, String defaultValue) throws EncryptionRuntimeException {
+        String value = getProperty(key);
+
+        if (value == null) return defaultValue;
+
+        return value;
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * @throws EncryptionRuntimeException Thrown if encryption fails.
+     */
+    @Override
+    public synchronized String setProperty(String key, String value) throws EncryptionRuntimeException {
+        int progressMark = 0;
+        try {
+            if ( key == null ) {
+                throw new NullPointerException("Property name may not be null.");
+            }
+            if ( value == null ) {
+                throw new NullPointerException("Property value may not be null.");
+            }
+            // NOTE: Not backward compatible w/ ESAPI 1.4.
+            PlainText pt = new PlainText(value);
+            CipherText ct = ESAPI.encryptor().encrypt(pt);
+            progressMark++;
+            byte[] serializedCiphertext = ct.asPortableSerializedByteArray();
+            progressMark++;
+            String b64str = ESAPI.encoder().encodeForBase64(serializedCiphertext, false);
+            progressMark++;
+            return (String)super.put(key, b64str);
+        } catch (Exception e) {
+            throw new EncryptionRuntimeException("Property setting failure",
+                                          "Couldn't set encrypted property " + key +
+                                          SET_ERROR_MESSAGES[progressMark], e);
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     * @throws IOException Thrown if input stream invalid or does not
+     *                        correspond to Java properties file format.
+     */
+    @Override
+    public void load(InputStream in) throws IOException {
+        super.load(in);
+        logger.trace(Logger.SECURITY_SUCCESS, "Encrypted properties loaded successfully");
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * For JDK 1.5 compatibility, this method has been overridden convert the Reader
+     * into an InputStream and call the superclass constructor.
+     *
+     * @throws IOException Thrown if {@code Reader} input stream invalid or does not
+     *                        correspond to Java properties file format.
+     */
+    public void load(Reader in) throws IOException {
+
+        if (in == null) return;
+
+        //read from the reader into a StringBuffer
+        char[] cbuf                = new char[65536];
+        BufferedReader buff        = new BufferedReader(in);
+        StringBuilder contents    = new StringBuilder();
+
+        int read_this_time = 0;
+        while (read_this_time != -1) {
+            read_this_time = buff.read(cbuf, 0, 65536);
+            if (read_this_time > 0) contents.append(cbuf, 0, read_this_time);
+        }
+
+        //create a new InputStream from the StringBuffer
+        InputStream is = new ByteArrayInputStream(contents.toString().getBytes());
+
+        super.load(is);
+        logger.trace(Logger.SECURITY_SUCCESS, "Encrypted properties loaded successfully");
+    }
+
+    /**
+     * This method has been overridden to throw an {@code UnsupportedOperationException}
+     */
+    @Override
+    public void list(PrintStream out) {
+        throw new UnsupportedOperationException("This method has been removed for security.");
+    }
+
+    /**
+     * This method has been overridden to throw an {@code UnsupportedOperationException}
+     */
+    @Override
+    public void list(PrintWriter out) {
+        throw new UnsupportedOperationException("This method has been removed for security.");
+    }
+
+    /**
+     * This method has been overridden to throw an {@code UnsupportedOperationException}
+     */
+    @SuppressWarnings({ "unchecked", "rawtypes" })
+    @Override
+    public Collection values() {
+        throw new UnsupportedOperationException("This method has been removed for security.");
+    }
+
+    /**
+     * This method has been overridden to throw an {@code UnsupportedOperationException}
+     */
+    @SuppressWarnings({ "unchecked", "rawtypes" })
+    @Override
+    public Set entrySet() {
+        throw new UnsupportedOperationException("This method has been removed for security.");
+    }
+
+    /**
+     * This method has been overridden to throw an {@code UnsupportedOperationException}
+     */
+    @SuppressWarnings({ "unchecked", "rawtypes" })
+    @Override
+    public Enumeration elements() {
+        throw new UnsupportedOperationException("This method has been removed for security.");
+    }
+
+    /**
+     * This method has been overridden to only accept Strings for key and value, and to encrypt
+     * those Strings before storing them. Outside classes should always use {@code setProperty}
+     * to add values to the Properties map. If an outside class does erroneously call this method
+     * with non-String parameters an {@code IllegalArgumentException} will be thrown.
+     *
+     * @param key    A String key to add
+     * @param value A String value to add
+     * @return        The old value associated with the specified key, or {@code null}
+     *                if the key did not exist.
+     */
+    @Override
+    public synchronized Object put(Object key, Object value) {
+        //if java.util.Properties is calling this method, just forward to the implementation in
+        //the superclass (java.util.Hashtable)
+        Throwable t = new Throwable();
+        for (StackTraceElement trace : t.getStackTrace()) {
+            if ("java.util.Properties".equals(trace.getClassName()) ) return super.put(key, value);
+        }
+
+        //otherwise, if both arguments are Strings, encrypt and store them
+        if (key instanceof String && value instanceof String) return setProperty((String)key, (String)value);
+
+        //other Object types are not allowed
+        throw new IllegalArgumentException("This method has been overridden to only accept Strings for key and value.");
+    }
+
+    /**
+     * This method has been overridden to not print out the keys and values stored in this properties file.
+     *
+     * @return The minimal String representation of this class, as per java.lang.Object.
+     */
+    @Override
+    public String toString() {
+        return getClass().getName() + "@" + Integer.toHexString(hashCode());
+    }
 
 }
diff --git a/src/main/java/org/owasp/esapi/reference/validation/BaseValidationRule.java b/src/main/java/org/owasp/esapi/reference/validation/BaseValidationRule.java
index 031a354..b925119 100644
--- a/src/main/java/org/owasp/esapi/reference/validation/BaseValidationRule.java
+++ b/src/main/java/org/owasp/esapi/reference/validation/BaseValidationRule.java
@@ -1,15 +1,15 @@
 /**
  * OWASP Enterprise Security API (ESAPI)
- * 
+ *
  * This file is part of the Open Web Application Security Project (OWASP)
  * Enterprise Security API (ESAPI) project. For details, please see
  * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
  *
  * Copyright (c) 2007 - The OWASP Foundation
- * 
+ *
  * The ESAPI is published by OWASP under the BSD license. You should read and accept the
  * LICENSE before you use, modify, and/or redistribute this software.
- * 
+ *
  * @author Jeff Williams <a href="http://www.aspectsecurity.com">Aspect Security</a>
  * @created 2007
  */
@@ -29,7 +29,7 @@ import org.owasp.esapi.errors.ValidationException;
 /**
  * A ValidationRule performs syntax and possibly semantic validation of a single
  * piece of data from an untrusted source.
- * 
+ *
  * @author Jeff Williams (jeff.williams .at. aspectsecurity.com) <a
  *         href="http://www.aspectsecurity.com">Aspect Security</a>
  * @since June 1, 2007
@@ -37,166 +37,166 @@ import org.owasp.esapi.errors.ValidationException;
  */
 public abstract class BaseValidationRule implements ValidationRule {
 
-	private String typeName = null;
-	protected boolean allowNull = false;
-	protected Encoder encoder = null;
-	
-	private BaseValidationRule() {
-		// prevent use of no-arg constructor
-	}
-	
-	public BaseValidationRule( String typeName ) {
-		this();
-		setEncoder( ESAPI.encoder() );
-		setTypeName( typeName );
-	}
-	
-	public BaseValidationRule( String typeName, Encoder encoder ) {
-		this();
-		setEncoder( encoder );
-		setTypeName( typeName );
-	}
-	
+    private String typeName = null;
+    protected boolean allowNull = false;
+    protected Encoder encoder = null;
+
+    private BaseValidationRule() {
+        // prevent use of no-arg constructor
+    }
+
+    public BaseValidationRule( String typeName ) {
+        this();
+        setEncoder( ESAPI.encoder() );
+        setTypeName( typeName );
+    }
+
+    public BaseValidationRule( String typeName, Encoder encoder ) {
+        this();
+        setEncoder( encoder );
+        setTypeName( typeName );
+    }
+
     /**
      * {@inheritDoc}
-	 */
-	public void setAllowNull( boolean flag ) {
-		allowNull = flag;
-	}
+     */
+    public void setAllowNull( boolean flag ) {
+        allowNull = flag;
+    }
 
     /**
      * {@inheritDoc}
-	 */
-	public String getTypeName() {
-		return typeName;
-	}
-	
+     */
+    public String getTypeName() {
+        return typeName;
+    }
+
     /**
      * {@inheritDoc}
-	 */
-	public final void setTypeName( String typeName ) {
-		this.typeName = typeName;
-	}
-	
+     */
+    public final void setTypeName( String typeName ) {
+        this.typeName = typeName;
+    }
+
     /**
      * {@inheritDoc}
-	 */
-	public final void setEncoder( Encoder encoder ) {
-		this.encoder = encoder;
-	}
-	
+     */
+    public final void setEncoder( Encoder encoder ) {
+        this.encoder = encoder;
+    }
+
     /**
      * {@inheritDoc}
-	 */
-	public void assertValid( String context, String input ) throws ValidationException {
-		getValid( context, input );
-	}
+     */
+    public void assertValid( String context, String input ) throws ValidationException {
+        getValid( context, input );
+    }
 
     /**
      * {@inheritDoc}
-	 */
-	public Object getValid( String context, String input, ValidationErrorList errorList ) throws ValidationException {
-		Object valid = null;
-		try {
-			valid = getValid( context, input );
-		} catch (ValidationException e) {
-			if( errorList == null) { 
-				throw e;
-			} else {
-				errorList.addError(context, e);
-			}
-		}
-		return valid;
-	}
-	
+     */
+    public Object getValid( String context, String input, ValidationErrorList errorList ) throws ValidationException {
+        Object valid = null;
+        try {
+            valid = getValid( context, input );
+        } catch (ValidationException e) {
+            if( errorList == null) {
+                throw e;
+            } else {
+                errorList.addError(context, e);
+            }
+        }
+        return valid;
+    }
+
     /**
      * {@inheritDoc}
-	 */
-	public Object getSafe( String context, String input ) {
-		Object valid = null;
-		try {
-			valid = getValid( context, input );
-		} catch ( ValidationException e ) {
-			return sanitize( context, input );
-		}
-		return valid;
-	}
-
-	/**
-	 * The method is similar to ValidationRuile.getSafe except that it returns a
-	 * harmless object that <b>may or may not have any similarity to the original
-	 * input (in some cases you may not care)</b>. In most cases this should be the
-	 * same as the getSafe method only instead of throwing an exception, return
-	 * some default value.
-	 * 
-	 * @param context
-	 * @param input
-	 * @return a parsed version of the input or a default value.
-	 */
-	protected abstract Object sanitize( String context, String input );
-	
+     */
+    public Object getSafe( String context, String input ) {
+        Object valid = null;
+        try {
+            valid = getValid( context, input );
+        } catch ( ValidationException e ) {
+            return sanitize( context, input );
+        }
+        return valid;
+    }
+
+    /**
+     * The method is similar to ValidationRuile.getSafe except that it returns a
+     * harmless object that <b>may or may not have any similarity to the original
+     * input (in some cases you may not care)</b>. In most cases this should be the
+     * same as the getSafe method only instead of throwing an exception, return
+     * some default value.
+     *
+     * @param context
+     * @param input
+     * @return a parsed version of the input or a default value.
+     */
+    protected abstract Object sanitize( String context, String input );
+
     /**
      * {@inheritDoc}
-	 */
-	public boolean isValid( String context, String input ) {
-		boolean valid = false;
-		try {
-			getValid( context, input );
-			valid = true;
-		} catch( Exception e ) {
-			valid = false;
-		}
-		
-		return valid;
-	}
+     */
+    public boolean isValid( String context, String input ) {
+        boolean valid = false;
+        try {
+            getValid( context, input );
+            valid = true;
+        } catch( Exception e ) {
+            valid = false;
+        }
+
+        return valid;
+    }
 
     /**
      * {@inheritDoc}
-	 */
-	public String whitelist( String input, char[] whitelist) {
-		return whitelist(input, charArrayToSet(whitelist));
-	}
-	
-	/**
-	 * Removes characters that aren't in the whitelist from the input String.  
-	 * O(input.length) whitelist performance
-	 * @param input String to be sanitized
-	 * @param whitelist allowed characters
-	 * @return input stripped of all chars that aren't in the whitelist 
-	 */
-	public String whitelist( String input, Set<Character> whitelist) {
-		StringBuilder stripped = new StringBuilder();
-		for (int i = 0; i < input.length(); i++) {
-			char c = input.charAt(i);
-			if (whitelist.contains(c)) {
-				stripped.append(c);
-			}
-		}
-		return stripped.toString();
-	}
-	
-	// CHECKME should be moved to some utility class (Would potentially be used by new EncoderConstants class)
-	// Is there a standard way to convert an array of primitives to a Collection
-	/**
-	 * Convert an array of characters to a {@code Set<Character>} (so duplicates
-	 * are removed).
-	 * @param array The character array.
-	 * @return A {@code Set<Character>} of the unique characters from {@code array}
-	 *         is returned.
-	 */
-	public static Set<Character> charArrayToSet(char[] array) {
-		Set<Character> toReturn = new HashSet<Character>(array.length);
-		for (char c : array) {
-			toReturn.add(c);
-		}
-		return toReturn;
-	}
-	
-	public boolean isAllowNull() {
-		return allowNull;
-	}
-
-	public Encoder getEncoder() {
-		return encoder;
-	}
+     */
+    public String whitelist( String input, char[] whitelist) {
+        return whitelist(input, charArrayToSet(whitelist));
+    }
+
+    /**
+     * Removes characters that aren't in the whitelist from the input String.
+     * O(input.length) whitelist performance
+     * @param input String to be sanitized
+     * @param whitelist allowed characters
+     * @return input stripped of all chars that aren't in the whitelist
+     */
+    public String whitelist( String input, Set<Character> whitelist) {
+        StringBuilder stripped = new StringBuilder();
+        for (int i = 0; i < input.length(); i++) {
+            char c = input.charAt(i);
+            if (whitelist.contains(c)) {
+                stripped.append(c);
+            }
+        }
+        return stripped.toString();
+    }
+
+    // CHECKME should be moved to some utility class (Would potentially be used by new EncoderConstants class)
+    // Is there a standard way to convert an array of primitives to a Collection
+    /**
+     * Convert an array of characters to a {@code Set<Character>} (so duplicates
+     * are removed).
+     * @param array The character array.
+     * @return A {@code Set<Character>} of the unique characters from {@code array}
+     *         is returned.
+     */
+    public static Set<Character> charArrayToSet(char[] array) {
+        Set<Character> toReturn = new HashSet<Character>(array.length);
+        for (char c : array) {
+            toReturn.add(c);
+        }
+        return toReturn;
+    }
+
+    public boolean isAllowNull() {
+        return allowNull;
+    }
+
+    public Encoder getEncoder() {
+        return encoder;
+    }
 }
diff --git a/src/main/java/org/owasp/esapi/reference/validation/CreditCardValidationRule.java b/src/main/java/org/owasp/esapi/reference/validation/CreditCardValidationRule.java
index 008f1a1..1e82c0e 100644
--- a/src/main/java/org/owasp/esapi/reference/validation/CreditCardValidationRule.java
+++ b/src/main/java/org/owasp/esapi/reference/validation/CreditCardValidationRule.java
@@ -1,15 +1,15 @@
 /**
  * OWASP Enterprise Security API (ESAPI)
- * 
+ *
  * This file is part of the Open Web Application Security Project (OWASP)
  * Enterprise Security API (ESAPI) project. For details, please see
  * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
  *
  * Copyright (c) 2007 - The OWASP Foundation
- * 
+ *
  * The ESAPI is published by OWASP under the BSD license. You should read and accept the
  * LICENSE before you use, modify, and/or redistribute this software.
- * 
+ *
  * @author Jeff Williams <a href="http://www.aspectsecurity.com">Aspect Security</a>
  * @created 2007
  */
@@ -26,140 +26,140 @@ import org.owasp.esapi.errors.ValidationException;
 /**
  * A validator performs syntax and possibly semantic validation of Credit Card
  * String from an untrusted source.
- * 
+ *
  * @author Jeff Williams (jeff.williams .at. aspectsecurity.com) <a
  *         href="http://www.aspectsecurity.com">Aspect Security</a>
  * @since June 1, 2007
  * @see org.owasp.esapi.Validator
  */
 public class CreditCardValidationRule extends BaseValidationRule {
-	private int maxCardLength = 19;
-	
-	/**
-	 * Key used to pull out encoder in configuration.  Prefixed with "Validator."
-	 */
-	protected static final String CREDIT_CARD_VALIDATOR_KEY = "CreditCard";
-	
-	private StringValidationRule ccrule = null; 
-	
-	/**
-	 * Creates a CreditCardValidator using the rule found in security configuration
-	 * @param typeName a description of the type of card being validated
-	 * @param encoder
-	 */
-	public CreditCardValidationRule( String typeName, Encoder encoder ) {
-		super( typeName, encoder );
-		ccrule = readDefaultCreditCardRule();
-	}
-	
-	public CreditCardValidationRule( String typeName, Encoder encoder, StringValidationRule validationRule ) {
-		super( typeName, encoder );
-		ccrule = validationRule;
-	}
-
-	private StringValidationRule readDefaultCreditCardRule() {
-		Pattern p = ESAPI.securityConfiguration().getValidationPattern( CREDIT_CARD_VALIDATOR_KEY );
-		StringValidationRule ccr = new StringValidationRule( "ccrule", encoder, p.pattern() );
-		ccr.setMaximumLength(getMaxCardLength());
-		ccr.setAllowNull( false );
-		return ccr;
-	}
-	
+    private int maxCardLength = 19;
+
+    /**
+     * Key used to pull out encoder in configuration.  Prefixed with "Validator."
+     */
+    protected static final String CREDIT_CARD_VALIDATOR_KEY = "CreditCard";
+
+    private StringValidationRule ccrule = null;
+
+    /**
+     * Creates a CreditCardValidator using the rule found in security configuration
+     * @param typeName a description of the type of card being validated
+     * @param encoder
+     */
+    public CreditCardValidationRule( String typeName, Encoder encoder ) {
+        super( typeName, encoder );
+        ccrule = readDefaultCreditCardRule();
+    }
+
+    public CreditCardValidationRule( String typeName, Encoder encoder, StringValidationRule validationRule ) {
+        super( typeName, encoder );
+        ccrule = validationRule;
+    }
+
+    private StringValidationRule readDefaultCreditCardRule() {
+        Pattern p = ESAPI.securityConfiguration().getValidationPattern( CREDIT_CARD_VALIDATOR_KEY );
+        StringValidationRule ccr = new StringValidationRule( "ccrule", encoder, p.pattern() );
+        ccr.setMaximumLength(getMaxCardLength());
+        ccr.setAllowNull( false );
+        return ccr;
+    }
+
     /**
      * {@inheritDoc}
      */
-	public String getValid( String context, String input ) throws ValidationException {
-		// CHECKME should this allow empty Strings? "   " us IsBlank instead?
-	    if ( StringUtilities.isEmpty(input) ) {
-			if (allowNull) {
-				return null;
-			}
-			throw new ValidationException( context + ": Input credit card required", "Input credit card required: context=" + context + ", input=" + input, context );
-	    }
-	    
-	    String canonical = ccrule.getValid( context, input );
-
-		if( ! validCreditCardFormat(canonical)) {
-			throw new ValidationException( context + ": Invalid credit card input", "Invalid credit card input: context=" + context, context );
-		}
-		
-		return canonical;	    
-	}
-
-	/**
-	 * Performs additional validation on the card nummber.
-	 * This implementation performs Luhn algorithm checking
-	 * @param ccNum number to be validated
-	 * @return true if the ccNum passes the Luhn Algorithm
-	 */
-	protected boolean validCreditCardFormat(String ccNum) {
-		
-	    StringBuilder digitsOnly = new StringBuilder();
-		char c;
-		for (int i = 0; i < ccNum.length(); i++) {
-			c = ccNum.charAt(i);
-			if (Character.isDigit(c)) {
-				digitsOnly.append(c);
-			}
-		}
-	
-		int sum = 0;
-		int digit = 0;
-		int addend = 0;
-		boolean timesTwo = false;
-	
-		for (int i = digitsOnly.length() - 1; i >= 0; i--) {
-			// guaranteed to be an int
-			digit = Integer.valueOf(digitsOnly.substring(i, i + 1));
-			if (timesTwo) {
-				addend = digit * 2;
-				if (addend > 9) {
-					addend -= 9;
-				}
-			} else {
-				addend = digit;
-			}
-			sum += addend;
-			timesTwo = !timesTwo;
-		}
-
-		return sum % 10 == 0; 
-	
-	}
-	
+    public String getValid( String context, String input ) throws ValidationException {
+        // CHECKME should this allow empty Strings? "   " us IsBlank instead?
+        if ( StringUtilities.isEmpty(input) ) {
+            if (allowNull) {
+                return null;
+            }
+            throw new ValidationException( context + ": Input credit card required", "Input credit card required: context=" + context + ", input=" + input, context );
+        }
+
+        String canonical = ccrule.getValid( context, input );
+
+        if( ! validCreditCardFormat(canonical)) {
+            throw new ValidationException( context + ": Invalid credit card input", "Invalid credit card input: context=" + context, context );
+        }
+
+        return canonical;
+    }
+
+    /**
+     * Performs additional validation on the card nummber.
+     * This implementation performs Luhn algorithm checking
+     * @param ccNum number to be validated
+     * @return true if the ccNum passes the Luhn Algorithm
+     */
+    protected boolean validCreditCardFormat(String ccNum) {
+
+        StringBuilder digitsOnly = new StringBuilder();
+        char c;
+        for (int i = 0; i < ccNum.length(); i++) {
+            c = ccNum.charAt(i);
+            if (Character.isDigit(c)) {
+                digitsOnly.append(c);
+            }
+        }
+
+        int sum = 0;
+        int digit = 0;
+        int addend = 0;
+        boolean timesTwo = false;
+
+        for (int i = digitsOnly.length() - 1; i >= 0; i--) {
+            // guaranteed to be an int
+            digit = Integer.valueOf(digitsOnly.substring(i, i + 1));
+            if (timesTwo) {
+                addend = digit * 2;
+                if (addend > 9) {
+                    addend -= 9;
+                }
+            } else {
+                addend = digit;
+            }
+            sum += addend;
+            timesTwo = !timesTwo;
+        }
+
+        return sum % 10 == 0;
+
+    }
+
     /**
      * {@inheritDoc}
      */
-	@Override
-	public String sanitize( String context, String input ) {
-		return whitelist( input, EncoderConstants.CHAR_DIGITS );
-	}
-
-	/**
-	 * @param ccrule the ccrule to set
-	 */
-	public void setStringValidatorRule(StringValidationRule ccrule) {
-		this.ccrule = ccrule;
-	}
-
-	/**
-	 * @return the ccrule
-	 */
-	public StringValidationRule getStringValidatorRule() {
-		return ccrule;
-	}
-
-	/**
-	 * @param maxCardLength the maxCardLength to set
-	 */
-	public void setMaxCardLength(int maxCardLength) {
-		this.maxCardLength = maxCardLength;
-	}
-
-	/**
-	 * @return the maxCardLength
-	 */
-	public int getMaxCardLength() {
-		return maxCardLength;
-	}
+    @Override
+    public String sanitize( String context, String input ) {
+        return whitelist( input, EncoderConstants.CHAR_DIGITS );
+    }
+
+    /**
+     * @param ccrule the ccrule to set
+     */
+    public void setStringValidatorRule(StringValidationRule ccrule) {
+        this.ccrule = ccrule;
+    }
+
+    /**
+     * @return the ccrule
+     */
+    public StringValidationRule getStringValidatorRule() {
+        return ccrule;
+    }
+
+    /**
+     * @param maxCardLength the maxCardLength to set
+     */
+    public void setMaxCardLength(int maxCardLength) {
+        this.maxCardLength = maxCardLength;
+    }
+
+    /**
+     * @return the maxCardLength
+     */
+    public int getMaxCardLength() {
+        return maxCardLength;
+    }
 }
diff --git a/src/main/java/org/owasp/esapi/reference/validation/DateValidationRule.java b/src/main/java/org/owasp/esapi/reference/validation/DateValidationRule.java
index dd600d8..3408004 100644
--- a/src/main/java/org/owasp/esapi/reference/validation/DateValidationRule.java
+++ b/src/main/java/org/owasp/esapi/reference/validation/DateValidationRule.java
@@ -1,15 +1,15 @@
 /**
  * OWASP Enterprise Security API (ESAPI)
- * 
+ *
  * This file is part of the Open Web Application Security Project (OWASP)
  * Enterprise Security API (ESAPI) project. For details, please see
  * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
  *
  * Copyright (c) 2007 - The OWASP Foundation
- * 
+ *
  * The ESAPI is published by OWASP under the BSD license. You should read and accept the
  * LICENSE before you use, modify, and/or redistribute this software.
- * 
+ *
  * @author Jeff Williams <a href="http://www.aspectsecurity.com">Aspect Security</a>
  * @created 2007
  */
@@ -27,31 +27,31 @@ import org.owasp.esapi.errors.ValidationException;
 /**
  * A validator performs syntax and possibly semantic validation of a single
  * piece of data from an untrusted source.
- * 
+ *
  * @author Jeff Williams (jeff.williams .at. aspectsecurity.com) <a
  *         href="http://www.aspectsecurity.com">Aspect Security</a>
  * @since June 1, 2007
  * @see org.owasp.esapi.Validator
  */
 public class DateValidationRule extends BaseValidationRule {
-	private DateFormat format = DateFormat.getDateInstance();
-	
-	public DateValidationRule( String typeName, Encoder encoder, DateFormat newFormat ) {
-		super( typeName, encoder );      
-		setDateFormat( newFormat );
-	}
-	
+    private DateFormat format = DateFormat.getDateInstance();
+
+    public DateValidationRule( String typeName, Encoder encoder, DateFormat newFormat ) {
+        super( typeName, encoder );
+        setDateFormat( newFormat );
+    }
+
     public final void setDateFormat( DateFormat newFormat ) {
         if (newFormat == null) {
-			throw new IllegalArgumentException("DateValidationRule.setDateFormat requires a non-null DateFormat");
-		}
-    	// CHECKME fail fast?
-/*		
-  		try {
-			newFormat.parse(new Date());
-		} catch (ParseException e) {
-			throw new IllegalArgumentException(e);
-		}
+            throw new IllegalArgumentException("DateValidationRule.setDateFormat requires a non-null DateFormat");
+        }
+        // CHECKME fail fast?
+/*
+          try {
+            newFormat.parse(new Date());
+        } catch (ParseException e) {
+            throw new IllegalArgumentException(e);
+        }
 */
         this.format = newFormat;
         this.format.setLenient( ESAPI.securityConfiguration().getLenientDatesAccepted() );
@@ -60,21 +60,21 @@ public class DateValidationRule extends BaseValidationRule {
     /**
      * {@inheritDoc}
      */
-	public Date getValid( String context, String input ) throws ValidationException {
-		return safelyParse(context, input, false);
-	}
+    public Date getValid( String context, String input ) throws ValidationException {
+        return safelyParse(context, input, false);
+    }
 
     /**
      * {@inheritDoc}
      */
-	@Override
-	public Date sanitize( String context, String input )  {
-		return sanitize(context, input, null);
-	}
-	
-	/**
+    @Override
+    public Date sanitize( String context, String input )  {
+        return sanitize(context, input, null);
+    }
+
+    /**
      * Same as sanitize(String, String) except it returns any ValidationException generated in the provided errorList.
-     * 
+     *
      *   @param errorList The error list to add any ValidationException to.
      *   @return The valid sanitized Date, or Date(0) if the supplied input was not a valid date.
      */
@@ -89,35 +89,35 @@ public class DateValidationRule extends BaseValidationRule {
         }
         return date;
     }
-	    
-	private Date safelyParse(String context, String input, boolean sanitize)
-			throws ValidationException {
-		// CHECKME should this allow empty Strings? "   " use IsBlank instead?
-		if (StringUtilities.isEmpty(input)) {
-			if (allowNull) {
-				return null;
-			}
-			throw new ValidationException(context + ": Input date required",
-					"Input date required: context=" + context + ", input="
-							+ input, context);
-		}
 
-		 String canonical = encoder.canonicalize(input);
-	        try {
-	            Date rval = format.parse(canonical);
-	            if (sanitize) {
-	                String cycled = format.format(rval);
-	                if (!cycled.equals(canonical)) {
-	                    throw new Exception("Parameter date is not a clean translation between String and Date contexts.  Check input for additional characters");
-	                }
-	            }
-	            return rval;
-		} catch (Exception e) {
-			throw new ValidationException(context
-					+ ": Invalid date must follow the "
-					+ format.getNumberFormat() + " format",
-					"Invalid date: context=" + context + ", format=" + format
-							+ ", input=" + input, e, context);
-		}
-	}
+    private Date safelyParse(String context, String input, boolean sanitize)
+            throws ValidationException {
+        // CHECKME should this allow empty Strings? "   " use IsBlank instead?
+        if (StringUtilities.isEmpty(input)) {
+            if (allowNull) {
+                return null;
+            }
+            throw new ValidationException(context + ": Input date required",
+                    "Input date required: context=" + context + ", input="
+                            + input, context);
+        }
+
+         String canonical = encoder.canonicalize(input);
+            try {
+                Date rval = format.parse(canonical);
+                if (sanitize) {
+                    String cycled = format.format(rval);
+                    if (!cycled.equals(canonical)) {
+                        throw new Exception("Parameter date is not a clean translation between String and Date contexts.  Check input for additional characters");
+                    }
+                }
+                return rval;
+        } catch (Exception e) {
+            throw new ValidationException(context
+                    + ": Invalid date must follow the "
+                    + format.getNumberFormat() + " format",
+                    "Invalid date: context=" + context + ", format=" + format
+                            + ", input=" + input, e, context);
+        }
+    }
 }
diff --git a/src/main/java/org/owasp/esapi/reference/validation/HTMLValidationRule.java b/src/main/java/org/owasp/esapi/reference/validation/HTMLValidationRule.java
index a1e725f..87de340 100644
--- a/src/main/java/org/owasp/esapi/reference/validation/HTMLValidationRule.java
+++ b/src/main/java/org/owasp/esapi/reference/validation/HTMLValidationRule.java
@@ -30,7 +30,10 @@ import org.owasp.esapi.SecurityConfiguration;
 import org.owasp.esapi.StringUtilities;
 import org.owasp.esapi.errors.ConfigurationException;
 import org.owasp.esapi.errors.ValidationException;
-import org.owasp.esapi.reference.DefaultSecurityConfiguration.DefaultSearchPath;
+import org.owasp.esapi.PropNames.DefaultSearchPath;
+import static org.owasp.esapi.PropNames.VALIDATOR_HTML_VALIDATION_ACTION;
+import static org.owasp.esapi.PropNames.VALIDATOR_HTML_VALIDATION_CONFIGURATION_FILE;
+
 import org.owasp.validator.html.AntiSamy;
 import org.owasp.validator.html.CleanResults;
 import org.owasp.validator.html.Policy;
@@ -49,77 +52,75 @@ import org.owasp.validator.html.ScanException;
  */
 public class HTMLValidationRule extends StringValidationRule {
 
-	/** OWASP AntiSamy markup verification policy */
-	private static Policy antiSamyPolicy = null;
-	private static final Logger LOGGER = ESAPI.getLogger( "HTMLValidationRule" );
-	private static final String ANTISAMYPOLICY_FILENAME = "antisamy-esapi.xml";
-
-	/*package */ static InputStream getResourceStreamFromClassLoader(String contextDescription, ClassLoader classLoader, String fileName, List<String> searchPaths) {
-	    InputStream result = null;
-	    
-	    for (String searchPath: searchPaths) {
-	        result = classLoader.getResourceAsStream(searchPath + fileName);
-	        
-	        if (result != null) {
-	            LOGGER.info(Logger.EVENT_SUCCESS, "SUCCESSFULLY LOADED " + fileName + " via the CLASSPATH from '" + 
-	                    searchPath + "' using " + contextDescription + "!");
-	                break; 
-	        }
-	    }
-	    
-	    return result;
-	}
-	
-	/*package */ static InputStream getResourceStreamFromClasspath(String fileName) {
-	    LOGGER.info(Logger.EVENT_FAILURE, "Loading " + fileName + " from classpaths");
-		
-	    InputStream resourceStream = null;
-		
-		List<String> orderedSearchPaths = Arrays.asList(DefaultSearchPath.ROOT.value(), 
-		        DefaultSearchPath.RESOURCE_DIRECTORY.value(),
-		        DefaultSearchPath.DOT_ESAPI.value(),
-		        DefaultSearchPath.ESAPI.value(),
-		        DefaultSearchPath.RESOURCES.value(),
-		        DefaultSearchPath.SRC_MAIN_RESOURCES.value());
-		
-		resourceStream = getResourceStreamFromClassLoader("current thread context class loader", Thread.currentThread().getContextClassLoader(), fileName, orderedSearchPaths);
-		 
-		//I'm lazy. Using ternary for shorthand "if null then do next thing"  Harder to read, sorry
-		resourceStream = resourceStream != null ? resourceStream : getResourceStreamFromClassLoader("system class loader", ClassLoader.getSystemClassLoader(), fileName, orderedSearchPaths);
-		resourceStream = resourceStream != null ? resourceStream : getResourceStreamFromClassLoader("class loader for DefaultSecurityConfiguration class", ESAPI.securityConfiguration().getClass().getClassLoader(), fileName, orderedSearchPaths);
-		
-		return resourceStream;
-	}
-	
-	/*package */ static Policy loadAntisamyPolicy(String antisamyPolicyFilename) throws IOException, PolicyException {
-	    InputStream resourceStream = null;
-	    SecurityConfiguration secCfg = ESAPI.securityConfiguration();
-	    
-	    //Rather than catching the IOException from the resource stream, let's ask if the file exists to give this a best-case resolution.
-	    //This helps with the IOException handling too.  If the file is there and we get an IOException from the SecurityConfiguration, then the file is there and something else is wrong (FAIL -- don't try the other path)
-	    File file = secCfg.getResourceFile(antisamyPolicyFilename);
-    
+    /** OWASP AntiSamy markup verification policy */
+    private static Policy antiSamyPolicy = null;
+    private static final Logger LOGGER = ESAPI.getLogger( "HTMLValidationRule" );
+    private static final String ANTISAMYPOLICY_FILENAME = "antisamy-esapi.xml";
+
+    /*package */ static InputStream getResourceStreamFromClassLoader(String contextDescription, ClassLoader classLoader, String fileName, List<String> searchPaths) {
+        InputStream result = null;
+
+        for (String searchPath: searchPaths) {
+            result = classLoader.getResourceAsStream(searchPath + fileName);
+
+            if (result != null) {
+                LOGGER.info(Logger.EVENT_SUCCESS, "SUCCESSFULLY LOADED " + fileName + " via the CLASSPATH from '" +
+                        searchPath + "' using " + contextDescription + "!");
+                    break;
+            }
+        }
+
+        return result;
+    }
+
+    /*package */ static InputStream getResourceStreamFromClasspath(String fileName) {
+        LOGGER.info(Logger.EVENT_FAILURE, "Loading " + fileName + " from classpaths");
+
+        InputStream resourceStream = null;
+
+        List<String> orderedSearchPaths = Arrays.asList(DefaultSearchPath.ROOT.value(),
+                DefaultSearchPath.RESOURCE_DIRECTORY.value(),
+                DefaultSearchPath.DOT_ESAPI.value(),
+                DefaultSearchPath.ESAPI.value(),
+                DefaultSearchPath.RESOURCES.value(),
+                DefaultSearchPath.SRC_MAIN_RESOURCES.value());
+
+        resourceStream = getResourceStreamFromClassLoader("current thread context class loader", Thread.currentThread().getContextClassLoader(), fileName, orderedSearchPaths);
+
+        //I'm lazy. Using ternary for shorthand "if null then do next thing"  Harder to read, sorry
+        resourceStream = resourceStream != null ? resourceStream : getResourceStreamFromClassLoader("system class loader", ClassLoader.getSystemClassLoader(), fileName, orderedSearchPaths);
+        resourceStream = resourceStream != null ? resourceStream : getResourceStreamFromClassLoader("class loader for DefaultSecurityConfiguration class", ESAPI.securityConfiguration().getClass().getClassLoader(), fileName, orderedSearchPaths);
+
+        return resourceStream;
+    }
+
+    /*package */ static Policy loadAntisamyPolicy(String antisamyPolicyFilename) throws IOException, PolicyException {
+        InputStream resourceStream = null;
+        SecurityConfiguration secCfg = ESAPI.securityConfiguration();
+
+        //Rather than catching the IOException from the resource stream, let's ask if the file exists to give this a best-case resolution.
+        //This helps with the IOException handling too.  If the file is there and we get an IOException from the SecurityConfiguration, then the file is there and something else is wrong (FAIL -- don't try the other path)
+        File file = secCfg.getResourceFile(antisamyPolicyFilename);
+
         resourceStream = file == null ? getResourceStreamFromClasspath(antisamyPolicyFilename) : secCfg.getResourceStream(antisamyPolicyFilename);
         return resourceStream == null ? null : Policy.getInstance(resourceStream);
-	}
+    }
 
-	/*package */ static String resolveAntisamyFilename() {
-	    String antisamyPolicyFilename = ANTISAMYPOLICY_FILENAME;
+    /*package */ static String resolveAntisamyFilename() {
+        String antisamyPolicyFilename = ANTISAMYPOLICY_FILENAME;
         try {
-            antisamyPolicyFilename = ESAPI.securityConfiguration().getStringProp(
-                    // Future: This will be moved to a new PropNames class
-                org.owasp.esapi.reference.DefaultSecurityConfiguration.VALIDATOR_HTML_VALIDATION_CONFIGURATION_FILE );
+            antisamyPolicyFilename = ESAPI.securityConfiguration().getStringProp( VALIDATOR_HTML_VALIDATION_CONFIGURATION_FILE );
         } catch (ConfigurationException cex) {
-            
-            LOGGER.info(Logger.EVENT_FAILURE, "ESAPI property " + 
-                           org.owasp.esapi.reference.DefaultSecurityConfiguration.VALIDATOR_HTML_VALIDATION_CONFIGURATION_FILE +
+
+            LOGGER.info(Logger.EVENT_FAILURE, "ESAPI property " +
+                           VALIDATOR_HTML_VALIDATION_CONFIGURATION_FILE +
                            " not set, using default value: " + ANTISAMYPOLICY_FILENAME);
         }
         return antisamyPolicyFilename;
-	}
-	
-	/*package */ static void configureInstance() {
-	    String antisamyPolicyFilename = resolveAntisamyFilename();
+    }
+
+    /*package */ static void configureInstance() {
+        String antisamyPolicyFilename = resolveAntisamyFilename();
 
         try {
             antiSamyPolicy = loadAntisamyPolicy(antisamyPolicyFilename);
@@ -130,50 +131,50 @@ public class HTMLValidationRule extends StringValidationRule {
             //Thrown if the resource stream was created, but the contents of the file are not compatible with antisamy expectations.
             throw new ConfigurationException("Couldn't parse " + antisamyPolicyFilename, e);
         }
-        
+
         if (antiSamyPolicy == null) {
             throw new ConfigurationException("Couldn't find " + antisamyPolicyFilename);
         }
 
-	}
-	
-	static {		
-	    configureInstance();
-	}
+    }
+
+    static {
+        configureInstance();
+    }
 
-	public HTMLValidationRule( String typeName ) {
-		super( typeName );
-	}
+    public HTMLValidationRule( String typeName ) {
+        super( typeName );
+    }
 
-	public HTMLValidationRule( String typeName, Encoder encoder ) {
-		super( typeName, encoder );
-	}
+    public HTMLValidationRule( String typeName, Encoder encoder ) {
+        super( typeName, encoder );
+    }
 
-	public HTMLValidationRule( String typeName, Encoder encoder, String whitelistPattern ) {
-		super( typeName, encoder, whitelistPattern );
-	}
+    public HTMLValidationRule( String typeName, Encoder encoder, String whitelistPattern ) {
+        super( typeName, encoder, whitelistPattern );
+    }
 
     /**
      * {@inheritDoc}
      */
-	@Override
-	public String getValid( String context, String input ) throws ValidationException {
-		return invokeAntiSamy( context, input );
-	}
+    @Override
+    public String getValid( String context, String input ) throws ValidationException {
+        return invokeAntiSamy( context, input );
+    }
 
     /**
      * {@inheritDoc}
      */
-	@Override
-	public String sanitize( String context, String input ) {
-		String safe = "";
-		try {
-			safe = invokeAntiSamy( context, input );
-		} catch( ValidationException e ) {
-			// just return safe
-		}
-		return safe;
-	}
+    @Override
+    public String sanitize( String context, String input ) {
+        String safe = "";
+        try {
+            safe = invokeAntiSamy( context, input );
+        } catch( ValidationException e ) {
+            // just return safe
+        }
+        return safe;
+    }
 
     /**
      * Check whether we want the legacy behavior ("clean") or the presumably intended
@@ -197,9 +198,7 @@ public class HTMLValidationRule extends StringValidationRule {
             // Hindsight: maybe we should have getBooleanProp(), getStringProp(),
             // getIntProp() methods that take a default arg as well?
             // At least for ESAPI 3.x.
-            propValue = ESAPI.securityConfiguration().getStringProp(
-                                // Future: This will be moved to a new PropNames class
-                            org.owasp.esapi.reference.DefaultSecurityConfiguration.VALIDATOR_HTML_VALIDATION_ACTION );
+            propValue = ESAPI.securityConfiguration().getStringProp( VALIDATOR_HTML_VALIDATION_ACTION );
             switch ( propValue.toLowerCase() ) {
                 case "throw":
                     legacy = false;     // New, presumably correct behavior, as addressed by GitHub issue 509
@@ -208,8 +207,8 @@ public class HTMLValidationRule extends StringValidationRule {
                     legacy = true;      // Give the caller that legacy behavior of sanitizing.
                     break;
                 default:
-                    LOGGER.warning(Logger.EVENT_FAILURE, "ESAPI property " + 
-                                   org.owasp.esapi.reference.DefaultSecurityConfiguration.VALIDATOR_HTML_VALIDATION_ACTION +
+                    LOGGER.warning(Logger.EVENT_FAILURE, "ESAPI property " +
+                                   VALIDATOR_HTML_VALIDATION_ACTION +
                                    " was set to \"" + propValue + "\".  Must be set to either \"clean\"" +
                                    " (the default for legacy support) or \"throw\"; assuming \"clean\" for legacy behavior.");
                     legacy = true;
@@ -218,8 +217,8 @@ public class HTMLValidationRule extends StringValidationRule {
         } catch( ConfigurationException cex ) {
             // OPEN ISSUE: Should we log this? I think so. Convince me otherwise. But maybe
             //             we should only log it once or every Nth time??
-            LOGGER.warning(Logger.EVENT_FAILURE, "ESAPI property " + 
-                           org.owasp.esapi.reference.DefaultSecurityConfiguration.VALIDATOR_HTML_VALIDATION_ACTION +
+            LOGGER.warning(Logger.EVENT_FAILURE, "ESAPI property " +
+                           VALIDATOR_HTML_VALIDATION_ACTION +
                            " must be set to either \"clean\" (the default for legacy support) or \"throw\"; assuming \"clean\"",
                            cex);
         }
@@ -227,37 +226,37 @@ public class HTMLValidationRule extends StringValidationRule {
         return legacy;
     }
 
-	private String invokeAntiSamy( String context, String input ) throws ValidationException {
-		// CHECKME should this allow empty Strings? "   " use IsBlank instead?
-	    if ( StringUtilities.isEmpty(input) ) {
-			if (allowNull) {
-				return null;
-			}
-			throw new ValidationException( context + " is required", "AntiSamy validation error: context=" + context + ", input=" + input, context );
-	    }
+    private String invokeAntiSamy( String context, String input ) throws ValidationException {
+        // CHECKME should this allow empty Strings? "   " use IsBlank instead?
+        if ( StringUtilities.isEmpty(input) ) {
+            if (allowNull) {
+                return null;
+            }
+            throw new ValidationException( context + " is required", "AntiSamy validation error: context=" + context + ", input=" + input, context );
+        }
 
-		String canonical = super.getValid( context, input );
+        String canonical = super.getValid( context, input );
 
-		try {
-			AntiSamy as = new AntiSamy();
-			CleanResults test = as.scan(canonical, antiSamyPolicy);     // Uses AntiSamy.DOM scanner.
+        try {
+            AntiSamy as = new AntiSamy();
+            CleanResults test = as.scan(canonical, antiSamyPolicy);     // Uses AntiSamy.DOM scanner.
 
-			List<String> errors = test.getErrorMessages();
-			if ( !errors.isEmpty() ) {
+            List<String> errors = test.getErrorMessages();
+            if ( !errors.isEmpty() ) {
                 if ( legacyHtmlValidation() ) {        // See GitHub issues 509 and 521
                     LOGGER.info(Logger.SECURITY_FAILURE, "Cleaned up invalid HTML input: " + errors );
                 } else {
-				    throw new ValidationException( context + ": Invalid HTML input", "Invalid HTML input does not follow rules in antisamy-esapi.xml: context=" + context + " errors=" + errors.toString());
+                    throw new ValidationException( context + ": Invalid HTML input", "Invalid HTML input does not follow rules in antisamy-esapi.xml: context=" + context + " errors=" + errors.toString());
                 }
-			}
+            }
 
-			return test.getCleanHTML().trim();
+            return test.getCleanHTML().trim();
 
-		} catch (ScanException e) {
-			throw new ValidationException( context + ": Invalid HTML input", "Invalid HTML input: context=" + context + " error=" + e.getMessage(), e, context );
-		} catch (PolicyException e) {
-			throw new ValidationException( context + ": Invalid HTML input", "Invalid HTML input does not follow rules in antisamy-esapi.xml: context=" + context + " error=" + e.getMessage(), e, context );
-		}
-	}
+        } catch (ScanException e) {
+            throw new ValidationException( context + ": Invalid HTML input", "Invalid HTML input: context=" + context + " error=" + e.getMessage(), e, context );
+        } catch (PolicyException e) {
+            throw new ValidationException( context + ": Invalid HTML input", "Invalid HTML input does not follow rules in antisamy-esapi.xml: context=" + context + " error=" + e.getMessage(), e, context );
+        }
+    }
 }
 
diff --git a/src/main/java/org/owasp/esapi/reference/validation/IntegerValidationRule.java b/src/main/java/org/owasp/esapi/reference/validation/IntegerValidationRule.java
index e010377..3137781 100644
--- a/src/main/java/org/owasp/esapi/reference/validation/IntegerValidationRule.java
+++ b/src/main/java/org/owasp/esapi/reference/validation/IntegerValidationRule.java
@@ -1,15 +1,15 @@
 /**
  * OWASP Enterprise Security API (ESAPI)
- * 
+ *
  * This file is part of the Open Web Application Security Project (OWASP)
  * Enterprise Security API (ESAPI) project. For details, please see
  * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
  *
  * Copyright (c) 2007 - The OWASP Foundation
- * 
+ *
  * The ESAPI is published by OWASP under the BSD license. You should read and accept the
  * LICENSE before you use, modify, and/or redistribute this software.
- * 
+ *
  * @author Jeff Williams <a href="http://www.aspectsecurity.com">Aspect Security</a>
  * @created 2007
  */
@@ -23,73 +23,73 @@ import org.owasp.esapi.errors.ValidationException;
 /**
  * A validator performs syntax and possibly semantic validation of a single
  * piece of data from an untrusted source.
- * 
+ *
  * @author Jeff Williams (jeff.williams .at. aspectsecurity.com) <a
  *         href="http://www.aspectsecurity.com">Aspect Security</a>
  * @since June 1, 2007
  * @see org.owasp.esapi.Validator
  */
 public class IntegerValidationRule extends BaseValidationRule {
-	
-	private int minValue = Integer.MIN_VALUE;
-	private int maxValue = Integer.MAX_VALUE;
-	
-	public IntegerValidationRule( String typeName, Encoder encoder ) {
-		super( typeName, encoder );
-	}
 
-	public IntegerValidationRule( String typeName, Encoder encoder, int minValue, int maxValue ) {
-		super( typeName, encoder );
-		this.minValue = minValue;
-		this.maxValue = maxValue;
-	}
+    private int minValue = Integer.MIN_VALUE;
+    private int maxValue = Integer.MAX_VALUE;
+
+    public IntegerValidationRule( String typeName, Encoder encoder ) {
+        super( typeName, encoder );
+    }
+
+    public IntegerValidationRule( String typeName, Encoder encoder, int minValue, int maxValue ) {
+        super( typeName, encoder );
+        this.minValue = minValue;
+        this.maxValue = maxValue;
+    }
+
+    public Integer getValid( String context, String input ) throws ValidationException {
+        return safelyParse(context, input);
+    }
+
+    private Integer safelyParse(String context, String input) throws ValidationException {
+        // do not allow empty Strings such as "   " - so trim to ensure
+        // isEmpty catches "    "
+        if (input != null) input = input.trim();
+
+        if ( StringUtilities.isEmpty(input) ) {
+            if (allowNull) {
+                return null;
+            }
+            throw new ValidationException( context + ": Input number required", "Input number required: context=" + context + ", input=" + input, context );
+        }
 
-	public Integer getValid( String context, String input ) throws ValidationException {
-		return safelyParse(context, input);
-	}
+        // canonicalize
+        String canonical = encoder.canonicalize( input );
 
-	private Integer safelyParse(String context, String input) throws ValidationException {
-		// do not allow empty Strings such as "   " - so trim to ensure 
-		// isEmpty catches "    "
-		if (input != null) input = input.trim();
-		
-	    if ( StringUtilities.isEmpty(input) ) {
-			if (allowNull) {
-				return null;
-			}
-			throw new ValidationException( context + ": Input number required", "Input number required: context=" + context + ", input=" + input, context );
-	    }
-	    
-	    // canonicalize
-	    String canonical = encoder.canonicalize( input );
+        if (minValue > maxValue) {
+            throw new ValidationException( context + ": Invalid number input: context", "Validation parameter error for number: maxValue ( " + maxValue + ") must be greater than minValue ( " + minValue + ") for " + context, context );
+        }
 
-		if (minValue > maxValue) {
-			throw new ValidationException( context + ": Invalid number input: context", "Validation parameter error for number: maxValue ( " + maxValue + ") must be greater than minValue ( " + minValue + ") for " + context, context );
-		}
-		
-		// validate min and max
-		try {
-			int i = Integer.valueOf(canonical);
-			if (i < minValue) {
-				throw new ValidationException( "Invalid number input must be between " + minValue + " and " + maxValue + ": context=" + context, "Invalid number input must be between " + minValue + " and " + maxValue + ": context=" + context + ", input=" + input, context );
-			}
-			if (i > maxValue) {
-				throw new ValidationException( "Invalid number input must be between " + minValue + " and " + maxValue + ": context=" + context, "Invalid number input must be between " + minValue + " and " + maxValue + ": context=" + context + ", input=" + input, context );
-			}			
-			return i;
-		} catch (NumberFormatException e) {
-			throw new ValidationException( context + ": Invalid number input", "Invalid number input format: context=" + context + ", input=" + input, e, context);
-		}
-	}
+        // validate min and max
+        try {
+            int i = Integer.valueOf(canonical);
+            if (i < minValue) {
+                throw new ValidationException( "Invalid number input must be between " + minValue + " and " + maxValue + ": context=" + context, "Invalid number input must be between " + minValue + " and " + maxValue + ": context=" + context + ", input=" + input, context );
+            }
+            if (i > maxValue) {
+                throw new ValidationException( "Invalid number input must be between " + minValue + " and " + maxValue + ": context=" + context, "Invalid number input must be between " + minValue + " and " + maxValue + ": context=" + context + ", input=" + input, context );
+            }
+            return i;
+        } catch (NumberFormatException e) {
+            throw new ValidationException( context + ": Invalid number input", "Invalid number input format: context=" + context + ", input=" + input, e, context);
+        }
+    }
 
-	@Override
-	public Integer sanitize( String context, String input ) {
-		Integer toReturn = Integer.valueOf( 0 );
-		try {
-			toReturn = safelyParse(context, input);
-		} catch (ValidationException e ) {
-			// do nothing
-		}
-		return toReturn;
-	}
+    @Override
+    public Integer sanitize( String context, String input ) {
+        Integer toReturn = Integer.valueOf( 0 );
+        try {
+            toReturn = safelyParse(context, input);
+        } catch (ValidationException e ) {
+            // do nothing
+        }
+        return toReturn;
+    }
 }
\ No newline at end of file
diff --git a/src/main/java/org/owasp/esapi/reference/validation/NumberValidationRule.java b/src/main/java/org/owasp/esapi/reference/validation/NumberValidationRule.java
index b5933a3..c19f2ab 100644
--- a/src/main/java/org/owasp/esapi/reference/validation/NumberValidationRule.java
+++ b/src/main/java/org/owasp/esapi/reference/validation/NumberValidationRule.java
@@ -1,15 +1,15 @@
 /**
  * OWASP Enterprise Security API (ESAPI)
- * 
+ *
  * This file is part of the Open Web Application Security Project (OWASP)
  * Enterprise Security API (ESAPI) project. For details, please see
  * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
  *
  * Copyright (c) 2007 - The OWASP Foundation
- * 
+ *
  * The ESAPI is published by OWASP under the BSD license. You should read and accept the
  * LICENSE before you use, modify, and/or redistribute this software.
- * 
+ *
  * @author Jeff Williams <a href="http://www.aspectsecurity.com">Aspect Security</a>
  * @created 2007
  */
@@ -25,122 +25,122 @@ import org.owasp.esapi.errors.ValidationException;
 /**
  * A validator performs syntax and possibly semantic validation of a single
  * piece of data from an untrusted source.
- * 
+ *
  * @author Jeff Williams (jeff.williams .at. aspectsecurity.com) <a
  *         href="http://www.aspectsecurity.com">Aspect Security</a>
  * @since June 1, 2007
  * @see org.owasp.esapi.Validator
  */
 public class NumberValidationRule extends BaseValidationRule {
-	
-	private double minValue = Double.NEGATIVE_INFINITY;
-	private double maxValue = Double.POSITIVE_INFINITY;
-	
-	public NumberValidationRule( String typeName, Encoder encoder ) {
-		super( typeName, encoder );
-	}
-
-	public NumberValidationRule( String typeName, Encoder encoder, double minValue, double maxValue ) {
-		super( typeName, encoder );
-		this.minValue = minValue;
-		this.maxValue = maxValue;
-	}
+
+    private double minValue = Double.NEGATIVE_INFINITY;
+    private double maxValue = Double.POSITIVE_INFINITY;
+
+    public NumberValidationRule( String typeName, Encoder encoder ) {
+        super( typeName, encoder );
+    }
+
+    public NumberValidationRule( String typeName, Encoder encoder, double minValue, double maxValue ) {
+        super( typeName, encoder );
+        this.minValue = minValue;
+        this.maxValue = maxValue;
+    }
 
     /**
      * {@inheritDoc}
      */
-	public Double getValid( String context, String input ) throws ValidationException {
-		return safelyParse(context, input);
-	}
-	
+    public Double getValid( String context, String input ) throws ValidationException {
+        return safelyParse(context, input);
+    }
+
     /**
      * {@inheritDoc}
      */
-	@Override
-	public Double sanitize( String context, String input ) {
-		Double toReturn = Double.valueOf(0);
-		try {
-			toReturn = safelyParse(context, input);
-		} catch (ValidationException e) {
-			// do nothing
-		}
-		return toReturn;
-	}
-	//
-	// These statics needed to detect double parsing DOS bug in Java
-	//
-	private static BigDecimal bigBad;
-	private static BigDecimal smallBad;
-
-	static {
-		
-		BigDecimal one = new BigDecimal(1);
-		BigDecimal two = new BigDecimal(2);
-		
-		BigDecimal tiny = one.divide(two.pow(1022));
-		
-		// 2^(-1022) ­ 2^(-1076)
-		bigBad = tiny.subtract(one.divide(two.pow(1076)));
-		//2^(-1022) ­ 2^(-1075)
-		smallBad = tiny.subtract(one.divide(two.pow(1075)));
-	}	
-
-	private Double safelyParse(String context, String input) throws ValidationException {
-
-		// CHECKME should this allow empty Strings? "   " us IsBlank instead?
-	    if ( StringUtilities.isEmpty(input) ) {
-			if (allowNull) {
-				return null;
-			}
-			throw new ValidationException( context + ": Input number required", "Input number required: context=" + context + ", input=" + input, context );
-	    }
-	    
-	    // canonicalize
-	    String canonical = encoder.canonicalize( input );
-
-	    //if MinValue is greater than maxValue then programmer is likely calling this wrong
-		if (minValue > maxValue) {
-			throw new ValidationException( context + ": Invalid number input: context", "Validation parameter error for number: maxValue ( " + maxValue + ") must be greater than minValue ( " + minValue + ") for " + context, context );
-		}
-		
-		//convert to BigDecimal so we can safely parse dangerous numbers to 
-		//check if the number may DOS the double parser
-		BigDecimal bd;
-		try {
-			bd = new BigDecimal(canonical);
-		} catch (NumberFormatException e) {
-			throw new ValidationException( context + ": Invalid number input", "Invalid number input format: context=" + context + ", input=" + input, e, context);
-		}
-		
-		// Thanks to Brian Chess for this suggestion
-		// Check if string input is in the "dangerous" double parsing range
-		if (bd.compareTo(smallBad) >= 0 && bd.compareTo(bigBad) <= 0) {
-			// if you get here you know you're looking at a bad value. The final
-			// value for any double in this range is supposed to be the following safe #			
-			return new Double("2.2250738585072014E-308");
-		}
-		
-		// the number is safe to parseDouble
-		Double d;
-		// validate min and max
-		try {
-			d = Double.valueOf(Double.parseDouble( canonical ));
-		} catch (NumberFormatException e) {
-			throw new ValidationException( context + ": Invalid number input", "Invalid number input format: context=" + context + ", input=" + input, e, context);
-		}
-	
-		if (d.isInfinite()) {
-			throw new ValidationException( "Invalid number input: context=" + context, "Invalid double input is infinite: context=" + context + ", input=" + input, context );
-	}
-		if (d.isNaN()) {
-			throw new ValidationException( "Invalid number input: context=" + context, "Invalid double input is not a number: context=" + context + ", input=" + input, context );
-		}
-		if (d.doubleValue() < minValue) {
-			throw new ValidationException( "Invalid number input must be between " + minValue + " and " + maxValue + ": context=" + context, "Invalid number input must be between " + minValue + " and " + maxValue + ": context=" + context + ", input=" + input, context );
-		}
-		if (d.doubleValue() > maxValue) {
-			throw new ValidationException( "Invalid number input must be between " + minValue + " and " + maxValue + ": context=" + context, "Invalid number input must be between " + minValue + " and " + maxValue + ": context=" + context + ", input=" + input, context );
-		}			
-		return d;
-	}
+    @Override
+    public Double sanitize( String context, String input ) {
+        Double toReturn = Double.valueOf(0);
+        try {
+            toReturn = safelyParse(context, input);
+        } catch (ValidationException e) {
+            // do nothing
+        }
+        return toReturn;
+    }
+    //
+    // These statics needed to detect double parsing DOS bug in Java
+    //
+    private static BigDecimal bigBad;
+    private static BigDecimal smallBad;
+
+    static {
+
+        BigDecimal one = new BigDecimal(1);
+        BigDecimal two = new BigDecimal(2);
+
+        BigDecimal tiny = one.divide(two.pow(1022));
+
+        // 2^(-1022) ­ 2^(-1076)
+        bigBad = tiny.subtract(one.divide(two.pow(1076)));
+        //2^(-1022) ­ 2^(-1075)
+        smallBad = tiny.subtract(one.divide(two.pow(1075)));
+    }
+
+    private Double safelyParse(String context, String input) throws ValidationException {
+
+        // CHECKME should this allow empty Strings? "   " us IsBlank instead?
+        if ( StringUtilities.isEmpty(input) ) {
+            if (allowNull) {
+                return null;
+            }
+            throw new ValidationException( context + ": Input number required", "Input number required: context=" + context + ", input=" + input, context );
+        }
+
+        // canonicalize
+        String canonical = encoder.canonicalize( input );
+
+        //if MinValue is greater than maxValue then programmer is likely calling this wrong
+        if (minValue > maxValue) {
+            throw new ValidationException( context + ": Invalid number input: context", "Validation parameter error for number: maxValue ( " + maxValue + ") must be greater than minValue ( " + minValue + ") for " + context, context );
+        }
+
+        //convert to BigDecimal so we can safely parse dangerous numbers to
+        //check if the number may DOS the double parser
+        BigDecimal bd;
+        try {
+            bd = new BigDecimal(canonical);
+        } catch (NumberFormatException e) {
+            throw new ValidationException( context + ": Invalid number input", "Invalid number input format: context=" + context + ", input=" + input, e, context);
+        }
+
+        // Thanks to Brian Chess for this suggestion
+        // Check if string input is in the "dangerous" double parsing range
+        if (bd.compareTo(smallBad) >= 0 && bd.compareTo(bigBad) <= 0) {
+            // if you get here you know you're looking at a bad value. The final
+            // value for any double in this range is supposed to be the following safe #
+            return new Double("2.2250738585072014E-308");
+        }
+
+        // the number is safe to parseDouble
+        Double d;
+        // validate min and max
+        try {
+            d = Double.valueOf(Double.parseDouble( canonical ));
+        } catch (NumberFormatException e) {
+            throw new ValidationException( context + ": Invalid number input", "Invalid number input format: context=" + context + ", input=" + input, e, context);
+        }
+
+        if (d.isInfinite()) {
+            throw new ValidationException( "Invalid number input: context=" + context, "Invalid double input is infinite: context=" + context + ", input=" + input, context );
+    }
+        if (d.isNaN()) {
+            throw new ValidationException( "Invalid number input: context=" + context, "Invalid double input is not a number: context=" + context + ", input=" + input, context );
+        }
+        if (d.doubleValue() < minValue) {
+            throw new ValidationException( "Invalid number input must be between " + minValue + " and " + maxValue + ": context=" + context, "Invalid number input must be between " + minValue + " and " + maxValue + ": context=" + context + ", input=" + input, context );
+        }
+        if (d.doubleValue() > maxValue) {
+            throw new ValidationException( "Invalid number input must be between " + minValue + " and " + maxValue + ": context=" + context, "Invalid number input must be between " + minValue + " and " + maxValue + ": context=" + context + ", input=" + input, context );
+        }
+        return d;
+    }
 }
diff --git a/src/main/java/org/owasp/esapi/reference/validation/StringValidationRule.java b/src/main/java/org/owasp/esapi/reference/validation/StringValidationRule.java
index 11fea31..740db8c 100644
--- a/src/main/java/org/owasp/esapi/reference/validation/StringValidationRule.java
+++ b/src/main/java/org/owasp/esapi/reference/validation/StringValidationRule.java
@@ -1,15 +1,15 @@
 /**
  * OWASP Enterprise Security API (ESAPI)
- * 
+ *
  * This file is part of the Open Web Application Security Project (OWASP)
  * Enterprise Security API (ESAPI) project. For details, please see
  * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
  *
  * Copyright (c) 2007 - The OWASP Foundation
- * 
+ *
  * The ESAPI is published by OWASP under the BSD license. You should read and accept the
  * LICENSE before you use, modify, and/or redistribute this software.
- * 
+ *
  * @author Jeff Williams <a href="http://www.aspectsecurity.com">Aspect Security</a>
  * @created 2007
  */
@@ -32,270 +32,270 @@ import org.owasp.esapi.util.NullSafe;
 /**
  * A validator performs syntax and possibly semantic validation of a single
  * piece of data from an untrusted source.
- * 
+ *
  * @author Jeff Williams (jeff.williams .at. aspectsecurity.com) <a
  *         href="http://www.aspectsecurity.com">Aspect Security</a>
  * @since June 1, 2007
  * @see org.owasp.esapi.Validator
- * 
+ *
  * http://en.wikipedia.org/wiki/Whitelist
  */
 public class StringValidationRule extends BaseValidationRule {
     private static final Logger LOGGER = ESAPI.getLogger(StringValidationRule.class);
-	protected List<Pattern> whitelistPatterns = new ArrayList<Pattern>();
-	protected List<Pattern> blacklistPatterns = new ArrayList<Pattern>();
-	protected int minLength = 0;
-	protected int maxLength = Integer.MAX_VALUE;
-	private boolean canonicalizeInput = true;
-
-	public StringValidationRule( String typeName ) {
-		super( typeName );
-	}
-
-	public StringValidationRule( String typeName, Encoder encoder ) {
-		super( typeName, encoder );
-	}
-
-	public StringValidationRule( String typeName, Encoder encoder, String whitelistPattern ) {
-		super( typeName, encoder );
-		addWhitelistPattern( whitelistPattern );
-	}
-
-	/**
-	 * @throws IllegalArgumentException if pattern is null
-	 */
-	public void addWhitelistPattern( String pattern ) {
-		if (pattern == null) {
-			throw new IllegalArgumentException("Pattern cannot be null");
-		}
-		try {
-			whitelistPatterns.add( Pattern.compile( pattern ) );
-		} catch( PatternSyntaxException e ) {
-			throw new IllegalArgumentException( "Validation misconfiguration, problem with specified pattern: " + pattern, e );
-		}
-	}
-
-	/**
-	 * @throws IllegalArgumentException if p is null
-	 */
-	public void addWhitelistPattern( Pattern p ) {
-		if (p == null) {
-			throw new IllegalArgumentException("Pattern cannot be null");
-		}
-		whitelistPatterns.add( p );
-	}
-
-	/**
-	 * @throws IllegalArgumentException if pattern is null
-	 */
-	public void addBlacklistPattern( String pattern ) {
-		if (pattern == null) {
-			throw new IllegalArgumentException("Pattern cannot be null");
-		}
-		try {
-			blacklistPatterns.add( Pattern.compile( pattern ) );
-		} catch( PatternSyntaxException e ) {
-			throw new IllegalArgumentException( "Validation misconfiguration, problem with specified pattern: " + pattern, e );
-		}
-	}
-
-	/**
-	 * @throws IllegalArgumentException if p is null
-	 */
-	public void addBlacklistPattern( Pattern p ) {
-		if (p == null) {
-			throw new IllegalArgumentException("Pattern cannot be null");
-		}
-		blacklistPatterns.add( p );
-	}
-
-	public void setMinimumLength( int length ) {
-		minLength = length;
-	}
-
-
-	public void setMaximumLength( int length ) {
-		maxLength = length;
-	}
-
-	public void setCanonicalize(boolean canonicalize) {
-	    this.canonicalizeInput = canonicalize;
-	}
-
-	/**
-	 * checks input against whitelists.
-	 * @param context The context to include in exception messages
-	 * @param input the input to check
-	 * @param orig A origional input to include in exception
-	 *	messages. This is not included if it is the same as
-	 *	input.
-	 * @return input upon a successful check
-	 * @throws ValidationException if the check fails.
-	 */
-	private String checkWhitelist(String context, String input, String orig) throws ValidationException
-	{
-		// check whitelist patterns
-		for (Pattern p : whitelistPatterns) {
-			if ( !p.matcher(input).matches() ) {
-				throw new ValidationException( context + ": Invalid input. Please conform to regex " + p.pattern() + ( maxLength == Integer.MAX_VALUE ? "" : " with a maximum length of " + maxLength ), "Invalid input: context=" + context + ", type(" + getTypeName() + ")=" + p.pattern() + ", input=" + input + (NullSafe.equals(orig,input) ? "" : ", orig=" + orig), context );
-			}
-		}
-
-		return input;
-	}
-
-	/**
-	 * checks input against whitelists.
-	 * @param context The context to include in exception messages
-	 * @param input the input to check
-	 * @return input upon a successful check
-	 * @throws ValidationException if the check fails.
-	 */
-	private String checkWhitelist(String context, String input) throws ValidationException
-	{
-		return checkWhitelist(context, input, input);
-	}
-
-	/**
-	 * checks input against blacklists.
-	 * @param context The context to include in exception messages
-	 * @param input the input to check
-	 * @param orig A origional input to include in exception
-	 *	messages. This is not included if it is the same as
-	 *	input.
-	 * @return input upon a successful check
-	 * @throws ValidationException if the check fails.
-	 */
-	private String checkBlacklist(String context, String input, String orig) throws ValidationException
-	{
-		// check blacklist patterns
-		for (Pattern p : blacklistPatterns) {
-			if ( p.matcher(input).matches() ) {
-				throw new ValidationException( context + ": Invalid input. Dangerous input matching " + p.pattern() + " detected.", "Dangerous input: context=" + context + ", type(" + getTypeName() + ")=" + p.pattern() + ", input=" + input + (NullSafe.equals(orig,input) ? "" : ", orig=" + orig), context );
-			}
-		}
-
-		return input;
-	}
-
-	/**
-	 * checks input against blacklists.
-	 * @param context The context to include in exception messages
-	 * @param input the input to check
-	 * @return input upon a successful check
-	 * @throws ValidationException if the check fails.
-	 */
-	private String checkBlacklist(String context, String input) throws ValidationException
-	{
-		return checkBlacklist(context, input, input);
-	}
-
-	/**
-	 * checks input lengths
-	 * @param context The context to include in exception messages
-	 * @param input the input to check
-	 * @param orig A origional input to include in exception
-	 *	messages. This is not included if it is the same as
-	 *	input.
-	 * @return input upon a successful check
-	 * @throws ValidationException if the check fails.
-	 */
-	private String checkLength(String context, String input, String orig) throws ValidationException
-	{
-		if (input.length() < minLength) {
-			throw new ValidationException( context + ": Invalid input. The minimum length of " + minLength + " characters was not met.", "Input does not meet the minimum length of " + minLength + " by " + (minLength - input.length()) + " characters: context=" + context + ", type=" + getTypeName() + "), input=" + input + (NullSafe.equals(input,orig) ? "" : ", orig=" + orig), context );
-		}
-
-		if (input.length() > maxLength) {
-			throw new ValidationException( context + ": Invalid input. The maximum length of " + maxLength + " characters was exceeded.", "Input exceeds maximum allowed length of " + maxLength + " by " + (input.length()-maxLength) + " characters: context=" + context + ", type=" + getTypeName() + ", orig=" + orig +", input=" + input, context );
-		}
-
-		return input;
-	}
-
-	/**
-	 * checks input lengths
-	 * @param context The context to include in exception messages
-	 * @param input the input to check
-	 * @return input upon a successful check
-	 * @throws ValidationException if the check fails.
-	 */
-	private String checkLength(String context, String input) throws ValidationException
-	{
-		return checkLength(context, input, input);
-	}
-
-	/**
-	 * checks input emptiness
-	 * @param context The context to include in exception messages
-	 * @param input the input to check
-	 * @param orig A origional input to include in exception
-	 *	messages. This is not included if it is the same as
-	 *	input.
-	 * @return input upon a successful check
-	 * @throws ValidationException if the check fails.
-	 */
-	private String checkEmpty(String context, String input, String orig) throws ValidationException
-	{
-		if(!StringUtilities.isEmpty(input))
-			return input;
-		if(allowNull)
-			return null;
-		throw new ValidationException( context + ": Input required.", "Input required: context=" + context + "), input=" + input + (NullSafe.equals(input,orig) ? "" : ", orig=" + orig), context );
-	}
-
-	/**
-	 * checks input emptiness
-	 * @param context The context to include in exception messages
-	 * @param input the input to check
-	 * @return input upon a successful check
-	 * @throws ValidationException if the check fails.
-	 */
-	private String checkEmpty(String context, String input) throws ValidationException
-	{
-		return checkEmpty(context, input, input);
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	public String getValid( String context, String input ) throws ValidationException
-	{
-		String data = null;
-
-		// check for empty/null
-		if(checkEmpty(context, input) == null)
-			return null;
-
-		// check length
-		checkLength(context, input);
-
-		// canonicalize
-		if (canonicalizeInput) {
-		    data = encoder.canonicalize(input);
-		} else {
-		    String message = String.format("Input validation excludes canonicalization.  Context: %s   Input: %s", context, input);
-		    LOGGER.warning(Logger.SECURITY_AUDIT, message);
+    protected List<Pattern> whitelistPatterns = new ArrayList<Pattern>();
+    protected List<Pattern> blacklistPatterns = new ArrayList<Pattern>();
+    protected int minLength = 0;
+    protected int maxLength = Integer.MAX_VALUE;
+    private boolean canonicalizeInput = true;
+
+    public StringValidationRule( String typeName ) {
+        super( typeName );
+    }
+
+    public StringValidationRule( String typeName, Encoder encoder ) {
+        super( typeName, encoder );
+    }
+
+    public StringValidationRule( String typeName, Encoder encoder, String whitelistPattern ) {
+        super( typeName, encoder );
+        addWhitelistPattern( whitelistPattern );
+    }
+
+    /**
+     * @throws IllegalArgumentException if pattern is null
+     */
+    public void addWhitelistPattern( String pattern ) {
+        if (pattern == null) {
+            throw new IllegalArgumentException("Pattern cannot be null");
+        }
+        try {
+            whitelistPatterns.add( Pattern.compile( pattern ) );
+        } catch( PatternSyntaxException e ) {
+            throw new IllegalArgumentException( "Validation misconfiguration, problem with specified pattern: " + pattern, e );
+        }
+    }
+
+    /**
+     * @throws IllegalArgumentException if p is null
+     */
+    public void addWhitelistPattern( Pattern p ) {
+        if (p == null) {
+            throw new IllegalArgumentException("Pattern cannot be null");
+        }
+        whitelistPatterns.add( p );
+    }
+
+    /**
+     * @throws IllegalArgumentException if pattern is null
+     */
+    public void addBlacklistPattern( String pattern ) {
+        if (pattern == null) {
+            throw new IllegalArgumentException("Pattern cannot be null");
+        }
+        try {
+            blacklistPatterns.add( Pattern.compile( pattern ) );
+        } catch( PatternSyntaxException e ) {
+            throw new IllegalArgumentException( "Validation misconfiguration, problem with specified pattern: " + pattern, e );
+        }
+    }
+
+    /**
+     * @throws IllegalArgumentException if p is null
+     */
+    public void addBlacklistPattern( Pattern p ) {
+        if (p == null) {
+            throw new IllegalArgumentException("Pattern cannot be null");
+        }
+        blacklistPatterns.add( p );
+    }
+
+    public void setMinimumLength( int length ) {
+        minLength = length;
+    }
+
+
+    public void setMaximumLength( int length ) {
+        maxLength = length;
+    }
+
+    public void setCanonicalize(boolean canonicalize) {
+        this.canonicalizeInput = canonicalize;
+    }
+
+    /**
+     * checks input against whitelists.
+     * @param context The context to include in exception messages
+     * @param input the input to check
+     * @param orig A origional input to include in exception
+     *    messages. This is not included if it is the same as
+     *    input.
+     * @return input upon a successful check
+     * @throws ValidationException if the check fails.
+     */
+    private String checkWhitelist(String context, String input, String orig) throws ValidationException
+    {
+        // check whitelist patterns
+        for (Pattern p : whitelistPatterns) {
+            if ( !p.matcher(input).matches() ) {
+                throw new ValidationException( context + ": Invalid input. Please conform to regex " + p.pattern() + ( maxLength == Integer.MAX_VALUE ? "" : " with a maximum length of " + maxLength ), "Invalid input: context=" + context + ", type(" + getTypeName() + ")=" + p.pattern() + ", input=" + input + (NullSafe.equals(orig,input) ? "" : ", orig=" + orig), context );
+            }
+        }
+
+        return input;
+    }
+
+    /**
+     * checks input against whitelists.
+     * @param context The context to include in exception messages
+     * @param input the input to check
+     * @return input upon a successful check
+     * @throws ValidationException if the check fails.
+     */
+    private String checkWhitelist(String context, String input) throws ValidationException
+    {
+        return checkWhitelist(context, input, input);
+    }
+
+    /**
+     * checks input against blacklists.
+     * @param context The context to include in exception messages
+     * @param input the input to check
+     * @param orig A origional input to include in exception
+     *    messages. This is not included if it is the same as
+     *    input.
+     * @return input upon a successful check
+     * @throws ValidationException if the check fails.
+     */
+    private String checkBlacklist(String context, String input, String orig) throws ValidationException
+    {
+        // check blacklist patterns
+        for (Pattern p : blacklistPatterns) {
+            if ( p.matcher(input).matches() ) {
+                throw new ValidationException( context + ": Invalid input. Dangerous input matching " + p.pattern() + " detected.", "Dangerous input: context=" + context + ", type(" + getTypeName() + ")=" + p.pattern() + ", input=" + input + (NullSafe.equals(orig,input) ? "" : ", orig=" + orig), context );
+            }
+        }
+
+        return input;
+    }
+
+    /**
+     * checks input against blacklists.
+     * @param context The context to include in exception messages
+     * @param input the input to check
+     * @return input upon a successful check
+     * @throws ValidationException if the check fails.
+     */
+    private String checkBlacklist(String context, String input) throws ValidationException
+    {
+        return checkBlacklist(context, input, input);
+    }
+
+    /**
+     * checks input lengths
+     * @param context The context to include in exception messages
+     * @param input the input to check
+     * @param orig A origional input to include in exception
+     *    messages. This is not included if it is the same as
+     *    input.
+     * @return input upon a successful check
+     * @throws ValidationException if the check fails.
+     */
+    private String checkLength(String context, String input, String orig) throws ValidationException
+    {
+        if (input.length() < minLength) {
+            throw new ValidationException( context + ": Invalid input. The minimum length of " + minLength + " characters was not met.", "Input does not meet the minimum length of " + minLength + " by " + (minLength - input.length()) + " characters: context=" + context + ", type=" + getTypeName() + "), input=" + input + (NullSafe.equals(input,orig) ? "" : ", orig=" + orig), context );
+        }
+
+        if (input.length() > maxLength) {
+            throw new ValidationException( context + ": Invalid input. The maximum length of " + maxLength + " characters was exceeded.", "Input exceeds maximum allowed length of " + maxLength + " by " + (input.length()-maxLength) + " characters: context=" + context + ", type=" + getTypeName() + ", orig=" + orig +", input=" + input, context );
+        }
+
+        return input;
+    }
+
+    /**
+     * checks input lengths
+     * @param context The context to include in exception messages
+     * @param input the input to check
+     * @return input upon a successful check
+     * @throws ValidationException if the check fails.
+     */
+    private String checkLength(String context, String input) throws ValidationException
+    {
+        return checkLength(context, input, input);
+    }
+
+    /**
+     * checks input emptiness
+     * @param context The context to include in exception messages
+     * @param input the input to check
+     * @param orig A origional input to include in exception
+     *    messages. This is not included if it is the same as
+     *    input.
+     * @return input upon a successful check
+     * @throws ValidationException if the check fails.
+     */
+    private String checkEmpty(String context, String input, String orig) throws ValidationException
+    {
+        if(!StringUtilities.isEmpty(input))
+            return input;
+        if(allowNull)
+            return null;
+        throw new ValidationException( context + ": Input required.", "Input required: context=" + context + "), input=" + input + (NullSafe.equals(input,orig) ? "" : ", orig=" + orig), context );
+    }
+
+    /**
+     * checks input emptiness
+     * @param context The context to include in exception messages
+     * @param input the input to check
+     * @return input upon a successful check
+     * @throws ValidationException if the check fails.
+     */
+    private String checkEmpty(String context, String input) throws ValidationException
+    {
+        return checkEmpty(context, input, input);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public String getValid( String context, String input ) throws ValidationException
+    {
+        String data = null;
+
+        // check for empty/null
+        if(checkEmpty(context, input) == null)
+            return null;
+
+        // check length
+        checkLength(context, input);
+
+        // canonicalize
+        if (canonicalizeInput) {
+            data = encoder.canonicalize(input);
+        } else {
+            String message = String.format("Input validation excludes canonicalization.  Context: %s   Input: %s", context, input);
+            LOGGER.warning(Logger.SECURITY_AUDIT, message);
             data = input;
-		}
-
-		// check whitelist patterns
-		checkWhitelist(context, data, input);
-
-		// check blacklist patterns
-		checkBlacklist(context, data, input);
-			
-		// validation passed
-		return data;
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	@Override
-		public String sanitize( String context, String input ) {
-			return whitelist( input, EncoderConstants.CHAR_ALPHANUMERICS );
-		}
+        }
+
+        // check whitelist patterns
+        checkWhitelist(context, data, input);
+
+        // check blacklist patterns
+        checkBlacklist(context, data, input);
+
+        // validation passed
+        return data;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+        public String sanitize( String context, String input ) {
+            return whitelist( input, EncoderConstants.CHAR_ALPHANUMERICS );
+        }
 
 
 }
diff --git a/src/main/java/org/owasp/esapi/reference/validation/package.html b/src/main/java/org/owasp/esapi/reference/validation/package.html
index b950c12..271bb16 100644
--- a/src/main/java/org/owasp/esapi/reference/validation/package.html
+++ b/src/main/java/org/owasp/esapi/reference/validation/package.html
@@ -6,6 +6,6 @@
 <body bgcolor="white">
 
 This package contains data format-specific validation rule functions.
- 
+
 </body>
 </html>
diff --git a/src/main/java/org/owasp/esapi/tags/BaseEncodeTag.java b/src/main/java/org/owasp/esapi/tags/BaseEncodeTag.java
index c40a04f..e52b740 100644
--- a/src/main/java/org/owasp/esapi/tags/BaseEncodeTag.java
+++ b/src/main/java/org/owasp/esapi/tags/BaseEncodeTag.java
@@ -28,43 +28,43 @@ import org.owasp.esapi.Encoder;
 /** Abstract base class for tags that just encode their bodies with Encoder methods. */
 public abstract class BaseEncodeTag extends BodyTagSupport
 {
-	private static final long serialVersionUID = 1L;
+    private static final long serialVersionUID = 1L;
 
-	/**
-	 * Encode tag's content.
-	 * @param content The tag's content as a String
-	 * @param enc Encoder provided as a convinence.
-	 * @return content encoded by the subclass's implementation.
-	 */
-	protected abstract String encode(String content, Encoder enc) throws JspTagException;
+    /**
+     * Encode tag's content.
+     * @param content The tag's content as a String
+     * @param enc Encoder provided as a convinence.
+     * @return content encoded by the subclass's implementation.
+     */
+    protected abstract String encode(String content, Encoder enc) throws JspTagException;
 
-	/**
-	 * After tag body parsing handler. This provides the necessary
-	 * plubming to allow subclasses to just concern themselves with
-	 * encoding a single string.
-	 * @return {@link javax.servlet.jsp.tagext.Tag#SKIP_BODY}
-	 * @throws JspTagException if writing to the bodyContent's
-	 * enclosing writer throws an IOException.
-	 */
-	public int doAfterBody() throws JspTagException
-	{
-		String content;
-		JspWriter out;
+    /**
+     * After tag body parsing handler. This provides the necessary
+     * plubming to allow subclasses to just concern themselves with
+     * encoding a single string.
+     * @return {@link javax.servlet.jsp.tagext.Tag#SKIP_BODY}
+     * @throws JspTagException if writing to the bodyContent's
+     * enclosing writer throws an IOException.
+     */
+    public int doAfterBody() throws JspTagException
+    {
+        String content;
+        JspWriter out;
 
-		content = bodyContent.getString();
-		out = bodyContent.getEnclosingWriter();
+        content = bodyContent.getString();
+        out = bodyContent.getEnclosingWriter();
 
-		content = encode(content, ESAPI.encoder());
-		try
-		{
-			out.print(content);
-		}
-		catch (IOException e)
-		{
-			throw new JspTagException("Error writing to body's enclosing JspWriter",e);
-		}
+        content = encode(content, ESAPI.encoder());
+        try
+        {
+            out.print(content);
+        }
+        catch (IOException e)
+        {
+            throw new JspTagException("Error writing to body's enclosing JspWriter",e);
+        }
 
-		bodyContent.clearBody();
-		return SKIP_BODY;
-	}
+        bodyContent.clearBody();
+        return SKIP_BODY;
+    }
 }
diff --git a/src/main/java/org/owasp/esapi/tags/ELEncodeFunctions.java b/src/main/java/org/owasp/esapi/tags/ELEncodeFunctions.java
index 5b74e1e..b8a2228 100644
--- a/src/main/java/org/owasp/esapi/tags/ELEncodeFunctions.java
+++ b/src/main/java/org/owasp/esapi/tags/ELEncodeFunctions.java
@@ -11,162 +11,162 @@ import org.owasp.esapi.errors.EncodingException;
  */
 public class ELEncodeFunctions
 {
-	private static final String DEFAULT_ENCODING = "UTF-8";
-
-	/**
-	 * Private constructor as this class shouldn't need to be
-	 * instantiated.
-	 */
-	private ELEncodeFunctions()
-	{
-	}
-
-	/**
-	 * Base64 encode a string. UTF-8 is used to encode the string and no line wrapping is performed.
-	 * @param str The string to encode.
-	 * @return The base64 encoded String.
-	 * @see Encoder#encodeForBase64(byte[],boolean)
-	 * @throws UnsupportedEncodingException if UTF-8 is an unsupported character set. This should not happen as UTF-8 is required to be supported by the JVM spec.
-	 */
-	public static String encodeForBase64(String str) throws UnsupportedEncodingException
-	{
-		return encodeForBase64Charset(DEFAULT_ENCODING, str);
-	}
-
-	/**
-	 * Base64 encode a string with line wrapping. UTF-8 is used to encode the string and lines are wrapped at 64 characters..
-	 * @param str The string to encode.
-	 * @return The base64 encoded String.
-	 * @see Encoder#encodeForBase64(byte[],boolean)
-	 * @throws UnsupportedEncodingException if UTF-8 is an unsupported character set. This should not happen as UTF-8 is required to be supported by the JVM spec.
-	 */
-	public static String encodeForBase64Wrap(String str) throws UnsupportedEncodingException
-	{
-		return encodeForBase64CharsetWrap(DEFAULT_ENCODING, str);
-	}
-
-	/**
-	 * Base64 encode a string after converting to bytes using the specified character set. No line wrapping is performed.
-	 * @param charset The character set used to convert str to bytes.
-	 * @param str The string to encode.
-	 * @return The base64 encoded String.
-	 * @see Encoder#encodeForBase64(byte[],boolean)
-	 * @throws UnsupportedEncodingException if charset is an unsupported character set.
-	 */
-	public static String encodeForBase64Charset(String charset, String str) throws UnsupportedEncodingException
-	{
-		return ESAPI.encoder().encodeForBase64(str.getBytes(charset), false);
-	}
-
-	/**
-	 * Base64 encode a string after converting to bytes using the specified character set and wrapping lines. Lines are wrapped at 64 characters.
-	 * @param charset The character set used to convert str to bytes.
-	 * @param str The string to encode.
-	 * @return The base64 encoded String.
-	 * @see Encoder#encodeForBase64(byte[],boolean)
-	 * @throws UnsupportedEncodingException if charset is an unsupported character set.
-	 */
-	public static String encodeForBase64CharsetWrap(String charset, String str) throws UnsupportedEncodingException
-	{
-		return ESAPI.encoder().encodeForBase64(str.getBytes(charset), true);
-	}
-
-	/**
-	 * Encode string for use in CSS.
-	 * @param str The string to encode.
-	 * @return str encoded for use in CSS.
-	 * @see Encoder#encodeForCSS(String)
-	 */
-	public static String encodeForCSS(String str)
-	{
-		return ESAPI.encoder().encodeForCSS(str);
-	}
-
-	/**
-	 * Encode string for use in HTML.
-	 * @param str The string to encode.
-	 * @return str encoded for use in HTML.
-	 * @see Encoder#encodeForHTML(String)
-	 */
-	public static String encodeForHTML(String str)
-	{
-		return ESAPI.encoder().encodeForHTML(str);
-	}
-
-	/**
-	 * Encode string for use in a HTML attribute.
-	 * @param str The string to encode.
-	 * @return str encoded for use in HTML attribute.
-	 * @see Encoder#encodeForHTMLAttribute(String)
-	 */
-	public static String encodeForHTMLAttribute(String str)
-	{
-		return ESAPI.encoder().encodeForHTMLAttribute(str);
-	}
-
-	/**
-	 * Encode string for use in JavaScript.
-	 * @param str The string to encode.
-	 * @return str encoded for use in JavaScript.
-	 * @see Encoder#encodeForJavaScript(String)
-	 */
-	public static String encodeForJavaScript(String str)
-	{
-		return ESAPI.encoder().encodeForJavaScript(str);
-	}
-
-	/**
-	 * Encode string for use in a URL.
-	 * @param str The string to encode.
-	 * @return str encoded for use in a URL.
-	 * @see Encoder#encodeForURL(String)
-	 */
-	public static String encodeForURL(String str) throws EncodingException
-	{
-		return ESAPI.encoder().encodeForURL(str);
-	}
-
-	/**
-	 * Encode string for use in VBScript.
-	 * @param str The string to encode.
-	 * @return str encoded for use in VBScript.
-	 * @see Encoder#encodeForVBScript(String)
-	 */
-	public static String encodeForVBScript(String str)
-	{
-		return ESAPI.encoder().encodeForVBScript(str);
-	}
-
-	/**
-	 * Encode string for use in XML.
-	 * @param str The string to encode.
-	 * @return str encoded for use in XML.
-	 * @see Encoder#encodeForXML(String)
-	 */
-	public static String encodeForXML(String str)
-	{
-		return ESAPI.encoder().encodeForXML(str);
-	}
-
-	/**
-	 * Encode string for use in a XML attribute.
-	 * @param str The string to encode.
-	 * @return str encoded for use in XML attribute.
-	 * @see Encoder#encodeForXMLAttribute(String)
-	 */
-	public static String encodeForXMLAttribute(String str)
-	{
-		return ESAPI.encoder().encodeForXMLAttribute(str);
-	}
-
-	/**
-	 * Encode string for use in XPath.
-	 * @param str The string to encode.
-	 * @return str encoded for use in XPath.
-	 * @see Encoder#encodeForXPath(String)
-	 */
-	public static String encodeForXPath(String str)
-	{
-		return ESAPI.encoder().encodeForXPath(str);
-	}
+    private static final String DEFAULT_ENCODING = "UTF-8";
+
+    /**
+     * Private constructor as this class shouldn't need to be
+     * instantiated.
+     */
+    private ELEncodeFunctions()
+    {
+    }
+
+    /**
+     * Base64 encode a string. UTF-8 is used to encode the string and no line wrapping is performed.
+     * @param str The string to encode.
+     * @return The base64 encoded String.
+     * @see Encoder#encodeForBase64(byte[],boolean)
+     * @throws UnsupportedEncodingException if UTF-8 is an unsupported character set. This should not happen as UTF-8 is required to be supported by the JVM spec.
+     */
+    public static String encodeForBase64(String str) throws UnsupportedEncodingException
+    {
+        return encodeForBase64Charset(DEFAULT_ENCODING, str);
+    }
+
+    /**
+     * Base64 encode a string with line wrapping. UTF-8 is used to encode the string and lines are wrapped at 64 characters..
+     * @param str The string to encode.
+     * @return The base64 encoded String.
+     * @see Encoder#encodeForBase64(byte[],boolean)
+     * @throws UnsupportedEncodingException if UTF-8 is an unsupported character set. This should not happen as UTF-8 is required to be supported by the JVM spec.
+     */
+    public static String encodeForBase64Wrap(String str) throws UnsupportedEncodingException
+    {
+        return encodeForBase64CharsetWrap(DEFAULT_ENCODING, str);
+    }
+
+    /**
+     * Base64 encode a string after converting to bytes using the specified character set. No line wrapping is performed.
+     * @param charset The character set used to convert str to bytes.
+     * @param str The string to encode.
+     * @return The base64 encoded String.
+     * @see Encoder#encodeForBase64(byte[],boolean)
+     * @throws UnsupportedEncodingException if charset is an unsupported character set.
+     */
+    public static String encodeForBase64Charset(String charset, String str) throws UnsupportedEncodingException
+    {
+        return ESAPI.encoder().encodeForBase64(str.getBytes(charset), false);
+    }
+
+    /**
+     * Base64 encode a string after converting to bytes using the specified character set and wrapping lines. Lines are wrapped at 64 characters.
+     * @param charset The character set used to convert str to bytes.
+     * @param str The string to encode.
+     * @return The base64 encoded String.
+     * @see Encoder#encodeForBase64(byte[],boolean)
+     * @throws UnsupportedEncodingException if charset is an unsupported character set.
+     */
+    public static String encodeForBase64CharsetWrap(String charset, String str) throws UnsupportedEncodingException
+    {
+        return ESAPI.encoder().encodeForBase64(str.getBytes(charset), true);
+    }
+
+    /**
+     * Encode string for use in CSS.
+     * @param str The string to encode.
+     * @return str encoded for use in CSS.
+     * @see Encoder#encodeForCSS(String)
+     */
+    public static String encodeForCSS(String str)
+    {
+        return ESAPI.encoder().encodeForCSS(str);
+    }
+
+    /**
+     * Encode string for use in HTML.
+     * @param str The string to encode.
+     * @return str encoded for use in HTML.
+     * @see Encoder#encodeForHTML(String)
+     */
+    public static String encodeForHTML(String str)
+    {
+        return ESAPI.encoder().encodeForHTML(str);
+    }
+
+    /**
+     * Encode string for use in a HTML attribute.
+     * @param str The string to encode.
+     * @return str encoded for use in HTML attribute.
+     * @see Encoder#encodeForHTMLAttribute(String)
+     */
+    public static String encodeForHTMLAttribute(String str)
+    {
+        return ESAPI.encoder().encodeForHTMLAttribute(str);
+    }
+
+    /**
+     * Encode string for use in JavaScript.
+     * @param str The string to encode.
+     * @return str encoded for use in JavaScript.
+     * @see Encoder#encodeForJavaScript(String)
+     */
+    public static String encodeForJavaScript(String str)
+    {
+        return ESAPI.encoder().encodeForJavaScript(str);
+    }
+
+    /**
+     * Encode string for use in a URL.
+     * @param str The string to encode.
+     * @return str encoded for use in a URL.
+     * @see Encoder#encodeForURL(String)
+     */
+    public static String encodeForURL(String str) throws EncodingException
+    {
+        return ESAPI.encoder().encodeForURL(str);
+    }
+
+    /**
+     * Encode string for use in VBScript.
+     * @param str The string to encode.
+     * @return str encoded for use in VBScript.
+     * @see Encoder#encodeForVBScript(String)
+     */
+    public static String encodeForVBScript(String str)
+    {
+        return ESAPI.encoder().encodeForVBScript(str);
+    }
+
+    /**
+     * Encode string for use in XML.
+     * @param str The string to encode.
+     * @return str encoded for use in XML.
+     * @see Encoder#encodeForXML(String)
+     */
+    public static String encodeForXML(String str)
+    {
+        return ESAPI.encoder().encodeForXML(str);
+    }
+
+    /**
+     * Encode string for use in a XML attribute.
+     * @param str The string to encode.
+     * @return str encoded for use in XML attribute.
+     * @see Encoder#encodeForXMLAttribute(String)
+     */
+    public static String encodeForXMLAttribute(String str)
+    {
+        return ESAPI.encoder().encodeForXMLAttribute(str);
+    }
+
+    /**
+     * Encode string for use in XPath.
+     * @param str The string to encode.
+     * @return str encoded for use in XPath.
+     * @see Encoder#encodeForXPath(String)
+     */
+    public static String encodeForXPath(String str)
+    {
+        return ESAPI.encoder().encodeForXPath(str);
+    }
 }
diff --git a/src/main/java/org/owasp/esapi/tags/EncodeForBase64Tag.java b/src/main/java/org/owasp/esapi/tags/EncodeForBase64Tag.java
index dbde61a..5551f22 100644
--- a/src/main/java/org/owasp/esapi/tags/EncodeForBase64Tag.java
+++ b/src/main/java/org/owasp/esapi/tags/EncodeForBase64Tag.java
@@ -11,72 +11,72 @@ import org.owasp.esapi.Encoder;
  */
 public class EncodeForBase64Tag extends BaseEncodeTag
 {
-	private static final long serialVersionUID = 3L;
-	/** @serial Flag determining line wrapping */
-	private boolean wrap = false;
-	/**
-	  * @serial Charset to use when converting content from a String
-	  * to byte[].
-	  */
-	private String encoding = "UTF-8";
+    private static final long serialVersionUID = 3L;
+    /** @serial Flag determining line wrapping */
+    private boolean wrap = false;
+    /**
+      * @serial Charset to use when converting content from a String
+      * to byte[].
+      */
+    private String encoding = "UTF-8";
 
-	/**
-	 * Encode tag's content using Base64.
-	 * @param content The tag's content as a String
-	 * @param enc Encoder used to call
-	 * 	{@link Encoder#encodeForBase64(byte[], boolean)}
-	 * @return content encoded in Base64
-	 */
-	protected String encode(String content, Encoder enc) throws JspTagException
-	{
-		try
-		{
-			return enc.encodeForBase64(content.getBytes(encoding), wrap);
-		}
-		catch(UnsupportedEncodingException e)
-		{
-			throw new JspTagException("Unsupported encoding " + enc,e);
-		}
-	}
+    /**
+     * Encode tag's content using Base64.
+     * @param content The tag's content as a String
+     * @param enc Encoder used to call
+     *     {@link Encoder#encodeForBase64(byte[], boolean)}
+     * @return content encoded in Base64
+     */
+    protected String encode(String content, Encoder enc) throws JspTagException
+    {
+        try
+        {
+            return enc.encodeForBase64(content.getBytes(encoding), wrap);
+        }
+        catch(UnsupportedEncodingException e)
+        {
+            throw new JspTagException("Unsupported encoding " + enc,e);
+        }
+    }
 
-	/**
-	 * Set the encoding used to convert the content to bytes for
-	 * encoding. This defaults to UTF-8 if not specified.
-	 * @param encoding The encoding passed to {@link String#getBytes(String)}.
-	 */
-	public void setEncoding(String encoding)
-	{
-		this.encoding=encoding;
-	}
+    /**
+     * Set the encoding used to convert the content to bytes for
+     * encoding. This defaults to UTF-8 if not specified.
+     * @param encoding The encoding passed to {@link String#getBytes(String)}.
+     */
+    public void setEncoding(String encoding)
+    {
+        this.encoding=encoding;
+    }
 
-	/**
-	 * Get the encoding used to convert the content to bytes for
-	 * encoding.
-	 * @return encoding The encoding passed to
-	 * {@link String#getBytes(String)}.
-	 */
-	public String getEncoding()
-	{
-		return encoding;
-	}
+    /**
+     * Get the encoding used to convert the content to bytes for
+     * encoding.
+     * @return encoding The encoding passed to
+     * {@link String#getBytes(String)}.
+     */
+    public String getEncoding()
+    {
+        return encoding;
+    }
 
-	/**
-	 * Set whether line wrapping at 64 characters is performed. This
-	 * defaults to false.
-	 * @param wrap flag determining wrapping.
-	 */
-	public void setWrap(boolean wrap)
-	{
-		this.wrap=wrap;
-	}
+    /**
+     * Set whether line wrapping at 64 characters is performed. This
+     * defaults to false.
+     * @param wrap flag determining wrapping.
+     */
+    public void setWrap(boolean wrap)
+    {
+        this.wrap=wrap;
+    }
 
-	/**
-	 * Get whether line wrapping at 64 characters is performed. This
-	 * defaults to false.
-	 * @return value of flag determining wrapping.
-	 */
-	public boolean getWrap()
-	{
-		return wrap;
-	}
+    /**
+     * Get whether line wrapping at 64 characters is performed. This
+     * defaults to false.
+     * @return value of flag determining wrapping.
+     */
+    public boolean getWrap()
+    {
+        return wrap;
+    }
 }
diff --git a/src/main/java/org/owasp/esapi/tags/EncodeForCSSTag.java b/src/main/java/org/owasp/esapi/tags/EncodeForCSSTag.java
index c4bfebd..1def5ee 100644
--- a/src/main/java/org/owasp/esapi/tags/EncodeForCSSTag.java
+++ b/src/main/java/org/owasp/esapi/tags/EncodeForCSSTag.java
@@ -7,17 +7,17 @@ import org.owasp.esapi.Encoder;
  */
 public class EncodeForCSSTag extends BaseEncodeTag
 {
-	private static final long serialVersionUID = 3L;
+    private static final long serialVersionUID = 3L;
 
-	/**
-	 * Encode tag's content for usage in CSS.
-	 * @param content The tag's content as a String
-	 * @param enc Encoder used to call
-	 * 	{@link Encoder#encodeForCSS(String)}
-	 * @return content encoded for usage in CSS
-	 */
-	protected String encode(String content, Encoder enc)
-	{
-		return enc.encodeForCSS(content);
-	}
+    /**
+     * Encode tag's content for usage in CSS.
+     * @param content The tag's content as a String
+     * @param enc Encoder used to call
+     *     {@link Encoder#encodeForCSS(String)}
+     * @return content encoded for usage in CSS
+     */
+    protected String encode(String content, Encoder enc)
+    {
+        return enc.encodeForCSS(content);
+    }
 }
diff --git a/src/main/java/org/owasp/esapi/tags/EncodeForHTMLAttributeTag.java b/src/main/java/org/owasp/esapi/tags/EncodeForHTMLAttributeTag.java
index ed48c97..5e07d8c 100644
--- a/src/main/java/org/owasp/esapi/tags/EncodeForHTMLAttributeTag.java
+++ b/src/main/java/org/owasp/esapi/tags/EncodeForHTMLAttributeTag.java
@@ -23,17 +23,17 @@ import org.owasp.esapi.Encoder;
  */
 public class EncodeForHTMLAttributeTag extends BaseEncodeTag
 {
-	private static final long serialVersionUID = 3L;
+    private static final long serialVersionUID = 3L;
 
-	/**
-	 * Encode tag's content for usage as a HTML attribute.
-	 * @param content The tag's content as a String
-	 * @param enc Encoder used to call
-	 * 	{@link Encoder#encodeForHTMLAttribute(String)}
-	 * @return content encoded for usage as a HTML attribute
-	 */
-	protected String encode(String content, Encoder enc)
-	{
-		return enc.encodeForHTMLAttribute(content);
-	}
+    /**
+     * Encode tag's content for usage as a HTML attribute.
+     * @param content The tag's content as a String
+     * @param enc Encoder used to call
+     *     {@link Encoder#encodeForHTMLAttribute(String)}
+     * @return content encoded for usage as a HTML attribute
+     */
+    protected String encode(String content, Encoder enc)
+    {
+        return enc.encodeForHTMLAttribute(content);
+    }
 }
diff --git a/src/main/java/org/owasp/esapi/tags/EncodeForHTMLTag.java b/src/main/java/org/owasp/esapi/tags/EncodeForHTMLTag.java
index ee7916f..3cd3175 100644
--- a/src/main/java/org/owasp/esapi/tags/EncodeForHTMLTag.java
+++ b/src/main/java/org/owasp/esapi/tags/EncodeForHTMLTag.java
@@ -23,17 +23,17 @@ import org.owasp.esapi.Encoder;
  */
 public class EncodeForHTMLTag extends BaseEncodeTag
 {
-	private static final long serialVersionUID = 3L;
+    private static final long serialVersionUID = 3L;
 
-	/**
-	 * Encode tag's content for usage in HTML.
-	 * @param content The tag's content as a String
-	 * @param enc Encoder used to call
-	 * 	{@link Encoder#encodeForHTML(String)}
-	 * @return content encoded for usage in HTML
-	 */
-	protected String encode(String content, Encoder enc)
-	{
-		return enc.encodeForHTML(content);
-	}
+    /**
+     * Encode tag's content for usage in HTML.
+     * @param content The tag's content as a String
+     * @param enc Encoder used to call
+     *     {@link Encoder#encodeForHTML(String)}
+     * @return content encoded for usage in HTML
+     */
+    protected String encode(String content, Encoder enc)
+    {
+        return enc.encodeForHTML(content);
+    }
 }
diff --git a/src/main/java/org/owasp/esapi/tags/EncodeForJavaScriptTag.java b/src/main/java/org/owasp/esapi/tags/EncodeForJavaScriptTag.java
index 8069401..fe4d68e 100644
--- a/src/main/java/org/owasp/esapi/tags/EncodeForJavaScriptTag.java
+++ b/src/main/java/org/owasp/esapi/tags/EncodeForJavaScriptTag.java
@@ -7,17 +7,17 @@ import org.owasp.esapi.Encoder;
  */
 public class EncodeForJavaScriptTag extends BaseEncodeTag
 {
-	private static final long serialVersionUID = 3L;
+    private static final long serialVersionUID = 3L;
 
-	/**
-	 * Encode tag's content for usage in JavaScript
-	 * @param content The tag's content as a String
-	 * @param enc Encoder used to call
-	 * 	{@link Encoder#encodeForJavaScript(String)}
-	 * @return content encoded for usage in JavaScript
-	 */
-	protected String encode(String content, Encoder enc)
-	{
-		return enc.encodeForJavaScript(content);
-	}
+    /**
+     * Encode tag's content for usage in JavaScript
+     * @param content The tag's content as a String
+     * @param enc Encoder used to call
+     *     {@link Encoder#encodeForJavaScript(String)}
+     * @return content encoded for usage in JavaScript
+     */
+    protected String encode(String content, Encoder enc)
+    {
+        return enc.encodeForJavaScript(content);
+    }
 }
diff --git a/src/main/java/org/owasp/esapi/tags/EncodeForURLTag.java b/src/main/java/org/owasp/esapi/tags/EncodeForURLTag.java
index d159676..28b03af 100644
--- a/src/main/java/org/owasp/esapi/tags/EncodeForURLTag.java
+++ b/src/main/java/org/owasp/esapi/tags/EncodeForURLTag.java
@@ -10,25 +10,25 @@ import org.owasp.esapi.errors.EncodingException;
  */
 public class EncodeForURLTag extends BaseEncodeTag
 {
-	private static final long serialVersionUID = 3L;
+    private static final long serialVersionUID = 3L;
 
-	/**
-	 * Encode tag's content for usage in a URL.
-	 * @param content The tag's content as a String
-	 * @param enc Encoder used to call
-	 * 	{@link Encoder#encodeForURL(String)}
-	 * @return content encoded for usage in a URL
-	 * @throws EncodingException if {@link Encoder#encodeForURL(String)} does.
-	 */
-	protected String encode(String content, Encoder enc) throws JspTagException
-	{
-		try
-		{
-			return enc.encodeForURL(content);
-		}
-		catch(EncodingException e)
-		{
-			throw new JspTagException("Unable to encode to URL encoding", e);
-		}
-	}
+    /**
+     * Encode tag's content for usage in a URL.
+     * @param content The tag's content as a String
+     * @param enc Encoder used to call
+     *     {@link Encoder#encodeForURL(String)}
+     * @return content encoded for usage in a URL
+     * @throws EncodingException if {@link Encoder#encodeForURL(String)} does.
+     */
+    protected String encode(String content, Encoder enc) throws JspTagException
+    {
+        try
+        {
+            return enc.encodeForURL(content);
+        }
+        catch(EncodingException e)
+        {
+            throw new JspTagException("Unable to encode to URL encoding", e);
+        }
+    }
 }
diff --git a/src/main/java/org/owasp/esapi/tags/EncodeForVBScriptTag.java b/src/main/java/org/owasp/esapi/tags/EncodeForVBScriptTag.java
index d090fad..43ddee2 100644
--- a/src/main/java/org/owasp/esapi/tags/EncodeForVBScriptTag.java
+++ b/src/main/java/org/owasp/esapi/tags/EncodeForVBScriptTag.java
@@ -23,17 +23,17 @@ import org.owasp.esapi.Encoder;
  */
 public class EncodeForVBScriptTag extends BaseEncodeTag
 {
-	private static final long serialVersionUID = 3L;
+    private static final long serialVersionUID = 3L;
 
-	/**
-	 * Encode tag's content for usage in VBScript.
-	 * @param content The tag's content as a String
-	 * @param enc Encoder used to call
-	 * 	{@link Encoder#encodeForVBScript(String)}
-	 * @return content encoded for usage in VBScript
-	 */
-	protected String encode(String content, Encoder enc)
-	{
-		return enc.encodeForVBScript(content);
-	}
+    /**
+     * Encode tag's content for usage in VBScript.
+     * @param content The tag's content as a String
+     * @param enc Encoder used to call
+     *     {@link Encoder#encodeForVBScript(String)}
+     * @return content encoded for usage in VBScript
+     */
+    protected String encode(String content, Encoder enc)
+    {
+        return enc.encodeForVBScript(content);
+    }
 }
diff --git a/src/main/java/org/owasp/esapi/tags/EncodeForXMLAttributeTag.java b/src/main/java/org/owasp/esapi/tags/EncodeForXMLAttributeTag.java
index c147467..4ad11e8 100644
--- a/src/main/java/org/owasp/esapi/tags/EncodeForXMLAttributeTag.java
+++ b/src/main/java/org/owasp/esapi/tags/EncodeForXMLAttributeTag.java
@@ -7,17 +7,17 @@ import org.owasp.esapi.Encoder;
  */
 public class EncodeForXMLAttributeTag extends BaseEncodeTag
 {
-	private static final long serialVersionUID = 3L;
+    private static final long serialVersionUID = 3L;
 
-	/**
-	 * Encode tag's content for usage as a XML attribute.
-	 * @param content The tag's content as a String
-	 * @param enc Encoder used to call
-	 * 	{@link Encoder#encodeForXMLAttribute(String)}
-	 * @return content encoded for usage as a XML attribute
-	 */
-	protected String encode(String content, Encoder enc)
-	{
-		return enc.encodeForXMLAttribute(content);
-	}
+    /**
+     * Encode tag's content for usage as a XML attribute.
+     * @param content The tag's content as a String
+     * @param enc Encoder used to call
+     *     {@link Encoder#encodeForXMLAttribute(String)}
+     * @return content encoded for usage as a XML attribute
+     */
+    protected String encode(String content, Encoder enc)
+    {
+        return enc.encodeForXMLAttribute(content);
+    }
 }
diff --git a/src/main/java/org/owasp/esapi/tags/EncodeForXMLTag.java b/src/main/java/org/owasp/esapi/tags/EncodeForXMLTag.java
index f86cfe1..320b048 100644
--- a/src/main/java/org/owasp/esapi/tags/EncodeForXMLTag.java
+++ b/src/main/java/org/owasp/esapi/tags/EncodeForXMLTag.java
@@ -7,17 +7,17 @@ import org.owasp.esapi.Encoder;
  */
 public class EncodeForXMLTag extends BaseEncodeTag
 {
-	private static final long serialVersionUID = 3L;
+    private static final long serialVersionUID = 3L;
 
-	/**
-	 * Encode tag's content for usage in XML.
-	 * @param content The tag's content as a String
-	 * @param enc Encoder used to call
-	 * 	{@link Encoder#encodeForXML(String)}
-	 * @return content encoded for usage in XML
-	 */
-	protected String encode(String content, Encoder enc)
-	{
-		return enc.encodeForXML(content);
-	}
+    /**
+     * Encode tag's content for usage in XML.
+     * @param content The tag's content as a String
+     * @param enc Encoder used to call
+     *     {@link Encoder#encodeForXML(String)}
+     * @return content encoded for usage in XML
+     */
+    protected String encode(String content, Encoder enc)
+    {
+        return enc.encodeForXML(content);
+    }
 }
diff --git a/src/main/java/org/owasp/esapi/tags/EncodeForXPathTag.java b/src/main/java/org/owasp/esapi/tags/EncodeForXPathTag.java
index 064b191..1ff9538 100644
--- a/src/main/java/org/owasp/esapi/tags/EncodeForXPathTag.java
+++ b/src/main/java/org/owasp/esapi/tags/EncodeForXPathTag.java
@@ -7,17 +7,17 @@ import org.owasp.esapi.Encoder;
  */
 public class EncodeForXPathTag extends BaseEncodeTag
 {
-	private static final long serialVersionUID = 3L;
+    private static final long serialVersionUID = 3L;
 
-	/**
-	 * Encode tag's content for usage in XPath.
-	 * @param content The tag's content as a String
-	 * @param enc Encoder used to call
-	 * 	{@link Encoder#encodeForXPath(String)}
-	 * @return content encoded for usage in XPath
-	 */
-	protected String encode(String content, Encoder enc)
-	{
-		return enc.encodeForXPath(content);
-	}
+    /**
+     * Encode tag's content for usage in XPath.
+     * @param content The tag's content as a String
+     * @param enc Encoder used to call
+     *     {@link Encoder#encodeForXPath(String)}
+     * @return content encoded for usage in XPath
+     */
+    protected String encode(String content, Encoder enc)
+    {
+        return enc.encodeForXPath(content);
+    }
 }
diff --git a/src/main/java/org/owasp/esapi/util/ByteConversionUtil.java b/src/main/java/org/owasp/esapi/util/ByteConversionUtil.java
index 506af4f..abb82c0 100644
--- a/src/main/java/org/owasp/esapi/util/ByteConversionUtil.java
+++ b/src/main/java/org/owasp/esapi/util/ByteConversionUtil.java
@@ -1,6 +1,6 @@
 /*
  * OWASP Enterprise Security API (ESAPI)
- * 
+ *
  * This file is part of the Open Web Application Security Project (OWASP)
  * Enterprise Security API (ESAPI) project. For details, please see
  * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
diff --git a/src/main/java/org/owasp/esapi/util/CollectionsUtil.java b/src/main/java/org/owasp/esapi/util/CollectionsUtil.java
index 3cb2f28..2607f62 100644
--- a/src/main/java/org/owasp/esapi/util/CollectionsUtil.java
+++ b/src/main/java/org/owasp/esapi/util/CollectionsUtil.java
@@ -1,5 +1,5 @@
 /**
- * 
+ *
  */
 package org.owasp.esapi.util;
 
@@ -9,107 +9,107 @@ import java.util.Set;
 
 /**
  * @author Neil Matatall (neil.matatall .at. gmail.com)
- * 
+ *
  * Are these necessary?  Are there any libraries or java.lang classes to take
  * care of the conversions?
- * 
+ *
  * FIXME: we can convert to using this, but it requires that the array be of Character, not char
  *      new HashSet(Arrays.asList(array))
- * 
+ *
  */
 public class CollectionsUtil
 {
-	private static final char[] EMPTY_CHAR_ARRAY = new char[0];
+    private static final char[] EMPTY_CHAR_ARRAY = new char[0];
 
-	/**
-	 * Converts an array of chars to a Set of Characters. 
-	 * @param array the contents of the new Set
-	 * @return a Set containing the elements in the array
-	 */
-	public static Set<Character> arrayToSet(char...array)
-	{
-		Set<Character> toReturn;
+    /**
+     * Converts an array of chars to a Set of Characters.
+     * @param array the contents of the new Set
+     * @return a Set containing the elements in the array
+     */
+    public static Set<Character> arrayToSet(char...array)
+    {
+        Set<Character> toReturn;
 
-		if(array == null)
-			return new HashSet<Character>();
-		toReturn = new HashSet<Character>(array.length);
-		for (char c : array) {
-			toReturn.add(c);
-		}
-		return toReturn;
-	}
+        if(array == null)
+            return new HashSet<Character>();
+        toReturn = new HashSet<Character>(array.length);
+        for (char c : array) {
+            toReturn.add(c);
+        }
+        return toReturn;
+    }
 
-	/**
-	 * Convert a char array to a unmodifiable Set.
-	 * @param array the contents of the new Set
-	 * @return a unmodifiable Set containing the elements in the
-	 * array.
-	 */
-	public static Set<Character> arrayToUnmodifiableSet(char...array)
-	{
-		if(array == null)
-			return Collections.emptySet();
-		if(array.length == 1)
-			return Collections.singleton(array[0]);
-		return Collections.unmodifiableSet(arrayToSet(array));
-	}
+    /**
+     * Convert a char array to a unmodifiable Set.
+     * @param array the contents of the new Set
+     * @return a unmodifiable Set containing the elements in the
+     * array.
+     */
+    public static Set<Character> arrayToUnmodifiableSet(char...array)
+    {
+        if(array == null)
+            return Collections.emptySet();
+        if(array.length == 1)
+            return Collections.singleton(array[0]);
+        return Collections.unmodifiableSet(arrayToSet(array));
+    }
 
-	/**
-	 * Convert a String to a char array
-	 * @param str The string to convert
-	 * @return character array containing the characters in str. An
-	 * 	empty array is returned if str is null.
-	 */
-	public static char[] strToChars(String str)
-	{
-		int len;
-		char[] ret;
+    /**
+     * Convert a String to a char array
+     * @param str The string to convert
+     * @return character array containing the characters in str. An
+     *     empty array is returned if str is null.
+     */
+    public static char[] strToChars(String str)
+    {
+        int len;
+        char[] ret;
 
-		if(str == null)
-			return EMPTY_CHAR_ARRAY;
-		len = str.length();
-		ret = new char[len];
-		str.getChars(0,len,ret,0);
-		return ret;
-	}
+        if(str == null)
+            return EMPTY_CHAR_ARRAY;
+        len = str.length();
+        ret = new char[len];
+        str.getChars(0,len,ret,0);
+        return ret;
+    }
 
-	/**
-	 * Convert a String to a set of characters.
-	 * @param str The string to convert
-	 * @return A set containing the characters in str. A empty set
-	 * 	is returned if str is null.
-	 */
-	public static Set<Character> strToSet(String str)
-	{
-		Set<Character> set;
+    /**
+     * Convert a String to a set of characters.
+     * @param str The string to convert
+     * @return A set containing the characters in str. A empty set
+     *     is returned if str is null.
+     */
+    public static Set<Character> strToSet(String str)
+    {
+        Set<Character> set;
 
-		if(str == null)
-			return new HashSet<Character>();
-		set = new HashSet<Character>(str.length());
-		for(int i=0;i<str.length();i++)
-			set.add(str.charAt(i));
-		return set;
-	}
+        if(str == null)
+            return new HashSet<Character>();
+        set = new HashSet<Character>(str.length());
+        for(int i=0;i<str.length();i++)
+            set.add(str.charAt(i));
+        return set;
+    }
 
-	/**
-	 * Convert a String to a unmodifiable set of characters.
-	 * @param str The string to convert
-	 * @return A set containing the characters in str. A empty set
-	 * 	is returned if str is null.
-	 */
-	public static Set<Character> strToUnmodifiableSet(String str)
-	{
-		if(str == null)
-			return Collections.emptySet();
-		if(str.length() == 1)
-			return Collections.singleton(str.charAt(0));
-		return Collections.unmodifiableSet(strToSet(str));
-	}
+    /**
+     * Convert a String to a unmodifiable set of characters.
+     * @param str The string to convert
+     * @return A set containing the characters in str. A empty set
+     *     is returned if str is null.
+     */
+    public static Set<Character> strToUnmodifiableSet(String str)
+    {
+        if(str == null)
+            return Collections.emptySet();
+        if(str.length() == 1)
+            return Collections.singleton(str.charAt(0));
+        return Collections.unmodifiableSet(strToSet(str));
+    }
 
-	/**
-	 * Private constructor to prevent instantiation.
-	 */
-	private CollectionsUtil()
-	{
-	}
+    /**
+     * Private constructor to prevent instantiation.
+     */
+    private CollectionsUtil()
+    {
+    }
 }
diff --git a/src/main/java/org/owasp/esapi/util/DefaultMessageUtil.java b/src/main/java/org/owasp/esapi/util/DefaultMessageUtil.java
index 1cce296..ee9de42 100644
--- a/src/main/java/org/owasp/esapi/util/DefaultMessageUtil.java
+++ b/src/main/java/org/owasp/esapi/util/DefaultMessageUtil.java
@@ -1,15 +1,15 @@
 /**
  * OWASP Enterprise Security API (ESAPI)
- * 
+ *
  * This file is part of the Open Web Application Security Project (OWASP)
  * Enterprise Security API (ESAPI) project. For details, please see
  * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
  *
  * Copyright (c) 2007 - The OWASP Foundation
- * 
+ *
  * The ESAPI is published by OWASP under the BSD license. You should read and accept the
  * LICENSE before you use, modify, and/or redistribute this software.
- * 
+ *
  * @author Pawan Singh (pawan.singh@owasp.org) <a href="www.owasp.org">OWASP</a>
  * @created 2009
  */
@@ -29,11 +29,11 @@ public class DefaultMessageUtil {
 
     private final String DEFAULT_LOCALE_LANG = "en";
     private final String DEFAULT_LOCALE_LOC = "US";
-    
+
     private ResourceBundle messages = null;
-    
+
     public void initialize() {
-    	try {
+        try {
                 messages = ResourceBundle.getBundle("ESAPI", ESAPI.authenticator().getCurrentUser().getLocale());
         } catch (Exception e) {
                 messages = ResourceBundle.getBundle("ESAPI", new Locale(DEFAULT_LOCALE_LANG,DEFAULT_LOCALE_LOC));
@@ -41,9 +41,9 @@ public class DefaultMessageUtil {
     }
 
 
-	public String getMessage(String msgKey, Object[] arguments) {
-		
-		initialize();
-		return MessageFormat.format( messages.getString(msgKey), arguments );
-	}
+    public String getMessage(String msgKey, Object[] arguments) {
+
+        initialize();
+        return MessageFormat.format( messages.getString(msgKey), arguments );
+    }
 }
\ No newline at end of file
diff --git a/src/main/java/org/owasp/esapi/util/NullSafe.java b/src/main/java/org/owasp/esapi/util/NullSafe.java
index 062c0fa..a0bee5f 100644
--- a/src/main/java/org/owasp/esapi/util/NullSafe.java
+++ b/src/main/java/org/owasp/esapi/util/NullSafe.java
@@ -2,51 +2,51 @@ package org.owasp.esapi.util;
 
 public class NullSafe
 {
-	/**
-	 * Class should not be instantiated.
-	 */
-	private NullSafe()
-	{
-	}
+    /**
+     * Class should not be instantiated.
+     */
+    private NullSafe()
+    {
+    }
 
-	/**
-	 * {@link Object#equals(Object)} that safely handles nulls.
-	 * @param a First object
-	 * @param b Second object
-	 * @return true if a == b or a.equals(b). false otherwise.
-	 */
-	public static boolean equals(Object a, Object b)
-	{
-		if(a==b)	// short cut same object
-			return true;
-		if(a == null)
-			return (b == null);
-		if(b == null)
-			return false;
-		return a.equals(b);
-	}
+    /**
+     * {@link Object#equals(Object)} that safely handles nulls.
+     * @param a First object
+     * @param b Second object
+     * @return true if a == b or a.equals(b). false otherwise.
+     */
+    public static boolean equals(Object a, Object b)
+    {
+        if(a==b)    // short cut same object
+            return true;
+        if(a == null)
+            return (b == null);
+        if(b == null)
+            return false;
+        return a.equals(b);
+    }
 
-	/**
-	 * {@link Object#hashCode()} of an object.
-	 * @param o Object to get a hashCode for.
-	 * @return 0 if o is null. Otherwise o.hashCode().
-	 */
-	public static int hashCode(Object o)
-	{
-		if(o == null)
-			return 0;
-		return o.hashCode();
-	}
+    /**
+     * {@link Object#hashCode()} of an object.
+     * @param o Object to get a hashCode for.
+     * @return 0 if o is null. Otherwise o.hashCode().
+     */
+    public static int hashCode(Object o)
+    {
+        if(o == null)
+            return 0;
+        return o.hashCode();
+    }
 
-	/**
-	 * {@link Object#toString()} of an object.
-	 * @param o Object to get a String for.
-	 * @return "(null)" o is null. Otherwise o.toString().
-	 */
-	public static String toString(Object o)
-	{
-		if(o == null)
-			return "(null)";
-		return o.toString();
-	}
+    /**
+     * {@link Object#toString()} of an object.
+     * @param o Object to get a String for.
+     * @return "(null)" o is null. Otherwise o.toString().
+     */
+    public static String toString(Object o)
+    {
+        if(o == null)
+            return "(null)";
+        return o.toString();
+    }
 }
diff --git a/src/main/java/org/owasp/esapi/util/ObjFactory.java b/src/main/java/org/owasp/esapi/util/ObjFactory.java
index 7853ef5..0e33408 100644
--- a/src/main/java/org/owasp/esapi/util/ObjFactory.java
+++ b/src/main/java/org/owasp/esapi/util/ObjFactory.java
@@ -1,6 +1,6 @@
 /*
  * OWASP Enterprise Security API (ESAPI)
- * 
+ *
  * This file is part of the Open Web Application Security Project (OWASP)
  * Enterprise Security API (ESAPI) project. For details, please see
  * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
@@ -25,17 +25,17 @@ import java.util.concurrent.ConcurrentHashMap;
  * <p>
  * Typical use is something like:
  * <pre>
- * 		import com.example.interfaces.DrinkingEstablishment;
- * 		import com.example.interfaces.Beer;
- * 		...
- * 		// Typically these would be populated from some Java properties file
- * 		String barName = "com.example.foo.Bar";
- * 		String beerBrand = "com.example.brewery.Guinness";
- * 		...
- * 		DrinkingEstablishment bar = ObjFactory.make(barName, "DrinkingEstablishment");
- * 		Beer beer = ObjFactory.make(beerBrand, "Beer");
- *		bar.drink(beer);	// Drink a Guinness beer at the foo Bar. :)
- *		...
+ *         import com.example.interfaces.DrinkingEstablishment;
+ *         import com.example.interfaces.Beer;
+ *         ...
+ *         // Typically these would be populated from some Java properties file
+ *         String barName = "com.example.foo.Bar";
+ *         String beerBrand = "com.example.brewery.Guinness";
+ *         ...
+ *         DrinkingEstablishment bar = ObjFactory.make(barName, "DrinkingEstablishment");
+ *         Beer beer = ObjFactory.make(beerBrand, "Beer");
+ *        bar.drink(beer);    // Drink a Guinness beer at the foo Bar. :)
+ *        ...
  * </pre>
  * </p><p>
  *  Copyright (c) 2009 - The OWASP Foundation
@@ -46,44 +46,44 @@ import java.util.concurrent.ConcurrentHashMap;
 public class ObjFactory {
 
     private static final int CACHE_INITIAL_CAPACITY = 32;
-	private static final float CACHE_LOAD_FACTOR = 0.75F;
-	private static final ConcurrentHashMap<String,Class<?>> CLASSES_CACHE = new ConcurrentHashMap<>(CACHE_INITIAL_CAPACITY, CACHE_LOAD_FACTOR);
-	private static final ConcurrentHashMap<String,MethodWrappedInfo> METHODS_CACHE = new ConcurrentHashMap<>(CACHE_INITIAL_CAPACITY, CACHE_LOAD_FACTOR);
+    private static final float CACHE_LOAD_FACTOR = 0.75F;
+    private static final ConcurrentHashMap<String,Class<?>> CLASSES_CACHE = new ConcurrentHashMap<>(CACHE_INITIAL_CAPACITY, CACHE_LOAD_FACTOR);
+    private static final ConcurrentHashMap<String,MethodWrappedInfo> METHODS_CACHE = new ConcurrentHashMap<>(CACHE_INITIAL_CAPACITY, CACHE_LOAD_FACTOR);
     private static boolean cacheEnabled = true;
 
-	/**
-	 * Create an object based on the <code>className</code> parameter.
-	 * 
-	 * @param className	The name of the class to construct. Should be a fully qualified name and
-	 * 					generally the same as type <code>T</code>
-	 * @param typeName	A type name used in error messages / exceptions.
-	 * @return	An object of type <code>className</code>, which is cast to type <code>T</code>.
-	 * @throws	ConfigurationException thrown if class name not found in class path, or does not
-	 * 			have a public, no-argument constructor, or is not a concrete class, or if it is
-	 * 			not a sub-type of <code>T</code> (or <code>T</code> itself). Usually this is
-	 * 			caused by a misconfiguration of the class names specified in the ESAPI.properties
-	 * 			file. Also thrown if the CTOR of the specified <code>className</code> throws
-	 * 			an <code>Exception</code> of some type.
-	 */
-	@SuppressWarnings({ "unchecked" })	// Added because of Eclipse warnings, but ClassCastException IS caught.
-	public static <T> T make(String className, String typeName) throws ConfigurationException {
-		Object obj = null;
-		String errMsg = null;
-		try {
-			if (null == className || "".equals(className) ) {
-				throw new IllegalArgumentException("Classname cannot be null or empty.");
-			}
-			if (null == typeName || "".equals(typeName) ) {
-				// No big deal...just use "[unknown?]" for this as it's only for an err msg.
-				typeName = "[unknown?]";	// CHECKME: Any better suggestions?
-			}
-
-			Class<?> theClass = loadClassByStringName(className);
-
-			try {
-				Method singleton = findSingletonCreateMethod(className, theClass);
-
-				obj = singleton.invoke( null );
+    /**
+     * Create an object based on the <code>className</code> parameter.
+     *
+     * @param className    The name of the class to construct. Should be a fully qualified name and
+     *                     generally the same as type <code>T</code>
+     * @param typeName    A type name used in error messages / exceptions.
+     * @return    An object of type <code>className</code>, which is cast to type <code>T</code>.
+     * @throws    ConfigurationException thrown if class name not found in class path, or does not
+     *             have a public, no-argument constructor, or is not a concrete class, or if it is
+     *             not a sub-type of <code>T</code> (or <code>T</code> itself). Usually this is
+     *             caused by a misconfiguration of the class names specified in the ESAPI.properties
+     *             file. Also thrown if the CTOR of the specified <code>className</code> throws
+     *             an <code>Exception</code> of some type.
+     */
+    @SuppressWarnings({ "unchecked" })    // Added because of Eclipse warnings, but ClassCastException IS caught.
+    public static <T> T make(String className, String typeName) throws ConfigurationException {
+        Object obj = null;
+        String errMsg = null;
+        try {
+            if (null == className || "".equals(className) ) {
+                throw new IllegalArgumentException("Classname cannot be null or empty.");
+            }
+            if (null == typeName || "".equals(typeName) ) {
+                // No big deal...just use "[unknown?]" for this as it's only for an err msg.
+                typeName = "[unknown?]";    // CHECKME: Any better suggestions?
+            }
+
+            Class<?> theClass = loadClassByStringName(className);
+
+            try {
+                Method singleton = findSingletonCreateMethod(className, theClass);
+
+                obj = singleton.invoke( null );
             } catch (NoSuchMethodException e) {
                 // This is a no-error exception, if this is caught we will continue on assuming the implementation was
                 // not meant to be used as a singleton.
@@ -96,40 +96,40 @@ public class ObjFactory {
                         "of the class [" + className + "]", e );
             }
 
-			return (T)obj;		// Eclipse warning here if @SupressWarnings omitted.
+            return (T)obj;        // Eclipse warning here if @SupressWarnings omitted.
 
             // Issue 66 - Removed System.out calls as we are throwing an exception in each of these cases
             // anyhow.
-		} catch( IllegalArgumentException ex ) {
-			errMsg = ex.toString() + " " + typeName + " type name cannot be null or empty.";
-			throw new ConfigurationException(errMsg, ex);
-		}catch ( ClassNotFoundException ex ) {
-			errMsg = ex.toString() + " " + typeName + " class (" + className + ") must be in class path.";
-			throw new ConfigurationException(errMsg, ex);
-		} catch( InstantiationException ex ) {
-			errMsg = ex.toString() + " " + typeName + " class (" + className + ") must be concrete.";
-			throw new ConfigurationException(errMsg, ex);
-		} catch( IllegalAccessException ex ) {
-			errMsg = ex.toString() + " " + typeName + " class (" + className + ") must have a public, no-arg constructor.";
-			throw new ConfigurationException(errMsg, ex);
-		} catch( ClassCastException ex ) {
-			errMsg = ex.toString() + " " + typeName + " class (" + className + ") must be a subtype of T in ObjFactory<T>";
-			throw new ConfigurationException(errMsg, ex);
-		} catch( Exception ex ) {
-			// Because we are using reflection, we want to catch any checked or unchecked Exceptions and
-			// re-throw them in a way we can handle them. Because using reflection to construct the object,
-			// we can't have the compiler notify us of uncaught exceptions. For example, JavaEncryptor()
-			// CTOR can throw [well, now it can] an EncryptionException if something goes wrong. That case
-			// is taken care of here.
-			//
-			// CHECKME: Should we first catch RuntimeExceptions so we just let unchecked Exceptions go through
-			//		    unaltered???
-			//
-			errMsg = ex.toString() + " " + typeName + " class (" + className + ") CTOR threw exception.";
-			throw new ConfigurationException(errMsg, ex);
-		}
-		// DISCUSS: Should we also catch ExceptionInInitializerError here? See Google Issue #61 comments.
-	}
+        } catch( IllegalArgumentException ex ) {
+            errMsg = ex.toString() + " " + typeName + " type name cannot be null or empty.";
+            throw new ConfigurationException(errMsg, ex);
+        }catch ( ClassNotFoundException ex ) {
+            errMsg = ex.toString() + " " + typeName + " class (" + className + ") must be in class path.";
+            throw new ConfigurationException(errMsg, ex);
+        } catch( InstantiationException ex ) {
+            errMsg = ex.toString() + " " + typeName + " class (" + className + ") must be concrete.";
+            throw new ConfigurationException(errMsg, ex);
+        } catch( IllegalAccessException ex ) {
+            errMsg = ex.toString() + " " + typeName + " class (" + className + ") must have a public, no-arg constructor.";
+            throw new ConfigurationException(errMsg, ex);
+        } catch( ClassCastException ex ) {
+            errMsg = ex.toString() + " " + typeName + " class (" + className + ") must be a subtype of T in ObjFactory<T>";
+            throw new ConfigurationException(errMsg, ex);
+        } catch( Exception ex ) {
+            // Because we are using reflection, we want to catch any checked or unchecked Exceptions and
+            // re-throw them in a way we can handle them. Because using reflection to construct the object,
+            // we can't have the compiler notify us of uncaught exceptions. For example, JavaEncryptor()
+            // CTOR can throw [well, now it can] an EncryptionException if something goes wrong. That case
+            // is taken care of here.
+            //
+            // CHECKME: Should we first catch RuntimeExceptions so we just let unchecked Exceptions go through
+            //            unaltered???
+            //
+            errMsg = ex.toString() + " " + typeName + " class (" + className + ") CTOR threw exception.";
+            throw new ConfigurationException(errMsg, ex);
+        }
+        // DISCUSS: Should we also catch ExceptionInInitializerError here? See Google Issue #61 comments.
+    }
 
     /**
      * Control whether cache for classes and method names should be enabled or disabled. Initial state is enabled.
@@ -143,32 +143,32 @@ public class ObjFactory {
         cacheEnabled = enable;
     }
 
-	/**
-	 * Load the class in cache, or load by the classloader and cache it
-	 *
-	 * @param className The name of the class to construct. Should be a fully qualified name
-	 * @return The target class
-	 * @throws ClassNotFoundException Failed to load class by the className
-	 */
-	private static Class<?> loadClassByStringName(String className) throws ClassNotFoundException {
-		Class<?> clazz;
-		if (cacheEnabled && CLASSES_CACHE.containsKey(className)) {
-			clazz = CLASSES_CACHE.get(className);
-		} else {
-			clazz = Class.forName(className);
-			if ( cacheEnabled ) CLASSES_CACHE.putIfAbsent(className, clazz);
-		}
-		return clazz;
-	}
-
-	/**
-	 * Find the method to create a singleton object
-	 *
-	 * @param className The name of the class to construct. Should be a fully qualified name
-	 * @param theClass The class loaded in prior
-	 * @return The method to create a singleton object
-	 * @throws NoSuchMethodException Failed to find the target method
-	 */
+    /**
+     * Load the class in cache, or load by the classloader and cache it
+     *
+     * @param className The name of the class to construct. Should be a fully qualified name
+     * @return The target class
+     * @throws ClassNotFoundException Failed to load class by the className
+     */
+    private static Class<?> loadClassByStringName(String className) throws ClassNotFoundException {
+        Class<?> clazz;
+        if (cacheEnabled && CLASSES_CACHE.containsKey(className)) {
+            clazz = CLASSES_CACHE.get(className);
+        } else {
+            clazz = Class.forName(className);
+            if ( cacheEnabled ) CLASSES_CACHE.putIfAbsent(className, clazz);
+        }
+        return clazz;
+    }
+
+    /**
+     * Find the method to create a singleton object
+     *
+     * @param className The name of the class to construct. Should be a fully qualified name
+     * @param theClass The class loaded in prior
+     * @return The method to create a singleton object
+     * @throws NoSuchMethodException Failed to find the target method
+     */
     private static Method findSingletonCreateMethod(String className, Class<?> theClass) throws NoSuchMethodException {
         MethodWrappedInfo singleton = loadMethodByStringName(className,theClass);
 
@@ -180,13 +180,13 @@ public class ObjFactory {
         return singleton.getMethod();
     }
 
-	/**
-	 *
-	 * @param className The name of the class to construct. Should be a fully qualified name
-	 * @param theClass The class loaded in prior
-	 * @return Wrapped data, contains the method object and the method is static method or not
-	 * @throws NoSuchMethodException Failed to find the target method
-	 */
+    /**
+     *
+     * @param className The name of the class to construct. Should be a fully qualified name
+     * @param theClass The class loaded in prior
+     * @return Wrapped data, contains the method object and the method is static method or not
+     * @throws NoSuchMethodException Failed to find the target method
+     */
     private static MethodWrappedInfo loadMethodByStringName(String className, Class<?> theClass) throws NoSuchMethodException {
         String methodName = className + "getInstance";
         MethodWrappedInfo methodInfo;
@@ -204,33 +204,33 @@ public class ObjFactory {
     }
 
     /**
-	 * Not instantiable
-	 */
-	private ObjFactory() { }
+     * Not instantiable
+     */
+    private ObjFactory() { }
 
-	/**
-	 * Wrapped data, contains the method object and the method is static method or not.<br>
-	 * The goal to store the boolean value in field staticMethod is reduce the check times: check once, use many times.<br>
+    /**
+     * Wrapped data, contains the method object and the method is static method or not.<br>
+     * The goal to store the boolean value in field staticMethod is reduce the check times: check once, use many times.<br>
      * The goal to store the exception in field nonStaticException is reduce the cost of new Exception(): create once, use many times.
-	 */
-	private static class MethodWrappedInfo {
-		private Method method;
-		private boolean staticMethod;
-		private ConfigurationException nonStaticEx;
-
-		MethodWrappedInfo(Method method, boolean staticMethod, ConfigurationException nonStaticEx) {
-			this.method = method;
-			this.staticMethod = staticMethod;
-			this.nonStaticEx = nonStaticEx;
-		}
-
-		Method getMethod() {
-			return method;
-		}
-
-		boolean isStaticMethod() {
-			return staticMethod;
-		}
+     */
+    private static class MethodWrappedInfo {
+        private Method method;
+        private boolean staticMethod;
+        private ConfigurationException nonStaticEx;
+
+        MethodWrappedInfo(Method method, boolean staticMethod, ConfigurationException nonStaticEx) {
+            this.method = method;
+            this.staticMethod = staticMethod;
+            this.nonStaticEx = nonStaticEx;
+        }
+
+        Method getMethod() {
+            return method;
+        }
+
+        boolean isStaticMethod() {
+            return staticMethod;
+        }
 
         ConfigurationException getNonStaticEx() {
             return nonStaticEx;
diff --git a/src/main/java/org/owasp/esapi/waf/ConfigurationException.java b/src/main/java/org/owasp/esapi/waf/ConfigurationException.java
index 644678e..8368e22 100644
--- a/src/main/java/org/owasp/esapi/waf/ConfigurationException.java
+++ b/src/main/java/org/owasp/esapi/waf/ConfigurationException.java
@@ -1,15 +1,15 @@
 /**
  * OWASP Enterprise Security API (ESAPI)
- * 
+ *
  * This file is part of the Open Web Application Security Project (OWASP)
  * Enterprise Security API (ESAPI) project. For details, please see
  * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
  *
  * Copyright (c) 2009 - The OWASP Foundation
- * 
+ *
  * The ESAPI is published by OWASP under the BSD license. You should read and accept the
  * LICENSE before you use, modify, and/or redistribute this software.
- * 
+ *
  * @author Arshan Dabirsiaghi <a href="http://www.aspectsecurity.com">Aspect Security</a>
  * @created 2009
  */
@@ -21,22 +21,22 @@ import org.owasp.esapi.errors.EnterpriseSecurityException;
 
 /**
  * The Exception to be thrown when there is an error parsing a policy file.
- * 
+ *
  * @author Arshan Dabirsiaghi
  * @see org.owasp.esapi.waf.configuration.ConfigurationParser
  *
  */
 public class ConfigurationException extends EnterpriseSecurityException {
 
-	protected static final long serialVersionUID = 1L;
+    protected static final long serialVersionUID = 1L;
 
-	public ConfigurationException(String userMsg, String logMsg) {
-		super(userMsg,logMsg);
-	}
+    public ConfigurationException(String userMsg, String logMsg) {
+        super(userMsg,logMsg);
+    }
 
-	public ConfigurationException(String userMsg, String logMsg,
-			Throwable t) {
-		super(userMsg,logMsg,t);
-	}
+    public ConfigurationException(String userMsg, String logMsg,
+            Throwable t) {
+        super(userMsg,logMsg,t);
+    }
 
 }
diff --git a/src/main/java/org/owasp/esapi/waf/ESAPIWebApplicationFirewallFilter.java b/src/main/java/org/owasp/esapi/waf/ESAPIWebApplicationFirewallFilter.java
index 82bd7e0..bd5e7f9 100644
--- a/src/main/java/org/owasp/esapi/waf/ESAPIWebApplicationFirewallFilter.java
+++ b/src/main/java/org/owasp/esapi/waf/ESAPIWebApplicationFirewallFilter.java
@@ -1,22 +1,21 @@
 /**
  * OWASP Enterprise Security API (ESAPI)
- * 
+ *
  * This file is part of the Open Web Application Security Project (OWASP)
  * Enterprise Security API (ESAPI) project. For details, please see
  * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
  *
  * Copyright (c) 2009 - The OWASP Foundation
- * 
+ *
  * The ESAPI is published by OWASP under the BSD license. You should read and accept the
  * LICENSE before you use, modify, and/or redistribute this software.
- * 
+ *
  * @author Arshan Dabirsiaghi <a href="http://www.aspectsecurity.com">Aspect Security</a>
  * @created 2009
  */
 package org.owasp.esapi.waf;
 
 import java.io.File;
-
 import java.io.FileInputStream;
 import java.io.FileNotFoundException;
 import java.io.IOException;
@@ -32,7 +31,6 @@ import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
 import org.apache.commons.fileupload.FileUploadException;
-import org.apache.log4j.xml.DOMConfigurator;
 import org.owasp.esapi.ESAPI;
 import org.owasp.esapi.Logger;
 import org.owasp.esapi.waf.actions.Action;
@@ -50,11 +48,11 @@ import org.owasp.esapi.waf.rules.Rule;
  * standard J2EE servlet filter that, in different methods, invokes the reading
  * of the configuration file and handles the runtime processing and enforcing of
  * the developer-specified rules.
- * 
+ *
  * Ideally the filter should be configured to catch all requests (/*) in
  * web.xml. If there are URL segments that need to be extremely fast and don't
  * require any protection, the pattern may be modified with extreme caution.
- * 
+ *
  * @author Arshan Dabirsiaghi
  *
  */
@@ -84,7 +82,7 @@ public class ESAPIWebApplicationFirewallFilter implements Filter {
 
 	/**
 	 * This function is used in testing to dynamically alter the configuration.
-	 * 
+	 *
 	 * @param policyFilePath
 	 *            The path to the policy file
 	 * @param webRootDir
@@ -102,7 +100,7 @@ public class ESAPIWebApplicationFirewallFilter implements Filter {
 			lastConfigReadTime = System.currentTimeMillis();
 			configurationFilename = policyFilePath;
 		} catch (ConfigurationException e) {
-			// TODO: It would be ideal if this method through the
+			// TODO: It would be ideal if this method threw the
 			// ConfigurationException rather than catching it and
 			// writing the error to the console.
 			e.printStackTrace();
@@ -122,11 +120,11 @@ public class ESAPIWebApplicationFirewallFilter implements Filter {
 	}
 
 	/**
-	 * 
+	 *
 	 * This function is invoked at application startup and when the
 	 * configuration file polling period has elapsed and a change in the
 	 * configuration file has been detected.
-	 * 
+	 *
 	 * It's main purpose is to read the configuration file and establish the
 	 * configuration object model for use at runtime during the
 	 * <code>doFilter()</code> method.
@@ -141,19 +139,18 @@ public class ESAPIWebApplicationFirewallFilter implements Filter {
 
 		logger.debug(Logger.EVENT_SUCCESS, ">> Initializing WAF");
 		/*
-		 * Pull logging file.
+		 * Pull logging file. -- We now ignore this arg, but will log something
+         * letting users know we are ignoring it, because many of them never
+         * seem to read the release notes. And this is probably better than
+         * throwing an exception.
 		 */
+        String logSettingsFilename = fc.getInitParameter(LOGGING_FILE_PARAM);
+        if ( logSettingsFilename != null ) {
+            logger.warning(Logger.EVENT_FAILURE, ">> Since ESAPI 2.5.0.0, ESAPI WAF ignoring parameter '" +
+                    LOGGING_FILE_PARAM + "; for further details, see " +
+                    "https://github.com/ESAPI/esapi-java-legacy/blob/develop/documentation/esapi4java-core-2.5.0.0-release-notes.txt");
 
-		// Demoted scope to a local since this is the only place it is
-		// referenced
-		String logSettingsFilename = fc.getInitParameter(LOGGING_FILE_PARAM);
-
-		String realLogSettingsFilename = fc.getServletContext().getRealPath(logSettingsFilename);
-
-		if (realLogSettingsFilename == null || (!new File(realLogSettingsFilename).exists())) {
-			throw new ServletException(
-					"[ESAPI WAF] Could not find log file at resolved path: " + realLogSettingsFilename);
-		}
+        }
 
 		/*
 		 * Pull main configuration file.
@@ -192,7 +189,6 @@ public class ESAPIWebApplicationFirewallFilter implements Filter {
 			String webRootDir = fc.getServletContext().getRealPath("/");
 			inputStream = new FileInputStream(configurationFilename);
 			appGuardConfig = ConfigurationParser.readConfigurationFile(inputStream, webRootDir);
-			DOMConfigurator.configure(realLogSettingsFilename);
 			lastConfigReadTime = System.currentTimeMillis();
 		} catch (FileNotFoundException e) {
 			throw new ServletException(e);
diff --git a/src/main/java/org/owasp/esapi/waf/actions/Action.java b/src/main/java/org/owasp/esapi/waf/actions/Action.java
index b15498a..46db8e3 100644
--- a/src/main/java/org/owasp/esapi/waf/actions/Action.java
+++ b/src/main/java/org/owasp/esapi/waf/actions/Action.java
@@ -1,15 +1,15 @@
 /**
  * OWASP Enterprise Security API (ESAPI)
- * 
+ *
  * This file is part of the Open Web Application Security Project (OWASP)
  * Enterprise Security API (ESAPI) project. For details, please see
  * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
  *
  * Copyright (c) 2009 - The OWASP Foundation
- * 
+ *
  * The ESAPI is published by OWASP under the BSD license. You should read and accept the
  * LICENSE before you use, modify, and/or redistribute this software.
- * 
+ *
  * @author Arshan Dabirsiaghi <a href="http://www.aspectsecurity.com">Aspect Security</a>
  * @created 2009
  */
@@ -17,29 +17,29 @@ package org.owasp.esapi.waf.actions;
 
 /**
  * The base class indicating what is to be done after a rule executes.
- * 
+ *
  * @author Arshan Dabirsiaghi
  * @see org.owasp.esapi.waf.rules.Rule
  */
 public abstract class Action {
 
-	protected boolean failed = true;
-	protected boolean actionNecessary = true;
+    protected boolean failed = true;
+    protected boolean actionNecessary = true;
 
-	public void setFailed(boolean didFail) {
-		failed = didFail;
-	}
+    public void setFailed(boolean didFail) {
+        failed = didFail;
+    }
 
-	public boolean failedRule() {
-		return failed;
-	}
+    public boolean failedRule() {
+        return failed;
+    }
 
-	public boolean isActionNecessary() {
-		return actionNecessary;
-	}
+    public boolean isActionNecessary() {
+        return actionNecessary;
+    }
 
-	public void setActionNecessary(boolean b) {
-		this.actionNecessary = b;
+    public void setActionNecessary(boolean b) {
+        this.actionNecessary = b;
 
-	}
+    }
 }
diff --git a/src/main/java/org/owasp/esapi/waf/actions/BlockAction.java b/src/main/java/org/owasp/esapi/waf/actions/BlockAction.java
index 5acfcf1..a9cf60f 100644
--- a/src/main/java/org/owasp/esapi/waf/actions/BlockAction.java
+++ b/src/main/java/org/owasp/esapi/waf/actions/BlockAction.java
@@ -1,15 +1,15 @@
 /**
  * OWASP Enterprise Security API (ESAPI)
- * 
+ *
  * This file is part of the Open Web Application Security Project (OWASP)
  * Enterprise Security API (ESAPI) project. For details, please see
  * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
  *
  * Copyright (c) 2009 - The OWASP Foundation
- * 
+ *
  * The ESAPI is published by OWASP under the BSD license. You should read and accept the
  * LICENSE before you use, modify, and/or redistribute this software.
- * 
+ *
  * @author Arshan Dabirsiaghi <a href="http://www.aspectsecurity.com">Aspect Security</a>
  * @created 2009
  */
@@ -18,18 +18,18 @@ package org.owasp.esapi.waf.actions;
 /**
  * The class that indicates the request processing should be halted and that a blank response
  * should be returned.
- * 
+ *
  * @author Arshan Dabirsiaghi
  */
 public class BlockAction extends Action {
 
-	public boolean failedRule() {
-		return true;
-	}
+    public boolean failedRule() {
+        return true;
+    }
 
 
-	public boolean isActionNecessary() {
-		return true;
-	}
+    public boolean isActionNecessary() {
+        return true;
+    }
 
 }
diff --git a/src/main/java/org/owasp/esapi/waf/actions/DefaultAction.java b/src/main/java/org/owasp/esapi/waf/actions/DefaultAction.java
index dd81431..7aad503 100644
--- a/src/main/java/org/owasp/esapi/waf/actions/DefaultAction.java
+++ b/src/main/java/org/owasp/esapi/waf/actions/DefaultAction.java
@@ -1,15 +1,15 @@
 /**
  * OWASP Enterprise Security API (ESAPI)
- * 
+ *
  * This file is part of the Open Web Application Security Project (OWASP)
  * Enterprise Security API (ESAPI) project. For details, please see
  * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
  *
  * Copyright (c) 2009 - The OWASP Foundation
- * 
+ *
  * The ESAPI is published by OWASP under the BSD license. You should read and accept the
  * LICENSE before you use, modify, and/or redistribute this software.
- * 
+ *
  * @author Arshan Dabirsiaghi <a href="http://www.aspectsecurity.com">Aspect Security</a>
  * @created 2009
  */
@@ -18,17 +18,17 @@ package org.owasp.esapi.waf.actions;
 /**
  * The class that indicates the default action as indicated by the policy file
  * should be executed.
- * 
+ *
  * @author Arshan Dabirsiaghi
  */
 public class DefaultAction extends Action {
 
-	public boolean failedRule() {
-		return true;
-	}
+    public boolean failedRule() {
+        return true;
+    }
 
-	public boolean isActionNecessary() {
-		return true;
-	}
+    public boolean isActionNecessary() {
+        return true;
+    }
 
 }
diff --git a/src/main/java/org/owasp/esapi/waf/actions/DoNothingAction.java b/src/main/java/org/owasp/esapi/waf/actions/DoNothingAction.java
index a75f588..70d5970 100644
--- a/src/main/java/org/owasp/esapi/waf/actions/DoNothingAction.java
+++ b/src/main/java/org/owasp/esapi/waf/actions/DoNothingAction.java
@@ -1,15 +1,15 @@
 /**
  * OWASP Enterprise Security API (ESAPI)
- * 
+ *
  * This file is part of the Open Web Application Security Project (OWASP)
  * Enterprise Security API (ESAPI) project. For details, please see
  * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
  *
  * Copyright (c) 2009 - The OWASP Foundation
- * 
+ *
  * The ESAPI is published by OWASP under the BSD license. You should read and accept the
  * LICENSE before you use, modify, and/or redistribute this software.
- * 
+ *
  * @author Arshan Dabirsiaghi <a href="http://www.aspectsecurity.com">Aspect Security</a>
  * @created 2009
  */
@@ -17,18 +17,18 @@ package org.owasp.esapi.waf.actions;
 
 /**
  * The class that indicates that no further action is necessary.
- * 
+ *
  * @author Arshan Dabirsiaghi
  */
 public class DoNothingAction extends Action {
 
-	public boolean failedRule() {
-		return this.failed;
-	}
+    public boolean failedRule() {
+        return this.failed;
+    }
 
 
-	public boolean isActionNecessary() {
-		return false;
-	}
+    public boolean isActionNecessary() {
+        return false;
+    }
 
 }
diff --git a/src/main/java/org/owasp/esapi/waf/actions/RedirectAction.java b/src/main/java/org/owasp/esapi/waf/actions/RedirectAction.java
index 0993b4a..b16fa4e 100644
--- a/src/main/java/org/owasp/esapi/waf/actions/RedirectAction.java
+++ b/src/main/java/org/owasp/esapi/waf/actions/RedirectAction.java
@@ -1,15 +1,15 @@
 /**
  * OWASP Enterprise Security API (ESAPI)
- * 
+ *
  * This file is part of the Open Web Application Security Project (OWASP)
  * Enterprise Security API (ESAPI) project. For details, please see
  * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
  *
  * Copyright (c) 2009 - The OWASP Foundation
- * 
+ *
  * The ESAPI is published by OWASP under the BSD license. You should read and accept the
  * LICENSE before you use, modify, and/or redistribute this software.
- * 
+ *
  * @author Arshan Dabirsiaghi <a href="http://www.aspectsecurity.com">Aspect Security</a>
  * @created 2009
  */
@@ -17,23 +17,23 @@ package org.owasp.esapi.waf.actions;
 
 /**
  * The class that indicates the user should be redirected to another location.
- * 
+ *
  * @author Arshan Dabirsiaghi
  */
 public class RedirectAction extends Action {
 
-	private String url = null;
+    private String url = null;
 
-	/*
-	 * Setting this overrides the default value read in the config file.
-	 */
-	public void setRedirectURL(String s) {
-		this.url = s;
-	}
+    /*
+     * Setting this overrides the default value read in the config file.
+     */
+    public void setRedirectURL(String s) {
+        this.url = s;
+    }
 
-	public String getRedirectURL() {
-		return this.url;
-	}
+    public String getRedirectURL() {
+        return this.url;
+    }
 
 
 }
diff --git a/src/main/java/org/owasp/esapi/waf/actions/package.html b/src/main/java/org/owasp/esapi/waf/actions/package.html
index 89657d0..4fee1e1 100644
--- a/src/main/java/org/owasp/esapi/waf/actions/package.html
+++ b/src/main/java/org/owasp/esapi/waf/actions/package.html
@@ -5,7 +5,7 @@
 
 <body bgcolor="white">
 
-This package contains the Action objects that are executed after a Rule subclass executes. 
- 
+This package contains the Action objects that are executed after a Rule subclass executes.
+
 </body>
 </html>
diff --git a/src/main/java/org/owasp/esapi/waf/configuration/AppGuardianConfiguration.java b/src/main/java/org/owasp/esapi/waf/configuration/AppGuardianConfiguration.java
index 29e398e..25eb248 100644
--- a/src/main/java/org/owasp/esapi/waf/configuration/AppGuardianConfiguration.java
+++ b/src/main/java/org/owasp/esapi/waf/configuration/AppGuardianConfiguration.java
@@ -1,191 +1,176 @@
 /**
  * OWASP Enterprise Security API (ESAPI)
- * 
+ *
  * This file is part of the Open Web Application Security Project (OWASP)
  * Enterprise Security API (ESAPI) project. For details, please see
  * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
  *
  * Copyright (c) 2009 - The OWASP Foundation
- * 
+ *
  * The ESAPI is published by OWASP under the BSD license. You should read and accept the
  * LICENSE before you use, modify, and/or redistribute this software.
- * 
+ *
  * @author Arshan Dabirsiaghi <a href="http://www.aspectsecurity.com">Aspect Security</a>
  * @created 2009
  */
 package org.owasp.esapi.waf.configuration;
 
 import java.util.ArrayList;
-import java.util.HashMap;
 import java.util.List;
 
-import org.apache.log4j.Level;
 import org.owasp.esapi.waf.rules.Rule;
 
 /**
  * This class is the object model of the policy file. Also holds a number of constants
  * used throughout the WAF.
- * 
+ *
  * @author Arshan Dabirsiaghi
  *
  */
 public class AppGuardianConfiguration {
 
-	/*
-	 * Fail modes (BLOCK blocks and logs the request, DONT_BLOCK simply logs)
-	 */
-	public static final int LOG = 0;
-	public static final int REDIRECT = 1;
-	public static final int BLOCK = 2;
-
-	/*
-	 * The operators.
-	 */
-	public static final int OPERATOR_EQ = 0;
-	public static final int OPERATOR_CONTAINS = 1;
-	public static final int OPERATOR_IN_LIST = 2;
-	public static final int OPERATOR_EXISTS = 3;
-
-	/*
-	 * We have static copies of the log settings so that the Rule objects
-	 * can access them, because they don't have access to the instance of
-	 * the configuration object.
-	 */
-	public static Level LOG_LEVEL = Level.INFO;	
-	public static String LOG_DIRECTORY = "/WEB-INF/logs";
-
-	/*
-	 * Logging settings.
-	 */
-	private Level logLevel = Level.INFO;
-	private String logDirectory = "/WEB-INF/logs";
-
-	/*
-	 * Default settings.
-	 */
-	public static int DEFAULT_FAIL_ACTION = LOG;
-
-	// TODO: use UTF-8
-	public static String DEFAULT_CHARACTER_ENCODING = "ISO-8859-1";
-	public static String DEFAULT_CONTENT_TYPE = "text/html; charset=" + DEFAULT_CHARACTER_ENCODING;
-
-	/*
-	 * The JavaScript to redirect users to the default error page. Have
-	 * to use this because response.sendRedirect() can't have an arbitrary
-	 * response code and that is a requirement.
-	 */
-	public static final String JAVASCRIPT_TARGET_TOKEN = "##1##";
-	public static final String JAVASCRIPT_REDIRECT = "<html><body><script>document.location='" + JAVASCRIPT_TARGET_TOKEN + "';</script></body></html>";
-
-	/*
-	 * Fail response settings.
-	 */
-	private String defaultErrorPage;
-	private int defaultResponseCode;
-
-	private boolean forceHttpOnlyFlagToSession = false;
-	private boolean forceSecureFlagToSession = false;
-
-	private String sessionCookieName;
-	
-	public String getSessionCookieName() {
-		return sessionCookieName;
-	}
-
-	public void setSessionCookieName(String sessionCookieName) {
-		this.sessionCookieName = sessionCookieName;
-	}
-
-	/*
-	 * The object-level rules encapsulated by the stage in which they are executed.
-	 */
-	private List<Rule> beforeBodyRules;
-	private List<Rule> afterBodyRules;
-	private List<Rule> beforeResponseRules;
-	private List<Rule> cookieRules;
-
-	public AppGuardianConfiguration() {
-		beforeBodyRules = new ArrayList<Rule>();
-		afterBodyRules = new ArrayList<Rule>();
-		beforeResponseRules = new ArrayList<Rule>();
-		cookieRules = new ArrayList<Rule>();
-	}
-
-	public String getDefaultErrorPage() {
-		return defaultErrorPage;
-	}
-
-	public void setDefaultErrorPage(String defaultErrorPage) {
-		this.defaultErrorPage = defaultErrorPage;
-	}
-
-	public int getDefaultResponseCode() {
-		return defaultResponseCode;
-	}
-
-	public void setDefaultResponseCode(int defaultResponseCode) {
-		this.defaultResponseCode = defaultResponseCode;
-	}
-
-
-	public List<Rule> getBeforeBodyRules() {
-		return beforeBodyRules;
-	}
-
-	public List<Rule> getAfterBodyRules() {
-		return afterBodyRules;
-	}
-
-	public List<Rule> getBeforeResponseRules() {
-		return beforeResponseRules;
-	}
-
-	public List<Rule> getCookieRules() {
-		return cookieRules;
-	}
-
-	public void addBeforeBodyRule(Rule r) {
-		beforeBodyRules.add(r);
-	}
-
-	public void addAfterBodyRule(Rule r) {
-		afterBodyRules.add(r);
-	}
-
-	public void addBeforeResponseRule(Rule r) {
-		beforeResponseRules.add(r);
-	}
-
-	public void addCookieRule(Rule r) {
-		cookieRules.add(r);
-	}
-
-	public void setApplyHTTPOnlyFlagToSessionCookie(boolean shouldApply) {
-		forceHttpOnlyFlagToSession = shouldApply;
-	}
-
-	public void setApplySecureFlagToSessionCookie(boolean shouldApply) {
-		forceSecureFlagToSession = shouldApply;
-	}
-	
-	public boolean isUsingHttpOnlyFlagOnSessionCookie() {
-		return forceHttpOnlyFlagToSession;
-	}
-
-	public boolean isUsingSecureFlagOnSessionCookie() {
-		return forceSecureFlagToSession;
-	}
-	
-	public String toString() {
-		StringBuilder sb = new StringBuilder( "WAF Configuration\n" );
-		sb.append( "Before body rules:\n" );
-		for ( Rule rule : beforeBodyRules ) sb.append( "  " + rule.toString() + "\n" );
-		sb.append( "After body rules:\n" );
-		for ( Rule rule : afterBodyRules ) sb.append( "  " + rule.toString() + "\n" );
-		sb.append( "Before response rules:\n" );
-		for ( Rule rule : beforeResponseRules ) sb.append( "  " + rule.toString() + "\n" );
-		sb.append( "Cookie rules:\n" );
-		for ( Rule rule : cookieRules ) sb.append( "  " + rule.toString() + "\n" );
-		return sb.toString();
-	}
+    /*
+     * Fail modes (BLOCK blocks and logs the request, DONT_BLOCK simply logs)
+     */
+    public static final int LOG = 0;
+    public static final int REDIRECT = 1;
+    public static final int BLOCK = 2;
+
+    /*
+     * The operators.
+     */
+    public static final int OPERATOR_EQ = 0;
+    public static final int OPERATOR_CONTAINS = 1;
+    public static final int OPERATOR_IN_LIST = 2;
+    public static final int OPERATOR_EXISTS = 3;
+
+
+    /*
+     * Default settings.
+     */
+    public static int DEFAULT_FAIL_ACTION = LOG;
+
+    // TODO: use UTF-8
+    public static String DEFAULT_CHARACTER_ENCODING = "ISO-8859-1";
+    public static String DEFAULT_CONTENT_TYPE = "text/html; charset=" + DEFAULT_CHARACTER_ENCODING;
+
+    /*
+     * The JavaScript to redirect users to the default error page. Have
+     * to use this because response.sendRedirect() can't have an arbitrary
+     * response code and that is a requirement.
+     */
+    public static final String JAVASCRIPT_TARGET_TOKEN = "##1##";
+    public static final String JAVASCRIPT_REDIRECT = "<html><body><script>document.location='" + JAVASCRIPT_TARGET_TOKEN + "';</script></body></html>";
+
+    /*
+     * Fail response settings.
+     */
+    private String defaultErrorPage;
+    private int defaultResponseCode;
+
+    private boolean forceHttpOnlyFlagToSession = false;
+    private boolean forceSecureFlagToSession = false;
+
+    private String sessionCookieName;
+
+    public String getSessionCookieName() {
+        return sessionCookieName;
+    }
+
+    public void setSessionCookieName(String sessionCookieName) {
+        this.sessionCookieName = sessionCookieName;
+    }
+
+    /*
+     * The object-level rules encapsulated by the stage in which they are executed.
+     */
+    private List<Rule> beforeBodyRules;
+    private List<Rule> afterBodyRules;
+    private List<Rule> beforeResponseRules;
+    private List<Rule> cookieRules;
+
+    public AppGuardianConfiguration() {
+        beforeBodyRules = new ArrayList<Rule>();
+        afterBodyRules = new ArrayList<Rule>();
+        beforeResponseRules = new ArrayList<Rule>();
+        cookieRules = new ArrayList<Rule>();
+    }
+
+    public String getDefaultErrorPage() {
+        return defaultErrorPage;
+    }
+
+    public void setDefaultErrorPage(String defaultErrorPage) {
+        this.defaultErrorPage = defaultErrorPage;
+    }
+
+    public int getDefaultResponseCode() {
+        return defaultResponseCode;
+    }
+
+    public void setDefaultResponseCode(int defaultResponseCode) {
+        this.defaultResponseCode = defaultResponseCode;
+    }
+
+
+    public List<Rule> getBeforeBodyRules() {
+        return beforeBodyRules;
+    }
+
+    public List<Rule> getAfterBodyRules() {
+        return afterBodyRules;
+    }
+
+    public List<Rule> getBeforeResponseRules() {
+        return beforeResponseRules;
+    }
+
+    public List<Rule> getCookieRules() {
+        return cookieRules;
+    }
+
+    public void addBeforeBodyRule(Rule r) {
+        beforeBodyRules.add(r);
+    }
+
+    public void addAfterBodyRule(Rule r) {
+        afterBodyRules.add(r);
+    }
+
+    public void addBeforeResponseRule(Rule r) {
+        beforeResponseRules.add(r);
+    }
+
+    public void addCookieRule(Rule r) {
+        cookieRules.add(r);
+    }
+
+    public void setApplyHTTPOnlyFlagToSessionCookie(boolean shouldApply) {
+        forceHttpOnlyFlagToSession = shouldApply;
+    }
+
+    public void setApplySecureFlagToSessionCookie(boolean shouldApply) {
+        forceSecureFlagToSession = shouldApply;
+    }
+
+    public boolean isUsingHttpOnlyFlagOnSessionCookie() {
+        return forceHttpOnlyFlagToSession;
+    }
+
+    public boolean isUsingSecureFlagOnSessionCookie() {
+        return forceSecureFlagToSession;
+    }
+
+    public String toString() {
+        StringBuilder sb = new StringBuilder( "WAF Configuration\n" );
+        sb.append( "Before body rules:\n" );
+        for ( Rule rule : beforeBodyRules ) sb.append( "  " + rule.toString() + "\n" );
+        sb.append( "After body rules:\n" );
+        for ( Rule rule : afterBodyRules ) sb.append( "  " + rule.toString() + "\n" );
+        sb.append( "Before response rules:\n" );
+        for ( Rule rule : beforeResponseRules ) sb.append( "  " + rule.toString() + "\n" );
+        sb.append( "Cookie rules:\n" );
+        for ( Rule rule : cookieRules ) sb.append( "  " + rule.toString() + "\n" );
+        return sb.toString();
+    }
 }
diff --git a/src/main/java/org/owasp/esapi/waf/configuration/ConfigurationParser.java b/src/main/java/org/owasp/esapi/waf/configuration/ConfigurationParser.java
index fefcff8..b5474c4 100644
--- a/src/main/java/org/owasp/esapi/waf/configuration/ConfigurationParser.java
+++ b/src/main/java/org/owasp/esapi/waf/configuration/ConfigurationParser.java
@@ -1,15 +1,15 @@
 /**
  * OWASP Enterprise Security API (ESAPI)
- * 
+ *
  * This file is part of the Open Web Application Security Project (OWASP)
  * Enterprise Security API (ESAPI) project. For details, please see
  * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
  *
  * Copyright (c) 2009 - The OWASP Foundation
- * 
+ *
  * The ESAPI is published by OWASP under the BSD license. You should read and accept the
  * LICENSE before you use, modify, and/or redistribute this software.
- * 
+ *
  * @author Arshan Dabirsiaghi <a href="http://www.aspectsecurity.com">Aspect Security</a>
  * @created 2009
  */
@@ -51,546 +51,546 @@ import org.owasp.esapi.waf.rules.SimpleVirtualPatchRule;
 import bsh.EvalError;
 
 /**
- * 
- * The class used to turn a policy file's contents into an object model. 
- * 
+ *
+ * The class used to turn a policy file's contents into an object model.
+ *
  * @author Arshan Dabirsiaghi
  * @see org.owasp.esapi.waf.configuration.AppGuardianConfiguration
  */
 public class ConfigurationParser {
 
-	private static final String REGEX = "regex";
-	private static final String DEFAULT_PATH_APPLY_ALL = ".*";
-	private static final int DEFAULT_RESPONSE_CODE = 403;
-	private static final String DEFAULT_SESSION_COOKIE;
-	
-	static {
-		String sessionIdName = null;
-		try {
-			sessionIdName = ESAPI.securityConfiguration().getHttpSessionIdName();
-		} catch (Throwable t) {
-			sessionIdName = "JSESSIONID";	// If all else fails...
-		}
-		DEFAULT_SESSION_COOKIE = sessionIdName;
-	}
-	
-	private static final String[] STAGES = {
-		"before-request-body",
-		"after-request-body",
-		"before-response"
-	};
-	
-	public static AppGuardianConfiguration readConfigurationFile(InputStream stream, String webRootDir) throws ConfigurationException {
-
-		AppGuardianConfiguration config = new AppGuardianConfiguration();
-
-		Builder parser = new Builder();
-		Document doc;
-		Element root;
-
-		try {
-
-			doc = parser.build(stream);
-			root = doc.getRootElement();
-
-			Element settingsRoot = root.getFirstChildElement("settings");
-			Element authNRoot = root.getFirstChildElement("authentication-rules");
-			Element authZRoot = root.getFirstChildElement("authorization-rules");
-			Element urlRoot = root.getFirstChildElement("url-rules");
-			Element headerRoot = root.getFirstChildElement("header-rules");
-			Element customRulesRoot = root.getFirstChildElement("custom-rules");;
-			Element virtualPatchesRoot = root.getFirstChildElement("virtual-patches");
-			Element outboundRoot = root.getFirstChildElement("outbound-rules");
-			Element beanShellRoot = root.getFirstChildElement("bean-shell-rules");
-			
-			
-			/**
-			 * Parse the 'settings' section.
-			 */
-			if ( settingsRoot == null ) {
+    private static final String REGEX = "regex";
+    private static final String DEFAULT_PATH_APPLY_ALL = ".*";
+    private static final int DEFAULT_RESPONSE_CODE = 403;
+    private static final String DEFAULT_SESSION_COOKIE;
+
+    static {
+        String sessionIdName = null;
+        try {
+            sessionIdName = ESAPI.securityConfiguration().getHttpSessionIdName();
+        } catch (Throwable t) {
+            sessionIdName = "JSESSIONID";    // If all else fails...
+        }
+        DEFAULT_SESSION_COOKIE = sessionIdName;
+    }
+
+    private static final String[] STAGES = {
+        "before-request-body",
+        "after-request-body",
+        "before-response"
+    };
+
+    public static AppGuardianConfiguration readConfigurationFile(InputStream stream, String webRootDir) throws ConfigurationException {
+
+        AppGuardianConfiguration config = new AppGuardianConfiguration();
+
+        Builder parser = new Builder();
+        Document doc;
+        Element root;
+
+        try {
+
+            doc = parser.build(stream);
+            root = doc.getRootElement();
+
+            Element settingsRoot = root.getFirstChildElement("settings");
+            Element authNRoot = root.getFirstChildElement("authentication-rules");
+            Element authZRoot = root.getFirstChildElement("authorization-rules");
+            Element urlRoot = root.getFirstChildElement("url-rules");
+            Element headerRoot = root.getFirstChildElement("header-rules");
+            Element customRulesRoot = root.getFirstChildElement("custom-rules");;
+            Element virtualPatchesRoot = root.getFirstChildElement("virtual-patches");
+            Element outboundRoot = root.getFirstChildElement("outbound-rules");
+            Element beanShellRoot = root.getFirstChildElement("bean-shell-rules");
+
+
+            /**
+             * Parse the 'settings' section.
+             */
+            if ( settingsRoot == null ) {
                 throw new ConfigurationException("", "The <settings> section is required");
-			} else if ( settingsRoot != null ) {
-				
-				
-				try {
-					String sessionCookieName = settingsRoot.getFirstChildElement("session-cookie-name").getValue();
-					if ( ! "".equals(sessionCookieName) ) {
-						config.setSessionCookieName(sessionCookieName);
-					}
-				} catch (NullPointerException npe) {
-					config.setSessionCookieName(DEFAULT_SESSION_COOKIE);
-				}
-
-				String mode = settingsRoot.getFirstChildElement("mode").getValue();
-				
-				if ( "block".equals(mode.toLowerCase() ) ) {
-					AppGuardianConfiguration.DEFAULT_FAIL_ACTION = AppGuardianConfiguration.BLOCK;
-				} else if ( "redirect".equals(mode.toLowerCase() ) ){
-					AppGuardianConfiguration.DEFAULT_FAIL_ACTION = AppGuardianConfiguration.REDIRECT;
-				} else {
-					AppGuardianConfiguration.DEFAULT_FAIL_ACTION = AppGuardianConfiguration.LOG;
-				}
-	
-				Element errorHandlingRoot = settingsRoot.getFirstChildElement("error-handling");
-	
-				config.setDefaultErrorPage( errorHandlingRoot.getFirstChildElement("default-redirect-page").getValue() );
-	
-				try {
-					config.setDefaultResponseCode( Integer.parseInt(errorHandlingRoot.getFirstChildElement("block-status").getValue()) );
-				} catch (Exception e) {
-					config.setDefaultResponseCode( DEFAULT_RESPONSE_CODE );
-				}
-			}
-			
-			/**
-			 * Parse the 'authentication-rules' section if they have one.
-			 */
-			if ( authNRoot != null ) {
-				String key = authNRoot.getAttributeValue("key");
-				String path = authNRoot.getAttributeValue("path");
-				String id = authNRoot.getAttributeValue("id");
-
-				if ( path != null && key != null ) {
-					config.addBeforeBodyRule(new AuthenticatedRule(id,key,Pattern.compile(path),getExceptionsFromElement(authNRoot)));
-				} else if ( key != null ) {
-					config.addBeforeBodyRule(new AuthenticatedRule(id,key,null,getExceptionsFromElement(authNRoot)));
-				} else {
-					throw new ConfigurationException("","The <authentication-rules> rule requires a 'key' attribute");
-				}
-			}
-
-			/**
-			 * Parse 'authorization-rules' section if they have one.
-			 */
-
-			if ( authZRoot != null ) {
-
-				Elements restrictNodes = authZRoot.getChildElements("restrict-source-ip");
-
-				for(int i=0;i<restrictNodes.size();i++) {
-
-					Element restrictNodeRoot = restrictNodes.get(i);
-					String id = restrictNodeRoot.getAttributeValue("id");
-					Pattern ips = Pattern.compile(restrictNodeRoot.getAttributeValue("ip-regex"));
-					String ipHeader = restrictNodeRoot.getAttributeValue("ip-header");
-					if ( REGEX.equalsIgnoreCase(restrictNodeRoot.getAttributeValue("type")) ) {
-						config.addBeforeBodyRule( new IPRule(id, ips, Pattern.compile(restrictNodeRoot.getValue()),ipHeader));
-					} else {
-						config.addBeforeBodyRule( new IPRule(id, ips, restrictNodeRoot.getValue()) );
-					}
-
-				}
-
-				Elements mustMatchNodes = authZRoot.getChildElements("must-match");
-
-				for(int i=0;i<mustMatchNodes.size();i++) {
-
-					Element e = mustMatchNodes.get(i);
-					Pattern path = Pattern.compile(e.getAttributeValue("path"));
-					String variable = e.getAttributeValue("variable");
-					String value = e.getAttributeValue("value");
-					String operator = e.getAttributeValue("operator");
-					String id = e.getAttributeValue("id");
-					int op = AppGuardianConfiguration.OPERATOR_EQ;
-
-					if ( "exists".equalsIgnoreCase(operator)) {
-						op = AppGuardianConfiguration.OPERATOR_EXISTS;
-					} else if ( "inList".equalsIgnoreCase(operator)) {
-						op = AppGuardianConfiguration.OPERATOR_IN_LIST;
-					} else if ( "contains".equalsIgnoreCase(operator)) {
-						op = AppGuardianConfiguration.OPERATOR_CONTAINS;
-					}
-
-					config.addAfterBodyRule( new MustMatchRule(id, path,variable,op,value) );
-				}
-
-			}
-
-			/**
-			 * Parse the 'url-rules' section if they have one.
-			 */
-			if ( urlRoot != null ) {
-
-				Elements restrictExtensionNodes = urlRoot.getChildElements("restrict-extension");
-				Elements restrictMethodNodes = urlRoot.getChildElements("restrict-method");
-				Elements enforceHttpsNodes = urlRoot.getChildElements("enforce-https");
-
-				/*
-				 * Read in rules that allow an app to restrict by extension.
-				 * E.g., you may want to explicitly only allow:
-				 *  .jsp, .jpg, .gif, .css, .js, etc.
-				 *
-				 * You may also want to instead explicitly deny:
-				 * .bak, .log, .txt, etc.
-				 */
-
-				for (int i=0;i<restrictExtensionNodes.size();i++) {
-
-					Element e = restrictExtensionNodes.get(i);
-					String allow = e.getAttributeValue("allow");
-					String deny = e.getAttributeValue("deny");
-					String id = e.getAttributeValue("id");
-
-					if ( allow != null && deny != null ) {
-						throw new ConfigurationException("", "restrict-extension rules can't have both 'allow' and 'deny'" );
-					}
-
-					if ( allow != null ) {
+            } else if ( settingsRoot != null ) {
+
+
+                try {
+                    String sessionCookieName = settingsRoot.getFirstChildElement("session-cookie-name").getValue();
+                    if ( ! "".equals(sessionCookieName) ) {
+                        config.setSessionCookieName(sessionCookieName);
+                    }
+                } catch (NullPointerException npe) {
+                    config.setSessionCookieName(DEFAULT_SESSION_COOKIE);
+                }
+
+                String mode = settingsRoot.getFirstChildElement("mode").getValue();
+
+                if ( "block".equals(mode.toLowerCase() ) ) {
+                    AppGuardianConfiguration.DEFAULT_FAIL_ACTION = AppGuardianConfiguration.BLOCK;
+                } else if ( "redirect".equals(mode.toLowerCase() ) ){
+                    AppGuardianConfiguration.DEFAULT_FAIL_ACTION = AppGuardianConfiguration.REDIRECT;
+                } else {
+                    AppGuardianConfiguration.DEFAULT_FAIL_ACTION = AppGuardianConfiguration.LOG;
+                }
+
+                Element errorHandlingRoot = settingsRoot.getFirstChildElement("error-handling");
+
+                config.setDefaultErrorPage( errorHandlingRoot.getFirstChildElement("default-redirect-page").getValue() );
+
+                try {
+                    config.setDefaultResponseCode( Integer.parseInt(errorHandlingRoot.getFirstChildElement("block-status").getValue()) );
+                } catch (Exception e) {
+                    config.setDefaultResponseCode( DEFAULT_RESPONSE_CODE );
+                }
+            }
+
+            /**
+             * Parse the 'authentication-rules' section if they have one.
+             */
+            if ( authNRoot != null ) {
+                String key = authNRoot.getAttributeValue("key");
+                String path = authNRoot.getAttributeValue("path");
+                String id = authNRoot.getAttributeValue("id");
+
+                if ( path != null && key != null ) {
+                    config.addBeforeBodyRule(new AuthenticatedRule(id,key,Pattern.compile(path),getExceptionsFromElement(authNRoot)));
+                } else if ( key != null ) {
+                    config.addBeforeBodyRule(new AuthenticatedRule(id,key,null,getExceptionsFromElement(authNRoot)));
+                } else {
+                    throw new ConfigurationException("","The <authentication-rules> rule requires a 'key' attribute");
+                }
+            }
+
+            /**
+             * Parse 'authorization-rules' section if they have one.
+             */
+
+            if ( authZRoot != null ) {
+
+                Elements restrictNodes = authZRoot.getChildElements("restrict-source-ip");
+
+                for(int i=0;i<restrictNodes.size();i++) {
+
+                    Element restrictNodeRoot = restrictNodes.get(i);
+                    String id = restrictNodeRoot.getAttributeValue("id");
+                    Pattern ips = Pattern.compile(restrictNodeRoot.getAttributeValue("ip-regex"));
+                    String ipHeader = restrictNodeRoot.getAttributeValue("ip-header");
+                    if ( REGEX.equalsIgnoreCase(restrictNodeRoot.getAttributeValue("type")) ) {
+                        config.addBeforeBodyRule( new IPRule(id, ips, Pattern.compile(restrictNodeRoot.getValue()),ipHeader));
+                    } else {
+                        config.addBeforeBodyRule( new IPRule(id, ips, restrictNodeRoot.getValue()) );
+                    }
+
+                }
+
+                Elements mustMatchNodes = authZRoot.getChildElements("must-match");
+
+                for(int i=0;i<mustMatchNodes.size();i++) {
+
+                    Element e = mustMatchNodes.get(i);
+                    Pattern path = Pattern.compile(e.getAttributeValue("path"));
+                    String variable = e.getAttributeValue("variable");
+                    String value = e.getAttributeValue("value");
+                    String operator = e.getAttributeValue("operator");
+                    String id = e.getAttributeValue("id");
+                    int op = AppGuardianConfiguration.OPERATOR_EQ;
+
+                    if ( "exists".equalsIgnoreCase(operator)) {
+                        op = AppGuardianConfiguration.OPERATOR_EXISTS;
+                    } else if ( "inList".equalsIgnoreCase(operator)) {
+                        op = AppGuardianConfiguration.OPERATOR_IN_LIST;
+                    } else if ( "contains".equalsIgnoreCase(operator)) {
+                        op = AppGuardianConfiguration.OPERATOR_CONTAINS;
+                    }
+
+                    config.addAfterBodyRule( new MustMatchRule(id, path,variable,op,value) );
+                }
+
+            }
+
+            /**
+             * Parse the 'url-rules' section if they have one.
+             */
+            if ( urlRoot != null ) {
+
+                Elements restrictExtensionNodes = urlRoot.getChildElements("restrict-extension");
+                Elements restrictMethodNodes = urlRoot.getChildElements("restrict-method");
+                Elements enforceHttpsNodes = urlRoot.getChildElements("enforce-https");
+
+                /*
+                 * Read in rules that allow an app to restrict by extension.
+                 * E.g., you may want to explicitly only allow:
+                 *  .jsp, .jpg, .gif, .css, .js, etc.
+                 *
+                 * You may also want to instead explicitly deny:
+                 * .bak, .log, .txt, etc.
+                 */
+
+                for (int i=0;i<restrictExtensionNodes.size();i++) {
+
+                    Element e = restrictExtensionNodes.get(i);
+                    String allow = e.getAttributeValue("allow");
+                    String deny = e.getAttributeValue("deny");
+                    String id = e.getAttributeValue("id");
+
+                    if ( allow != null && deny != null ) {
+                        throw new ConfigurationException("", "restrict-extension rules can't have both 'allow' and 'deny'" );
+                    }
+
+                    if ( allow != null ) {
+
+                        config.addBeforeBodyRule( new PathExtensionRule(id,Pattern.compile( ".*\\" + allow + "$"),null) );
+
+                    } else if ( deny != null ) {
+
+                        config.addBeforeBodyRule( new PathExtensionRule(id, null,Pattern.compile( ".*\\" + deny + "$")) );
+
+                    } else {
+                        throw new ConfigurationException("", "restrict extension rule should have either a 'deny' or 'allow' attribute");
+                    }
+                }
+
+                /*
+                 * Read in rules that allow the site to control
+                 * which HTTP methods are allowed to reach the
+                 * app.
+                 *
+                 * 99% of the time, you'll only need POST and
+                 * GET.
+                 */
+                for (int i=0;i<restrictMethodNodes.size();i++) {
+
+                    Element e = restrictMethodNodes.get(i);
+
+                    String allow = e.getAttributeValue("allow");
+                    String deny = e.getAttributeValue("deny");
+                    String path = e.getAttributeValue("path");
+                    String id = e.getAttributeValue("id");
+
+                    if ( path == null ) {
+                        path = DEFAULT_PATH_APPLY_ALL;
+                    }
+
+                    if ( allow != null && deny != null ) {
+                        throw new ConfigurationException("", "restrict-method rule should not have both 'allow' and 'deny' values");
+                    }
+
+                    if ( allow != null ) {
+
+                        config.addBeforeBodyRule( new HTTPMethodRule(id, Pattern.compile(allow), null, Pattern.compile(path)) );
+
+                    } else if ( deny != null ) {
+
+                        config.addBeforeBodyRule( new HTTPMethodRule(id, null, Pattern.compile(deny), Pattern.compile(path)) );
+
+                    } else {
+                        throw new ConfigurationException("", "restrict-method rule should have either an 'allow' or 'deny' value");
+                    }
+                }
+
+                for (int i=0;i<enforceHttpsNodes.size();i++) {
+
+                    Element e = enforceHttpsNodes.get(i);
+                    String path = e.getAttributeValue("path");
+                    String action = e.getAttributeValue("action");
+                    String id = e.getAttributeValue("id");
+                    List<Object> exceptions = getExceptionsFromElement(e);
+
+                    config.addBeforeBodyRule( new EnforceHTTPSRule(id, Pattern.compile(path), exceptions, action) );
+                }
+
+            }
+
+            if ( headerRoot != null ) {
+
+                Elements restrictContentTypes = headerRoot.getChildElements("restrict-content-type");
+                Elements restrictUserAgents = headerRoot.getChildElements("restrict-user-agent");
+
+                for(int i=0;i<restrictContentTypes.size();i++) {
+
+                    Element e = restrictContentTypes.get(i);
+                    String allow = e.getAttributeValue("allow");
+                    String deny = e.getAttributeValue("deny");
+                    String id = e.getAttributeValue("id");
+
+                    if ( allow != null && deny != null ) {
+                        throw new ConfigurationException("", "restrict-content-type rule should not have both 'allow' and 'deny' values");
+                    }
+
+                    if ( allow != null ) {
+
+                        config.addBeforeBodyRule( new RestrictContentTypeRule(id, Pattern.compile(allow), null) );
+
+                    } else if ( deny != null ) {
 
-						config.addBeforeBodyRule( new PathExtensionRule(id,Pattern.compile( ".*\\" + allow + "$"),null) );
+                        config.addBeforeBodyRule( new RestrictContentTypeRule(id, null, Pattern.compile(deny)) );
 
-					} else if ( deny != null ) {
+                    } else {
+                        throw new ConfigurationException("", "restrict-content-type rule should have either an 'allow' or 'deny' value");
+                    }
+                }
 
-						config.addBeforeBodyRule( new PathExtensionRule(id, null,Pattern.compile( ".*\\" + deny + "$")) );
+                for(int i=0;i<restrictUserAgents.size();i++) {
+                    Element e = restrictUserAgents.get(i);
+                    String id = e.getAttributeValue("id");
+                    String allow = e.getAttributeValue("allow");
+                    String deny = e.getAttributeValue("deny");
+                    if ( allow != null && deny != null ) {
+                        throw new ConfigurationException("", "restrict-user-agent rule should not have both 'allow' and 'deny' values");
+                    }
 
-					} else {
-						throw new ConfigurationException("", "restrict extension rule should have either a 'deny' or 'allow' attribute");
-					}
-				}
+                    if ( allow != null ) {
 
-				/*
-				 * Read in rules that allow the site to control
-				 * which HTTP methods are allowed to reach the
-				 * app.
-				 *
-				 * 99% of the time, you'll only need POST and
-				 * GET.
-				 */
-				for (int i=0;i<restrictMethodNodes.size();i++) {
+                        config.addBeforeBodyRule( new RestrictUserAgentRule(id, Pattern.compile(allow), null) );
 
-					Element e = restrictMethodNodes.get(i);
+                    } else if ( deny != null ) {
 
-					String allow = e.getAttributeValue("allow");
-					String deny = e.getAttributeValue("deny");
-					String path = e.getAttributeValue("path");
-					String id = e.getAttributeValue("id");
+                        config.addBeforeBodyRule( new RestrictUserAgentRule(id, null, Pattern.compile(deny)) );
 
-					if ( path == null ) {
-						path = DEFAULT_PATH_APPLY_ALL;
-					}
+                    } else {
+                        throw new ConfigurationException("", "restrict-user-agent rule should have either an 'allow' or 'deny' value");
+                    }
+                }
 
-					if ( allow != null && deny != null ) {
-						throw new ConfigurationException("", "restrict-method rule should not have both 'allow' and 'deny' values");
-					}
+            }
 
-					if ( allow != null ) {
+            if ( virtualPatchesRoot != null ) {
+                Elements virtualPatchNodes = virtualPatchesRoot.getChildElements("virtual-patch");
+                for(int i=0;i<virtualPatchNodes.size();i++) {
+                    Element e = virtualPatchNodes.get(i);
+                    String id = e.getAttributeValue("id");
+                    String path = e.getAttributeValue("path");
+                    String variable = e.getAttributeValue("variable");
+                    String pattern = e.getAttributeValue("pattern");
+                    String message = e.getAttributeValue("message");
 
-						config.addBeforeBodyRule( new HTTPMethodRule(id, Pattern.compile(allow), null, Pattern.compile(path)) );
+                    config.addAfterBodyRule( new SimpleVirtualPatchRule(id, Pattern.compile(path), variable, Pattern.compile(pattern), message) );
+                }
+            }
 
-					} else if ( deny != null ) {
+            // Haven't implemented this yet. Not sure what we want those rules to look like.
+            /*
+            if ( customRulesRoot != null ) {
+                Elements rules = customRulesRoot.getChildElements("rule");
 
-						config.addBeforeBodyRule( new HTTPMethodRule(id, null, Pattern.compile(deny), Pattern.compile(path)) );
+                 // Parse the complex rules.
 
-					} else {
-						throw new ConfigurationException("", "restrict-method rule should have either an 'allow' or 'deny' value");
-					}
-				}
-
-				for (int i=0;i<enforceHttpsNodes.size();i++) {
+            }
+            */
 
-					Element e = enforceHttpsNodes.get(i);
-					String path = e.getAttributeValue("path");
-					String action = e.getAttributeValue("action");
-					String id = e.getAttributeValue("id");
-					List<Object> exceptions = getExceptionsFromElement(e);
+            if ( outboundRoot != null ) {
 
-					config.addBeforeBodyRule( new EnforceHTTPSRule(id, Pattern.compile(path), exceptions, action) );
-				}
+                /*
+                 * Parse the <add-header> rules. This could be used to add:
+                 * - X-I-DONT-WANT-TO-BE-FRAMED
+                 * - Caching prevention headers
+                 * - Custom application headers
+                 */
 
-			}
+                Elements addHeaderNodes = outboundRoot.getChildElements("add-header");
 
-			if ( headerRoot != null ) {
+                for(int i=0;i<addHeaderNodes.size();i++) {
+                    Element e = addHeaderNodes.get(i);
+                    String name = e.getAttributeValue("name");
+                    String value = e.getAttributeValue("value");
+                    String path = e.getAttributeValue("path");
+                    String id = e.getAttributeValue("id");
 
-				Elements restrictContentTypes = headerRoot.getChildElements("restrict-content-type");
-				Elements restrictUserAgents = headerRoot.getChildElements("restrict-user-agent");
+                    if ( path == null ) {
+                        path = DEFAULT_PATH_APPLY_ALL;
+                    }
 
-				for(int i=0;i<restrictContentTypes.size();i++) {
+                    AddHeaderRule ahr = new AddHeaderRule(id, name, value, Pattern.compile(path), getExceptionsFromElement(e));
+                    config.addBeforeResponseRule(ahr);
 
-					Element e = restrictContentTypes.get(i);
-					String allow = e.getAttributeValue("allow");
-					String deny = e.getAttributeValue("deny");
-					String id = e.getAttributeValue("id");
+                }
 
-					if ( allow != null && deny != null ) {
-						throw new ConfigurationException("", "restrict-content-type rule should not have both 'allow' and 'deny' values");
-					}
+                /*
+                 * Parse the <add-http-only-flag> rules that allow
+                 * us to add the HTTPOnly flag to cookies, both
+                 * custom and app server.
+                 */
+                Elements addHTTPOnlyFlagNodes = outboundRoot.getChildElements("add-http-only-flag");
+
+                for(int i=0;i<addHTTPOnlyFlagNodes.size();i++) {
+                    Element e = addHTTPOnlyFlagNodes.get(i);
 
-					if ( allow != null ) {
+                    Elements cookiePatterns = e.getChildElements("cookie");
+                    String id = e.getAttributeValue("id");
+                    ArrayList<Pattern> patterns = new ArrayList<Pattern>();
 
-						config.addBeforeBodyRule( new RestrictContentTypeRule(id, Pattern.compile(allow), null) );
+                    for(int j=0;j<cookiePatterns.size();j++) {
+                        Element cookie = cookiePatterns.get(j);
+                        patterns.add(Pattern.compile(cookie.getAttributeValue("name")));
+                    }
+
+                    AddHTTPOnlyFlagRule ahfr = new AddHTTPOnlyFlagRule(id, patterns);
+                    config.addCookieRule(ahfr);
 
-					} else if ( deny != null ) {
+                    if ( ahfr.doesCookieMatch(config.getSessionCookieName()) ) {
+                        config.setApplyHTTPOnlyFlagToSessionCookie(true);
+                    }
+                }
 
-						config.addBeforeBodyRule( new RestrictContentTypeRule(id, null, Pattern.compile(deny)) );
+                /*
+                 * Parse the <add-secure-flag> rules that allow
+                 * us to add the secure flag to cookies, both
+                 * custom and app server.
+                 */
+                Elements addSecureFlagNodes = outboundRoot.getChildElements("add-secure-flag");
 
-					} else {
-						throw new ConfigurationException("", "restrict-content-type rule should have either an 'allow' or 'deny' value");
-					}
-				}
+                for(int i=0;i<addSecureFlagNodes.size();i++) {
+                    Element e = addSecureFlagNodes.get(i);
+                    String id = e.getAttributeValue("id");
+                    Elements cookiePatterns = e.getChildElements("cookie");
+                    ArrayList<Pattern> patterns = new ArrayList<Pattern>();
 
-				for(int i=0;i<restrictUserAgents.size();i++) {
-					Element e = restrictUserAgents.get(i);
-					String id = e.getAttributeValue("id");
-					String allow = e.getAttributeValue("allow");
-					String deny = e.getAttributeValue("deny");
-					if ( allow != null && deny != null ) {
-						throw new ConfigurationException("", "restrict-user-agent rule should not have both 'allow' and 'deny' values");
-					}
+                    for(int j=0;j<cookiePatterns.size();j++) {
+                        Element cookie = cookiePatterns.get(j);
+                        patterns.add(Pattern.compile(cookie.getAttributeValue("name")));
+                    }
 
-					if ( allow != null ) {
-						
-						config.addBeforeBodyRule( new RestrictUserAgentRule(id, Pattern.compile(allow), null) );
-
-					} else if ( deny != null ) {
-
-						config.addBeforeBodyRule( new RestrictUserAgentRule(id, null, Pattern.compile(deny)) );
-
-					} else {
-						throw new ConfigurationException("", "restrict-user-agent rule should have either an 'allow' or 'deny' value");
-					}
-				}
-
-			}
-
-			if ( virtualPatchesRoot != null ) {
-				Elements virtualPatchNodes = virtualPatchesRoot.getChildElements("virtual-patch");
-				for(int i=0;i<virtualPatchNodes.size();i++) {
-					Element e = virtualPatchNodes.get(i);
-					String id = e.getAttributeValue("id");
-					String path = e.getAttributeValue("path");
-					String variable = e.getAttributeValue("variable");
-					String pattern = e.getAttributeValue("pattern");
-					String message = e.getAttributeValue("message");
-
-					config.addAfterBodyRule( new SimpleVirtualPatchRule(id, Pattern.compile(path), variable, Pattern.compile(pattern), message) );
-				}
-			}
+                    AddSecureFlagRule asfr = new AddSecureFlagRule(id, patterns);
+                    config.addCookieRule(asfr);
+
+                    if ( asfr.doesCookieMatch(config.getSessionCookieName()) ) {
+                        config.setApplySecureFlagToSessionCookie(true);
+                    }
+
+                }
+
+                /*
+                 * Parse dynamic-insertion nodes that allow us to dynamically
+                 * insert stuff into responses.
+                 */
+                Elements dynamicInsertionNodes = outboundRoot.getChildElements("dynamic-insertion");
+
+                for(int i=0;i<dynamicInsertionNodes.size();i++) {
+
+                    Element e = dynamicInsertionNodes.get(i);
+                    String pattern = e.getAttributeValue("pattern");
+                    String id = e.getAttributeValue("id");
+                    String contentType = e.getAttributeValue("content-type");
+                    String urlPaths = e.getAttributeValue("path");
+                    Element replacement = e.getFirstChildElement("replacement");
+
+                    ReplaceContentRule rcr = new ReplaceContentRule(
+                            id,
+                            Pattern.compile(pattern,Pattern.DOTALL),
+                            replacement.getValue(),
+                            contentType != null ? Pattern.compile(contentType) : null,
+                            urlPaths != null ? Pattern.compile(urlPaths) : null);
+
+                    config.addBeforeResponseRule(rcr);
+
+                }
+
+                /*
+                 * Parse detect-content nodes that allow us to simply detect data
+                 * leaving in responses.
+                 */
+                Elements detectContentNodes = outboundRoot.getChildElements("detect-content");
+
+                for(int i=0;i<detectContentNodes.size();i++) {
+
+                    Element e = detectContentNodes.get(i);
+                    String token = e.getAttributeValue("pattern");
+                    String contentType = e.getAttributeValue("content-type");
+                    String id = e.getAttributeValue("id");
+                    String path = e.getAttributeValue("path");
+
+                    if ( token == null ) {
+                        throw new ConfigurationException("", "<detect-content> rules must contain a 'pattern' attribute");
+                    } else if ( contentType == null ) {
+                        throw new ConfigurationException("", "<detect-content> rules must contain a 'content-type' attribute");
+                    }
+
+                    DetectOutboundContentRule docr = new DetectOutboundContentRule(
+                            id,
+                            Pattern.compile(contentType),
+                            Pattern.compile(token,Pattern.DOTALL),
+                            path != null ? Pattern.compile(path) : null);
+
+                    config.addBeforeResponseRule(docr);
+
+                }
+
+            }
+
+            /**
+             * Parse the 'bean-shell-rules' section.
+             */
+
+            if ( beanShellRoot != null ) {
+
+                Elements beanShellRules = beanShellRoot.getChildElements("bean-shell-script");
+
+                for (int i=0;i<beanShellRules.size(); i++) {
+
+                    Element e = beanShellRules.get(i);
+
+                    String id = e.getAttributeValue("id");
+                    String fileName = e.getAttributeValue("file");
+                    String stage = e.getAttributeValue("stage"); //
+                    String path = e.getAttributeValue("path");
+
+                    if ( id == null ) {
+                        throw new ConfigurationException("", "bean shell rules all require a unique 'id' attribute");
+                    }
+
+                    if ( fileName == null ) {
+                        throw new ConfigurationException("", "bean shell rules all require a unique 'file' attribute that has the location of the .bsh script" );
+                    }
+
+                    try {
+
+                        BeanShellRule bsr = new BeanShellRule(
+                                webRootDir + fileName,
+                                id,
+                                path != null ? Pattern.compile(path) : null);
+
+                        if ( STAGES[0].equals(stage) ) {
+                            config.addBeforeBodyRule(bsr);
+                        } else if ( STAGES[1].equals(stage)) {
+                            config.addAfterBodyRule(bsr);
+                        } else if ( STAGES[2].equals(stage)) {
+                            config.addBeforeResponseRule(bsr);
+                        } else {
+                            throw new ConfigurationException("", "bean shell rules all require a 'stage' attribute when the rule should be fired (valid values are " + STAGES[0] + ", " + STAGES[1] + ", or " + STAGES[2] + ")" );
+                        }
+
+                    } catch (FileNotFoundException fnfe) {
+                        throw new ConfigurationException ("", "bean shell rule '" + id + "' had a source file that could not be found (" + fileName + "), web directory = " + webRootDir );
+                    } catch (EvalError ee) {
+                        throw new ConfigurationException ("", "bean shell rule '" + id + "' contained an error (" + ee.getErrorText() + "): " + ee.getScriptStackTrace());
+                    }
+
+                }
+            }
+
+        } catch (ValidityException e) {
+            throw new ConfigurationException("", "Problem validating WAF XML file", e);
+        } catch (ParsingException e) {
+            throw new ConfigurationException("", "Problem parsing WAF XML file", e);
+        } catch (IOException e) {
+            throw new ConfigurationException("", "I/O problem reading WAF XML file", e);
+        }
+
+        return config;
+
+    }
 
-			// Haven't implemented this yet. Not sure what we want those rules to look like.
-			/*
-			if ( customRulesRoot != null ) {
-				Elements rules = customRulesRoot.getChildElements("rule");
-				
-				 // Parse the complex rules.
-				 
-			}
-			*/
-			
-			if ( outboundRoot != null ) {
-
-				/*
-				 * Parse the <add-header> rules. This could be used to add:
-				 * - X-I-DONT-WANT-TO-BE-FRAMED
-				 * - Caching prevention headers
-				 * - Custom application headers
-				 */
-
-				Elements addHeaderNodes = outboundRoot.getChildElements("add-header");
-
-				for(int i=0;i<addHeaderNodes.size();i++) {
-					Element e = addHeaderNodes.get(i);
-					String name = e.getAttributeValue("name");
-					String value = e.getAttributeValue("value");
-					String path = e.getAttributeValue("path");
-					String id = e.getAttributeValue("id");
-
-					if ( path == null ) {
-						path = DEFAULT_PATH_APPLY_ALL;
-					}
-
-					AddHeaderRule ahr = new AddHeaderRule(id, name, value, Pattern.compile(path), getExceptionsFromElement(e));
-					config.addBeforeResponseRule(ahr);
-
-				}
-
-				/*
-				 * Parse the <add-http-only-flag> rules that allow
-				 * us to add the HTTPOnly flag to cookies, both
-				 * custom and app server.
-				 */
-				Elements addHTTPOnlyFlagNodes = outboundRoot.getChildElements("add-http-only-flag");
-
-				for(int i=0;i<addHTTPOnlyFlagNodes.size();i++) {
-					Element e = addHTTPOnlyFlagNodes.get(i);
-
-					Elements cookiePatterns = e.getChildElements("cookie");
-					String id = e.getAttributeValue("id");
-					ArrayList<Pattern> patterns = new ArrayList<Pattern>();
-
-					for(int j=0;j<cookiePatterns.size();j++) {
-						Element cookie = cookiePatterns.get(j);
-						patterns.add(Pattern.compile(cookie.getAttributeValue("name")));
-					}
-
-					AddHTTPOnlyFlagRule ahfr = new AddHTTPOnlyFlagRule(id, patterns);
-					config.addCookieRule(ahfr);
-
-					if ( ahfr.doesCookieMatch(config.getSessionCookieName()) ) {
-						config.setApplyHTTPOnlyFlagToSessionCookie(true);
-					}
-				}
-
-				/*
-				 * Parse the <add-secure-flag> rules that allow
-				 * us to add the secure flag to cookies, both
-				 * custom and app server.
-				 */
-				Elements addSecureFlagNodes = outboundRoot.getChildElements("add-secure-flag");
-
-				for(int i=0;i<addSecureFlagNodes.size();i++) {
-					Element e = addSecureFlagNodes.get(i);
-					String id = e.getAttributeValue("id");
-					Elements cookiePatterns = e.getChildElements("cookie");
-					ArrayList<Pattern> patterns = new ArrayList<Pattern>();
-
-					for(int j=0;j<cookiePatterns.size();j++) {
-						Element cookie = cookiePatterns.get(j);
-						patterns.add(Pattern.compile(cookie.getAttributeValue("name")));
-					}
-
-					AddSecureFlagRule asfr = new AddSecureFlagRule(id, patterns);
-					config.addCookieRule(asfr);
-
-					if ( asfr.doesCookieMatch(config.getSessionCookieName()) ) {
-						config.setApplySecureFlagToSessionCookie(true);
-					}
-
-				}
-
-				/*
-				 * Parse dynamic-insertion nodes that allow us to dynamically
-				 * insert stuff into responses.
-				 */
-				Elements dynamicInsertionNodes = outboundRoot.getChildElements("dynamic-insertion");
-
-				for(int i=0;i<dynamicInsertionNodes.size();i++) {
-
-					Element e = dynamicInsertionNodes.get(i);
-					String pattern = e.getAttributeValue("pattern");
-					String id = e.getAttributeValue("id");
-					String contentType = e.getAttributeValue("content-type");
-					String urlPaths = e.getAttributeValue("path");
-					Element replacement = e.getFirstChildElement("replacement");
-
-					ReplaceContentRule rcr = new ReplaceContentRule(
-							id, 
-							Pattern.compile(pattern,Pattern.DOTALL), 
-							replacement.getValue(),
-							contentType != null ? Pattern.compile(contentType) : null,
-							urlPaths != null ? Pattern.compile(urlPaths) : null);
-					
-					config.addBeforeResponseRule(rcr);
-
-				}
-
-				/*
-				 * Parse detect-content nodes that allow us to simply detect data
-				 * leaving in responses.
-				 */
-				Elements detectContentNodes = outboundRoot.getChildElements("detect-content");
-
-				for(int i=0;i<detectContentNodes.size();i++) {
-
-					Element e = detectContentNodes.get(i);
-					String token = e.getAttributeValue("pattern");
-					String contentType = e.getAttributeValue("content-type");
-					String id = e.getAttributeValue("id");
-					String path = e.getAttributeValue("path");
-
-					if ( token == null ) {
-						throw new ConfigurationException("", "<detect-content> rules must contain a 'pattern' attribute");
-					} else if ( contentType == null ) {
-						throw new ConfigurationException("", "<detect-content> rules must contain a 'content-type' attribute");
-					}
-
-					DetectOutboundContentRule docr = new DetectOutboundContentRule(
-							id, 
-							Pattern.compile(contentType),
-							Pattern.compile(token,Pattern.DOTALL),
-							path != null ? Pattern.compile(path) : null);
-					
-					config.addBeforeResponseRule(docr);
-
-				}
-
-			}
-			
-			/**
-			 * Parse the 'bean-shell-rules' section.
-			 */
-			
-			if ( beanShellRoot != null ) {
-			
-				Elements beanShellRules = beanShellRoot.getChildElements("bean-shell-script");
-				
-				for (int i=0;i<beanShellRules.size(); i++) {
-
-					Element e = beanShellRules.get(i);
-					
-					String id = e.getAttributeValue("id");
-					String fileName = e.getAttributeValue("file");
-					String stage = e.getAttributeValue("stage"); //
-					String path = e.getAttributeValue("path");
-					
-					if ( id == null ) {
-						throw new ConfigurationException("", "bean shell rules all require a unique 'id' attribute");
-					}
-					
-					if ( fileName == null ) {
-						throw new ConfigurationException("", "bean shell rules all require a unique 'file' attribute that has the location of the .bsh script" );
-					}
-					
-					try {
-						
-						BeanShellRule bsr = new BeanShellRule(
-								webRootDir + fileName, 
-								id,
-								path != null ? Pattern.compile(path) : null);
-						
-						if ( STAGES[0].equals(stage) ) {
-							config.addBeforeBodyRule(bsr);
-						} else if ( STAGES[1].equals(stage)) {
-							config.addAfterBodyRule(bsr);
-						} else if ( STAGES[2].equals(stage)) {
-							config.addBeforeResponseRule(bsr);
-						} else {
-							throw new ConfigurationException("", "bean shell rules all require a 'stage' attribute when the rule should be fired (valid values are " + STAGES[0] + ", " + STAGES[1] + ", or " + STAGES[2] + ")" );
-						}
-												
-					} catch (FileNotFoundException fnfe) {
-						throw new ConfigurationException ("", "bean shell rule '" + id + "' had a source file that could not be found (" + fileName + "), web directory = " + webRootDir );
-					} catch (EvalError ee) {
-						throw new ConfigurationException ("", "bean shell rule '" + id + "' contained an error (" + ee.getErrorText() + "): " + ee.getScriptStackTrace());
-					}
-					
-				}
-			}
-
-		} catch (ValidityException e) {
-			throw new ConfigurationException("", "Problem validating WAF XML file", e);
-		} catch (ParsingException e) {
-			throw new ConfigurationException("", "Problem parsing WAF XML file", e);
-		} catch (IOException e) {
-			throw new ConfigurationException("", "I/O problem reading WAF XML file", e);
-		}
-
-		return config;
-
-	}
-
-	private static List<Object> getExceptionsFromElement(Element root) {
-		Elements exceptions = root.getChildElements("path-exception");
-		ArrayList<Object> exceptionList = new ArrayList<Object>();
-
-		for(int i=0;i<exceptions.size();i++) {
-			Element e = exceptions.get(i);
-			if ( REGEX.equalsIgnoreCase(e.getAttributeValue("type"))) {
-				exceptionList.add( Pattern.compile(e.getValue()) );
-			} else {
-				exceptionList.add( e.getValue() );
-			}
-		}
-		return exceptionList;
-	}
+    private static List<Object> getExceptionsFromElement(Element root) {
+        Elements exceptions = root.getChildElements("path-exception");
+        ArrayList<Object> exceptionList = new ArrayList<Object>();
+
+        for(int i=0;i<exceptions.size();i++) {
+            Element e = exceptions.get(i);
+            if ( REGEX.equalsIgnoreCase(e.getAttributeValue("type"))) {
+                exceptionList.add( Pattern.compile(e.getValue()) );
+            } else {
+                exceptionList.add( e.getValue() );
+            }
+        }
+        return exceptionList;
+    }
 
 }
diff --git a/src/main/java/org/owasp/esapi/waf/configuration/package.html b/src/main/java/org/owasp/esapi/waf/configuration/package.html
index 8c41b3a..bca8693 100644
--- a/src/main/java/org/owasp/esapi/waf/configuration/package.html
+++ b/src/main/java/org/owasp/esapi/waf/configuration/package.html
@@ -5,8 +5,8 @@
 
 <body bgcolor="white">
 
-This package contains the both the configuration object model and the 
-utility class to create that object model from an existing policy file. 
- 
+This package contains the both the configuration object model and the
+utility class to create that object model from an existing policy file.
+
 </body>
 </html>
diff --git a/src/main/java/org/owasp/esapi/waf/internal/InterceptingHTTPServletRequest.java b/src/main/java/org/owasp/esapi/waf/internal/InterceptingHTTPServletRequest.java
index d91f95f..8c4c2b0 100644
--- a/src/main/java/org/owasp/esapi/waf/internal/InterceptingHTTPServletRequest.java
+++ b/src/main/java/org/owasp/esapi/waf/internal/InterceptingHTTPServletRequest.java
@@ -1,15 +1,15 @@
 /**
  * OWASP Enterprise Security API (ESAPI)
- * 
+ *
  * This file is part of the Open Web Application Security Project (OWASP)
  * Enterprise Security API (ESAPI) project. For details, please see
  * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
  *
  * Copyright (c) 2009 - The OWASP Foundation
- * 
+ *
  * The ESAPI is published by OWASP under the BSD license. You should read and accept the
  * LICENSE before you use, modify, and/or redistribute this software.
- * 
+ *
  * @author Arshan Dabirsiaghi <a href="http://www.aspectsecurity.com">Aspect Security</a>
  * @created 2009
  */
@@ -38,172 +38,172 @@ import org.apache.commons.fileupload.util.Streams;
 /**
  * The wrapper for the HttpServletRequest object which will be passed to the application
  * being protected by the WAF. It contains logic for parsing multipart parameters out of
- * the request and provided downstream application logic a way of accessing it like it 
+ * the request and provided downstream application logic a way of accessing it like it
  * hasn't been touched.
- * 
+ *
  * @author Arshan Dabirsiaghi
  *
  */
 public class InterceptingHTTPServletRequest extends HttpServletRequestWrapper {
 
-	private Vector<Parameter> allParameters;
-	private Vector<String> allParameterNames;
-	private static int CHUNKED_BUFFER_SIZE = 1024;
-	
-	private boolean isMultipart = false;
-	private RandomAccessFile requestBody;
-	private RAFInputStream is;
-	
-	public ServletInputStream getInputStream() throws IOException {
-		
-		if ( isMultipart ) {
-			return is;	
-		} else {
-			return super.getInputStream();
-		}
-        
+    private Vector<Parameter> allParameters;
+    private Vector<String> allParameterNames;
+    private static int CHUNKED_BUFFER_SIZE = 1024;
+
+    private boolean isMultipart = false;
+    private RandomAccessFile requestBody;
+    private RAFInputStream is;
+
+    public ServletInputStream getInputStream() throws IOException {
+
+        if ( isMultipart ) {
+            return is;
+        } else {
+            return super.getInputStream();
+        }
+
     }
-	
-	public BufferedReader getReader() throws IOException {
+
+    public BufferedReader getReader() throws IOException {
         String enc = getCharacterEncoding();
         if(enc == null) enc = "UTF-8";
         return new BufferedReader(new InputStreamReader(getInputStream(), enc));
     }
-	
-	public InterceptingHTTPServletRequest(HttpServletRequest request) throws FileUploadException, IOException {
-
-		super(request);
-
-		allParameters = new Vector<Parameter>();
-		allParameterNames = new Vector<String>();
-
-
-		/*
-		 * Get all the regular parameters.
-		 */
-
-		Enumeration e = request.getParameterNames();
-
-		while(e.hasMoreElements()) {
-			String param = (String)e.nextElement();
-			allParameters.add(new Parameter(param,request.getParameter(param),false));
-			allParameterNames.add(param);
-		}
-
-
-		/*
-		 * Get all the multipart fields.
-		 */
-
-		isMultipart = ServletFileUpload.isMultipartContent(request);
-
-		if ( isMultipart ) {
-
-			requestBody = new RandomAccessFile( File.createTempFile("oew","mpc"), "rw");
-	    	
-	    	byte buffer[] = new byte[CHUNKED_BUFFER_SIZE];
-
-	    	long size = 0;
-	    	int len = 0;
-
-	    	while ( len != -1 && size <= Integer.MAX_VALUE) {
-	    		len = request.getInputStream().read(buffer, 0, CHUNKED_BUFFER_SIZE);
-	    		if ( len != -1 ) {
-	    			size += len;
-	    			requestBody.write(buffer,0,len);	
-	    		}
-	    	}
-			
-	    	is = new RAFInputStream(requestBody);
-	    	
-			ServletFileUpload sfu = new ServletFileUpload();
-			FileItemIterator iter = sfu.getItemIterator(this);
-
-			while(iter.hasNext()) {
-				FileItemStream item = iter.next();
-				String name = item.getFieldName();
-				InputStream stream = item.openStream();
-
-				/*
-				 * If this is a regular form field, add it to our
-				 * parameter collection.
-				 */
-
-				if (item.isFormField()) {
-
-					String value = Streams.asString(stream);
-
-					allParameters.add(new Parameter(name,value,true));
-			    	allParameterNames.add(name);
-
-			    } else {
-			    	/*
-			    	 * This is a multipart content that is not a
-			    	 * regular form field. Nothing to do here.
-			    	 */
-			    	
-			    }
-
-			}
-			
-			requestBody.seek(0);
-			
-		}
-
-	}
-
-	public String getDictionaryParameter(String s) {
-
-		for(int i=0;i<allParameters.size();i++) {
-			Parameter p = allParameters.get(i);
-			if ( p.getName().equals(s) ) {
-				return p.getValue();
-			}
-		}
-		
-		return null;
-	}
-
-	public Enumeration getDictionaryParameterNames() {
-		return allParameterNames.elements();
-	}
-	
-	
-	private class RAFInputStream extends ServletInputStream {
-		
-		RandomAccessFile raf;
-		boolean isDone = false;
-		
-		public RAFInputStream(RandomAccessFile raf) throws IOException {
-			this.raf = raf;
-			this.raf.seek(0);
-		}
-
-		public int read() throws IOException {
-			int rval = raf.read();
-			isDone = rval == -1;
-			return rval;
-		}
-		
-		public synchronized void reset() throws IOException {
-			raf.seek(0);
-			isDone=false;
-		}
-
-		@Override
-		public boolean isFinished() {
-			return isDone;
-		}
-
-		@Override
-		public boolean isReady() {
-			return false;
-		}
-
-		@Override
-		public void setReadListener(ReadListener readListener) {
-			//NO-OP.  Unused in this scope
-		}
-	}
-	
+
+    public InterceptingHTTPServletRequest(HttpServletRequest request) throws FileUploadException, IOException {
+
+        super(request);
+
+        allParameters = new Vector<Parameter>();
+        allParameterNames = new Vector<String>();
+
+
+        /*
+         * Get all the regular parameters.
+         */
+
+        Enumeration e = request.getParameterNames();
+
+        while(e.hasMoreElements()) {
+            String param = (String)e.nextElement();
+            allParameters.add(new Parameter(param,request.getParameter(param),false));
+            allParameterNames.add(param);
+        }
+
+
+        /*
+         * Get all the multipart fields.
+         */
+
+        isMultipart = ServletFileUpload.isMultipartContent(request);
+
+        if ( isMultipart ) {
+
+            requestBody = new RandomAccessFile( File.createTempFile("oew","mpc"), "rw");
+
+            byte buffer[] = new byte[CHUNKED_BUFFER_SIZE];
+
+            long size = 0;
+            int len = 0;
+
+            while ( len != -1 && size <= Integer.MAX_VALUE) {
+                len = request.getInputStream().read(buffer, 0, CHUNKED_BUFFER_SIZE);
+                if ( len != -1 ) {
+                    size += len;
+                    requestBody.write(buffer,0,len);
+                }
+            }
+
+            is = new RAFInputStream(requestBody);
+
+            ServletFileUpload sfu = new ServletFileUpload();
+            FileItemIterator iter = sfu.getItemIterator(this);
+
+            while(iter.hasNext()) {
+                FileItemStream item = iter.next();
+                String name = item.getFieldName();
+                InputStream stream = item.openStream();
+
+                /*
+                 * If this is a regular form field, add it to our
+                 * parameter collection.
+                 */
+
+                if (item.isFormField()) {
+
+                    String value = Streams.asString(stream);
+
+                    allParameters.add(new Parameter(name,value,true));
+                    allParameterNames.add(name);
+
+                } else {
+                    /*
+                     * This is a multipart content that is not a
+                     * regular form field. Nothing to do here.
+                     */
+
+                }
+
+            }
+
+            requestBody.seek(0);
+
+        }
+
+    }
+
+    public String getDictionaryParameter(String s) {
+
+        for(int i=0;i<allParameters.size();i++) {
+            Parameter p = allParameters.get(i);
+            if ( p.getName().equals(s) ) {
+                return p.getValue();
+            }
+        }
+
+        return null;
+    }
+
+    public Enumeration getDictionaryParameterNames() {
+        return allParameterNames.elements();
+    }
+
+
+    private class RAFInputStream extends ServletInputStream {
+
+        RandomAccessFile raf;
+        boolean isDone = false;
+
+        public RAFInputStream(RandomAccessFile raf) throws IOException {
+            this.raf = raf;
+            this.raf.seek(0);
+        }
+
+        public int read() throws IOException {
+            int rval = raf.read();
+            isDone = rval == -1;
+            return rval;
+        }
+
+        public synchronized void reset() throws IOException {
+            raf.seek(0);
+            isDone=false;
+        }
+
+        @Override
+        public boolean isFinished() {
+            return isDone;
+        }
+
+        @Override
+        public boolean isReady() {
+            return false;
+        }
+
+        @Override
+        public void setReadListener(ReadListener readListener) {
+            //NO-OP.  Unused in this scope
+        }
+    }
+
 }
diff --git a/src/main/java/org/owasp/esapi/waf/internal/InterceptingHTTPServletResponse.java b/src/main/java/org/owasp/esapi/waf/internal/InterceptingHTTPServletResponse.java
index dac1738..37bf402 100644
--- a/src/main/java/org/owasp/esapi/waf/internal/InterceptingHTTPServletResponse.java
+++ b/src/main/java/org/owasp/esapi/waf/internal/InterceptingHTTPServletResponse.java
@@ -1,15 +1,15 @@
 /**
  * OWASP Enterprise Security API (ESAPI)
- * 
+ *
  * This file is part of the Open Web Application Security Project (OWASP)
  * Enterprise Security API (ESAPI) project. For details, please see
  * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
  *
  * Copyright (c) 2009 - The OWASP Foundation
- * 
+ *
  * The ESAPI is published by OWASP under the BSD license. You should read and accept the
  * LICENSE before you use, modify, and/or redistribute this software.
- * 
+ *
  * @author Arshan Dabirsiaghi <a href="http://www.aspectsecurity.com">Aspect Security</a>
  * @created 2009
  */
@@ -34,135 +34,135 @@ import org.owasp.esapi.waf.rules.Rule;
  * being protected by the WAF. It contains logic for the response building API in order
  * to allow the WAF rules regarding responses to work. Much of the work is delegated to
  * other classes, especially InterceptingServletOutputStream
- * 
+ *
  * @author Arshan Dabirsiaghi
  *
  */
 public class InterceptingHTTPServletResponse extends HttpServletResponseWrapper {
 
-	private InterceptingPrintWriter ipw;
-	private InterceptingServletOutputStream isos;
-	private String contentType;
-
-	private List<AddSecureFlagRule> addSecureFlagRules = null;
-	private List<AddHTTPOnlyFlagRule> addHTTPOnlyFlagRules = null;
-	private boolean alreadyCalledWriter = false;
-	private boolean alreadyCalledOutputStream = false;
-
-	public InterceptingHTTPServletResponse(HttpServletResponse response, boolean buffering, List<Rule> cookieRules) throws IOException {
-
-		super(response);
-		
-		this.contentType = response.getContentType();
-		
-		this.isos = new InterceptingServletOutputStream(response.getOutputStream(), buffering);
-		this.ipw = new InterceptingPrintWriter(new PrintWriter(isos));
-
-		addSecureFlagRules = new ArrayList<AddSecureFlagRule>();
-		addHTTPOnlyFlagRules = new ArrayList<AddHTTPOnlyFlagRule>();
-
-		for(int i=0;i<cookieRules.size();i++) {
-			Rule r = cookieRules.get(i);
-			if ( r instanceof AddSecureFlagRule ) {
-				addSecureFlagRules.add((AddSecureFlagRule)r);
-			} else if ( r instanceof AddHTTPOnlyFlagRule ) {
-				addHTTPOnlyFlagRules.add((AddHTTPOnlyFlagRule)r);
-			}
-		}
-	}
-
-	public boolean isUsingWriter() {
-		return alreadyCalledWriter;
-	}
-
-	public InterceptingServletOutputStream getInterceptingServletOutputStream() {
-		return isos;
-	}
-
-	public ServletOutputStream getOutputStream() throws IllegalStateException, IOException {
-		if ( alreadyCalledWriter == true ) {
-			throw new IllegalStateException();
-		}
-
-		alreadyCalledOutputStream = true;
-
-		return isos;
+    private InterceptingPrintWriter ipw;
+    private InterceptingServletOutputStream isos;
+    private String contentType;
+
+    private List<AddSecureFlagRule> addSecureFlagRules = null;
+    private List<AddHTTPOnlyFlagRule> addHTTPOnlyFlagRules = null;
+    private boolean alreadyCalledWriter = false;
+    private boolean alreadyCalledOutputStream = false;
+
+    public InterceptingHTTPServletResponse(HttpServletResponse response, boolean buffering, List<Rule> cookieRules) throws IOException {
+
+        super(response);
+
+        this.contentType = response.getContentType();
+
+        this.isos = new InterceptingServletOutputStream(response.getOutputStream(), buffering);
+        this.ipw = new InterceptingPrintWriter(new PrintWriter(isos));
+
+        addSecureFlagRules = new ArrayList<AddSecureFlagRule>();
+        addHTTPOnlyFlagRules = new ArrayList<AddHTTPOnlyFlagRule>();
+
+        for(int i=0;i<cookieRules.size();i++) {
+            Rule r = cookieRules.get(i);
+            if ( r instanceof AddSecureFlagRule ) {
+                addSecureFlagRules.add((AddSecureFlagRule)r);
+            } else if ( r instanceof AddHTTPOnlyFlagRule ) {
+                addHTTPOnlyFlagRules.add((AddHTTPOnlyFlagRule)r);
+            }
+        }
     }
 
-	public PrintWriter getWriter() throws IOException {
-		if ( alreadyCalledOutputStream == true ) {
-			throw new IllegalStateException();
-		}
-		alreadyCalledWriter = true;
+    public boolean isUsingWriter() {
+        return alreadyCalledWriter;
+    }
 
-		return ipw;
-	}
+    public InterceptingServletOutputStream getInterceptingServletOutputStream() {
+        return isos;
+    }
+
+    public ServletOutputStream getOutputStream() throws IllegalStateException, IOException {
+        if ( alreadyCalledWriter == true ) {
+            throw new IllegalStateException();
+        }
+
+        alreadyCalledOutputStream = true;
+
+        return isos;
+    }
+
+    public PrintWriter getWriter() throws IOException {
+        if ( alreadyCalledOutputStream == true ) {
+            throw new IllegalStateException();
+        }
+        alreadyCalledWriter = true;
+
+        return ipw;
+    }
 
     public String getContentType() {
         return contentType;
     }
 
     public void setContentType(String s) {
-    	contentType = s;
+        contentType = s;
     }
 
     public void flush() {
-    	ipw.flush();
+        ipw.flush();
     }
 
     public void commit() throws IOException {
 
-    	if ( alreadyCalledWriter ) {
-    		ipw.flush();
-    	}
+        if ( alreadyCalledWriter ) {
+            ipw.flush();
+        }
 
-    	isos.commit();
+        isos.commit();
     }
 
     public void addCookie(Cookie cookie) {
-    	addCookie(cookie, cookie.getMaxAge()<=0);
+        addCookie(cookie, cookie.getMaxAge()<=0);
     }
-    
-	public void addCookie(Cookie cookie, boolean isSession) {
-
-		boolean addSecureFlag = cookie.getSecure();
-		boolean addHTTPOnlyFlag = false;
-
-		if ( ! cookie.getSecure() && addSecureFlagRules != null ) {
-			for(int i=0;i<addSecureFlagRules.size();i++) {
-				AddSecureFlagRule asfr = addSecureFlagRules.get(i);
-				if ( asfr.doesCookieMatch(cookie.getName())) {
-					addSecureFlag = true;
-				}
-			}
-		}
-
-		if ( addHTTPOnlyFlagRules != null ) {
-			for(int i=0;i<addHTTPOnlyFlagRules.size();i++) {
-				AddHTTPOnlyFlagRule ashr = addHTTPOnlyFlagRules.get(i);
-				if ( ashr.doesCookieMatch(cookie.getName())) {
-					addHTTPOnlyFlag = true;
-				}
-			}
-		}
-
-		String cookieValue = createCookieHeader(cookie.getName(),cookie.getValue(),
-												cookie.getMaxAge(),cookie.getDomain(),
-												cookie.getPath(), addSecureFlag,
-												addHTTPOnlyFlag, isSession);
-		addHeader("Set-Cookie", cookieValue);
-
-
-	}
-
-	private String createCookieHeader(String name, String value, int maxAge, String domain, String path, boolean secure, boolean httpOnly, boolean isTemporary) {
+
+    public void addCookie(Cookie cookie, boolean isSession) {
+
+        boolean addSecureFlag = cookie.getSecure();
+        boolean addHTTPOnlyFlag = false;
+
+        if ( ! cookie.getSecure() && addSecureFlagRules != null ) {
+            for(int i=0;i<addSecureFlagRules.size();i++) {
+                AddSecureFlagRule asfr = addSecureFlagRules.get(i);
+                if ( asfr.doesCookieMatch(cookie.getName())) {
+                    addSecureFlag = true;
+                }
+            }
+        }
+
+        if ( addHTTPOnlyFlagRules != null ) {
+            for(int i=0;i<addHTTPOnlyFlagRules.size();i++) {
+                AddHTTPOnlyFlagRule ashr = addHTTPOnlyFlagRules.get(i);
+                if ( ashr.doesCookieMatch(cookie.getName())) {
+                    addHTTPOnlyFlag = true;
+                }
+            }
+        }
+
+        String cookieValue = createCookieHeader(cookie.getName(),cookie.getValue(),
+                                                cookie.getMaxAge(),cookie.getDomain(),
+                                                cookie.getPath(), addSecureFlag,
+                                                addHTTPOnlyFlag, isSession);
+        addHeader("Set-Cookie", cookieValue);
+
+
+    }
+
+    private String createCookieHeader(String name, String value, int maxAge, String domain, String path, boolean secure, boolean httpOnly, boolean isTemporary) {
         // create the special cookie header instead of creating a Java cookie
         // Set-Cookie:<name>=<value>[; <name>=<value>][; expires=<date>][;
         // domain=<domain_name>][; path=<some_path>][; secure][;HttpOnly
         String header = name + "=" + value;
 
         if ( ! isTemporary ) {
-        	header += "; Max-Age=" + maxAge;
+            header += "; Max-Age=" + maxAge;
         }
 
         if (domain != null) {
@@ -173,11 +173,11 @@ public class InterceptingHTTPServletResponse extends HttpServletResponseWrapper
         }
 
         if ( secure ) {
-        	header += "; Secure";
+            header += "; Secure";
         }
 
         if (httpOnly) {
-        	header += "; HttpOnly";
+            header += "; HttpOnly";
         }
 
         return header;
diff --git a/src/main/java/org/owasp/esapi/waf/internal/InterceptingPrintWriter.java b/src/main/java/org/owasp/esapi/waf/internal/InterceptingPrintWriter.java
index a156450..57200e7 100644
--- a/src/main/java/org/owasp/esapi/waf/internal/InterceptingPrintWriter.java
+++ b/src/main/java/org/owasp/esapi/waf/internal/InterceptingPrintWriter.java
@@ -1,15 +1,15 @@
 /**
  * OWASP Enterprise Security API (ESAPI)
- * 
+ *
  * This file is part of the Open Web Application Security Project (OWASP)
  * Enterprise Security API (ESAPI) project. For details, please see
  * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
  *
  * Copyright (c) 2009 - The OWASP Foundation
- * 
+ *
  * The ESAPI is published by OWASP under the BSD license. You should read and accept the
  * LICENSE before you use, modify, and/or redistribute this software.
- * 
+ *
  * @author Arshan Dabirsiaghi <a href="http://www.aspectsecurity.com">Aspect Security</a>
  * @created 2009
  */
@@ -22,161 +22,161 @@ import java.util.Locale;
 /**
  * The PrintWriter needed to buffer outbound data generated by the application
  * being protected by the WAF. Currently no logic is needed here right now due
- * to the WAF things have been architected in the main file, 
+ * to the WAF things have been architected in the main file,
  * InterceptingHTTPServletResponse.
- * 
+ *
  * @author Arshan Dabirsiaghi
  * @see org.owasp.esapi.waf.internal.InterceptingHTTPServletResponse
  */
 public class InterceptingPrintWriter extends PrintWriter {
 
-	public InterceptingPrintWriter(Writer out) {
-		super(out);
-	}
+    public InterceptingPrintWriter(Writer out) {
+        super(out);
+    }
 
-	public PrintWriter append(char c) {
-		return super.append(c);
-	}
+    public PrintWriter append(char c) {
+        return super.append(c);
+    }
 
-	public PrintWriter append(CharSequence csq, int start, int end) {
-		return super.append(csq, start, end);
-	}
+    public PrintWriter append(CharSequence csq, int start, int end) {
+        return super.append(csq, start, end);
+    }
 
-	public PrintWriter append(CharSequence csq) {
-		return super.append(csq);
-	}
+    public PrintWriter append(CharSequence csq) {
+        return super.append(csq);
+    }
 
-	public boolean checkError() {
-		return super.checkError();
-	}
+    public boolean checkError() {
+        return super.checkError();
+    }
 
 // Java 1.6 only
-//	protected void clearError() {
-//		super.clearError();
-//	}
+//    protected void clearError() {
+//        super.clearError();
+//    }
 
-	public void close() {
-		super.close();
-	}
+    public void close() {
+        super.close();
+    }
 
-	public void flush() {
-		super.flush();
-	}
+    public void flush() {
+        super.flush();
+    }
 
-	public PrintWriter format(Locale l, String format, Object... args) {
-		return super.format(l, format, args);
-	}
+    public PrintWriter format(Locale l, String format, Object... args) {
+        return super.format(l, format, args);
+    }
 
-	public PrintWriter format(String format, Object... args) {
-		return super.format(format, args);
-	}
+    public PrintWriter format(String format, Object... args) {
+        return super.format(format, args);
+    }
 
-	public void print(boolean b) {
-		super.print(b);
-	}
+    public void print(boolean b) {
+        super.print(b);
+    }
 
-	public void print(char c) {
-		super.print(c);
-	}
+    public void print(char c) {
+        super.print(c);
+    }
 
-	public void print(char[] s) {
-		super.print(s);
-	}
+    public void print(char[] s) {
+        super.print(s);
+    }
 
-	public void print(double d) {
-		super.print(d);
-	}
+    public void print(double d) {
+        super.print(d);
+    }
 
-	public void print(float f) {
-		super.print(f);
-	}
+    public void print(float f) {
+        super.print(f);
+    }
 
-	public void print(int i) {
-		super.print(i);
-	}
+    public void print(int i) {
+        super.print(i);
+    }
 
-	public void print(long l) {
-		super.print(l);
-	}
+    public void print(long l) {
+        super.print(l);
+    }
 
-	public void print(Object obj) {
-		super.print(obj);
-	}
+    public void print(Object obj) {
+        super.print(obj);
+    }
 
-	public void print(String s) {
-		super.print(s);
-	}
+    public void print(String s) {
+        super.print(s);
+    }
 
-	public PrintWriter printf(Locale l, String format, Object... args) {
-		return super.printf(l, format, args);
-	}
+    public PrintWriter printf(Locale l, String format, Object... args) {
+        return super.printf(l, format, args);
+    }
 
-	public PrintWriter printf(String format, Object... args) {
-		return super.printf(format, args);
-	}
+    public PrintWriter printf(String format, Object... args) {
+        return super.printf(format, args);
+    }
 
-	public void println() {
-		super.println();
-	}
+    public void println() {
+        super.println();
+    }
 
-	public void println(boolean x) {
-		super.println(x);
-	}
+    public void println(boolean x) {
+        super.println(x);
+    }
 
-	public void println(char x) {
-		super.println(x);
-	}
+    public void println(char x) {
+        super.println(x);
+    }
 
-	public void println(char[] x) {
-		super.println(x);
-	}
+    public void println(char[] x) {
+        super.println(x);
+    }
 
-	public void println(double x) {
-		super.println(x);
-	}
+    public void println(double x) {
+        super.println(x);
+    }
 
-	public void println(float x) {
-		super.println(x);
-	}
+    public void println(float x) {
+        super.println(x);
+    }
 
-	public void println(int x) {
-		super.println(x);
-	}
+    public void println(int x) {
+        super.println(x);
+    }
 
-	public void println(long x) {
-		super.println(x);
-	}
+    public void println(long x) {
+        super.println(x);
+    }
 
-	public void println(Object x) {
-		super.println(x);
-	}
+    public void println(Object x) {
+        super.println(x);
+    }
 
-	public void println(String x) {
-		super.println(x);
-	}
+    public void println(String x) {
+        super.println(x);
+    }
 
-	protected void setError() {
-		super.setError();
-	}
+    protected void setError() {
+        super.setError();
+    }
 
-	public void write(char[] buf, int off, int len) {
-		super.write(buf, off, len);
-	}
+    public void write(char[] buf, int off, int len) {
+        super.write(buf, off, len);
+    }
 
-	public void write(char[] buf) {
-		super.write(buf);
-	}
+    public void write(char[] buf) {
+        super.write(buf);
+    }
 
-	public void write(int c) {
-		super.write(c);
-	}
+    public void write(int c) {
+        super.write(c);
+    }
 
-	public void write(String s, int off, int len) {
-		super.write(s, off, len);
-	}
+    public void write(String s, int off, int len) {
+        super.write(s, off, len);
+    }
 
-	public void write(String s) {
-		super.write(s);
-	}
+    public void write(String s) {
+        super.write(s);
+    }
 
 }
diff --git a/src/main/java/org/owasp/esapi/waf/internal/InterceptingServletOutputStream.java b/src/main/java/org/owasp/esapi/waf/internal/InterceptingServletOutputStream.java
index 8dcac00..47fd19f 100644
--- a/src/main/java/org/owasp/esapi/waf/internal/InterceptingServletOutputStream.java
+++ b/src/main/java/org/owasp/esapi/waf/internal/InterceptingServletOutputStream.java
@@ -1,15 +1,15 @@
 /**
  * OWASP Enterprise Security API (ESAPI)
- * 
+ *
  * This file is part of the Open Web Application Security Project (OWASP)
  * Enterprise Security API (ESAPI) project. For details, please see
  * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
  *
  * Copyright (c) 2009 - The OWASP Foundation
- * 
+ *
  * The ESAPI is published by OWASP under the BSD license. You should read and accept the
  * LICENSE before you use, modify, and/or redistribute this software.
- * 
+ *
  * @author Arshan Dabirsiaghi <a href="http://www.aspectsecurity.com">Aspect Security</a>
  * @created 2009
  */
@@ -31,145 +31,145 @@ import javax.servlet.WriteListener;
  *
  * If not, we just forward everything through, otherwise we write data to our
  * byte stream that we will eventually forward en totale to the user agent.
- * 
+ *
  * @author Arshan Dabirsiaghi
  */
 
 public class InterceptingServletOutputStream extends ServletOutputStream {
 
-	private static final int FLUSH_BLOCK_SIZE = 1024;
-	private ServletOutputStream os;
-	private boolean buffering;
-	private boolean committed;
-	private boolean closed;
-	
-	private RandomAccessFile out;
-	
-	public InterceptingServletOutputStream(ServletOutputStream os, boolean buffered) throws FileNotFoundException, IOException {
-		super();
-		this.os = os;
-		this.buffering = buffered;
-		this.committed = false;
-		this.closed = false;
-		
-		/*
-		 * Creating a RandomAccessFile to keep track of output generated. I made
-		 * the prefix and suffix small for less processing. The "oew" is intended
-		 * to stand for "OWASP ESAPI WAF" and the "hop" for HTTP output.
-		 */
-		File tempFile= File.createTempFile("oew", ".hop");
-		this.out = new RandomAccessFile (tempFile, "rw" ); 
-		tempFile.deleteOnExit();
-		
-	}
-
-	public void reset() throws IOException {
-		out.setLength(0L);
-	}
-
-	public byte[] getResponseBytes() throws IOException {
-		
-		byte[] buffer = new byte[(int) out.length()];
-		out.seek(0);
-		out.read(buffer, 0, (int)out.length());
-		out.seek(out.length());
-		return buffer;
-		
-	}
-
-	public void setResponseBytes(byte[] responseBytes) throws IOException {
-		
-		if ( ! buffering && out.length() > 0 ) {
-			throw new IOException("Already committed response because not currently buffering");
-		}
-
-		out.setLength(0L);
-		out.write(responseBytes);
-	}
-
-	public void write(int i) throws IOException {
-		if (!buffering) {
-			os.write(i);
-		}
-		out.write(i);
-	}
-
-	public void write(byte[] b) throws IOException {
+    private static final int FLUSH_BLOCK_SIZE = 1024;
+    private ServletOutputStream os;
+    private boolean buffering;
+    private boolean committed;
+    private boolean closed;
+
+    private RandomAccessFile out;
+
+    public InterceptingServletOutputStream(ServletOutputStream os, boolean buffered) throws FileNotFoundException, IOException {
+        super();
+        this.os = os;
+        this.buffering = buffered;
+        this.committed = false;
+        this.closed = false;
+
+        /*
+         * Creating a RandomAccessFile to keep track of output generated. I made
+         * the prefix and suffix small for less processing. The "oew" is intended
+         * to stand for "OWASP ESAPI WAF" and the "hop" for HTTP output.
+         */
+        File tempFile= File.createTempFile("oew", ".hop");
+        this.out = new RandomAccessFile (tempFile, "rw" );
+        tempFile.deleteOnExit();
+
+    }
+
+    public void reset() throws IOException {
+        out.setLength(0L);
+    }
+
+    public byte[] getResponseBytes() throws IOException {
+
+        byte[] buffer = new byte[(int) out.length()];
+        out.seek(0);
+        out.read(buffer, 0, (int)out.length());
+        out.seek(out.length());
+        return buffer;
+
+    }
+
+    public void setResponseBytes(byte[] responseBytes) throws IOException {
+
+        if ( ! buffering && out.length() > 0 ) {
+            throw new IOException("Already committed response because not currently buffering");
+        }
+
+        out.setLength(0L);
+        out.write(responseBytes);
+    }
+
+    public void write(int i) throws IOException {
+        if (!buffering) {
+            os.write(i);
+        }
+        out.write(i);
+    }
+
+    public void write(byte[] b) throws IOException {
         if (!buffering) {
-        	os.write(b, 0, b.length);
+            os.write(b, 0, b.length);
         }
         out.write(b, 0, b.length);
     }
 
-	public void write(byte[] b, int off, int len) throws IOException {
+    public void write(byte[] b, int off, int len) throws IOException {
         if (!buffering) {
-        	os.write(b, off, len);
+            os.write(b, off, len);
         }
         out.write(b, off, len);
     }
 
-	public void flush() throws IOException {
-		
-		if (buffering) {
-		
-			synchronized(out) {
-
-				out.seek(0);
-				
-				byte[] buff = new byte[FLUSH_BLOCK_SIZE];
-				
-				for(int i=0;i<out.length();) {
-					
-					long currentPos = out.getFilePointer();
-					long totalSize = out.length();
-					int amountToWrite = FLUSH_BLOCK_SIZE;
-					
-					if ( (totalSize - currentPos) < FLUSH_BLOCK_SIZE ) {
-						amountToWrite = (int) (totalSize - currentPos);
-					}
-			
-					out.read(buff, 0, amountToWrite);
-					
-					os.write(buff,0,amountToWrite);
-					
-					i+=amountToWrite;
-					
-				}
-				
-				out.setLength(0);
-				
-			}
-		}
-
-	}
-
-	public void commit() throws IOException {
-		
-		if (!buffering) { // || committed || closed
-        	return;
+    public void flush() throws IOException {
+
+        if (buffering) {
+
+            synchronized(out) {
+
+                out.seek(0);
+
+                byte[] buff = new byte[FLUSH_BLOCK_SIZE];
+
+                for(int i=0;i<out.length();) {
+
+                    long currentPos = out.getFilePointer();
+                    long totalSize = out.length();
+                    int amountToWrite = FLUSH_BLOCK_SIZE;
+
+                    if ( (totalSize - currentPos) < FLUSH_BLOCK_SIZE ) {
+                        amountToWrite = (int) (totalSize - currentPos);
+                    }
+
+                    out.read(buff, 0, amountToWrite);
+
+                    os.write(buff,0,amountToWrite);
+
+                    i+=amountToWrite;
+
+                }
+
+                out.setLength(0);
+
+            }
+        }
+
+    }
+
+    public void commit() throws IOException {
+
+        if (!buffering) { // || committed || closed
+            return;
         } else {
-        	flush();
+            flush();
         }
-		committed = true;
+        committed = true;
     }
 
     public void close() throws IOException {
-    	
+
         if (!buffering)  {
-        	os.close();
+            os.close();
         }
         closed = true;
 
     }
 
-	@Override
-	public boolean isReady() {
-		return os.isReady();
-	}
+    @Override
+    public boolean isReady() {
+        return os.isReady();
+    }
 
-	@Override
-	public void setWriteListener(WriteListener writeListener) {
-		os.setWriteListener(writeListener);
-	}
+    @Override
+    public void setWriteListener(WriteListener writeListener) {
+        os.setWriteListener(writeListener);
+    }
 
 }
diff --git a/src/main/java/org/owasp/esapi/waf/internal/Parameter.java b/src/main/java/org/owasp/esapi/waf/internal/Parameter.java
index 1cae3dc..0f14299 100644
--- a/src/main/java/org/owasp/esapi/waf/internal/Parameter.java
+++ b/src/main/java/org/owasp/esapi/waf/internal/Parameter.java
@@ -1,15 +1,15 @@
 /**
  * OWASP Enterprise Security API (ESAPI)
- * 
+ *
  * This file is part of the Open Web Application Security Project (OWASP)
  * Enterprise Security API (ESAPI) project. For details, please see
  * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
  *
  * Copyright (c) 2009 - The OWASP Foundation
- * 
+ *
  * The ESAPI is published by OWASP under the BSD license. You should read and accept the
  * LICENSE before you use, modify, and/or redistribute this software.
- * 
+ *
  * @author Arshan Dabirsiaghi <a href="http://www.aspectsecurity.com">Aspect Security</a>
  * @created 2009
  */
@@ -17,33 +17,33 @@ package org.owasp.esapi.waf.internal;
 
 /**
  * A simple object to represent a name=value HTTP parameter.
- * 
+ *
  * @author Arshan Dabirsiaghi
  *
  */
 public class Parameter {
 
-	private String name;
-	private String value;
-	private boolean fromMultipart;
+    private String name;
+    private String value;
+    private boolean fromMultipart;
 
-	public Parameter(String name, String value, boolean fromMultipart) {
-		this.name = name;
-		this.value = value;
-		this.fromMultipart = fromMultipart;
-	}
+    public Parameter(String name, String value, boolean fromMultipart) {
+        this.name = name;
+        this.value = value;
+        this.fromMultipart = fromMultipart;
+    }
 
-	public String getName() {
-		return name;
-	}
-	public void setName(String name) {
-		this.name = name;
-	}
-	public String getValue() {
-		return value;
-	}
-	public void setValue(String value) {
-		this.value = value;
-	}
+    public String getName() {
+        return name;
+    }
+    public void setName(String name) {
+        this.name = name;
+    }
+    public String getValue() {
+        return value;
+    }
+    public void setValue(String value) {
+        this.value = value;
+    }
 
 }
diff --git a/src/main/java/org/owasp/esapi/waf/internal/package.html b/src/main/java/org/owasp/esapi/waf/internal/package.html
index a948700..92d808c 100644
--- a/src/main/java/org/owasp/esapi/waf/internal/package.html
+++ b/src/main/java/org/owasp/esapi/waf/internal/package.html
@@ -6,7 +6,7 @@
 <body bgcolor="white">
 
 This package contains all HTTP-related classes used internally by the WAF for the implementation
-of its rules. 
- 
+of its rules.
+
 </body>
 </html>
diff --git a/src/main/java/org/owasp/esapi/waf/package.html b/src/main/java/org/owasp/esapi/waf/package.html
index 8f025e3..186c820 100644
--- a/src/main/java/org/owasp/esapi/waf/package.html
+++ b/src/main/java/org/owasp/esapi/waf/package.html
@@ -9,6 +9,6 @@ This package contains the ESAPI Web Application Firewall (WAF). It is an optiona
 that can be used with or without ESAPI's other security controls in place. It's purpose is to provide
 fast virtual patching capabilities against known vulnerabilities or the enforcement of existing
 security policies where possible.
- 
+
 </body>
 </html>
diff --git a/src/main/java/org/owasp/esapi/waf/rules/AddHTTPOnlyFlagRule.java b/src/main/java/org/owasp/esapi/waf/rules/AddHTTPOnlyFlagRule.java
index 36e6bc8..21395cb 100644
--- a/src/main/java/org/owasp/esapi/waf/rules/AddHTTPOnlyFlagRule.java
+++ b/src/main/java/org/owasp/esapi/waf/rules/AddHTTPOnlyFlagRule.java
@@ -1,15 +1,15 @@
 /**
  * OWASP Enterprise Security API (ESAPI)
- * 
+ *
  * This file is part of the Open Web Application Security Project (OWASP)
  * Enterprise Security API (ESAPI) project. For details, please see
  * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
  *
  * Copyright (c) 2009 - The OWASP Foundation
- * 
+ *
  * The ESAPI is published by OWASP under the BSD license. You should read and accept the
  * LICENSE before you use, modify, and/or redistribute this software.
- * 
+ *
  * @author Arshan Dabirsiaghi <a href="http://www.aspectsecurity.com">Aspect Security</a>
  * @created 2009
  */
@@ -32,32 +32,32 @@ import org.owasp.esapi.waf.internal.InterceptingHTTPServletResponse;
  */
 public class AddHTTPOnlyFlagRule extends Rule {
 
-	private List<Pattern> name;
+    private List<Pattern> name;
 
-	public AddHTTPOnlyFlagRule(String id, List<Pattern> name) {
-		setId(id);
-		this.name = name;
-	}
+    public AddHTTPOnlyFlagRule(String id, List<Pattern> name) {
+        setId(id);
+        this.name = name;
+    }
 
-	public Action check(HttpServletRequest request,
-			InterceptingHTTPServletResponse response, 
-			HttpServletResponse httpResponse) {
+    public Action check(HttpServletRequest request,
+            InterceptingHTTPServletResponse response,
+            HttpServletResponse httpResponse) {
 
-		DoNothingAction action = new DoNothingAction();
+        DoNothingAction action = new DoNothingAction();
 
-		return action;
-	}
+        return action;
+    }
 
-	public boolean doesCookieMatch(String cookieName) {
+    public boolean doesCookieMatch(String cookieName) {
 
-		for(int i=0;i<name.size();i++) {
-			Pattern p = name.get(i);
-			if ( p.matcher(cookieName).matches() ) {
-				return true;
-			}
-		}
+        for(int i=0;i<name.size();i++) {
+            Pattern p = name.get(i);
+            if ( p.matcher(cookieName).matches() ) {
+                return true;
+            }
+        }
 
-		return false;
-	}
+        return false;
+    }
 
 }
diff --git a/src/main/java/org/owasp/esapi/waf/rules/AddHeaderRule.java b/src/main/java/org/owasp/esapi/waf/rules/AddHeaderRule.java
index 88c2686..68bb05e 100644
--- a/src/main/java/org/owasp/esapi/waf/rules/AddHeaderRule.java
+++ b/src/main/java/org/owasp/esapi/waf/rules/AddHeaderRule.java
@@ -1,15 +1,15 @@
 /**
  * OWASP Enterprise Security API (ESAPI)
- * 
+ *
  * This file is part of the Open Web Application Security Project (OWASP)
  * Enterprise Security API (ESAPI) project. For details, please see
  * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
  *
  * Copyright (c) 2009 - The OWASP Foundation
- * 
+ *
  * The ESAPI is published by OWASP under the BSD license. You should read and accept the
  * LICENSE before you use, modify, and/or redistribute this software.
- * 
+ *
  * @author Arshan Dabirsiaghi <a href="http://www.aspectsecurity.com">Aspect Security</a>
  * @created 2009
  */
@@ -32,61 +32,61 @@ import org.owasp.esapi.waf.internal.InterceptingHTTPServletResponse;
  */
 public class AddHeaderRule extends Rule {
 
-	private String header;
-	private String value;
-	private Pattern path;
-	private List<Object> exceptions;
+    private String header;
+    private String value;
+    private Pattern path;
+    private List<Object> exceptions;
 
-	public AddHeaderRule(String id, String header, String value, Pattern path, List<Object> exceptions) {
-		setId(id);
-		this.header = header;
-		this.value = value;
-		this.path = path;
-		this.exceptions = exceptions;
-	}
+    public AddHeaderRule(String id, String header, String value, Pattern path, List<Object> exceptions) {
+        setId(id);
+        this.header = header;
+        this.value = value;
+        this.path = path;
+        this.exceptions = exceptions;
+    }
 
-	public Action check(
-			HttpServletRequest request, 
-			InterceptingHTTPServletResponse response, 
-			HttpServletResponse httpResponse) {
+    public Action check(
+            HttpServletRequest request,
+            InterceptingHTTPServletResponse response,
+            HttpServletResponse httpResponse) {
 
-		DoNothingAction action = new DoNothingAction();
+        DoNothingAction action = new DoNothingAction();
 
-		if ( path.matcher(request.getRequestURI()).matches() ) {
+        if ( path.matcher(request.getRequestURI()).matches() ) {
 
-			for(int i=0;i<exceptions.size();i++) {
+            for(int i=0;i<exceptions.size();i++) {
 
-				Object o = exceptions.get(i);
+                Object o = exceptions.get(i);
 
-				if ( o instanceof String ) {
-					if ( request.getRequestURI().equals((String)o)) {
-						action.setFailed(false);
-						action.setActionNecessary(false);
-						return action;
-					}
-				} else if ( o instanceof Pattern ) {
-					if ( ((Pattern)o).matcher(request.getRequestURI()).matches() ) {
-						action.setFailed(false);
-						action.setActionNecessary(false);
-						return action;					
-					}
-				}
+                if ( o instanceof String ) {
+                    if ( request.getRequestURI().equals((String)o)) {
+                        action.setFailed(false);
+                        action.setActionNecessary(false);
+                        return action;
+                    }
+                } else if ( o instanceof Pattern ) {
+                    if ( ((Pattern)o).matcher(request.getRequestURI()).matches() ) {
+                        action.setFailed(false);
+                        action.setActionNecessary(false);
+                        return action;
+                    }
+                }
 
-			}
+            }
 
 
-			action.setFailed(true);
-			action.setActionNecessary(false);
+            action.setFailed(true);
+            action.setActionNecessary(false);
 
-			if ( response != null ) {
-				response.setHeader(header, value);
-			} else {
-				httpResponse.setHeader(header, value);
-			}
+            if ( response != null ) {
+                response.setHeader(header, value);
+            } else {
+                httpResponse.setHeader(header, value);
+            }
 
-		}
+        }
 
-		return action;
-	}
+        return action;
+    }
 
 }
diff --git a/src/main/java/org/owasp/esapi/waf/rules/AddSecureFlagRule.java b/src/main/java/org/owasp/esapi/waf/rules/AddSecureFlagRule.java
index 6a85f38..5158401 100644
--- a/src/main/java/org/owasp/esapi/waf/rules/AddSecureFlagRule.java
+++ b/src/main/java/org/owasp/esapi/waf/rules/AddSecureFlagRule.java
@@ -1,15 +1,15 @@
 /**
  * OWASP Enterprise Security API (ESAPI)
- * 
+ *
  * This file is part of the Open Web Application Security Project (OWASP)
  * Enterprise Security API (ESAPI) project. For details, please see
  * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
  *
  * Copyright (c) 2009 - The OWASP Foundation
- * 
+ *
  * The ESAPI is published by OWASP under the BSD license. You should read and accept the
  * LICENSE before you use, modify, and/or redistribute this software.
- * 
+ *
  * @author Arshan Dabirsiaghi <a href="http://www.aspectsecurity.com">Aspect Security</a>
  * @created 2009
  */
@@ -32,32 +32,32 @@ import org.owasp.esapi.waf.internal.InterceptingHTTPServletResponse;
  */
 public class AddSecureFlagRule extends Rule {
 
-	private List<Pattern> name;
+    private List<Pattern> name;
+
+    public AddSecureFlagRule(String id, List<Pattern> name) {
+        this.name = name;
+        setId(id);
+    }
 
-	public AddSecureFlagRule(String id, List<Pattern> name) {
-		this.name = name;
-		setId(id);
-	}
+    public Action check(HttpServletRequest request,
+            InterceptingHTTPServletResponse response,
+            HttpServletResponse httpResponse) {
 
-	public Action check(HttpServletRequest request,
-			InterceptingHTTPServletResponse response, 
-			HttpServletResponse httpResponse) {
-		
-		DoNothingAction action = new DoNothingAction();
+        DoNothingAction action = new DoNothingAction();
 
-		return action;
-	}
+        return action;
+    }
 
-	public boolean doesCookieMatch(String cookieName) {
+    public boolean doesCookieMatch(String cookieName) {
 
-		for(int i=0;i<name.size();i++) {
-			Pattern p = name.get(i);
-			if ( p.matcher(cookieName).matches() ) {
-				return true;
-			}
-		}
+        for(int i=0;i<name.size();i++) {
+            Pattern p = name.get(i);
+            if ( p.matcher(cookieName).matches() ) {
+                return true;
+            }
+        }
 
-		return false;
-	}
+        return false;
+    }
 
 }
diff --git a/src/main/java/org/owasp/esapi/waf/rules/AuthenticatedRule.java b/src/main/java/org/owasp/esapi/waf/rules/AuthenticatedRule.java
index b42f95e..d232b7e 100644
--- a/src/main/java/org/owasp/esapi/waf/rules/AuthenticatedRule.java
+++ b/src/main/java/org/owasp/esapi/waf/rules/AuthenticatedRule.java
@@ -1,15 +1,15 @@
 /**
  * OWASP Enterprise Security API (ESAPI)
- * 
+ *
  * This file is part of the Open Web Application Security Project (OWASP)
  * Enterprise Security API (ESAPI) project. For details, please see
  * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
  *
  * Copyright (c) 2009 - The OWASP Foundation
- * 
+ *
  * The ESAPI is published by OWASP under the BSD license. You should read and accept the
  * LICENSE before you use, modify, and/or redistribute this software.
- * 
+ *
  * @author Arshan Dabirsiaghi <a href="http://www.aspectsecurity.com">Aspect Security</a>
  * @created 2009
  */
@@ -35,58 +35,58 @@ import org.owasp.esapi.waf.internal.InterceptingHTTPServletResponse;
  */
 public class AuthenticatedRule extends Rule {
 
-	private String sessionAttribute;
-	private Pattern path;
-	private List<Object> exceptions;
+    private String sessionAttribute;
+    private Pattern path;
+    private List<Object> exceptions;
 
-	public AuthenticatedRule(String id, String sessionAttribute, Pattern path, List<Object> exceptions) {
-		this.sessionAttribute = sessionAttribute;
-		this.path = path;
-		this.exceptions = exceptions;
-		setId(id);
-	}
+    public AuthenticatedRule(String id, String sessionAttribute, Pattern path, List<Object> exceptions) {
+        this.sessionAttribute = sessionAttribute;
+        this.path = path;
+        this.exceptions = exceptions;
+        setId(id);
+    }
 
-	public Action check(HttpServletRequest request,
-			InterceptingHTTPServletResponse response, 
-			HttpServletResponse httpResponse) {
+    public Action check(HttpServletRequest request,
+            InterceptingHTTPServletResponse response,
+            HttpServletResponse httpResponse) {
 
-		HttpSession session = request.getSession();
-		String uri = request.getRequestURI();
+        HttpSession session = request.getSession();
+        String uri = request.getRequestURI();
 
-		if ( path != null && ! path.matcher(uri).matches() ) {
-			return new DoNothingAction();
-		}
+        if ( path != null && ! path.matcher(uri).matches() ) {
+            return new DoNothingAction();
+        }
 
-		if ( session != null && session.getAttribute(sessionAttribute) != null ) {
+        if ( session != null && session.getAttribute(sessionAttribute) != null ) {
 
-			return new DoNothingAction();
+            return new DoNothingAction();
 
-		} else { /* check if it's one of the exceptions */
+        } else { /* check if it's one of the exceptions */
 
-			Iterator<Object> it = exceptions.iterator();
+            Iterator<Object> it = exceptions.iterator();
 
-			while(it.hasNext()) {
-				Object o = it.next();
-				if ( o instanceof Pattern ) {
+            while(it.hasNext()) {
+                Object o = it.next();
+                if ( o instanceof Pattern ) {
 
-					Pattern p = (Pattern)o;
-					if ( p.matcher(uri).matches() ) {
-						return new DoNothingAction();
-					}
+                    Pattern p = (Pattern)o;
+                    if ( p.matcher(uri).matches() ) {
+                        return new DoNothingAction();
+                    }
 
-				} else if ( o instanceof String ) {
+                } else if ( o instanceof String ) {
 
-					if ( uri.equals((String)o)) {
-						return new DoNothingAction();
-					}
+                    if ( uri.equals((String)o)) {
+                        return new DoNothingAction();
+                    }
 
-				}
-			}
-		}
+                }
+            }
+        }
 
-		log(request, "User requested unauthenticated access to URI '" + request.getRequestURI() + "' [querystring="+request.getQueryString()+"]");
+        log(request, "User requested unauthenticated access to URI '" + request.getRequestURI() + "' [querystring="+request.getQueryString()+"]");
 
-		return new DefaultAction();
-	}
+        return new DefaultAction();
+    }
 
 }
diff --git a/src/main/java/org/owasp/esapi/waf/rules/BeanShellRule.java b/src/main/java/org/owasp/esapi/waf/rules/BeanShellRule.java
index f90da57..7d03107 100644
--- a/src/main/java/org/owasp/esapi/waf/rules/BeanShellRule.java
+++ b/src/main/java/org/owasp/esapi/waf/rules/BeanShellRule.java
@@ -1,15 +1,15 @@
 /**
  * OWASP Enterprise Security API (ESAPI)
- * 
+ *
  * This file is part of the Open Web Application Security Project (OWASP)
  * Enterprise Security API (ESAPI) project. For details, please see
  * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
  *
  * Copyright (c) 2009 - The OWASP Foundation
- * 
+ *
  * The ESAPI is published by OWASP under the BSD license. You should read and accept the
  * LICENSE before you use, modify, and/or redistribute this software.
- * 
+ *
  * @author Arshan Dabirsiaghi <a href="http://www.aspectsecurity.com">Aspect Security</a>
  * @created 2009
  */
@@ -40,80 +40,80 @@ import bsh.Interpreter;
  */
 public class BeanShellRule extends Rule {
 
-	private Interpreter i;
-	private String script;
-	private Pattern path;
-
-	public BeanShellRule(String fileLocation, String id, Pattern path) throws IOException, EvalError {
-		i = new Interpreter();
-		i.set("logger", logger);
-		this.script = getFileContents(ESAPI.securityConfiguration().getResourceFile(fileLocation));
-		this.id = id;
-		this.path = path;
-	}
-
-	public Action check(HttpServletRequest request, InterceptingHTTPServletResponse response,
-			HttpServletResponse httpResponse) {
-
-		/*
-		 * Early fail: if the URL doesn't match one we're interested in.
-		 */
-
-		if (path != null && !path.matcher(request.getRequestURI()).matches()) {
-			return new DoNothingAction();
-		}
-
-		/*
-		 * Run the beanshell that we've already parsed and pre-compiled.
-		 * Populate the "request" and "response" objects so the script has
-		 * access to the same variables we do here.
-		 */
-
-		try {
-
-			Action a = null;
-
-			i.set("action", a);
-			i.set("request", request);
-
-			if (response != null) {
-				i.set("response", response);
-			} else {
-				i.set("response", httpResponse);
-			}
-
-			i.set("session", request.getSession());
-			i.eval(script);
-
-			a = (Action) i.get("action");
-
-			if (a != null) {
-				return a;
-			}
-
-		} catch (EvalError e) {
-			log(request, "Error running custom beanshell rule (" + id + ") - " + e.getMessage());
-		}
-
-		return new DoNothingAction();
-	}
-
-	private String getFileContents(File f) throws IOException {
-		StringBuffer sb = new StringBuffer();
-		BufferedReader br = null;
-
-		try {
-			br = new BufferedReader(new FileReader(f));
-			String line;
-			while ((line = br.readLine()) != null) {
-				sb.append(line + System.getProperty("line.separator"));
-			}
-
-		} finally {
-			if (br != null) {
-				br.close();
-			}
-		}
-		return sb.toString();
-	}
+    private Interpreter i;
+    private String script;
+    private Pattern path;
+
+    public BeanShellRule(String fileLocation, String id, Pattern path) throws IOException, EvalError {
+        i = new Interpreter();
+        i.set("logger", logger);
+        this.script = getFileContents(ESAPI.securityConfiguration().getResourceFile(fileLocation));
+        this.id = id;
+        this.path = path;
+    }
+
+    public Action check(HttpServletRequest request, InterceptingHTTPServletResponse response,
+            HttpServletResponse httpResponse) {
+
+        /*
+         * Early fail: if the URL doesn't match one we're interested in.
+         */
+
+        if (path != null && !path.matcher(request.getRequestURI()).matches()) {
+            return new DoNothingAction();
+        }
+
+        /*
+         * Run the beanshell that we've already parsed and pre-compiled.
+         * Populate the "request" and "response" objects so the script has
+         * access to the same variables we do here.
+         */
+
+        try {
+
+            Action a = null;
+
+            i.set("action", a);
+            i.set("request", request);
+
+            if (response != null) {
+                i.set("response", response);
+            } else {
+                i.set("response", httpResponse);
+            }
+
+            i.set("session", request.getSession());
+            i.eval(script);
+
+            a = (Action) i.get("action");
+
+            if (a != null) {
+                return a;
+            }
+
+        } catch (EvalError e) {
+            log(request, "Error running custom beanshell rule (" + id + ") - " + e.getMessage());
+        }
+
+        return new DoNothingAction();
+    }
+
+    private String getFileContents(File f) throws IOException {
+        StringBuffer sb = new StringBuffer();
+        BufferedReader br = null;
+
+        try {
+            br = new BufferedReader(new FileReader(f));
+            String line;
+            while ((line = br.readLine()) != null) {
+                sb.append(line + System.getProperty("line.separator"));
+            }
+
+        } finally {
+            if (br != null) {
+                br.close();
+            }
+        }
+        return sb.toString();
+    }
 }
diff --git a/src/main/java/org/owasp/esapi/waf/rules/DetectOutboundContentRule.java b/src/main/java/org/owasp/esapi/waf/rules/DetectOutboundContentRule.java
index d4f68f5..92931fb 100644
--- a/src/main/java/org/owasp/esapi/waf/rules/DetectOutboundContentRule.java
+++ b/src/main/java/org/owasp/esapi/waf/rules/DetectOutboundContentRule.java
@@ -1,15 +1,15 @@
 /**
  * OWASP Enterprise Security API (ESAPI)
- * 
+ *
  * This file is part of the Open Web Application Security Project (OWASP)
  * Enterprise Security API (ESAPI) project. For details, please see
  * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
  *
  * Copyright (c) 2009 - The OWASP Foundation
- * 
+ *
  * The ESAPI is published by OWASP under the BSD license. You should read and accept the
  * LICENSE before you use, modify, and/or redistribute this software.
- * 
+ *
  * @author Arshan Dabirsiaghi <a href="http://www.aspectsecurity.com">Aspect Security</a>
  * @created 2009
  */
@@ -35,82 +35,82 @@ import org.owasp.esapi.waf.internal.InterceptingHTTPServletResponse;
  */
 public class DetectOutboundContentRule extends Rule {
 
-	private Pattern contentType;
-	private Pattern pattern;
-	private Pattern uri;
-	
-	public DetectOutboundContentRule(String id, Pattern contentType, Pattern pattern, Pattern uri) {
-		this.contentType = contentType;
-		this.pattern = pattern;
-		this.uri = uri;
-		setId(id);
-	}
-
-	public Action check(HttpServletRequest request,
-			InterceptingHTTPServletResponse response, 
-			HttpServletResponse httpResponse) {
-
-		/*
-		 * Early fail: if URI doesn't match.
-		 */
-		if ( uri != null && ! uri.matcher(request.getRequestURI()).matches() ) {
-			return new DoNothingAction(); 
-		}
-
-		/*
-		 * Early fail: if the content type is one we'd like to search for output patterns.
-		 */
-
-		String inboundContentType;
-		String charEnc;
-		
-		if ( response != null ) {
-			if ( response.getContentType() == null ) {
-				response.setContentType(AppGuardianConfiguration.DEFAULT_CONTENT_TYPE);
-			}
-			inboundContentType = response.getContentType();
-			charEnc = response.getCharacterEncoding();
-			
-		} else {
-			if ( httpResponse.getContentType() == null ) {
-				httpResponse.setContentType(AppGuardianConfiguration.DEFAULT_CONTENT_TYPE);
-			}
-			inboundContentType = httpResponse.getContentType();
-			charEnc = httpResponse.getCharacterEncoding();
-		}
-	
-		if ( contentType.matcher(inboundContentType).matches() ) {
-			/*
-			 * Depending on the encoding, search through the bytes
-			 * for the pattern.
-			 */
-			try {
-
-				byte[] bytes = null;
-				
-				try {
-					bytes = response.getInterceptingServletOutputStream().getResponseBytes();
-				} catch (IOException ioe) {
-					log(request,"Error matching pattern '" + pattern.pattern() + "', IOException encountered (possibly too large?): " + ioe.getMessage() + " (in response to URL: '" + request.getRequestURL() + "')");
-					return new DoNothingAction(); // yes this is a fail open!
-				}
-
-				String s = new String(bytes,charEnc);
-
-				if ( pattern.matcher(s).matches() ) {
-
-					log(request,"Content pattern '" + pattern.pattern() + "' was found in response to URL: '" + request.getRequestURL() + "'");
-					return new DefaultAction();
-
-				}
-
-			} catch (UnsupportedEncodingException uee) {
-				log(request,"Content pattern '" + pattern.pattern() + "' could not be found due to encoding error: " + uee.getMessage());
-			}
-		}
-
-		return new DoNothingAction();
-
-	}
+    private Pattern contentType;
+    private Pattern pattern;
+    private Pattern uri;
+
+    public DetectOutboundContentRule(String id, Pattern contentType, Pattern pattern, Pattern uri) {
+        this.contentType = contentType;
+        this.pattern = pattern;
+        this.uri = uri;
+        setId(id);
+    }
+
+    public Action check(HttpServletRequest request,
+            InterceptingHTTPServletResponse response,
+            HttpServletResponse httpResponse) {
+
+        /*
+         * Early fail: if URI doesn't match.
+         */
+        if ( uri != null && ! uri.matcher(request.getRequestURI()).matches() ) {
+            return new DoNothingAction();
+        }
+
+        /*
+         * Early fail: if the content type is one we'd like to search for output patterns.
+         */
+
+        String inboundContentType;
+        String charEnc;
+
+        if ( response != null ) {
+            if ( response.getContentType() == null ) {
+                response.setContentType(AppGuardianConfiguration.DEFAULT_CONTENT_TYPE);
+            }
+            inboundContentType = response.getContentType();
+            charEnc = response.getCharacterEncoding();
+
+        } else {
+            if ( httpResponse.getContentType() == null ) {
+                httpResponse.setContentType(AppGuardianConfiguration.DEFAULT_CONTENT_TYPE);
+            }
+            inboundContentType = httpResponse.getContentType();
+            charEnc = httpResponse.getCharacterEncoding();
+        }
+
+        if ( contentType.matcher(inboundContentType).matches() ) {
+            /*
+             * Depending on the encoding, search through the bytes
+             * for the pattern.
+             */
+            try {
+
+                byte[] bytes = null;
+
+                try {
+                    bytes = response.getInterceptingServletOutputStream().getResponseBytes();
+                } catch (IOException ioe) {
+                    log(request,"Error matching pattern '" + pattern.pattern() + "', IOException encountered (possibly too large?): " + ioe.getMessage() + " (in response to URL: '" + request.getRequestURL() + "')");
+                    return new DoNothingAction(); // yes this is a fail open!
+                }
+
+                String s = new String(bytes,charEnc);
+
+                if ( pattern.matcher(s).matches() ) {
+
+                    log(request,"Content pattern '" + pattern.pattern() + "' was found in response to URL: '" + request.getRequestURL() + "'");
+                    return new DefaultAction();
+
+                }
+
+            } catch (UnsupportedEncodingException uee) {
+                log(request,"Content pattern '" + pattern.pattern() + "' could not be found due to encoding error: " + uee.getMessage());
+            }
+        }
+
+        return new DoNothingAction();
+
+    }
 
 }
diff --git a/src/main/java/org/owasp/esapi/waf/rules/EnforceHTTPSRule.java b/src/main/java/org/owasp/esapi/waf/rules/EnforceHTTPSRule.java
index d158755..bd31562 100644
--- a/src/main/java/org/owasp/esapi/waf/rules/EnforceHTTPSRule.java
+++ b/src/main/java/org/owasp/esapi/waf/rules/EnforceHTTPSRule.java
@@ -1,15 +1,15 @@
 /**
  * OWASP Enterprise Security API (ESAPI)
- * 
+ *
  * This file is part of the Open Web Application Security Project (OWASP)
  * Enterprise Security API (ESAPI) project. For details, please see
  * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
  *
  * Copyright (c) 2009 - The OWASP Foundation
- * 
+ *
  * The ESAPI is published by OWASP under the BSD license. You should read and accept the
  * LICENSE before you use, modify, and/or redistribute this software.
- * 
+ *
  * @author Arshan Dabirsiaghi <a href="http://www.aspectsecurity.com">Aspect Security</a>
  * @created 2009
  */
@@ -35,61 +35,61 @@ import org.owasp.esapi.waf.internal.InterceptingHTTPServletResponse;
  */
 public class EnforceHTTPSRule extends Rule {
 
-	private Pattern path;
-	private List<Object> exceptions;
-	private String action;
+    private Pattern path;
+    private List<Object> exceptions;
+    private String action;
 
-	/*
-	 * action = [ redirect | block ] [=default (redirect will redirect to error page]
-	 */
+    /*
+     * action = [ redirect | block ] [=default (redirect will redirect to error page]
+     */
 
-	public EnforceHTTPSRule(String id, Pattern path, List<Object> exceptions, String action) {
-		this.path = path;
-		this.exceptions = exceptions;
-		this.action = action;
-		setId(id);
-	}
+    public EnforceHTTPSRule(String id, Pattern path, List<Object> exceptions, String action) {
+        this.path = path;
+        this.exceptions = exceptions;
+        this.action = action;
+        setId(id);
+    }
 
-	public Action check(HttpServletRequest request,
-			InterceptingHTTPServletResponse response, 
-			HttpServletResponse httpResponse) {
+    public Action check(HttpServletRequest request,
+            InterceptingHTTPServletResponse response,
+            HttpServletResponse httpResponse) {
 
-		if ( ! request.isSecure() ) {
+        if ( ! request.isSecure() ) {
 
-			if ( path.matcher(request.getRequestURI()).matches() ) {
+            if ( path.matcher(request.getRequestURI()).matches() ) {
 
-				Iterator<Object> it = exceptions.iterator();
+                Iterator<Object> it = exceptions.iterator();
 
-				while(it.hasNext()){
+                while(it.hasNext()){
 
-					Object o = it.next();
+                    Object o = it.next();
 
-					if ( o instanceof String ) {
-						if ( ((String)o).equalsIgnoreCase(request.getRequestURI()) ) {
-							return new DoNothingAction();
-						}
-					} else if ( o instanceof Pattern ) {
-						if ( ((Pattern)o).matcher(request.getRequestURI()).matches() ) {
-							return new DoNothingAction();
-						}
-					}
+                    if ( o instanceof String ) {
+                        if ( ((String)o).equalsIgnoreCase(request.getRequestURI()) ) {
+                            return new DoNothingAction();
+                        }
+                    } else if ( o instanceof Pattern ) {
+                        if ( ((Pattern)o).matcher(request.getRequestURI()).matches() ) {
+                            return new DoNothingAction();
+                        }
+                    }
 
-				}
+                }
 
-				log(request,"Insecure request to resource detected in URL: '" + request.getRequestURL() + "'");
+                log(request,"Insecure request to resource detected in URL: '" + request.getRequestURL() + "'");
 
-				if ( "redirect".equals(action) ) {
-					RedirectAction ra = new RedirectAction();
-					ra.setRedirectURL(request.getRequestURL().toString().replaceFirst("http", "https"));
-					return ra;
-				}
+                if ( "redirect".equals(action) ) {
+                    RedirectAction ra = new RedirectAction();
+                    ra.setRedirectURL(request.getRequestURL().toString().replaceFirst("http", "https"));
+                    return ra;
+                }
 
-				return new DefaultAction();
+                return new DefaultAction();
 
-			}
-		}
+            }
+        }
 
-		return new DoNothingAction();
+        return new DoNothingAction();
 
-	}
+    }
 }
diff --git a/src/main/java/org/owasp/esapi/waf/rules/GeneralAttackSignatureRule.java b/src/main/java/org/owasp/esapi/waf/rules/GeneralAttackSignatureRule.java
index 56fad6c..66edec4 100644
--- a/src/main/java/org/owasp/esapi/waf/rules/GeneralAttackSignatureRule.java
+++ b/src/main/java/org/owasp/esapi/waf/rules/GeneralAttackSignatureRule.java
@@ -1,15 +1,15 @@
 /**
  * OWASP Enterprise Security API (ESAPI)
- * 
+ *
  * This file is part of the Open Web Application Security Project (OWASP)
  * Enterprise Security API (ESAPI) project. For details, please see
  * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
  *
  * Copyright (c) 2009 - The OWASP Foundation
- * 
+ *
  * The ESAPI is published by OWASP under the BSD license. You should read and accept the
  * LICENSE before you use, modify, and/or redistribute this software.
- * 
+ *
  * @author Arshan Dabirsiaghi <a href="http://www.aspectsecurity.com">Aspect Security</a>
  * @created 2009
  */
@@ -28,36 +28,36 @@ import org.owasp.esapi.waf.internal.InterceptingHTTPServletRequest;
 import org.owasp.esapi.waf.internal.InterceptingHTTPServletResponse;
 
 /**
- * This is the Rule subclass executed for &lt;general-attack-signature&gt; rules, which 
+ * This is the Rule subclass executed for &lt;general-attack-signature&gt; rules, which
  * are not currently implemented.
  * @author Arshan Dabirsiaghi
  *
  */
 public class GeneralAttackSignatureRule extends Rule {
 
-	private Pattern signature;
+    private Pattern signature;
 
-	public GeneralAttackSignatureRule(String id, Pattern signature) {
-		this.signature = signature;
-		setId(id);
-	}
+    public GeneralAttackSignatureRule(String id, Pattern signature) {
+        this.signature = signature;
+        setId(id);
+    }
 
-	public Action check(HttpServletRequest req,
-			InterceptingHTTPServletResponse response, 
-			HttpServletResponse httpResponse) {
+    public Action check(HttpServletRequest req,
+            InterceptingHTTPServletResponse response,
+            HttpServletResponse httpResponse) {
 
-		InterceptingHTTPServletRequest request = (InterceptingHTTPServletRequest)req;
-		Enumeration e = request.getParameterNames();
+        InterceptingHTTPServletRequest request = (InterceptingHTTPServletRequest)req;
+        Enumeration e = request.getParameterNames();
 
-		while(e.hasMoreElements()) {
-			String param = (String)e.nextElement();
-			if ( signature.matcher(request.getDictionaryParameter(param)).matches() ) {
-				log(request,"General attack signature detected in parameter '" + param + "' value '" + request.getDictionaryParameter(param) + "'");
-				return new DefaultAction();
-			}
-		}
+        while(e.hasMoreElements()) {
+            String param = (String)e.nextElement();
+            if ( signature.matcher(request.getDictionaryParameter(param)).matches() ) {
+                log(request,"General attack signature detected in parameter '" + param + "' value '" + request.getDictionaryParameter(param) + "'");
+                return new DefaultAction();
+            }
+        }
 
-		return new DoNothingAction();
-	}
+        return new DoNothingAction();
+    }
 
 }
diff --git a/src/main/java/org/owasp/esapi/waf/rules/HTTPMethodRule.java b/src/main/java/org/owasp/esapi/waf/rules/HTTPMethodRule.java
index cd9e603..1c8e8e1 100644
--- a/src/main/java/org/owasp/esapi/waf/rules/HTTPMethodRule.java
+++ b/src/main/java/org/owasp/esapi/waf/rules/HTTPMethodRule.java
@@ -1,15 +1,15 @@
 /**
  * OWASP Enterprise Security API (ESAPI)
- * 
+ *
  * This file is part of the Open Web Application Security Project (OWASP)
  * Enterprise Security API (ESAPI) project. For details, please see
  * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
  *
  * Copyright (c) 2009 - The OWASP Foundation
- * 
+ *
  * The ESAPI is published by OWASP under the BSD license. You should read and accept the
  * LICENSE before you use, modify, and/or redistribute this software.
- * 
+ *
  * @author Arshan Dabirsiaghi <a href="http://www.aspectsecurity.com">Aspect Security</a>
  * @created 2009
  */
@@ -32,47 +32,47 @@ import org.owasp.esapi.waf.internal.InterceptingHTTPServletResponse;
  */
 public class HTTPMethodRule extends Rule {
 
-	private Pattern allowedMethods;
-	private Pattern deniedMethods;
-	private Pattern path;
+    private Pattern allowedMethods;
+    private Pattern deniedMethods;
+    private Pattern path;
 
-	public HTTPMethodRule(String id, Pattern allowedMethods, Pattern deniedMethods, Pattern path) {
-		this.allowedMethods = allowedMethods;
-		this.deniedMethods = deniedMethods;
-		this.path = path;
-		setId(id);
-	}
+    public HTTPMethodRule(String id, Pattern allowedMethods, Pattern deniedMethods, Pattern path) {
+        this.allowedMethods = allowedMethods;
+        this.deniedMethods = deniedMethods;
+        this.path = path;
+        setId(id);
+    }
 
-	public Action check(HttpServletRequest request,
-			InterceptingHTTPServletResponse response, 
-			HttpServletResponse httpResponse) {
+    public Action check(HttpServletRequest request,
+            InterceptingHTTPServletResponse response,
+            HttpServletResponse httpResponse) {
 
-		/*
-		 * If no path is specified, apply rule globally.
-		 */
-		String uri = request.getRequestURI();
-		String method = request.getMethod();
+        /*
+         * If no path is specified, apply rule globally.
+         */
+        String uri = request.getRequestURI();
+        String method = request.getMethod();
 
-		if ( path == null || path.matcher(uri).matches() ) {
-			/*
-			 *	Order allow, deny.
-			 */
+        if ( path == null || path.matcher(uri).matches() ) {
+            /*
+             *    Order allow, deny.
+             */
 
-			if ( allowedMethods != null && allowedMethods.matcher(method).matches() ) {
-				return new DoNothingAction();
-			} else if ( allowedMethods != null ) {
-				log(request,"Disallowed HTTP method '" + request.getMethod() + "' found for URL: " + request.getRequestURL());
-				return new DefaultAction();
-			}
+            if ( allowedMethods != null && allowedMethods.matcher(method).matches() ) {
+                return new DoNothingAction();
+            } else if ( allowedMethods != null ) {
+                log(request,"Disallowed HTTP method '" + request.getMethod() + "' found for URL: " + request.getRequestURL());
+                return new DefaultAction();
+            }
 
-			if ( deniedMethods != null && deniedMethods.matcher(method).matches() ) {
-				log(request,"Disallowed HTTP method '" + request.getMethod() + "' found for URL: " + request.getRequestURL());
-				return new DefaultAction();
-			}
+            if ( deniedMethods != null && deniedMethods.matcher(method).matches() ) {
+                log(request,"Disallowed HTTP method '" + request.getMethod() + "' found for URL: " + request.getRequestURL());
+                return new DefaultAction();
+            }
 
-		}
+        }
 
-		return new DoNothingAction();
-	}
+        return new DoNothingAction();
+    }
 
 }
diff --git a/src/main/java/org/owasp/esapi/waf/rules/IPRule.java b/src/main/java/org/owasp/esapi/waf/rules/IPRule.java
index 3381afe..eaa534e 100644
--- a/src/main/java/org/owasp/esapi/waf/rules/IPRule.java
+++ b/src/main/java/org/owasp/esapi/waf/rules/IPRule.java
@@ -1,15 +1,15 @@
 /**
  * OWASP Enterprise Security API (ESAPI)
- * 
+ *
  * This file is part of the Open Web Application Security Project (OWASP)
  * Enterprise Security API (ESAPI) project. For details, please see
  * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
  *
  * Copyright (c) 2009 - The OWASP Foundation
- * 
+ *
  * The ESAPI is published by OWASP under the BSD license. You should read and accept the
  * LICENSE before you use, modify, and/or redistribute this software.
- * 
+ *
  * @author Arshan Dabirsiaghi <a href="http://www.aspectsecurity.com">Aspect Security</a>
  * @created 2009
  */
@@ -32,48 +32,48 @@ import org.owasp.esapi.waf.internal.InterceptingHTTPServletResponse;
  */
 public class IPRule extends Rule {
 
-	private Pattern allowedIP;
-	private String exactPath;
-	private Pattern path;
-	private boolean useExactPath = false;
-	private String ipHeader;
+    private Pattern allowedIP;
+    private String exactPath;
+    private Pattern path;
+    private boolean useExactPath = false;
+    private String ipHeader;
+
+    public IPRule(String id, Pattern allowedIP, Pattern path, String ipHeader) {
+        this.allowedIP = allowedIP;
+        this.path = path;
+        this.useExactPath = false;
+        this.ipHeader = ipHeader;
+        setId(id);
+    }
+
+    public IPRule(String id, Pattern allowedIP, String exactPath) {
+        this.path = null;
+        this.exactPath = exactPath;
+        this.useExactPath = true;
+        setId(id);
+    }
+
+    public Action check(HttpServletRequest request,
+            InterceptingHTTPServletResponse response,
+            HttpServletResponse httpResponse) {
 
-	public IPRule(String id, Pattern allowedIP, Pattern path, String ipHeader) {
-		this.allowedIP = allowedIP;
-		this.path = path;
-		this.useExactPath = false;
-		this.ipHeader = ipHeader;
-		setId(id);
-	}
+        String uri = request.getRequestURI();
 
-	public IPRule(String id, Pattern allowedIP, String exactPath) {
-		this.path = null;
-		this.exactPath = exactPath;
-		this.useExactPath = true;
-		setId(id);
-	}
+        if ( (!useExactPath && path.matcher(uri).matches()) ||
+             ( useExactPath && exactPath.equals(uri)) ) {
 
-	public Action check(HttpServletRequest request,
-			InterceptingHTTPServletResponse response, 
-			HttpServletResponse httpResponse) {
+            String sourceIP = request.getRemoteAddr() + "";
 
-		String uri = request.getRequestURI();
+            if ( ipHeader != null ) {
+                sourceIP = request.getHeader(ipHeader);
+            }
 
-		if ( (!useExactPath && path.matcher(uri).matches()) ||
-			 ( useExactPath && exactPath.equals(uri)) ) {
-			
-			String sourceIP = request.getRemoteAddr() + "";
-			
-			if ( ipHeader != null ) {
-				sourceIP = request.getHeader(ipHeader);
-			}
-			
-			if ( ! allowedIP.matcher(sourceIP).matches() ) {
-				log(request, "IP not allowed to access URI '" + uri + "'");
-				return new DefaultAction();
-			}
-		}
+            if ( ! allowedIP.matcher(sourceIP).matches() ) {
+                log(request, "IP not allowed to access URI '" + uri + "'");
+                return new DefaultAction();
+            }
+        }
 
-		return new DoNothingAction();
-	}
+        return new DoNothingAction();
+    }
 }
diff --git a/src/main/java/org/owasp/esapi/waf/rules/MustMatchRule.java b/src/main/java/org/owasp/esapi/waf/rules/MustMatchRule.java
index b761e23..9b0c42f 100644
--- a/src/main/java/org/owasp/esapi/waf/rules/MustMatchRule.java
+++ b/src/main/java/org/owasp/esapi/waf/rules/MustMatchRule.java
@@ -1,15 +1,15 @@
 /**
  * OWASP Enterprise Security API (ESAPI)
- * 
+ *
  * This file is part of the Open Web Application Security Project (OWASP)
  * Enterprise Security API (ESAPI) project. For details, please see
  * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
  *
  * Copyright (c) 2009 - The OWASP Foundation
- * 
+ *
  * The ESAPI is published by OWASP under the BSD license. You should read and accept the
  * LICENSE before you use, modify, and/or redistribute this software.
- * 
+ *
  * @author Arshan Dabirsiaghi <a href="http://www.aspectsecurity.com">Aspect Security</a>
  * @created 2009
  */
@@ -37,300 +37,300 @@ import org.owasp.esapi.waf.internal.InterceptingHTTPServletResponse;
  */
 public class MustMatchRule extends Rule {
 
-	private static final String REQUEST_PARAMETERS = "request.parameters.";
-	private static final String REQUEST_HEADERS = "request.headers.";
-	private static final String REQUEST_URI = "request.uri";
-	private static final String REQUEST_URL = "request.url";
-	private static final String SESSION_ATTRIBUTES = "session.";
+    private static final String REQUEST_PARAMETERS = "request.parameters.";
+    private static final String REQUEST_HEADERS = "request.headers.";
+    private static final String REQUEST_URI = "request.uri";
+    private static final String REQUEST_URL = "request.url";
+    private static final String SESSION_ATTRIBUTES = "session.";
 
-	private Pattern path;
-	private String variable;
-	private int operator;
-	private String value;
+    private Pattern path;
+    private String variable;
+    private int operator;
+    private String value;
 
-	public MustMatchRule(String id, Pattern path, String variable, int operator, String value) {
-		this.path = path;
-		this.variable = variable;
-		this.operator = operator;
-		this.value = value;
-		setId(id);
-	}
+    public MustMatchRule(String id, Pattern path, String variable, int operator, String value) {
+        this.path = path;
+        this.variable = variable;
+        this.operator = operator;
+        this.value = value;
+        setId(id);
+    }
 
-	public Action check(HttpServletRequest req,
-			InterceptingHTTPServletResponse response,
-			HttpServletResponse httpResponse) {
+    public Action check(HttpServletRequest req,
+            InterceptingHTTPServletResponse response,
+            HttpServletResponse httpResponse) {
 
-		InterceptingHTTPServletRequest request = (InterceptingHTTPServletRequest)req;
+        InterceptingHTTPServletRequest request = (InterceptingHTTPServletRequest)req;
 
-		String uri = request.getRequestURI();
-		if ( ! path.matcher(uri).matches() ) {
+        String uri = request.getRequestURI();
+        if ( ! path.matcher(uri).matches() ) {
 
-			return new DoNothingAction();
+            return new DoNothingAction();
 
-		} else {
+        } else {
 
-			String target = null;
+            String target = null;
 
-			/*
-			 * First check if we're going to be dealing with request parameters
-			 */
-			if ( variable.startsWith( REQUEST_PARAMETERS ) ) {
+            /*
+             * First check if we're going to be dealing with request parameters
+             */
+            if ( variable.startsWith( REQUEST_PARAMETERS ) ) {
 
-				if ( operator == AppGuardianConfiguration.OPERATOR_EXISTS ) {
+                if ( operator == AppGuardianConfiguration.OPERATOR_EXISTS ) {
 
-					target = variable.substring(REQUEST_PARAMETERS.length());
+                    target = variable.substring(REQUEST_PARAMETERS.length());
 
-					if ( request.getParameter(target) != null ) {
-						return new DoNothingAction();
-					}
+                    if ( request.getParameter(target) != null ) {
+                        return new DoNothingAction();
+                    }
 
-				} else if ( operator == AppGuardianConfiguration.OPERATOR_IN_LIST ) {
+                } else if ( operator == AppGuardianConfiguration.OPERATOR_IN_LIST ) {
 
-					/*
-					 * This doesn't make sense. The variable to test is a request parameter
-					 * but the rule is looking for a List. Let the control fall through
-					 * to the bottom where we'll return false.
-					 */
+                    /*
+                     * This doesn't make sense. The variable to test is a request parameter
+                     * but the rule is looking for a List. Let the control fall through
+                     * to the bottom where we'll return false.
+                     */
 
-				} else if ( operator == AppGuardianConfiguration.OPERATOR_EQ || operator == AppGuardianConfiguration.OPERATOR_CONTAINS ) {
+                } else if ( operator == AppGuardianConfiguration.OPERATOR_EQ || operator == AppGuardianConfiguration.OPERATOR_CONTAINS ) {
 
-					/**
-					 * Working with request parameters. If we detect
-					 * simple regex characters, we treat it as a regex.
-					 * Otherwise we treat it as a single parameter.
-					 */
-					target = variable.substring(REQUEST_PARAMETERS.length());
+                    /**
+                     * Working with request parameters. If we detect
+                     * simple regex characters, we treat it as a regex.
+                     * Otherwise we treat it as a single parameter.
+                     */
+                    target = variable.substring(REQUEST_PARAMETERS.length());
 
-					if ( target.contains("*") || target.contains("?") ) {
+                    if ( target.contains("*") || target.contains("?") ) {
 
-						target = target.replaceAll("*", ".*");
-						Pattern p = Pattern.compile(target);
+                        target = target.replaceAll("*", ".*");
+                        Pattern p = Pattern.compile(target);
 
-						Enumeration e = request.getParameterNames();
+                        Enumeration e = request.getParameterNames();
 
-						while(e.hasMoreElements()) {
-							String param = (String)e.nextElement();
+                        while(e.hasMoreElements()) {
+                            String param = (String)e.nextElement();
 
-							if ( p.matcher(param).matches() ) {
-								String s = request.getParameter(param);
-								if ( ! RuleUtil.testValue(s, value, operator) ) {
-									log(request, "MustMatch rule failed (operator="+operator+"), value='" + value + "', input='" + s + "' parameter='"+param+"'");
-									return new DefaultAction();
-								}
-							}
-						}
+                            if ( p.matcher(param).matches() ) {
+                                String s = request.getParameter(param);
+                                if ( ! RuleUtil.testValue(s, value, operator) ) {
+                                    log(request, "MustMatch rule failed (operator="+operator+"), value='" + value + "', input='" + s + "' parameter='"+param+"'");
+                                    return new DefaultAction();
+                                }
+                            }
+                        }
 
-					} else {
+                    } else {
 
-						String s = request.getParameter(target);
+                        String s = request.getParameter(target);
 
-						if ( ! RuleUtil.testValue(s, value, operator) ) {
-							log(request, "MustMatch rule failed (operator="+operator+"), value='" + value + "', input='" + s + "', parameter='"+target+"'");
-							return new DefaultAction();
-						}
+                        if ( ! RuleUtil.testValue(s, value, operator) ) {
+                            log(request, "MustMatch rule failed (operator="+operator+"), value='" + value + "', input='" + s + "', parameter='"+target+"'");
+                            return new DefaultAction();
+                        }
 
-					}
-				}
+                    }
+                }
 
-			} else if ( variable.startsWith( REQUEST_HEADERS ) ) {
+            } else if ( variable.startsWith( REQUEST_HEADERS ) ) {
 
-				/**
-				 * Do the same for request headers.
-				 */
+                /**
+                 * Do the same for request headers.
+                 */
 
-				if ( operator == AppGuardianConfiguration.OPERATOR_EXISTS ) {
+                if ( operator == AppGuardianConfiguration.OPERATOR_EXISTS ) {
 
-					target = variable.substring(REQUEST_HEADERS.length());
+                    target = variable.substring(REQUEST_HEADERS.length());
 
-					if ( request.getHeader(target) != null ) {
-						return new DoNothingAction();
-					}
+                    if ( request.getHeader(target) != null ) {
+                        return new DoNothingAction();
+                    }
 
-				} else if ( operator == AppGuardianConfiguration.OPERATOR_IN_LIST ) {
+                } else if ( operator == AppGuardianConfiguration.OPERATOR_IN_LIST ) {
 
-					/*
-					 * This doesn't make sense. The variable to test is a request header
-					 * but the rule is looking for a List. Let the control fall through
-					 * to the bottom where we'll return false.
-					 */
+                    /*
+                     * This doesn't make sense. The variable to test is a request header
+                     * but the rule is looking for a List. Let the control fall through
+                     * to the bottom where we'll return false.
+                     */
 
-				} else if ( operator == AppGuardianConfiguration.OPERATOR_EQ || operator == AppGuardianConfiguration.OPERATOR_CONTAINS ) {
+                } else if ( operator == AppGuardianConfiguration.OPERATOR_EQ || operator == AppGuardianConfiguration.OPERATOR_CONTAINS ) {
 
-					target = variable.substring(REQUEST_HEADERS.length());
+                    target = variable.substring(REQUEST_HEADERS.length());
 
-					if ( target.contains("*") || target.contains("?") ) {
+                    if ( target.contains("*") || target.contains("?") ) {
 
-						target = target.replaceAll("*", ".*");
-						Pattern p = Pattern.compile(target);
+                        target = target.replaceAll("*", ".*");
+                        Pattern p = Pattern.compile(target);
 
-						Enumeration e = request.getHeaderNames();
+                        Enumeration e = request.getHeaderNames();
 
-						while(e.hasMoreElements()) {
-							String header = (String)e.nextElement();
-							if ( p.matcher(header).matches() ) {
-								String s = request.getHeader(header);
-								if ( ! RuleUtil.testValue(s, value, operator) ) {
-									log(request, "MustMatch rule failed (operator="+operator+"), value='" + value + "', input='" + s + "', header='"+header+"'");
-									return new DefaultAction();
-								}
-							}
-						}
+                        while(e.hasMoreElements()) {
+                            String header = (String)e.nextElement();
+                            if ( p.matcher(header).matches() ) {
+                                String s = request.getHeader(header);
+                                if ( ! RuleUtil.testValue(s, value, operator) ) {
+                                    log(request, "MustMatch rule failed (operator="+operator+"), value='" + value + "', input='" + s + "', header='"+header+"'");
+                                    return new DefaultAction();
+                                }
+                            }
+                        }
 
-						return new DoNothingAction();
+                        return new DoNothingAction();
 
-					} else {
+                    } else {
 
-						String s = request.getHeader(target);
+                        String s = request.getHeader(target);
 
-						if ( s == null || ! RuleUtil.testValue(s, value, operator) ) {
-							log(request, "MustMatch rule failed (operator="+operator+"), value='" + value + "', input='" + s + "', header='"+target+"'");
-							return new DefaultAction();
-						}
+                        if ( s == null || ! RuleUtil.testValue(s, value, operator) ) {
+                            log(request, "MustMatch rule failed (operator="+operator+"), value='" + value + "', input='" + s + "', header='"+target+"'");
+                            return new DefaultAction();
+                        }
 
-						return new DoNothingAction();
+                        return new DoNothingAction();
 
-					}
+                    }
 
-				}
+                }
 
-			} else if ( variable.startsWith(SESSION_ATTRIBUTES) ) {
+            } else if ( variable.startsWith(SESSION_ATTRIBUTES) ) {
 
-				/**
-				 * Do the same for session attributes. Can't possibly match
-				 * ANY rule if there is no session object.
-				 */
-				if ( request.getSession(false) == null ) {
-					return new DefaultAction();
-				}
+                /**
+                 * Do the same for session attributes. Can't possibly match
+                 * ANY rule if there is no session object.
+                 */
+                if ( request.getSession(false) == null ) {
+                    return new DefaultAction();
+                }
 
-				target = variable.substring(SESSION_ATTRIBUTES.length()+1);
+                target = variable.substring(SESSION_ATTRIBUTES.length()+1);
 
-				if ( operator == AppGuardianConfiguration.OPERATOR_IN_LIST ) {
+                if ( operator == AppGuardianConfiguration.OPERATOR_IN_LIST ) {
 
-					/*
-					 * Want to check if the List/Enumeration/whatever stored
-					 * in "target" contains the value in "value".
-					 */
+                    /*
+                     * Want to check if the List/Enumeration/whatever stored
+                     * in "target" contains the value in "value".
+                     */
 
-					Object o = request.getSession(false).getAttribute(target);
+                    Object o = request.getSession(false).getAttribute(target);
 
-					if ( o instanceof Collection ) {
-						if ( RuleUtil.isInList((Collection)o, value) ) {
-							return new DoNothingAction();
-						} else {
-							log(request, "MustMatch rule failed - looking for value='" + value + "', in session Collection attribute '" + target + "']");
-							return new DefaultAction();
-						}
-					} else if ( o instanceof Map ) {
-						if ( RuleUtil.isInList((Map)o, value) ) {
-							return new DoNothingAction();
-						} else {
-							log(request, "MustMatch rule failed - looking for value='" + value + "', in session Map attribute '" + target + "']");
-							return new DefaultAction();
-						}
-					} else if ( o instanceof Enumeration ) {
-						if ( RuleUtil.isInList((Enumeration)o, value) ) {
-							return new DoNothingAction();
-						} else {
-							log(request, "MustMatch rule failed - looking for value='" + value + "', in session Enumeration attribute '" + target + "']");
-							return new DefaultAction();
-						}
-					}
+                    if ( o instanceof Collection ) {
+                        if ( RuleUtil.isInList((Collection)o, value) ) {
+                            return new DoNothingAction();
+                        } else {
+                            log(request, "MustMatch rule failed - looking for value='" + value + "', in session Collection attribute '" + target + "']");
+                            return new DefaultAction();
+                        }
+                    } else if ( o instanceof Map ) {
+                        if ( RuleUtil.isInList((Map)o, value) ) {
+                            return new DoNothingAction();
+                        } else {
+                            log(request, "MustMatch rule failed - looking for value='" + value + "', in session Map attribute '" + target + "']");
+                            return new DefaultAction();
+                        }
+                    } else if ( o instanceof Enumeration ) {
+                        if ( RuleUtil.isInList((Enumeration)o, value) ) {
+                            return new DoNothingAction();
+                        } else {
+                            log(request, "MustMatch rule failed - looking for value='" + value + "', in session Enumeration attribute '" + target + "']");
+                            return new DefaultAction();
+                        }
+                    }
 
-					/*
-					 * The attribute was not a common list-type of Java object s
-					 * let the control fall through to the bottom where it will
-					 * fail.
-					 */
+                    /*
+                     * The attribute was not a common list-type of Java object s
+                     * let the control fall through to the bottom where it will
+                     * fail.
+                     */
 
-				} else if ( operator == AppGuardianConfiguration.OPERATOR_EXISTS) {
+                } else if ( operator == AppGuardianConfiguration.OPERATOR_EXISTS) {
 
-					Object o = request.getSession(false).getAttribute(target);
+                    Object o = request.getSession(false).getAttribute(target);
 
-					if ( o != null ) {
-						return new DoNothingAction();
-					} else {
-						log(request, "MustMatch rule failed - couldn't find required session attribute='" + target + "'");
-						return new DefaultAction();
-					}
+                    if ( o != null ) {
+                        return new DoNothingAction();
+                    } else {
+                        log(request, "MustMatch rule failed - couldn't find required session attribute='" + target + "'");
+                        return new DefaultAction();
+                    }
 
-				} else if ( operator == AppGuardianConfiguration.OPERATOR_EQ || operator == AppGuardianConfiguration.OPERATOR_CONTAINS ) {
+                } else if ( operator == AppGuardianConfiguration.OPERATOR_EQ || operator == AppGuardianConfiguration.OPERATOR_CONTAINS ) {
 
-					if ( target.contains("*") || target.contains("?") ) {
+                    if ( target.contains("*") || target.contains("?") ) {
 
-						target = target.replaceAll("\\*", ".*");
-						Pattern p = Pattern.compile(target);
+                        target = target.replaceAll("\\*", ".*");
+                        Pattern p = Pattern.compile(target);
 
-						Enumeration e = request.getSession(false).getAttributeNames();
+                        Enumeration e = request.getSession(false).getAttributeNames();
 
-						while(e.hasMoreElements()) {
+                        while(e.hasMoreElements()) {
 
-							String attr = (String)e.nextElement();
+                            String attr = (String)e.nextElement();
 
-							if (p.matcher(attr).matches() ) {
+                            if (p.matcher(attr).matches() ) {
 
-								Object o = request.getSession(false).getAttribute(attr);
+                                Object o = request.getSession(false).getAttribute(attr);
 
-								if ( ! RuleUtil.testValue((String)o, value, operator) ) {
-									log(request, "MustMatch rule failed (operator="+operator+"), value='" + value + "', session attribute='" + attr + "', attribute value='"+(String)o+"'");
-									return new DefaultAction();
-								} else {
-									return new DoNothingAction();
-								}
-							}
-						}
+                                if ( ! RuleUtil.testValue((String)o, value, operator) ) {
+                                    log(request, "MustMatch rule failed (operator="+operator+"), value='" + value + "', session attribute='" + attr + "', attribute value='"+(String)o+"'");
+                                    return new DefaultAction();
+                                } else {
+                                    return new DoNothingAction();
+                                }
+                            }
+                        }
 
-					} else {
+                    } else {
 
-						Object o = request.getSession(false).getAttribute(target);
+                        Object o = request.getSession(false).getAttribute(target);
 
-						if ( ! RuleUtil.testValue((String)o, value, operator) ) {
-							log(request, "MustMatch rule failed (operator="+operator+"), value='" + value + "', session attribute='" + target + "', attribute value='"+(String)o+"'");
-							return new DefaultAction();
-						} else {
-							return new DoNothingAction();
-						}
+                        if ( ! RuleUtil.testValue((String)o, value, operator) ) {
+                            log(request, "MustMatch rule failed (operator="+operator+"), value='" + value + "', session attribute='" + target + "', attribute value='"+(String)o+"'");
+                            return new DefaultAction();
+                        } else {
+                            return new DoNothingAction();
+                        }
 
-					}
-
-				}
-
-			} else if ( variable.equals( REQUEST_URI ) ) {
-
-				if ( operator == AppGuardianConfiguration.OPERATOR_EQ || operator == AppGuardianConfiguration.OPERATOR_CONTAINS ) {
-					if ( RuleUtil.testValue(request.getRequestURI(), value, operator) ) {
-						return new DoNothingAction();
-					} else {
-						log(request, "MustMatch rule on request URI failed (operator="+operator+"), requestURI='" + request.getRequestURI() + "', value='" + value+ "'");
-						return new DefaultAction();
-					}
-				}
-
-				/*
-				 * Any other operator doesn't make sense.
-				 */
-
-			} else if ( variable.equals( REQUEST_URL ) ) {
-
-				if ( operator == AppGuardianConfiguration.OPERATOR_EQ || operator == AppGuardianConfiguration.OPERATOR_CONTAINS ) {
-					if ( RuleUtil.testValue(request.getRequestURL().toString(), value, operator) ) {
-						return new DoNothingAction();
-					} else {
-						log(request, "MustMatch rule on request URL failed (operator="+operator+"), requestURL='" + request.getRequestURL() + "', value='" + value+ "'");
-						return new DefaultAction();
-					}
-				}
-
-				/*
-				 * Any other operator doesn't make sense.
-				 */
-			}
+                    }
+
+                }
+
+            } else if ( variable.equals( REQUEST_URI ) ) {
+
+                if ( operator == AppGuardianConfiguration.OPERATOR_EQ || operator == AppGuardianConfiguration.OPERATOR_CONTAINS ) {
+                    if ( RuleUtil.testValue(request.getRequestURI(), value, operator) ) {
+                        return new DoNothingAction();
+                    } else {
+                        log(request, "MustMatch rule on request URI failed (operator="+operator+"), requestURI='" + request.getRequestURI() + "', value='" + value+ "'");
+                        return new DefaultAction();
+                    }
+                }
+
+                /*
+                 * Any other operator doesn't make sense.
+                 */
+
+            } else if ( variable.equals( REQUEST_URL ) ) {
+
+                if ( operator == AppGuardianConfiguration.OPERATOR_EQ || operator == AppGuardianConfiguration.OPERATOR_CONTAINS ) {
+                    if ( RuleUtil.testValue(request.getRequestURL().toString(), value, operator) ) {
+                        return new DoNothingAction();
+                    } else {
+                        log(request, "MustMatch rule on request URL failed (operator="+operator+"), requestURL='" + request.getRequestURL() + "', value='" + value+ "'");
+                        return new DefaultAction();
+                    }
+                }
+
+                /*
+                 * Any other operator doesn't make sense.
+                 */
+            }
 
-		}
+        }
 
-		log(request, "MustMatch rule failed close on URL '" + request.getRequestURL() + "'");
-		return new DefaultAction();
+        log(request, "MustMatch rule failed close on URL '" + request.getRequestURL() + "'");
+        return new DefaultAction();
 
-	}
+    }
 
 }
diff --git a/src/main/java/org/owasp/esapi/waf/rules/PathExtensionRule.java b/src/main/java/org/owasp/esapi/waf/rules/PathExtensionRule.java
index 06b13e2..c059ca8 100644
--- a/src/main/java/org/owasp/esapi/waf/rules/PathExtensionRule.java
+++ b/src/main/java/org/owasp/esapi/waf/rules/PathExtensionRule.java
@@ -1,15 +1,15 @@
 /**
  * OWASP Enterprise Security API (ESAPI)
- * 
+ *
  * This file is part of the Open Web Application Security Project (OWASP)
  * Enterprise Security API (ESAPI) project. For details, please see
  * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
  *
  * Copyright (c) 2009 - The OWASP Foundation
- * 
+ *
  * The ESAPI is published by OWASP under the BSD license. You should read and accept the
  * LICENSE before you use, modify, and/or redistribute this software.
- * 
+ *
  * @author Arshan Dabirsiaghi <a href="http://www.aspectsecurity.com">Aspect Security</a>
  * @created 2009
  */
@@ -32,29 +32,29 @@ import org.owasp.esapi.waf.internal.InterceptingHTTPServletResponse;
  */
 public class PathExtensionRule extends Rule {
 
-	private Pattern allow;
-	private Pattern deny;
+    private Pattern allow;
+    private Pattern deny;
 
-	public PathExtensionRule (String id, Pattern allow, Pattern deny) {
-		this.allow = allow;
-		this.deny = deny;
-		setId(id);
-	}
+    public PathExtensionRule (String id, Pattern allow, Pattern deny) {
+        this.allow = allow;
+        this.deny = deny;
+        setId(id);
+    }
 
-	public Action check(HttpServletRequest request,
-			InterceptingHTTPServletResponse response, 
-			HttpServletResponse httpResponse) {
+    public Action check(HttpServletRequest request,
+            InterceptingHTTPServletResponse response,
+            HttpServletResponse httpResponse) {
 
-		if ( allow != null && allow.matcher(request.getRequestURI()).matches() ) {
-			return new DoNothingAction();
-		} else if ( deny != null && deny.matcher(request.getRequestURI()).matches() ) {
+        if ( allow != null && allow.matcher(request.getRequestURI()).matches() ) {
+            return new DoNothingAction();
+        } else if ( deny != null && deny.matcher(request.getRequestURI()).matches() ) {
 
-			log(request, "Disallowed extension pattern '" + deny.pattern() + "' found on URI '" + request.getRequestURI() + "'");
+            log(request, "Disallowed extension pattern '" + deny.pattern() + "' found on URI '" + request.getRequestURI() + "'");
 
-			return new DefaultAction();
-		}
+            return new DefaultAction();
+        }
 
-		return new DoNothingAction();
-	}
+        return new DoNothingAction();
+    }
 
 }
diff --git a/src/main/java/org/owasp/esapi/waf/rules/ReplaceContentRule.java b/src/main/java/org/owasp/esapi/waf/rules/ReplaceContentRule.java
index fd308cc..b36062b 100644
--- a/src/main/java/org/owasp/esapi/waf/rules/ReplaceContentRule.java
+++ b/src/main/java/org/owasp/esapi/waf/rules/ReplaceContentRule.java
@@ -1,15 +1,15 @@
 /**
  * OWASP Enterprise Security API (ESAPI)
- * 
+ *
  * This file is part of the Open Web Application Security Project (OWASP)
  * Enterprise Security API (ESAPI) project. For details, please see
  * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
  *
  * Copyright (c) 2009 - The OWASP Foundation
- * 
+ *
  * The ESAPI is published by OWASP under the BSD license. You should read and accept the
  * LICENSE before you use, modify, and/or redistribute this software.
- * 
+ *
  * @author Arshan Dabirsiaghi <a href="http://www.aspectsecurity.com">Aspect Security</a>
  * @created 2009
  */
@@ -36,78 +36,78 @@ import org.owasp.esapi.waf.internal.InterceptingHTTPServletResponse;
  */
 public class ReplaceContentRule extends Rule {
 
-	private Pattern pattern;
-	private String replacement;
-	private Pattern contentType;
-	private Pattern path;
-	
-	public ReplaceContentRule(String id, Pattern pattern, String replacement, Pattern contentType, Pattern path) {
-		this.pattern = pattern;
-		this.replacement = replacement;
-		this.path = path;
-		this.contentType = contentType;
-		setId(id);
-	}
-
-	/*
-	 * Use regular expressions with capturing parentheses to perform replacement.
-	 */
-
-	public Action check(HttpServletRequest request,
-			InterceptingHTTPServletResponse response, 
-			HttpServletResponse httpResponse) {
-
-		/*
-		 * First early fail: if the URI doesn't match the paths we're interested in.
-		 */
-		String uri = request.getRequestURI();
-		if ( path != null && ! path.matcher(uri).matches() ) {
-			return new DoNothingAction();
-		}
-		
-		/*
-		 * Second early fail: if the content type is one we'd like to search for output patterns.
-		 */
-
-		if ( contentType != null ) {
-			if ( response.getContentType() != null && ! contentType.matcher(response.getContentType()).matches() ) {
-				return new DoNothingAction();
-			}
-		}
-
-		byte[] bytes = null;
-
-		try {
-			bytes = response.getInterceptingServletOutputStream().getResponseBytes();
-		} catch (IOException ioe) {
-			log(request,"Error matching pattern '" + pattern.pattern() + "', IOException encountered (possibly too large?): " + ioe.getMessage() + " (in response to URL: '" + request.getRequestURL() + "')");
-			return new DoNothingAction(); // yes this is a fail open!
-		}
-
-		
-		try {
-
-			String s = new String(bytes,response.getCharacterEncoding());
-
-			Matcher m = pattern.matcher(s);
-			String canary = m.replaceAll(replacement);
-			
-			try {
-				
-				if ( ! s.equals(canary) ) {
-					response.getInterceptingServletOutputStream().setResponseBytes(canary.getBytes(response.getCharacterEncoding()));
-					logger.debug(Logger.SECURITY_SUCCESS, "Successfully replaced pattern '" + pattern.pattern() + "' on response to URL '" + request.getRequestURL() + "'");
-				}
-				
-			} catch (IOException ioe) {
-				logger.error(Logger.SECURITY_FAILURE, "Failed to replace pattern '" + pattern.pattern() + "' on response to URL '" + request.getRequestURL() + "' due to [" + ioe.getMessage() + "]");
-			}
-
-		} catch(UnsupportedEncodingException uee) {
-			logger.error(Logger.SECURITY_FAILURE, "Failed to replace pattern '" + pattern.pattern() + "' on response to URL '" + request.getRequestURL() + "' due to [" + uee.getMessage() + "]");
-		}
-
-		return new DoNothingAction();
-	}
+    private Pattern pattern;
+    private String replacement;
+    private Pattern contentType;
+    private Pattern path;
+
+    public ReplaceContentRule(String id, Pattern pattern, String replacement, Pattern contentType, Pattern path) {
+        this.pattern = pattern;
+        this.replacement = replacement;
+        this.path = path;
+        this.contentType = contentType;
+        setId(id);
+    }
+
+    /*
+     * Use regular expressions with capturing parentheses to perform replacement.
+     */
+
+    public Action check(HttpServletRequest request,
+            InterceptingHTTPServletResponse response,
+            HttpServletResponse httpResponse) {
+
+        /*
+         * First early fail: if the URI doesn't match the paths we're interested in.
+         */
+        String uri = request.getRequestURI();
+        if ( path != null && ! path.matcher(uri).matches() ) {
+            return new DoNothingAction();
+        }
+
+        /*
+         * Second early fail: if the content type is one we'd like to search for output patterns.
+         */
+
+        if ( contentType != null ) {
+            if ( response.getContentType() != null && ! contentType.matcher(response.getContentType()).matches() ) {
+                return new DoNothingAction();
+            }
+        }
+
+        byte[] bytes = null;
+
+        try {
+            bytes = response.getInterceptingServletOutputStream().getResponseBytes();
+        } catch (IOException ioe) {
+            log(request,"Error matching pattern '" + pattern.pattern() + "', IOException encountered (possibly too large?): " + ioe.getMessage() + " (in response to URL: '" + request.getRequestURL() + "')");
+            return new DoNothingAction(); // yes this is a fail open!
+        }
+
+
+        try {
+
+            String s = new String(bytes,response.getCharacterEncoding());
+
+            Matcher m = pattern.matcher(s);
+            String canary = m.replaceAll(replacement);
+
+            try {
+
+                if ( ! s.equals(canary) ) {
+                    response.getInterceptingServletOutputStream().setResponseBytes(canary.getBytes(response.getCharacterEncoding()));
+                    logger.debug(Logger.SECURITY_SUCCESS, "Successfully replaced pattern '" + pattern.pattern() + "' on response to URL '" + request.getRequestURL() + "'");
+                }
+
+            } catch (IOException ioe) {
+                logger.error(Logger.SECURITY_FAILURE, "Failed to replace pattern '" + pattern.pattern() + "' on response to URL '" + request.getRequestURL() + "' due to [" + ioe.getMessage() + "]");
+            }
+
+        } catch(UnsupportedEncodingException uee) {
+            logger.error(Logger.SECURITY_FAILURE, "Failed to replace pattern '" + pattern.pattern() + "' on response to URL '" + request.getRequestURL() + "' due to [" + uee.getMessage() + "]");
+        }
+
+        return new DoNothingAction();
+    }
 
 }
diff --git a/src/main/java/org/owasp/esapi/waf/rules/RestrictContentTypeRule.java b/src/main/java/org/owasp/esapi/waf/rules/RestrictContentTypeRule.java
index 298df33..43ea63a 100644
--- a/src/main/java/org/owasp/esapi/waf/rules/RestrictContentTypeRule.java
+++ b/src/main/java/org/owasp/esapi/waf/rules/RestrictContentTypeRule.java
@@ -1,15 +1,15 @@
 /**
  * OWASP Enterprise Security API (ESAPI)
- * 
+ *
  * This file is part of the Open Web Application Security Project (OWASP)
  * Enterprise Security API (ESAPI) project. For details, please see
  * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
  *
  * Copyright (c) 2009 - The OWASP Foundation
- * 
+ *
  * The ESAPI is published by OWASP under the BSD license. You should read and accept the
  * LICENSE before you use, modify, and/or redistribute this software.
- * 
+ *
  * @author Arshan Dabirsiaghi <a href="http://www.aspectsecurity.com">Aspect Security</a>
  * @created 2009
  */
@@ -32,39 +32,39 @@ import org.owasp.esapi.waf.internal.InterceptingHTTPServletResponse;
  */
 public class RestrictContentTypeRule extends Rule {
 
-	private Pattern allow;
-	private Pattern deny;
+    private Pattern allow;
+    private Pattern deny;
 
-	public RestrictContentTypeRule(String id, Pattern allow, Pattern deny) {
-		this.allow = allow;
-		this.deny = deny;
-		setId(id);
-	}
+    public RestrictContentTypeRule(String id, Pattern allow, Pattern deny) {
+        this.allow = allow;
+        this.deny = deny;
+        setId(id);
+    }
 
-	public Action check(HttpServletRequest request,
-			InterceptingHTTPServletResponse response, 
-			HttpServletResponse httpResponse) {
+    public Action check(HttpServletRequest request,
+            InterceptingHTTPServletResponse response,
+            HttpServletResponse httpResponse) {
 
-		/* can't check content type if it's not available */
-		if ( request.getContentType() == null ) {
-			return new DoNothingAction();
-		}
+        /* can't check content type if it's not available */
+        if ( request.getContentType() == null ) {
+            return new DoNothingAction();
+        }
 
-		if ( allow != null ) {
-			if ( allow.matcher(request.getContentType()).matches() ) {
-				return new DoNothingAction();
-			}
-			log(request, "Disallowed content type based on allow pattern '" + allow.pattern() + "' found on URI '" + request.getRequestURI() + "' (value was '" + request.getContentType() +"')");
-		} else if ( deny != null ) {
-			if ( ! deny.matcher(request.getContentType()).matches() ) {
-				return new DoNothingAction();
-			}
-			log(request, "Disallowed content type based on deny pattern '" + deny.pattern() + "' found on URI '" + request.getRequestURI() + "' (value was '" + request.getContentType() + ")'");
-		}
+        if ( allow != null ) {
+            if ( allow.matcher(request.getContentType()).matches() ) {
+                return new DoNothingAction();
+            }
+            log(request, "Disallowed content type based on allow pattern '" + allow.pattern() + "' found on URI '" + request.getRequestURI() + "' (value was '" + request.getContentType() +"')");
+        } else if ( deny != null ) {
+            if ( ! deny.matcher(request.getContentType()).matches() ) {
+                return new DoNothingAction();
+            }
+            log(request, "Disallowed content type based on deny pattern '" + deny.pattern() + "' found on URI '" + request.getRequestURI() + "' (value was '" + request.getContentType() + ")'");
+        }
 
 
-		return new DefaultAction();
+        return new DefaultAction();
 
-	}
+    }
 
 }
diff --git a/src/main/java/org/owasp/esapi/waf/rules/RestrictUserAgentRule.java b/src/main/java/org/owasp/esapi/waf/rules/RestrictUserAgentRule.java
index 5598853..ae31b19 100644
--- a/src/main/java/org/owasp/esapi/waf/rules/RestrictUserAgentRule.java
+++ b/src/main/java/org/owasp/esapi/waf/rules/RestrictUserAgentRule.java
@@ -1,15 +1,15 @@
 /**
  * OWASP Enterprise Security API (ESAPI)
- * 
+ *
  * This file is part of the Open Web Application Security Project (OWASP)
  * Enterprise Security API (ESAPI) project. For details, please see
  * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
  *
  * Copyright (c) 2009 - The OWASP Foundation
- * 
+ *
  * The ESAPI is published by OWASP under the BSD license. You should read and accept the
  * LICENSE before you use, modify, and/or redistribute this software.
- * 
+ *
  * @author Arshan Dabirsiaghi <a href="http://www.aspectsecurity.com">Aspect Security</a>
  * @created 2009
  */
@@ -34,47 +34,47 @@ import org.owasp.esapi.waf.internal.InterceptingHTTPServletResponse;
  */
 public class RestrictUserAgentRule extends Rule {
 
-	private static final String USER_AGENT_HEADER = "User-Agent";
+    private static final String USER_AGENT_HEADER = "User-Agent";
+
+    private Pattern allow;
+    private Pattern deny;
+
+    public RestrictUserAgentRule(String id, Pattern allow, Pattern deny) {
+        this.allow = allow;
+        this.deny = deny;
+        setId(id);
+    }
+
+    public Action check(HttpServletRequest request, InterceptingHTTPServletResponse response, HttpServletResponse httpResponse) {
+
+        String userAgent = request.getHeader( USER_AGENT_HEADER );
 
-	private Pattern allow;
-	private Pattern deny;
+        if ( userAgent == null ) userAgent="";
 
-	public RestrictUserAgentRule(String id, Pattern allow, Pattern deny) {
-		this.allow = allow;
-		this.deny = deny;
-		setId(id);
-	}
+        if ( allow != null ) {
+            if ( allow.matcher(userAgent).matches() ) {
+                return new DoNothingAction();
+            }
+        } else if ( deny != null ) {
+            if ( ! deny.matcher(userAgent).matches() ) {
+                return new DoNothingAction();
+            }
+        }
 
-	public Action check(HttpServletRequest request, InterceptingHTTPServletResponse response, HttpServletResponse httpResponse) {
-		
-		String userAgent = request.getHeader( USER_AGENT_HEADER );
-		
-		if ( userAgent == null ) userAgent="";
-		
-		if ( allow != null ) {
-			if ( allow.matcher(userAgent).matches() ) {
-				return new DoNothingAction();
-			}
-		} else if ( deny != null ) {
-			if ( ! deny.matcher(userAgent).matches() ) {
-				return new DoNothingAction();
-			}
-		}
+        log(request, "Disallowed user agent pattern '" + deny.pattern() + "' found in user agent '" + request.getHeader(USER_AGENT_HEADER) + "'");
 
-		log(request, "Disallowed user agent pattern '" + deny.pattern() + "' found in user agent '" + request.getHeader(USER_AGENT_HEADER) + "'");
-	
-		/*
-		 * If we don't force this to "block", the user will be in an infinite loop, possibly
-		 * eating our bandwidth, and in the case of a dread false positive, really piss them
-		 * off.
-		 * 
-		 * Better to just reject.
-		 */
-		if ( AppGuardianConfiguration.DEFAULT_FAIL_ACTION == AppGuardianConfiguration.REDIRECT ) {
-			return new BlockAction();
-		}
+        /*
+         * If we don't force this to "block", the user will be in an infinite loop, possibly
+         * eating our bandwidth, and in the case of a dread false positive, really piss them
+         * off.
+         *
+         * Better to just reject.
+         */
+        if ( AppGuardianConfiguration.DEFAULT_FAIL_ACTION == AppGuardianConfiguration.REDIRECT ) {
+            return new BlockAction();
+        }
 
-		return new DefaultAction();
-	}
+        return new DefaultAction();
+    }
 
 }
diff --git a/src/main/java/org/owasp/esapi/waf/rules/Rule.java b/src/main/java/org/owasp/esapi/waf/rules/Rule.java
index c4773a5..26adc95 100644
--- a/src/main/java/org/owasp/esapi/waf/rules/Rule.java
+++ b/src/main/java/org/owasp/esapi/waf/rules/Rule.java
@@ -1,15 +1,15 @@
 /**
  * OWASP Enterprise Security API (ESAPI)
- * 
+ *
  * This file is part of the Open Web Application Security Project (OWASP)
  * Enterprise Security API (ESAPI) project. For details, please see
  * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
  *
  * Copyright (c) 2009 - The OWASP Foundation
- * 
+ *
  * The ESAPI is published by OWASP under the BSD license. You should read and accept the
  * LICENSE before you use, modify, and/or redistribute this software.
- * 
+ *
  * @author Arshan Dabirsiaghi <a href="http://www.aspectsecurity.com">Aspect Security</a>
  * @created 2009
  */
@@ -32,24 +32,24 @@ import org.owasp.esapi.waf.internal.InterceptingHTTPServletResponse;
  */
 public abstract class Rule {
 
-	protected String id = "(no rule ID)";
-	protected static Logger logger = ESAPI.getLogger(Rule.class);
+    protected String id = "(no rule ID)";
+    protected static Logger logger = ESAPI.getLogger(Rule.class);
 
-	public abstract Action check( HttpServletRequest request, InterceptingHTTPServletResponse response, HttpServletResponse httpResponse );
+    public abstract Action check( HttpServletRequest request, InterceptingHTTPServletResponse response, HttpServletResponse httpResponse );
 
-	public void log( HttpServletRequest request, String message ) {
-		logger.warning(Logger.SECURITY_FAILURE,"[IP=" + request.getRemoteAddr() +
-				",Rule=" + this.getClass().getSimpleName() + ",ID="+id+"] " + message);
-	}
+    public void log( HttpServletRequest request, String message ) {
+        logger.warning(Logger.SECURITY_FAILURE,"[IP=" + request.getRemoteAddr() +
+                ",Rule=" + this.getClass().getSimpleName() + ",ID="+id+"] " + message);
+    }
 
-	protected void setId(String id) {
-		if ( id == null || "".equals(id) )
-			return;
+    protected void setId(String id) {
+        if ( id == null || "".equals(id) )
+            return;
 
-		this.id = id;
-	}
+        this.id = id;
+    }
 
-	public String toString() {
-		return "Rule:" + this.getClass().getName();
-	}
+    public String toString() {
+        return "Rule:" + this.getClass().getName();
+    }
 }
diff --git a/src/main/java/org/owasp/esapi/waf/rules/RuleUtil.java b/src/main/java/org/owasp/esapi/waf/rules/RuleUtil.java
index 3213d12..3b22edb 100644
--- a/src/main/java/org/owasp/esapi/waf/rules/RuleUtil.java
+++ b/src/main/java/org/owasp/esapi/waf/rules/RuleUtil.java
@@ -1,15 +1,15 @@
 /**
  * OWASP Enterprise Security API (ESAPI)
- * 
+ *
  * This file is part of the Open Web Application Security Project (OWASP)
  * Enterprise Security API (ESAPI) project. For details, please see
  * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
  *
  * Copyright (c) 2009 - The OWASP Foundation
- * 
+ *
  * The ESAPI is published by OWASP under the BSD license. You should read and accept the
  * LICENSE before you use, modify, and/or redistribute this software.
- * 
+ *
  * @author Arshan Dabirsiaghi <a href="http://www.aspectsecurity.com">Aspect Security</a>
  * @created 2009
  */
@@ -29,123 +29,123 @@ import org.owasp.esapi.waf.configuration.AppGuardianConfiguration;
  */
 public class RuleUtil {
 
-	public static boolean isInList(Map m, String s) {
+    public static boolean isInList(Map m, String s) {
 
-		Iterator it = m.keySet().iterator();
+        Iterator it = m.keySet().iterator();
 
-		while( it.hasNext() ) {
-			String key = (String)it.next();
-			if ( key.equals(s) ) {
-				return true;
-			}
-		}
+        while( it.hasNext() ) {
+            String key = (String)it.next();
+            if ( key.equals(s) ) {
+                return true;
+            }
+        }
 
-		return false;
-	}
+        return false;
+    }
 
-	public static boolean isInList(Collection c, String s) {
+    public static boolean isInList(Collection c, String s) {
 
-		Iterator it = c.iterator();
+        Iterator it = c.iterator();
 
-		while(it.hasNext()) {
+        while(it.hasNext()) {
 
-			Object o = it.next();
+            Object o = it.next();
 
-			if ( o instanceof String ) {
+            if ( o instanceof String ) {
 
-				if ( s.equals((String)o)) {
-					return true;
-				}
+                if ( s.equals((String)o)) {
+                    return true;
+                }
 
-			} else if ( o instanceof Integer ) {
+            } else if ( o instanceof Integer ) {
 
-				try {
-					if ( Integer.parseInt(s) == ((Integer)o).intValue() ) {
-						return true;
-					}
-				} catch (Exception e) {}
+                try {
+                    if ( Integer.parseInt(s) == ((Integer)o).intValue() ) {
+                        return true;
+                    }
+                } catch (Exception e) {}
 
-			} else if ( o instanceof Long ) {
+            } else if ( o instanceof Long ) {
 
-				try {
-					if ( Long.parseLong(s) == ((Long)o).longValue() ) {
-						return true;
-					}
-				} catch (Exception e) {}
+                try {
+                    if ( Long.parseLong(s) == ((Long)o).longValue() ) {
+                        return true;
+                    }
+                } catch (Exception e) {}
 
-			} else if ( o instanceof Double ) {
+            } else if ( o instanceof Double ) {
 
-				try {
-					if ( Double.compare(Double.parseDouble(s), ((Double)o).doubleValue()) ==  0 ) {
-						return true;
-					}
-				} catch (Exception e) {}
-			}
+                try {
+                    if ( Double.compare(Double.parseDouble(s), ((Double)o).doubleValue()) ==  0 ) {
+                        return true;
+                    }
+                } catch (Exception e) {}
+            }
 
-		}
+        }
 
-		return false;
-	}
+        return false;
+    }
 
-	/*
-	 * Enumeration
-	 */
-	public static boolean isInList(Enumeration en, String s) {
+    /*
+     * Enumeration
+     */
+    public static boolean isInList(Enumeration en, String s) {
 
-		for(; en.hasMoreElements();) {
+        for(; en.hasMoreElements();) {
 
-			Object o = en.nextElement();
+            Object o = en.nextElement();
 
-			if ( o instanceof String ) {
+            if ( o instanceof String ) {
 
-				if ( s.equals((String)o)) {
-					return true;
-				}
+                if ( s.equals((String)o)) {
+                    return true;
+                }
 
-			} else if ( o instanceof Integer ) {
+            } else if ( o instanceof Integer ) {
 
-				try {
-					if ( Integer.parseInt(s) == ((Integer)o).intValue() ) {
-						return true;
-					}
-				} catch (Exception e) {}
+                try {
+                    if ( Integer.parseInt(s) == ((Integer)o).intValue() ) {
+                        return true;
+                    }
+                } catch (Exception e) {}
 
-			} else if ( o instanceof Long ) {
+            } else if ( o instanceof Long ) {
 
-				try {
-					if ( Long.parseLong(s) == ((Long)o).longValue() ) {
-						return true;
-					}
-				} catch (Exception e) {}
+                try {
+                    if ( Long.parseLong(s) == ((Long)o).longValue() ) {
+                        return true;
+                    }
+                } catch (Exception e) {}
 
-			} else if ( o instanceof Double ) {
+            } else if ( o instanceof Double ) {
 
-				try {
-					if ( Double.compare(Double.parseDouble(s), ((Double)o).doubleValue()) ==  0 ) {
-						return true;
-					}
-				} catch (Exception e) {}
-			}
+                try {
+                    if ( Double.compare(Double.parseDouble(s), ((Double)o).doubleValue()) ==  0 ) {
+                        return true;
+                    }
+                } catch (Exception e) {}
+            }
 
-		}
+        }
 
-		return false;
-	}
+        return false;
+    }
 
-	public static boolean testValue(String s, String test, int operator) {
+    public static boolean testValue(String s, String test, int operator) {
 
-		switch(operator) {
-			case AppGuardianConfiguration.OPERATOR_EQ:
+        switch(operator) {
+            case AppGuardianConfiguration.OPERATOR_EQ:
 
-				return test.equals(s);
+                return test.equals(s);
 
-			case AppGuardianConfiguration.OPERATOR_CONTAINS:
+            case AppGuardianConfiguration.OPERATOR_CONTAINS:
 
-				return test.contains(s);
+                return test.contains(s);
 
-		}
+        }
 
-		return false;
-	}
+        return false;
+    }
 
 }
diff --git a/src/main/java/org/owasp/esapi/waf/rules/SimpleVirtualPatchRule.java b/src/main/java/org/owasp/esapi/waf/rules/SimpleVirtualPatchRule.java
index b4834fe..44c8e18 100644
--- a/src/main/java/org/owasp/esapi/waf/rules/SimpleVirtualPatchRule.java
+++ b/src/main/java/org/owasp/esapi/waf/rules/SimpleVirtualPatchRule.java
@@ -1,15 +1,15 @@
 /**
  * OWASP Enterprise Security API (ESAPI)
- * 
+ *
  * This file is part of the Open Web Application Security Project (OWASP)
  * Enterprise Security API (ESAPI) project. For details, please see
  * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
  *
  * Copyright (c) 2009 - The OWASP Foundation
- * 
+ *
  * The ESAPI is published by OWASP under the BSD license. You should read and accept the
  * LICENSE before you use, modify, and/or redistribute this software.
- * 
+ *
  * @author Arshan Dabirsiaghi <a href="http://www.aspectsecurity.com">Aspect Security</a>
  * @created 2009
  */
@@ -34,106 +34,106 @@ import org.owasp.esapi.waf.internal.InterceptingHTTPServletResponse;
  */
 public class SimpleVirtualPatchRule extends Rule {
 
-	private static final String REQUEST_PARAMETERS = "request.parameters.";
-	private static final String REQUEST_HEADERS = "request.headers.";
-
-	private Pattern path;
-	private String variable;
-	private Pattern valid;
-	private String message;
-
-	public SimpleVirtualPatchRule(String id, Pattern path, String variable, Pattern valid, String message) {
-		setId(id);
-		this.path = path;
-		this.variable = variable;
-		this.valid = valid;
-		this.message = message;
-	}
-
-	public Action check(HttpServletRequest req,
-			InterceptingHTTPServletResponse response, 
-			HttpServletResponse httpResponse) {
-
-		InterceptingHTTPServletRequest request = (InterceptingHTTPServletRequest)req;
-
-		String uri = request.getRequestURI();
-		if ( ! path.matcher(uri).matches() ) {
-
-			return new DoNothingAction();
-
-		} else {
-
-			/*
-			 * Decide which parameters/headers to act on.
-			 */
-			String target = null;
-			Enumeration en = null;
-			boolean parameter = true;
-
-			if ( variable.startsWith(REQUEST_PARAMETERS)) {
-
-				target = variable.substring(REQUEST_PARAMETERS.length());
-				en = request.getParameterNames();
-
-			} else if ( variable.startsWith(REQUEST_HEADERS) ) {
-
-				parameter = false;
-				target = variable.substring(REQUEST_HEADERS.length());
-				en = request.getHeaderNames();
-
-			} else {
-				log(request, "Patch failed (improperly configured variable '" + variable + "')");
-				return new DefaultAction();
-			}
-
-			/*
-			 * If it contains a regex character, it's a regex. Loop through elements and grab any matches.
-			 */
-			if ( target.contains("*") || target.contains("?") ) {
-
-				target = target.replaceAll("\\*", ".*");
-				Pattern p = Pattern.compile(target);
-				while (en.hasMoreElements() ) {
-					String s = (String)en.nextElement();
-					String value = null;
-					if ( p.matcher(s).matches() ) {
-						if ( parameter ) {
-							value = request.getDictionaryParameter(s);
-						} else {
-							value = request.getHeader(s);
-						}
-						if ( value != null && ! valid.matcher(value).matches() ) {
-							log(request, "Virtual patch tripped on variable '" + variable + "' (specifically '" + s + "'). User input was '" + value + "' and legal pattern was '" + valid.pattern() + "': " + message);
-							return new DefaultAction();
-						}
-					}
-				}
-				
-				return new DoNothingAction();
-
-			} else {
-
-				if ( parameter ) {
-					String value = request.getDictionaryParameter(target);
-					if ( value == null || valid.matcher(value).matches() ) {
-						return new DoNothingAction();
-					} else {
-						log(request, "Virtual patch tripped on parameter '" + target + "'. User input was '" + value + "' and legal pattern was '" + valid.pattern() + "': " + message);
-						return new DefaultAction();
-					}
-				} else {
-					String value = request.getHeader(target);
-					if ( value == null || valid.matcher(value).matches() ) {
-						return new DoNothingAction();
-					} else {
-						log(request, "Virtual patch tripped on header '" + target + "'. User input was '" + value + "' and legal pattern was '" + valid.pattern() + "': " + message);
-						return new DefaultAction();
-					}
-				}
-			}
-
-		}
-
-	}
+    private static final String REQUEST_PARAMETERS = "request.parameters.";
+    private static final String REQUEST_HEADERS = "request.headers.";
+
+    private Pattern path;
+    private String variable;
+    private Pattern valid;
+    private String message;
+
+    public SimpleVirtualPatchRule(String id, Pattern path, String variable, Pattern valid, String message) {
+        setId(id);
+        this.path = path;
+        this.variable = variable;
+        this.valid = valid;
+        this.message = message;
+    }
+
+    public Action check(HttpServletRequest req,
+            InterceptingHTTPServletResponse response,
+            HttpServletResponse httpResponse) {
+
+        InterceptingHTTPServletRequest request = (InterceptingHTTPServletRequest)req;
+
+        String uri = request.getRequestURI();
+        if ( ! path.matcher(uri).matches() ) {
+
+            return new DoNothingAction();
+
+        } else {
+
+            /*
+             * Decide which parameters/headers to act on.
+             */
+            String target = null;
+            Enumeration en = null;
+            boolean parameter = true;
+
+            if ( variable.startsWith(REQUEST_PARAMETERS)) {
+
+                target = variable.substring(REQUEST_PARAMETERS.length());
+                en = request.getParameterNames();
+
+            } else if ( variable.startsWith(REQUEST_HEADERS) ) {
+
+                parameter = false;
+                target = variable.substring(REQUEST_HEADERS.length());
+                en = request.getHeaderNames();
+
+            } else {
+                log(request, "Patch failed (improperly configured variable '" + variable + "')");
+                return new DefaultAction();
+            }
+
+            /*
+             * If it contains a regex character, it's a regex. Loop through elements and grab any matches.
+             */
+            if ( target.contains("*") || target.contains("?") ) {
+
+                target = target.replaceAll("\\*", ".*");
+                Pattern p = Pattern.compile(target);
+                while (en.hasMoreElements() ) {
+                    String s = (String)en.nextElement();
+                    String value = null;
+                    if ( p.matcher(s).matches() ) {
+                        if ( parameter ) {
+                            value = request.getDictionaryParameter(s);
+                        } else {
+                            value = request.getHeader(s);
+                        }
+                        if ( value != null && ! valid.matcher(value).matches() ) {
+                            log(request, "Virtual patch tripped on variable '" + variable + "' (specifically '" + s + "'). User input was '" + value + "' and legal pattern was '" + valid.pattern() + "': " + message);
+                            return new DefaultAction();
+                        }
+                    }
+                }
+
+                return new DoNothingAction();
+
+            } else {
+
+                if ( parameter ) {
+                    String value = request.getDictionaryParameter(target);
+                    if ( value == null || valid.matcher(value).matches() ) {
+                        return new DoNothingAction();
+                    } else {
+                        log(request, "Virtual patch tripped on parameter '" + target + "'. User input was '" + value + "' and legal pattern was '" + valid.pattern() + "': " + message);
+                        return new DefaultAction();
+                    }
+                } else {
+                    String value = request.getHeader(target);
+                    if ( value == null || valid.matcher(value).matches() ) {
+                        return new DoNothingAction();
+                    } else {
+                        log(request, "Virtual patch tripped on header '" + target + "'. User input was '" + value + "' and legal pattern was '" + valid.pattern() + "': " + message);
+                        return new DefaultAction();
+                    }
+                }
+            }
+
+        }
+
+    }
 
 }
diff --git a/src/main/java/org/owasp/esapi/waf/rules/package.html b/src/main/java/org/owasp/esapi/waf/rules/package.html
index 0f29d7e..bf418c0 100644
--- a/src/main/java/org/owasp/esapi/waf/rules/package.html
+++ b/src/main/java/org/owasp/esapi/waf/rules/package.html
@@ -5,8 +5,8 @@
 
 <body bgcolor="white">
 
-This package contains all of the Rule subclasses that correspond to policy file entries. Each 
-class contains the logic for enforcing its rule. 
- 
+This package contains all of the Rule subclasses that correspond to policy file entries. Each
+class contains the logic for enforcing its rule.
+
 </body>
 </html>
diff --git a/src/site/resources/images/owasp.png b/src/site/resources/images/owasp.png
new file mode 100644
index 0000000..90fb9d2
Binary files /dev/null and b/src/site/resources/images/owasp.png differ
diff --git a/src/site/site.xml b/src/site/site.xml
new file mode 100644
index 0000000..3da4596
--- /dev/null
+++ b/src/site/site.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project name="${project.name}" xmlns="https://maven.apache.org/DECORATION/1.8.0"
+    xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
+    xsi:schemaLocation="https://maven.apache.org/DECORATION/1.8.0 https://maven.apache.org/xsd/decoration-1.8.0.xsd">
+    <bannerLeft>
+        <src>/images/owasp.png</src>
+        <href>https://owasp.org/www-project-enterprise-security-api/</href>
+    </bannerLeft>
+    <skin>
+        <groupId>org.apache.maven.skins</groupId>
+        <artifactId>maven-fluido-skin</artifactId>
+    </skin>
+    <custom>
+        <fluidoSkin>
+            <topBarEnabled>false</topBarEnabled>
+            <sideBarEnabled>true</sideBarEnabled>
+        </fluidoSkin>
+    </custom>
+    <body>
+        <links>
+            <item name="OWASP ESAPI" href="https://owasp.org/www-project-enterprise-security-api/" />
+        </links>
+        <menu ref="reports" />
+    </body>
+</project>
+
diff --git a/src/test/java/org/owasp/esapi/ESAPIContractAPITest.java b/src/test/java/org/owasp/esapi/ESAPIContractAPITest.java
index e23a606..059eb00 100644
--- a/src/test/java/org/owasp/esapi/ESAPIContractAPITest.java
+++ b/src/test/java/org/owasp/esapi/ESAPIContractAPITest.java
@@ -20,33 +20,33 @@ public class ESAPIContractAPITest {
 
     @Mock
     private SecurityConfiguration mockSecConfig;
-    
+
     @Mock
     private Validator mockValidator;
-    
+
     @Before
     public void configureStaticContexts() throws Exception {
         PowerMockito.mockStatic(ObjFactory.class);
         PowerMockito.when(ObjFactory.class, "make", ArgumentMatchers.anyString(), ArgumentMatchers.eq("SecurityConfiguration")).thenReturn(mockSecConfig);
         PowerMockito.when(ObjFactory.class, "make", ArgumentMatchers.eq("MOCK_TEST_VALIDATOR"), ArgumentMatchers.eq("Validator")).thenReturn(mockValidator);
-        
+
         PowerMockito.when(mockSecConfig.getValidationImplementation()).thenReturn("MOCK_TEST_VALIDATOR");
     }
-    
+
     @Test
     public void testValidatorFromConfiguration() {
         Validator validator = ESAPI.validator();
         Assert.assertEquals("ESAPI Configuration should return Validator as specified by the SecurityConfiguration", mockValidator, validator);
-        
+
         PowerMockito.verifyStatic(ObjFactory.class, VerificationModeFactory.times(1));
         ObjFactory.make(ArgumentMatchers.anyString(), ArgumentMatchers.eq("SecurityConfiguration"));
-        
+
         PowerMockito.verifyStatic(ObjFactory.class, VerificationModeFactory.times(1));
         ObjFactory.make(ArgumentMatchers.eq("MOCK_TEST_VALIDATOR"), ArgumentMatchers.eq("Validator"));
-        
+
         PowerMockito.verifyNoMoreInteractions(ObjFactory.class);
-        
+
         Mockito.verify(mockSecConfig, Mockito.times(1)).getValidationImplementation();
     }
-   
+
 }
diff --git a/src/test/java/org/owasp/esapi/SecurityConfigurationWrapper.java b/src/test/java/org/owasp/esapi/SecurityConfigurationWrapper.java
index a051d6f..1d5a521 100644
--- a/src/test/java/org/owasp/esapi/SecurityConfigurationWrapper.java
+++ b/src/test/java/org/owasp/esapi/SecurityConfigurationWrapper.java
@@ -9,7 +9,7 @@ import java.util.List;
 import java.util.regex.Pattern;
 
 /**
- * Simple wrapper implementation of {@link SecurityConfiguration}. 
+ * Simple wrapper implementation of {@link SecurityConfiguration}.
  * This allows for easy subclassing and property fixups for unit tests.
  *
  * Note that there are some compilers have issues with Override
@@ -19,560 +19,560 @@ import java.util.regex.Pattern;
  */
 public class SecurityConfigurationWrapper implements SecurityConfiguration
 {
-	private SecurityConfiguration wrapped;
-
-	/**
-	 * Constructor wrapping the given configuration.
-	 * @param wrapped The configuration to wrap.
-	 */
-	public SecurityConfigurationWrapper(SecurityConfiguration wrapped)
-	{
-		this.wrapped = wrapped;
-	}
-
-	/**
-	 * Access the wrapped configuration.
-	 * @return The wrapped configuration.
-	 */
-	public SecurityConfiguration getWrappedSecurityConfiguration()
-	{
-		return wrapped;
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	// @Override
-	public String getApplicationName()
-	{
-		return wrapped.getApplicationName();
-	}
-	
-	/**
-	 * {@inheritDoc}
-	 */
-	// @Override
-	public String getLogImplementation()
-	{
-		return wrapped.getLogImplementation();
-	}
-	
-	/**
-	 * {@inheritDoc}
-	 */
-	// @Override
-	public String getAuthenticationImplementation()
-	{
-		return wrapped.getAuthenticationImplementation();
-	}
-	
-	/**
-	 * {@inheritDoc}
-	 */
-	// @Override
-	public String getEncoderImplementation()
-	{
-		return wrapped.getEncoderImplementation();
-	}
-	
-	/**
-	 * {@inheritDoc}
-	 */
-	// @Override
-	public String getAccessControlImplementation()
-	{
-		return wrapped.getAccessControlImplementation();
-	}
-	
-	/**
-	 * {@inheritDoc}
-	 */
-	// @Override
-	public String getIntrusionDetectionImplementation()
-	{
-		return wrapped.getIntrusionDetectionImplementation();
-	}
-	
-	/**
-	 * {@inheritDoc}
-	 */
-	// @Override
-	public String getRandomizerImplementation()
-	{
-		return wrapped.getRandomizerImplementation();
-	}
-	
-	/**
-	 * {@inheritDoc}
-	 */
-	// @Override
-	public String getEncryptionImplementation()
-	{
-		return wrapped.getEncryptionImplementation();
-	}
-	
-	/**
-	 * {@inheritDoc}
-	 */
-	// @Override
-	public String getValidationImplementation()
-	{
-		return wrapped.getValidationImplementation();
-	}
-	
-	/**
-	 * {@inheritDoc}
-	 */
-	// @Override
-	public Pattern getValidationPattern( String typeName )
-	{
-		return wrapped.getValidationPattern(typeName);
-	}
-	
-	/**
-	 * {@inheritDoc}
-	 */
-	// @Override
-	public String getExecutorImplementation()
-	{
-		return wrapped.getExecutorImplementation();
-	}
-	
-	/**
-	 * {@inheritDoc}
-	 */
-	// @Override
-	public String getHTTPUtilitiesImplementation()
-	{
-		return wrapped.getHTTPUtilitiesImplementation();
-	}
-	
-	/**
-	 * {@inheritDoc}
-	 */
-	// @Override
-	public byte[] getMasterKey()
-	{
-		return wrapped.getMasterKey();
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	// @Override
-	public File getUploadDirectory()
-	{
-		return wrapped.getUploadDirectory();
-	}
-	
-	/**
-	 * {@inheritDoc}
-	 */
-	// @Override
-	public File getUploadTempDirectory()
-	{
-		return wrapped.getUploadTempDirectory();
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	// @Override
-	public int getEncryptionKeyLength()
-	{
-		return wrapped.getEncryptionKeyLength();
-	}
-    
-	/**
-	 * {@inheritDoc}
-	 */
-	// @Override
-	public byte[] getMasterSalt()
-	{
-		return wrapped.getMasterSalt();
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	// @Override
-	public List getAllowedExecutables()
-	{
-		return wrapped.getAllowedExecutables();
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	// @Override
-	public List getAllowedFileExtensions()
-	{
-		return wrapped.getAllowedFileExtensions();
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	// @Override
-	public int getAllowedFileUploadSize()
-	{
-		return wrapped.getAllowedFileUploadSize();
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	// @Override
-	public String getPasswordParameterName()
-	{
-		return wrapped.getPasswordParameterName();
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	// @Override
-	public String getUsernameParameterName()
-	{
-		return wrapped.getUsernameParameterName();
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	// @Override
-	public String getEncryptionAlgorithm()
-	{
-		return wrapped.getEncryptionAlgorithm();
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	// @Override
-	public String getCipherTransformation()
-	{
-		return wrapped.getCipherTransformation();
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	// @Override
-	public String setCipherTransformation(String cipherXform)
-	{
-		return wrapped.setCipherTransformation(cipherXform);
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	// @Override
-	public boolean useMACforCipherText()
-	{
-		return wrapped.useMACforCipherText();
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	// @Override
-	public boolean overwritePlainText()
-	{
-		return wrapped.overwritePlainText();
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	// @Override
-	public String getIVType()
-	{
-		return wrapped.getIVType();
-	}
-
-
-	/**
-	 * {@inheritDoc}
-	 */
-	// @Override
-	public String getHashAlgorithm()
-	{
-		return wrapped.getHashAlgorithm();
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	// @Override
-	public int getHashIterations()
-	{
-		return wrapped.getHashIterations();
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	// @Override
-	public String getCharacterEncoding()
-	{
-		return wrapped.getCharacterEncoding();
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	// @Override
-	public boolean getAllowMultipleEncoding()
-	{
-		return wrapped.getAllowMultipleEncoding();
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	// @Override
-	public boolean getAllowMixedEncoding()
-	{
-		return wrapped.getAllowMixedEncoding();
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	// @Override
-	public List getDefaultCanonicalizationCodecs()
-	{
-		return wrapped.getDefaultCanonicalizationCodecs();
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	// @Override
-	public String getDigitalSignatureAlgorithm()
-	{
-		return wrapped.getDigitalSignatureAlgorithm();
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	// @Override
-	public int getDigitalSignatureKeyLength()
-	{
-		return wrapped.getDigitalSignatureKeyLength();
-	}
-		   
-	/**
-	 * {@inheritDoc}
-	 */
-	// @Override
-	public String getRandomAlgorithm()
-	{
-		return wrapped.getRandomAlgorithm();
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	// @Override
-	public int getAllowedLoginAttempts()
-	{
-		return wrapped.getAllowedLoginAttempts();
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	// @Override
-	public int getMaxOldPasswordHashes()
-	{
-		return wrapped.getMaxOldPasswordHashes();
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	// @Override
-	public Threshold getQuota(String eventName)
-	{
-		return wrapped.getQuota(eventName);
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	// @Override
-	public File getResourceFile( String filename )
-	{
-		return wrapped.getResourceFile(filename);
-	}
-    
-	/**
-	 * {@inheritDoc}
-	 */
-	// @Override
-	public boolean getForceHttpOnlySession() 
-	{
-		return wrapped.getForceHttpOnlySession();
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	// @Override
-	public boolean getForceSecureSession() 
-	{
-		return wrapped.getForceSecureSession();
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	// @Override
-	public boolean getForceHttpOnlyCookies()
-	{
-		return wrapped.getForceHttpOnlyCookies();
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	// @Override
-	public boolean getForceSecureCookies()
-	{
-		return wrapped.getForceSecureCookies();
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	// @Override
-	public int getMaxHttpHeaderSize() {
+    private SecurityConfiguration wrapped;
+
+    /**
+     * Constructor wrapping the given configuration.
+     * @param wrapped The configuration to wrap.
+     */
+    public SecurityConfigurationWrapper(SecurityConfiguration wrapped)
+    {
+        this.wrapped = wrapped;
+    }
+
+    /**
+     * Access the wrapped configuration.
+     * @return The wrapped configuration.
+     */
+    public SecurityConfiguration getWrappedSecurityConfiguration()
+    {
+        return wrapped;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    // @Override
+    public String getApplicationName()
+    {
+        return wrapped.getApplicationName();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    // @Override
+    public String getLogImplementation()
+    {
+        return wrapped.getLogImplementation();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    // @Override
+    public String getAuthenticationImplementation()
+    {
+        return wrapped.getAuthenticationImplementation();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    // @Override
+    public String getEncoderImplementation()
+    {
+        return wrapped.getEncoderImplementation();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    // @Override
+    public String getAccessControlImplementation()
+    {
+        return wrapped.getAccessControlImplementation();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    // @Override
+    public String getIntrusionDetectionImplementation()
+    {
+        return wrapped.getIntrusionDetectionImplementation();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    // @Override
+    public String getRandomizerImplementation()
+    {
+        return wrapped.getRandomizerImplementation();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    // @Override
+    public String getEncryptionImplementation()
+    {
+        return wrapped.getEncryptionImplementation();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    // @Override
+    public String getValidationImplementation()
+    {
+        return wrapped.getValidationImplementation();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    // @Override
+    public Pattern getValidationPattern( String typeName )
+    {
+        return wrapped.getValidationPattern(typeName);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    // @Override
+    public String getExecutorImplementation()
+    {
+        return wrapped.getExecutorImplementation();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    // @Override
+    public String getHTTPUtilitiesImplementation()
+    {
+        return wrapped.getHTTPUtilitiesImplementation();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    // @Override
+    public byte[] getMasterKey()
+    {
+        return wrapped.getMasterKey();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    // @Override
+    public File getUploadDirectory()
+    {
+        return wrapped.getUploadDirectory();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    // @Override
+    public File getUploadTempDirectory()
+    {
+        return wrapped.getUploadTempDirectory();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    // @Override
+    public int getEncryptionKeyLength()
+    {
+        return wrapped.getEncryptionKeyLength();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    // @Override
+    public byte[] getMasterSalt()
+    {
+        return wrapped.getMasterSalt();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    // @Override
+    public List getAllowedExecutables()
+    {
+        return wrapped.getAllowedExecutables();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    // @Override
+    public List getAllowedFileExtensions()
+    {
+        return wrapped.getAllowedFileExtensions();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    // @Override
+    public int getAllowedFileUploadSize()
+    {
+        return wrapped.getAllowedFileUploadSize();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    // @Override
+    public String getPasswordParameterName()
+    {
+        return wrapped.getPasswordParameterName();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    // @Override
+    public String getUsernameParameterName()
+    {
+        return wrapped.getUsernameParameterName();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    // @Override
+    public String getEncryptionAlgorithm()
+    {
+        return wrapped.getEncryptionAlgorithm();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    // @Override
+    public String getCipherTransformation()
+    {
+        return wrapped.getCipherTransformation();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    // @Override
+    public String setCipherTransformation(String cipherXform)
+    {
+        return wrapped.setCipherTransformation(cipherXform);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    // @Override
+    public boolean useMACforCipherText()
+    {
+        return wrapped.useMACforCipherText();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    // @Override
+    public boolean overwritePlainText()
+    {
+        return wrapped.overwritePlainText();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    // @Override
+    public String getIVType()
+    {
+        return wrapped.getIVType();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    // @Override
+    public String getHashAlgorithm()
+    {
+        return wrapped.getHashAlgorithm();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    // @Override
+    public int getHashIterations()
+    {
+        return wrapped.getHashIterations();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    // @Override
+    public String getCharacterEncoding()
+    {
+        return wrapped.getCharacterEncoding();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    // @Override
+    public boolean getAllowMultipleEncoding()
+    {
+        return wrapped.getAllowMultipleEncoding();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    // @Override
+    public boolean getAllowMixedEncoding()
+    {
+        return wrapped.getAllowMixedEncoding();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    // @Override
+    public List getDefaultCanonicalizationCodecs()
+    {
+        return wrapped.getDefaultCanonicalizationCodecs();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    // @Override
+    public String getDigitalSignatureAlgorithm()
+    {
+        return wrapped.getDigitalSignatureAlgorithm();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    // @Override
+    public int getDigitalSignatureKeyLength()
+    {
+        return wrapped.getDigitalSignatureKeyLength();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    // @Override
+    public String getRandomAlgorithm()
+    {
+        return wrapped.getRandomAlgorithm();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    // @Override
+    public int getAllowedLoginAttempts()
+    {
+        return wrapped.getAllowedLoginAttempts();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    // @Override
+    public int getMaxOldPasswordHashes()
+    {
+        return wrapped.getMaxOldPasswordHashes();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    // @Override
+    public Threshold getQuota(String eventName)
+    {
+        return wrapped.getQuota(eventName);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    // @Override
+    public File getResourceFile( String filename )
+    {
+        return wrapped.getResourceFile(filename);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    // @Override
+    public boolean getForceHttpOnlySession()
+    {
+        return wrapped.getForceHttpOnlySession();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    // @Override
+    public boolean getForceSecureSession()
+    {
+        return wrapped.getForceSecureSession();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    // @Override
+    public boolean getForceHttpOnlyCookies()
+    {
+        return wrapped.getForceHttpOnlyCookies();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    // @Override
+    public boolean getForceSecureCookies()
+    {
+        return wrapped.getForceSecureCookies();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    // @Override
+    public int getMaxHttpHeaderSize() {
         return wrapped.getMaxHttpHeaderSize();
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	// @Override
-	public InputStream getResourceStream( String filename ) throws IOException
-	{
-		return wrapped.getResourceStream(filename);
-	}
-
-    	
-	/**
-	 * {@inheritDoc}
-	 */
-	// @Override
-	public void setResourceDirectory(String dir)
-	{
-		wrapped.setResourceDirectory(dir);
-	}
-	
-	/**
-	 * {@inheritDoc}
-	 */
-	// @Override
-	public String getResponseContentType()
-	{
-		return wrapped.getResponseContentType();
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	// @Override
-	public String getHttpSessionIdName() {
-		return wrapped.getHttpSessionIdName();
-	}
-	
-	/**
-	 * {@inheritDoc}
-	 */
-	// @Override
-	public long getRememberTokenDuration()
-	{
-		return wrapped.getRememberTokenDuration();
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	// @Override
-	public int getSessionIdleTimeoutLength()
-	{
-		return wrapped.getSessionIdleTimeoutLength();
-	}
-	
-	/**
-	 * {@inheritDoc}
-	 */
-	// @Override
-	public int getSessionAbsoluteTimeoutLength()
-	{
-		return wrapped.getSessionAbsoluteTimeoutLength();
-	}
-	
-	/**
-	 * {@inheritDoc}
-	 */
-	// @Override
-	public boolean getLogEncodingRequired()
-	{
-		return wrapped.getLogEncodingRequired();
-	}
-	
-	/**
-	 * {@inheritDoc}
-	 */
-	// @Override
-	public boolean getLogApplicationName()
-	{
-		return wrapped.getLogApplicationName();
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	// @Override
-	public boolean getLogServerIP()
-	{
-		return wrapped.getLogServerIP();
-	}
-
-	@Override
-	public int getIntProp(String propertyName) throws ConfigurationException {
-		return wrapped.getIntProp(propertyName);
-	}
-
-	@Override
-	public byte[] getByteArrayProp(String propertyName) throws ConfigurationException {
-		return wrapped.getByteArrayProp(propertyName);
-	}
-
-	@Override
-	public Boolean getBooleanProp(String propertyName) throws ConfigurationException {
-		return wrapped.getBooleanProp(propertyName);
-	}
-
-	@Override
-	public String getStringProp(String propertyName) throws ConfigurationException {
-		return wrapped.getStringProp(propertyName);
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	// @Override
-	public File getWorkingDirectory()
-	{
-		return wrapped.getWorkingDirectory();
-	}
-
-	/**
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    // @Override
+    public InputStream getResourceStream( String filename ) throws IOException
+    {
+        return wrapped.getResourceStream(filename);
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    // @Override
+    public void setResourceDirectory(String dir)
+    {
+        wrapped.setResourceDirectory(dir);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    // @Override
+    public String getResponseContentType()
+    {
+        return wrapped.getResponseContentType();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    // @Override
+    public String getHttpSessionIdName() {
+        return wrapped.getHttpSessionIdName();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    // @Override
+    public long getRememberTokenDuration()
+    {
+        return wrapped.getRememberTokenDuration();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    // @Override
+    public int getSessionIdleTimeoutLength()
+    {
+        return wrapped.getSessionIdleTimeoutLength();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    // @Override
+    public int getSessionAbsoluteTimeoutLength()
+    {
+        return wrapped.getSessionAbsoluteTimeoutLength();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    // @Override
+    public boolean getLogEncodingRequired()
+    {
+        return wrapped.getLogEncodingRequired();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    // @Override
+    public boolean getLogApplicationName()
+    {
+        return wrapped.getLogApplicationName();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    // @Override
+    public boolean getLogServerIP()
+    {
+        return wrapped.getLogServerIP();
+    }
+
+    @Override
+    public int getIntProp(String propertyName) throws ConfigurationException {
+        return wrapped.getIntProp(propertyName);
+    }
+
+    @Override
+    public byte[] getByteArrayProp(String propertyName) throws ConfigurationException {
+        return wrapped.getByteArrayProp(propertyName);
+    }
+
+    @Override
+    public Boolean getBooleanProp(String propertyName) throws ConfigurationException {
+        return wrapped.getBooleanProp(propertyName);
+    }
+
+    @Override
+    public String getStringProp(String propertyName) throws ConfigurationException {
+        return wrapped.getStringProp(propertyName);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    // @Override
+    public File getWorkingDirectory()
+    {
+        return wrapped.getWorkingDirectory();
+    }
+
+    /**
      * {@inheritDoc}
      */
     // @Override
@@ -595,26 +595,26 @@ public class SecurityConfigurationWrapper implements SecurityConfiguration
         return wrapped.getPreferredJCEProvider();
     }
 
-	/**
-	 * {@inheritDoc}
-	 */
-	// @Override
-	public boolean getDisableIntrusionDetection() {
-		return wrapped.getDisableIntrusionDetection();
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	// @Override
-	public String getKDFPseudoRandomFunction() {
-		return wrapped.getKDFPseudoRandomFunction();
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	public boolean getLenientDatesAccepted() {
-		return wrapped.getLenientDatesAccepted();
-	}
+    /**
+     * {@inheritDoc}
+     */
+    // @Override
+    public boolean getDisableIntrusionDetection() {
+        return wrapped.getDisableIntrusionDetection();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    // @Override
+    public String getKDFPseudoRandomFunction() {
+        return wrapped.getKDFPseudoRandomFunction();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean getLenientDatesAccepted() {
+        return wrapped.getLenientDatesAccepted();
+    }
 }
diff --git a/src/test/java/org/owasp/esapi/StringUtilitiesTest.java b/src/test/java/org/owasp/esapi/StringUtilitiesTest.java
index 967b632..c7f29d2 100644
--- a/src/test/java/org/owasp/esapi/StringUtilitiesTest.java
+++ b/src/test/java/org/owasp/esapi/StringUtilitiesTest.java
@@ -9,74 +9,74 @@ import org.owasp.esapi.StringUtilities;
 
 public class StringUtilitiesTest extends TestCase {
 
-	/**
+    /**
      * Run all the test cases in this suite.
      * This is to allow running from {@code org.owasp.esapi.AllTests}.
-     * 
-	 * @return the test
-	 */
+     *
+     * @return the test
+     */
     public static Test suite() {
         TestSuite suite = new TestSuite(StringUtilitiesTest.class);
         return suite;
     }
-    
+
     /** Test the getLevenshteinDistance() method. */
     public void testGetLevenshteinDistance() {
-    	String src    = "GUMBO";
-    	String target = "GAMBOL";
-    	assertTrue( 2 == StringUtilities.getLevenshteinDistance(src, target) );
-    	assertTrue( 2 == StringUtilities.getLevenshteinDistance(target, src) );
-    	assertTrue( 0 == StringUtilities.getLevenshteinDistance(src, src) );
-    	assertTrue( 5 == StringUtilities.getLevenshteinDistance(src, "") );
-    	assertTrue( 6 == StringUtilities.getLevenshteinDistance("", target) );
+        String src    = "GUMBO";
+        String target = "GAMBOL";
+        assertTrue( 2 == StringUtilities.getLevenshteinDistance(src, target) );
+        assertTrue( 2 == StringUtilities.getLevenshteinDistance(target, src) );
+        assertTrue( 0 == StringUtilities.getLevenshteinDistance(src, src) );
+        assertTrue( 5 == StringUtilities.getLevenshteinDistance(src, "") );
+        assertTrue( 6 == StringUtilities.getLevenshteinDistance("", target) );
 
-    	try {
-    		@SuppressWarnings("unused")
-			int ldist = StringUtilities.getLevenshteinDistance(null, "abc");
-    	} catch ( IllegalArgumentException ex ) {
-    		assertTrue( ex.getClass().getName().equals( IllegalArgumentException.class.getName() ));
-    	}
+        try {
+            @SuppressWarnings("unused")
+            int ldist = StringUtilities.getLevenshteinDistance(null, "abc");
+        } catch ( IllegalArgumentException ex ) {
+            assertTrue( ex.getClass().getName().equals( IllegalArgumentException.class.getName() ));
+        }
 
-    	try {
-    		@SuppressWarnings("unused")
-			int ldist = StringUtilities.getLevenshteinDistance("abc", null);
-    	} catch ( IllegalArgumentException ex ) {
-    		assertTrue( ex.getClass().getName().equals( IllegalArgumentException.class.getName() ));
-    	}
+        try {
+            @SuppressWarnings("unused")
+            int ldist = StringUtilities.getLevenshteinDistance("abc", null);
+        } catch ( IllegalArgumentException ex ) {
+            assertTrue( ex.getClass().getName().equals( IllegalArgumentException.class.getName() ));
+        }
     }
 
     /** Test the union() method. */
     public void testUnion() {
-		char[] a1 = { 'a', 'b', 'c' };
-		char[] a2 = { 'c', 'd', 'e' };
-		char[] union = StringUtilities.union(a1, a2);
-		assertTrue( Arrays.equals( union, new char[] {'a','b','c','d','e' } ) );
+        char[] a1 = { 'a', 'b', 'c' };
+        char[] a2 = { 'c', 'd', 'e' };
+        char[] union = StringUtilities.union(a1, a2);
+        assertTrue( Arrays.equals( union, new char[] {'a','b','c','d','e' } ) );
     }
-    
+
     /** Test the contains() method. */
     public void contains() {
-		StringBuilder sb = new StringBuilder( "abc" );
-		assertTrue( StringUtilities.contains(sb, 'b') );
-		assertFalse( StringUtilities.contains(sb, 'x') );
+        StringBuilder sb = new StringBuilder( "abc" );
+        assertTrue( StringUtilities.contains(sb, 'b') );
+        assertFalse( StringUtilities.contains(sb, 'x') );
     }
 
     /** Test the notNullOrEmpty() method. */
     public void testNotNullOrEmpty() {
-    	String str = "A string";
-    	assertTrue( StringUtilities.notNullOrEmpty(str, false) );
-    	assertTrue( StringUtilities.notNullOrEmpty(str, true) );
-    	str = "   A  string  ";
-       	assertTrue( StringUtilities.notNullOrEmpty(str, false) );
-    	assertTrue( StringUtilities.notNullOrEmpty(str, true) );
-    	str = "   ";
-       	assertTrue( StringUtilities.notNullOrEmpty(str, false) );
-    	assertFalse( StringUtilities.notNullOrEmpty(str, true) );
-    	str = "";
-       	assertFalse( StringUtilities.notNullOrEmpty(str, false) );
-    	assertFalse( StringUtilities.notNullOrEmpty(str, true) );
-    	str = null;
-       	assertFalse( StringUtilities.notNullOrEmpty(str, false) );
-    	assertFalse( StringUtilities.notNullOrEmpty(str, true) );
+        String str = "A string";
+        assertTrue( StringUtilities.notNullOrEmpty(str, false) );
+        assertTrue( StringUtilities.notNullOrEmpty(str, true) );
+        str = "   A  string  ";
+           assertTrue( StringUtilities.notNullOrEmpty(str, false) );
+        assertTrue( StringUtilities.notNullOrEmpty(str, true) );
+        str = "   ";
+           assertTrue( StringUtilities.notNullOrEmpty(str, false) );
+        assertFalse( StringUtilities.notNullOrEmpty(str, true) );
+        str = "";
+           assertFalse( StringUtilities.notNullOrEmpty(str, false) );
+        assertFalse( StringUtilities.notNullOrEmpty(str, true) );
+        str = null;
+           assertFalse( StringUtilities.notNullOrEmpty(str, false) );
+        assertFalse( StringUtilities.notNullOrEmpty(str, true) );
     }
 
     public void testReplaceNull() {
diff --git a/src/test/java/org/owasp/esapi/UserTest.java b/src/test/java/org/owasp/esapi/UserTest.java
index 62b465b..109a625 100644
--- a/src/test/java/org/owasp/esapi/UserTest.java
+++ b/src/test/java/org/owasp/esapi/UserTest.java
@@ -1,15 +1,15 @@
 /**
  * OWASP Enterprise Security API (ESAPI)
- * 
+ *
  * This file is part of the Open Web Application Security Project (OWASP)
  * Enterprise Security API (ESAPI) project. For details, please see
  * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
  *
  * Copyright (c) 2007 - The OWASP Foundation
- * 
+ *
  * The ESAPI is published by OWASP under the BSD license. You should read and accept the
  * LICENSE before you use, modify, and/or redistribute this software.
- * 
+ *
  * @author Jeff Williams <a href="http://www.aspectsecurity.com">Aspect Security</a>
  * @created 2007
  */
@@ -24,83 +24,83 @@ import junit.framework.TestSuite;
  */
 public class UserTest extends TestCase {
 
-	public UserTest(String testName) {
-		super(testName);
-	}
+    public UserTest(String testName) {
+        super(testName);
+    }
+
+    protected void setUp() throws Exception {
+        // none
+    }
+
+    protected void tearDown() throws Exception {
+        // none
+    }
+
+    public static Test suite() {
+        TestSuite suite = new TestSuite(UserTest.class);
+        return suite;
+    }
 
-	protected void setUp() throws Exception {
-		// none
-	}
+    public void testAllMethods() throws Exception {
+        // create a user to test Anonymous
+        String accountName = ESAPI.randomizer().getRandomString(8, EncoderConstants.CHAR_ALPHANUMERICS);
+        Authenticator instance = ESAPI.authenticator();
+        String password = instance.generateStrongPassword();
 
-	protected void tearDown() throws Exception {
-		// none
-	}
+            // Probably could skip the assignment here, but maybe someone had
+            // future plans to use this. So will just suppress warning for now.
+        @SuppressWarnings("unused")
+        User user = instance.createUser(accountName, password, password);
 
-	public static Test suite() {
-		TestSuite suite = new TestSuite(UserTest.class);
-		return suite;
-	}
-	
-	public void testAllMethods() throws Exception {
-		// create a user to test Anonymous
-		String accountName = ESAPI.randomizer().getRandomString(8, EncoderConstants.CHAR_ALPHANUMERICS);
-		Authenticator instance = ESAPI.authenticator();
-		String password = instance.generateStrongPassword();
-		
-			// Probably could skip the assignment here, but maybe someone had
-			// future plans to use this. So will just suppress warning for now.
-		@SuppressWarnings("unused")
-		User user = instance.createUser(accountName, password, password);
-		
-		// test the rest of the Anonymous user
-		try { User.ANONYMOUS.addRole(null); } catch( RuntimeException e ) {}
-		try { User.ANONYMOUS.addRoles(null); } catch( RuntimeException e ) {}
-		try { User.ANONYMOUS.changePassword(null, null, null); } catch( RuntimeException e ) {}
-		try { User.ANONYMOUS.disable(); } catch( RuntimeException e ) {}
-		try { User.ANONYMOUS.enable(); } catch( RuntimeException e ) {}
-		try { User.ANONYMOUS.getAccountId(); } catch( RuntimeException e ) {}
-		try { User.ANONYMOUS.getAccountName(); } catch( RuntimeException e ) {}
-		try { User.ANONYMOUS.getName(); } catch( RuntimeException e ) {}
-		try { User.ANONYMOUS.getCSRFToken(); } catch( RuntimeException e ) {}
-		try { User.ANONYMOUS.getExpirationTime(); } catch( RuntimeException e ) {}
-		try { User.ANONYMOUS.getFailedLoginCount(); } catch( RuntimeException e ) {}
-		try { User.ANONYMOUS.getLastFailedLoginTime(); } catch( RuntimeException e ) {}
-		try { User.ANONYMOUS.getLastLoginTime(); } catch( RuntimeException e ) {}
-		try { User.ANONYMOUS.getLastPasswordChangeTime(); } catch( RuntimeException e ) {}
-		try { User.ANONYMOUS.getRoles(); } catch( RuntimeException e ) {}
-		try { User.ANONYMOUS.getScreenName(); } catch( RuntimeException e ) {}
-		try { User.ANONYMOUS.addSession(null); } catch( RuntimeException e ) {}
-		try { User.ANONYMOUS.removeSession(null); } catch( RuntimeException e ) {}
-		try { User.ANONYMOUS.incrementFailedLoginCount(); } catch( RuntimeException e ) {}
-		try { User.ANONYMOUS.isAnonymous(); } catch( RuntimeException e ) {}
-		try { User.ANONYMOUS.isEnabled(); } catch( RuntimeException e ) {}
-		try { User.ANONYMOUS.isExpired(); } catch( RuntimeException e ) {}
-		try { User.ANONYMOUS.isInRole(null); } catch( RuntimeException e ) {}
-		try { User.ANONYMOUS.isLocked(); } catch( RuntimeException e ) {}
-		try { User.ANONYMOUS.isLoggedIn(); } catch( RuntimeException e ) {}
-		try { User.ANONYMOUS.isSessionAbsoluteTimeout(); } catch( RuntimeException e ) {}
-		try { User.ANONYMOUS.isSessionTimeout(); } catch( RuntimeException e ) {}
-		try { User.ANONYMOUS.lock(); } catch( RuntimeException e ) {}
-		try { User.ANONYMOUS.loginWithPassword(null); } catch( RuntimeException e ) {}
-		try { User.ANONYMOUS.logout(); } catch( RuntimeException e ) {}
-		try { User.ANONYMOUS.removeRole(null); } catch( RuntimeException e ) {}
-		try { User.ANONYMOUS.resetCSRFToken(); } catch( RuntimeException e ) {}
-		try { User.ANONYMOUS.setAccountName(null); } catch( RuntimeException e ) {}
-		try { User.ANONYMOUS.setExpirationTime(null); } catch( RuntimeException e ) {}
-		try { User.ANONYMOUS.setRoles(null); } catch( RuntimeException e ) {}
-		try { User.ANONYMOUS.setScreenName(null); } catch( RuntimeException e ) {}
-		try { User.ANONYMOUS.unlock(); } catch( RuntimeException e ) {}
-		try { User.ANONYMOUS.verifyPassword(null); } catch( RuntimeException e ) {}
-		try { User.ANONYMOUS.setLastFailedLoginTime(null); } catch( RuntimeException e ) {}
-		try { User.ANONYMOUS.setLastLoginTime(null); } catch( RuntimeException e ) {}
-		try { User.ANONYMOUS.setLastHostAddress(null); } catch( RuntimeException e ) {}
-		try { User.ANONYMOUS.setLastPasswordChangeTime(null); } catch( RuntimeException e ) {}
-		try { User.ANONYMOUS.getEventMap(); } catch( RuntimeException e ) {}
-		try { User.ANONYMOUS.getLocale(); } catch( RuntimeException e ) {}
-		try { User.ANONYMOUS.setLocale(null); } catch( RuntimeException e ) {}
-		try { User.ANONYMOUS.getAccountName(); } catch( RuntimeException e ) {}
-		try { User.ANONYMOUS.getAccountName(); } catch( RuntimeException e ) {}
-	}
+        // test the rest of the Anonymous user
+        try { User.ANONYMOUS.addRole(null); } catch( RuntimeException e ) {}
+        try { User.ANONYMOUS.addRoles(null); } catch( RuntimeException e ) {}
+        try { User.ANONYMOUS.changePassword(null, null, null); } catch( RuntimeException e ) {}
+        try { User.ANONYMOUS.disable(); } catch( RuntimeException e ) {}
+        try { User.ANONYMOUS.enable(); } catch( RuntimeException e ) {}
+        try { User.ANONYMOUS.getAccountId(); } catch( RuntimeException e ) {}
+        try { User.ANONYMOUS.getAccountName(); } catch( RuntimeException e ) {}
+        try { User.ANONYMOUS.getName(); } catch( RuntimeException e ) {}
+        try { User.ANONYMOUS.getCSRFToken(); } catch( RuntimeException e ) {}
+        try { User.ANONYMOUS.getExpirationTime(); } catch( RuntimeException e ) {}
+        try { User.ANONYMOUS.getFailedLoginCount(); } catch( RuntimeException e ) {}
+        try { User.ANONYMOUS.getLastFailedLoginTime(); } catch( RuntimeException e ) {}
+        try { User.ANONYMOUS.getLastLoginTime(); } catch( RuntimeException e ) {}
+        try { User.ANONYMOUS.getLastPasswordChangeTime(); } catch( RuntimeException e ) {}
+        try { User.ANONYMOUS.getRoles(); } catch( RuntimeException e ) {}
+        try { User.ANONYMOUS.getScreenName(); } catch( RuntimeException e ) {}
+        try { User.ANONYMOUS.addSession(null); } catch( RuntimeException e ) {}
+        try { User.ANONYMOUS.removeSession(null); } catch( RuntimeException e ) {}
+        try { User.ANONYMOUS.incrementFailedLoginCount(); } catch( RuntimeException e ) {}
+        try { User.ANONYMOUS.isAnonymous(); } catch( RuntimeException e ) {}
+        try { User.ANONYMOUS.isEnabled(); } catch( RuntimeException e ) {}
+        try { User.ANONYMOUS.isExpired(); } catch( RuntimeException e ) {}
+        try { User.ANONYMOUS.isInRole(null); } catch( RuntimeException e ) {}
+        try { User.ANONYMOUS.isLocked(); } catch( RuntimeException e ) {}
+        try { User.ANONYMOUS.isLoggedIn(); } catch( RuntimeException e ) {}
+        try { User.ANONYMOUS.isSessionAbsoluteTimeout(); } catch( RuntimeException e ) {}
+        try { User.ANONYMOUS.isSessionTimeout(); } catch( RuntimeException e ) {}
+        try { User.ANONYMOUS.lock(); } catch( RuntimeException e ) {}
+        try { User.ANONYMOUS.loginWithPassword(null); } catch( RuntimeException e ) {}
+        try { User.ANONYMOUS.logout(); } catch( RuntimeException e ) {}
+        try { User.ANONYMOUS.removeRole(null); } catch( RuntimeException e ) {}
+        try { User.ANONYMOUS.resetCSRFToken(); } catch( RuntimeException e ) {}
+        try { User.ANONYMOUS.setAccountName(null); } catch( RuntimeException e ) {}
+        try { User.ANONYMOUS.setExpirationTime(null); } catch( RuntimeException e ) {}
+        try { User.ANONYMOUS.setRoles(null); } catch( RuntimeException e ) {}
+        try { User.ANONYMOUS.setScreenName(null); } catch( RuntimeException e ) {}
+        try { User.ANONYMOUS.unlock(); } catch( RuntimeException e ) {}
+        try { User.ANONYMOUS.verifyPassword(null); } catch( RuntimeException e ) {}
+        try { User.ANONYMOUS.setLastFailedLoginTime(null); } catch( RuntimeException e ) {}
+        try { User.ANONYMOUS.setLastLoginTime(null); } catch( RuntimeException e ) {}
+        try { User.ANONYMOUS.setLastHostAddress(null); } catch( RuntimeException e ) {}
+        try { User.ANONYMOUS.setLastPasswordChangeTime(null); } catch( RuntimeException e ) {}
+        try { User.ANONYMOUS.getEventMap(); } catch( RuntimeException e ) {}
+        try { User.ANONYMOUS.getLocale(); } catch( RuntimeException e ) {}
+        try { User.ANONYMOUS.setLocale(null); } catch( RuntimeException e ) {}
+        try { User.ANONYMOUS.getAccountName(); } catch( RuntimeException e ) {}
+        try { User.ANONYMOUS.getAccountName(); } catch( RuntimeException e ) {}
+    }
 }
 
 
diff --git a/src/test/java/org/owasp/esapi/ValidationErrorListTest.java b/src/test/java/org/owasp/esapi/ValidationErrorListTest.java
index 18c6450..42762d7 100644
--- a/src/test/java/org/owasp/esapi/ValidationErrorListTest.java
+++ b/src/test/java/org/owasp/esapi/ValidationErrorListTest.java
@@ -1,15 +1,15 @@
 /**
  * OWASP Enterprise Security API (ESAPI)
- * 
+ *
  * This file is part of the Open Web Application Security Project (OWASP)
  * Enterprise Security API (ESAPI) project. For details, please see
  * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
  *
  * Copyright (c) 2007 - The OWASP Foundation
- * 
+ *
  * The ESAPI is published by OWASP under the BSD license. You should read and accept the
  * LICENSE before you use, modify, and/or redistribute this software.
- * 
+ *
  * @author Jeff Williams <a href="http://www.aspectsecurity.com">Aspect Security</a>
  * @created 2007
  */
diff --git a/src/test/java/org/owasp/esapi/codecs/AbstractCodecTest.java b/src/test/java/org/owasp/esapi/codecs/AbstractCodecTest.java
index 813330e..f4f1b7b 100644
--- a/src/test/java/org/owasp/esapi/codecs/AbstractCodecTest.java
+++ b/src/test/java/org/owasp/esapi/codecs/AbstractCodecTest.java
@@ -1,15 +1,15 @@
 /**
  * OWASP Enterprise Security API (ESAPI)
- * 
+ *
  * This file is part of the Open Web Application Security Project (OWASP)
  * Enterprise Security API (ESAPI) project. For details, please see
  * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
  *
  * Copyright (c) 2007 - The OWASP Foundation
- * 
+ *
  * The ESAPI is published by OWASP under the BSD license. You should read and accept the
  * LICENSE before you use, modify, and/or redistribute this software.
- * 
+ *
  * @author Jeff Williams <a href="http://www.aspectsecurity.com">Aspect Security</a>
  * @created 2007
  */
@@ -44,7 +44,7 @@ public class AbstractCodecTest extends TestCase {
 
     /**
      * Instantiates a new access reference map test.
-     * 
+     *
      * @param testName
      *            the test name
      */
@@ -70,7 +70,7 @@ public class AbstractCodecTest extends TestCase {
 
     /**
      * Suite.
-     * 
+     *
      * @return the test
      */
     public static Test suite() {
@@ -78,552 +78,552 @@ public class AbstractCodecTest extends TestCase {
         return suite;
     }
 
-	public void testHtmlEncode()
-	{
-        	assertEquals( "test", htmlCodec.encode( EMPTY_CHAR_ARRAY, "test") );
-	}
-
-	public void testPercentEncode()
-	{
-        	assertEquals( "%3C", percentCodec.encode(EMPTY_CHAR_ARRAY, "<") );
-	}
-
-
-	public void testJavaScriptEncode()
-	{
-        	assertEquals( "\\x3C", javaScriptCodec.encode(EMPTY_CHAR_ARRAY, "<") );
-	}
-
-	public void testVBScriptEncode()
-	{
-        	assertEquals( "chrw(60)", vbScriptCodec.encode(EMPTY_CHAR_ARRAY, "<") );
-	}
-
-	public void testCSSEncode()
-	{
-        	assertEquals( "\\3c ", cssCodec.encode(EMPTY_CHAR_ARRAY, "<") );
-	}
-
-	public void testCSSInvalidCodepointDecode()
-	{
-		assertEquals("\uFFFDg", cssCodec.decode("\\abcdefg") );
-	}
-
-	public void testMySQLANSCIEncode()
-	{
-        	assertEquals( "\'\'", mySQLCodecANSI.encode(EMPTY_CHAR_ARRAY, "\'") );
-	}
-
-	public void testMySQLStandardEncode()
-	{
-        	assertEquals( "\\<", mySQLCodecStandard.encode(EMPTY_CHAR_ARRAY, "<") );
-	}
-
-	public void testOracleEncode()
-	{
-        	assertEquals( "\'\'", oracleCodec.encode(EMPTY_CHAR_ARRAY, "\'") );
-	}
-
-	public void testUnixEncode()
-	{
-        	assertEquals( "\\<", unixCodec.encode(EMPTY_CHAR_ARRAY, "<") );
-	}
-
-	public void testWindowsEncode()
-	{
-        	assertEquals( "^<", windowsCodec.encode(EMPTY_CHAR_ARRAY, "<") );
-	}
-
-	
-	public void testHtmlEncodeChar()
-	{
-		
-        	assertEquals( "&lt;", htmlCodec.encodeCharacter(EMPTY_CHAR_ARRAY, (int) LESS_THAN) );
-	}
-
-	public void testHtmlEncodeChar0x100()
-	{
-		Character in = 0x100;
-		String inStr = Character.toString(in);
-		String expected = "&#x100;";
-		String result;
-		//The new default for HTMLEntityCodec is ints/Integers.  Use Character/char at your own risk!
-		//Characters destroy non-BMP codepoints.  This Codec is now supposed surpass that. 
-    	result = htmlCodec.encodeCharacter(EMPTY_CHAR_ARRAY, (int) in);
-    	// this should be escaped
-    	assertFalse(inStr.equals(result));
-    	// UTF-8 encoded and then percent escaped
-    	assertEquals(expected, result);
-	}
-
-	public void testHtmlEncodeStr0x100()
-	{
-		Character in = 0x100;
-		String inStr = Character.toString(in);
-		String expected = "&#x100;";
-		String result;
-
-        	result = htmlCodec.encode(EMPTY_CHAR_ARRAY, inStr);
-		// this should be escaped
-        	assertFalse(inStr.equals(result));
-		// UTF-8 encoded and then percent escaped
-        	assertEquals(expected, result);
-	}
-
-	public void testPercentEncodeChar()
-	{
-        	assertEquals( "%3C", percentCodec.encodeCharacter(EMPTY_CHAR_ARRAY, LESS_THAN) );
-	}
-
-	public void testPercentEncodeChar0x100()
-	{
-		Character in = 0x100;
-		String inStr = Character.toString(in);
-		String expected = "%C4%80";
-		String result;
-
-        	result = percentCodec.encodeCharacter(EMPTY_CHAR_ARRAY, in);
-		// this should be escaped
-        	assertFalse(inStr.equals(result));
-		// UTF-8 encoded and then percent escaped
-        	assertEquals(expected, result);
-	}
-
-	public void testPercentEncodeStr0x100()
-	{
-		Character in = 0x100;
-		String inStr = Character.toString(in);
-		String expected = "%C4%80";
-		String result;
-
-        	result = percentCodec.encode(EMPTY_CHAR_ARRAY, inStr);
-		// this should be escaped
-        	assertFalse(inStr.equals(result));
-		// UTF-8 encoded and then percent escaped
-        	assertEquals(expected, result);
-	}
-
-	public void testJavaScriptEncodeChar()
-	{
-        	assertEquals( "\\x3C", javaScriptCodec.encodeCharacter(EMPTY_CHAR_ARRAY, LESS_THAN) );
-	}
-
-	public void testJavaScriptEncodeChar0x100()
-	{
-		Character in = 0x100;
-		String inStr = Character.toString(in);
-		String expected = "\\u0100";
-		String result;
-
-        	result = javaScriptCodec.encodeCharacter(EMPTY_CHAR_ARRAY, in);
-		// this should be escaped
-        	assertFalse(inStr.equals(result));
-        	assertEquals(expected,result);
-	}
-
-	public void testJavaScriptEncodeStr0x100()
-	{
-		Character in = 0x100;
-		String inStr = Character.toString(in);
-		String expected = "\\u0100";
-		String result;
-
-        	result = javaScriptCodec.encode(EMPTY_CHAR_ARRAY, inStr);
-		// this should be escaped
-        	assertFalse(inStr.equals(result));
-        	assertEquals(expected,result);
-	}
-        
-	public void testVBScriptEncodeChar()
-	{
-        	assertEquals( "chrw(60)", vbScriptCodec.encodeCharacter(EMPTY_CHAR_ARRAY, LESS_THAN) );
-	}
-
-	public void testVBScriptEncodeChar0x100()
-	{
-		Character in = 0x100;
-		String inStr = Character.toString(in);
-		// FIXME I don't know vb...
-		// String expected = "\\u0100";
-		String result;
-
-        	result = vbScriptCodec.encodeCharacter(EMPTY_CHAR_ARRAY, in);
-		// this should be escaped
-        	assertFalse(inStr.equals(result));
-        	//assertEquals(expected,result);
-	}
-
-	public void testVBScriptEncodeStr0x100()
-	{
-		Character in = 0x100;
-		String inStr = Character.toString(in);
-		// FIXME I don't know vb...
-		// String expected = "chrw(0x100)";
-		String result;
-
-        	result = vbScriptCodec.encode(EMPTY_CHAR_ARRAY, inStr);
-		// this should be escaped
-        	assertFalse(inStr.equals(result));
-        	// assertEquals(expected,result);
-	}
-
-	public void testCSSEncodeChar()
-	{
-        	assertEquals( "\\3c ", cssCodec.encodeCharacter(EMPTY_CHAR_ARRAY, LESS_THAN) );
-	}
-
-	public void testCSSEncodeChar0x100()
-	{
-		Character in = 0x100;
-		String inStr = Character.toString(in);
-		String expected = "\\100 ";
-		String result;
-
-        	result = cssCodec.encodeCharacter(EMPTY_CHAR_ARRAY, in);
-		// this should be escaped
-        	assertFalse(inStr.equals(result));
-        	assertEquals(expected,result);
-	}
-
-	public void testCSSEncodeStr0x100()
-	{
-		Character in = 0x100;
-		String inStr = Character.toString(in);
-		String expected = "\\100 ";
-		String result;
-
-        	result = cssCodec.encode(EMPTY_CHAR_ARRAY, inStr);
-		// this should be escaped
-        	assertFalse(inStr.equals(result));
-        	assertEquals(expected,result);
-	}
-
-	public void testMySQLANSIEncodeChar()
-	{
-        	assertEquals( "\'\'", mySQLCodecANSI.encodeCharacter(EMPTY_CHAR_ARRAY, SINGLE_QUOTE));
-	}
-
-	public void testMySQLStandardEncodeChar0x100()
-	{
-		Character in = 0x100;
-		String inStr = Character.toString(in);
-		String expected = "\\" + in;
-		String result;
-
-        	result = mySQLCodecStandard.encodeCharacter(EMPTY_CHAR_ARRAY, in);
-		// this should be escaped
-        	assertFalse(inStr.equals(result));
-        	assertEquals(expected,result);
-	}
-
-	public void testMySQLStandardEncodeStr0x100()
-	{
-		Character in = 0x100;
-		String inStr = Character.toString(in);
-		String expected = "\\" + in;
-		String result;
-
-        	result = mySQLCodecStandard.encode(EMPTY_CHAR_ARRAY, inStr);
-		// this should be escaped
-        	assertFalse(inStr.equals(result));
-        	assertEquals(expected,result);
-	}
-
-	public void testMySQLStandardEncodeChar()
-	{
-        	assertEquals( "\\<", mySQLCodecStandard.encodeCharacter(EMPTY_CHAR_ARRAY, LESS_THAN) );
-	}
-
-	public void testOracleEncodeChar()
-	{
-        	assertEquals( "\'\'", oracleCodec.encodeCharacter(EMPTY_CHAR_ARRAY, SINGLE_QUOTE) );
-	}
-
-	public void testUnixEncodeChar()
-	{
-        	assertEquals( "\\<", unixCodec.encodeCharacter(EMPTY_CHAR_ARRAY, LESS_THAN) );
-	}
-
-	public void testUnixEncodeChar0x100()
-	{
-		Character in = 0x100;
-		String inStr = Character.toString(in);
-		String expected = "\\" + in;
-		String result;
-
-        	result = unixCodec.encodeCharacter(EMPTY_CHAR_ARRAY, in);
-		// this should be escaped
-        	assertFalse(inStr.equals(result));
-        	assertEquals(expected,result);
-	}
-
-	public void testUnixEncodeStr0x100()
-	{
-		Character in = 0x100;
-		String inStr = Character.toString(in);
-		String expected = "\\" + in;
-		String result;
-
-        	result = unixCodec.encode(EMPTY_CHAR_ARRAY, inStr);
-		// this should be escaped
-        	assertFalse(inStr.equals(result));
-        	assertEquals(expected,result);
-	}
-
-	public void testWindowsEncodeChar()
-	{
-        	assertEquals( "^<", windowsCodec.encodeCharacter(EMPTY_CHAR_ARRAY, LESS_THAN) );
-	}
-
-	public void testWindowsEncodeChar0x100()
-	{
-		Character in = 0x100;
-		String inStr = Character.toString(in);
-		String expected = "^" + in;
-		String result;
-
-        	result = windowsCodec.encodeCharacter(EMPTY_CHAR_ARRAY, in);
-		// this should be escaped
-        	assertFalse(inStr.equals(result));
-        	assertEquals(expected,result);
-	}
-
-	public void testWindowsEncodeStr0x100()
-	{
-		Character in = 0x100;
-		String inStr = Character.toString(in);
-		String expected = "^" + in;
-		String result;
-
-        	result = windowsCodec.encode(EMPTY_CHAR_ARRAY, inStr);
-		// this should be escaped
-        	assertFalse(inStr.equals(result));
-        	assertEquals(expected,result);
-	}
-	
-	public void testHtmlDecodeDecimalEntities()
-	{
-        	assertEquals( "test!", htmlCodec.decode("&#116;&#101;&#115;&#116;!") );
-	}
-
-	public void testHtmlDecodeHexEntitites()
-	{
-        	assertEquals( "test!", htmlCodec.decode("&#x74;&#x65;&#x73;&#x74;!") );
-	}
-
-	public void testHtmlDecodeInvalidAttribute()
-	{
-        	assertEquals( "&jeff;", htmlCodec.decode("&jeff;") );
-	}
-
-	public void testHtmlDecodeAmp()
-	{
-		assertEquals("&", htmlCodec.decode("&amp;"));
-		assertEquals("&X", htmlCodec.decode("&amp;X"));
-		assertEquals("&", htmlCodec.decode("&amp"));
-		assertEquals("&X", htmlCodec.decode("&ampX"));
-	}
-
-	public void testHtmlDecodeLt()
-	{
-		assertEquals("<", htmlCodec.decode("&lt;"));
-		assertEquals("<X", htmlCodec.decode("&lt;X"));
-		assertEquals("<", htmlCodec.decode("&lt"));
-		assertEquals("<X", htmlCodec.decode("&ltX"));
-	}
-
-	public void testHtmlDecodeSup1()
-	{
-		assertEquals("\u00B9", htmlCodec.decode("&sup1;"));
-		assertEquals("\u00B9X", htmlCodec.decode("&sup1;X"));
-		assertEquals("\u00B9", htmlCodec.decode("&sup1"));
-		assertEquals("\u00B9X", htmlCodec.decode("&sup1X"));
-	}
-
-	public void testHtmlDecodeSup2()
-	{
-		assertEquals("\u00B2", htmlCodec.decode("&sup2;"));
-		assertEquals("\u00B2X", htmlCodec.decode("&sup2;X"));
-		assertEquals("\u00B2", htmlCodec.decode("&sup2"));
-		assertEquals("\u00B2X", htmlCodec.decode("&sup2X"));
-	}
-
-	public void testHtmlDecodeSup3()
-	{
-		assertEquals("\u00B3", htmlCodec.decode("&sup3;"));
-		assertEquals("\u00B3X", htmlCodec.decode("&sup3;X"));
-		assertEquals("\u00B3", htmlCodec.decode("&sup3"));
-		assertEquals("\u00B3X", htmlCodec.decode("&sup3X"));
-	}
-
-	public void testHtmlDecodeSup()
-	{
-		assertEquals("\u2283", htmlCodec.decode("&sup;"));
-		assertEquals("\u2283X", htmlCodec.decode("&sup;X"));
-		assertEquals("\u2283", htmlCodec.decode("&sup"));
-		assertEquals("\u2283X", htmlCodec.decode("&supX"));
-	}
-
-	public void testHtmlDecodeSupe()
-	{
-		assertEquals("\u2287", htmlCodec.decode("&supe;"));
-		assertEquals("\u2287X", htmlCodec.decode("&supe;X"));
-		assertEquals("\u2287", htmlCodec.decode("&supe"));
-		assertEquals("\u2287X", htmlCodec.decode("&supeX"));
-	}
-
-	public void testHtmlDecodePi()
-	{
-		assertEquals("\u03C0", htmlCodec.decode("&pi;"));
-		assertEquals("\u03C0X", htmlCodec.decode("&pi;X"));
-		assertEquals("\u03C0", htmlCodec.decode("&pi"));
-		assertEquals("\u03C0X", htmlCodec.decode("&piX"));
-	}
-
-	public void testHtmlDecodePiv()
-	{
-		assertEquals("\u03D6", htmlCodec.decode("&piv;"));
-		assertEquals("\u03D6X", htmlCodec.decode("&piv;X"));
-		assertEquals("\u03D6", htmlCodec.decode("&piv"));
-		assertEquals("\u03D6X", htmlCodec.decode("&pivX"));
-	}
-
-	public void testHtmlDecodeTheta()
-	{
-		assertEquals("\u03B8", htmlCodec.decode("&theta;"));
-		assertEquals("\u03B8X", htmlCodec.decode("&theta;X"));
-		assertEquals("\u03B8", htmlCodec.decode("&theta"));
-		assertEquals("\u03B8X", htmlCodec.decode("&thetaX"));
-	}
-
-	public void testHtmlDecodeThetasym()
-	{
-		assertEquals("\u03D1", htmlCodec.decode("&thetasym;"));
-		assertEquals("\u03D1X", htmlCodec.decode("&thetasym;X"));
-		assertEquals("\u03D1", htmlCodec.decode("&thetasym"));
-		assertEquals("\u03D1X", htmlCodec.decode("&thetasymX"));
-	}
-
-	public void testPercentDecode()
-	{
-        	assertEquals( "<", percentCodec.decode("%3c") );
-	}
-
-	public void testJavaScriptDecodeBackSlashHex()
-	{
-        	assertEquals( "<", javaScriptCodec.decode("\\x3c") );
-	}
-        
-	public void testVBScriptDecode()
-	{
-        	assertEquals( "<", vbScriptCodec.decode("\"<") );
-	}
-
-	public void testCSSDecode()
-	{
-        	assertEquals("<", cssCodec.decode("\\<") );
-	}
-
-	public void testCSSDecodeHexNoSpace()
-	{
-        	assertEquals("Axyz", cssCodec.decode("\\41xyz") );
-	}
-
-	public void testCSSDecodeZeroHexNoSpace()
-	{
-        	assertEquals("Aabc", cssCodec.decode("\\000041abc") );
-	}
-
-	public void testCSSDecodeHexSpace()
-	{
-        	assertEquals("Aabc", cssCodec.decode("\\41 abc") );
-	}
-
-	public void testCSSDecodeNL()
-	{
-        	assertEquals("abcxyz", cssCodec.decode("abc\\\nxyz") );
-	}
-
-	public void testCSSDecodeCRNL()
-	{
-        	assertEquals("abcxyz", cssCodec.decode("abc\\\r\nxyz") );
-	}
-
-	public void testMySQLANSIDecode()
-	{
-        	assertEquals( "\'", mySQLCodecANSI.decode("\'\'") );
-	}
-
-	public void testMySQLStandardDecode()
-	{
-        	assertEquals( "<", mySQLCodecStandard.decode("\\<") );
-	}
-
-	public void testOracleDecode()
-	{
-        	assertEquals( "\'", oracleCodec.decode("\'\'") );
-	}
-
-	public void testUnixDecode()
-	{
-        	assertEquals( "<", unixCodec.decode("\\<") );
-	}
+    public void testHtmlEncode()
+    {
+            assertEquals( "test", htmlCodec.encode( EMPTY_CHAR_ARRAY, "test") );
+    }
+
+    public void testPercentEncode()
+    {
+            assertEquals( "%3C", percentCodec.encode(EMPTY_CHAR_ARRAY, "<") );
+    }
+
+
+    public void testJavaScriptEncode()
+    {
+            assertEquals( "\\x3C", javaScriptCodec.encode(EMPTY_CHAR_ARRAY, "<") );
+    }
+
+    public void testVBScriptEncode()
+    {
+            assertEquals( "chrw(60)", vbScriptCodec.encode(EMPTY_CHAR_ARRAY, "<") );
+    }
+
+    public void testCSSEncode()
+    {
+            assertEquals( "\\3c ", cssCodec.encode(EMPTY_CHAR_ARRAY, "<") );
+    }
+
+    public void testCSSInvalidCodepointDecode()
+    {
+        assertEquals("\uFFFDg", cssCodec.decode("\\abcdefg") );
+    }
+
+    public void testMySQLANSCIEncode()
+    {
+            assertEquals( "\'\'", mySQLCodecANSI.encode(EMPTY_CHAR_ARRAY, "\'") );
+    }
+
+    public void testMySQLStandardEncode()
+    {
+            assertEquals( "\\<", mySQLCodecStandard.encode(EMPTY_CHAR_ARRAY, "<") );
+    }
+
+    public void testOracleEncode()
+    {
+            assertEquals( "\'\'", oracleCodec.encode(EMPTY_CHAR_ARRAY, "\'") );
+    }
+
+    public void testUnixEncode()
+    {
+            assertEquals( "\\<", unixCodec.encode(EMPTY_CHAR_ARRAY, "<") );
+    }
+
+    public void testWindowsEncode()
+    {
+            assertEquals( "^<", windowsCodec.encode(EMPTY_CHAR_ARRAY, "<") );
+    }
+
+
+    public void testHtmlEncodeChar()
+    {
+
+            assertEquals( "&lt;", htmlCodec.encodeCharacter(EMPTY_CHAR_ARRAY, (int) LESS_THAN) );
+    }
+
+    public void testHtmlEncodeChar0x100()
+    {
+        Character in = 0x100;
+        String inStr = Character.toString(in);
+        String expected = "&#x100;";
+        String result;
+        //The new default for HTMLEntityCodec is ints/Integers.  Use Character/char at your own risk!
+        //Characters destroy non-BMP codepoints.  This Codec is now supposed surpass that.
+        result = htmlCodec.encodeCharacter(EMPTY_CHAR_ARRAY, (int) in);
+        // this should be escaped
+        assertFalse(inStr.equals(result));
+        // UTF-8 encoded and then percent escaped
+        assertEquals(expected, result);
+    }
+
+    public void testHtmlEncodeStr0x100()
+    {
+        Character in = 0x100;
+        String inStr = Character.toString(in);
+        String expected = "&#x100;";
+        String result;
+
+            result = htmlCodec.encode(EMPTY_CHAR_ARRAY, inStr);
+        // this should be escaped
+            assertFalse(inStr.equals(result));
+        // UTF-8 encoded and then percent escaped
+            assertEquals(expected, result);
+    }
+
+    public void testPercentEncodeChar()
+    {
+            assertEquals( "%3C", percentCodec.encodeCharacter(EMPTY_CHAR_ARRAY, LESS_THAN) );
+    }
+
+    public void testPercentEncodeChar0x100()
+    {
+        Character in = 0x100;
+        String inStr = Character.toString(in);
+        String expected = "%C4%80";
+        String result;
+
+            result = percentCodec.encodeCharacter(EMPTY_CHAR_ARRAY, in);
+        // this should be escaped
+            assertFalse(inStr.equals(result));
+        // UTF-8 encoded and then percent escaped
+            assertEquals(expected, result);
+    }
+
+    public void testPercentEncodeStr0x100()
+    {
+        Character in = 0x100;
+        String inStr = Character.toString(in);
+        String expected = "%C4%80";
+        String result;
+
+            result = percentCodec.encode(EMPTY_CHAR_ARRAY, inStr);
+        // this should be escaped
+            assertFalse(inStr.equals(result));
+        // UTF-8 encoded and then percent escaped
+            assertEquals(expected, result);
+    }
+
+    public void testJavaScriptEncodeChar()
+    {
+            assertEquals( "\\x3C", javaScriptCodec.encodeCharacter(EMPTY_CHAR_ARRAY, LESS_THAN) );
+    }
+
+    public void testJavaScriptEncodeChar0x100()
+    {
+        Character in = 0x100;
+        String inStr = Character.toString(in);
+        String expected = "\\u0100";
+        String result;
+
+            result = javaScriptCodec.encodeCharacter(EMPTY_CHAR_ARRAY, in);
+        // this should be escaped
+            assertFalse(inStr.equals(result));
+            assertEquals(expected,result);
+    }
+
+    public void testJavaScriptEncodeStr0x100()
+    {
+        Character in = 0x100;
+        String inStr = Character.toString(in);
+        String expected = "\\u0100";
+        String result;
+
+            result = javaScriptCodec.encode(EMPTY_CHAR_ARRAY, inStr);
+        // this should be escaped
+            assertFalse(inStr.equals(result));
+            assertEquals(expected,result);
+    }
+
+    public void testVBScriptEncodeChar()
+    {
+            assertEquals( "chrw(60)", vbScriptCodec.encodeCharacter(EMPTY_CHAR_ARRAY, LESS_THAN) );
+    }
+
+    public void testVBScriptEncodeChar0x100()
+    {
+        Character in = 0x100;
+        String inStr = Character.toString(in);
+        // FIXME I don't know vb...
+        // String expected = "\\u0100";
+        String result;
+
+            result = vbScriptCodec.encodeCharacter(EMPTY_CHAR_ARRAY, in);
+        // this should be escaped
+            assertFalse(inStr.equals(result));
+            //assertEquals(expected,result);
+    }
+
+    public void testVBScriptEncodeStr0x100()
+    {
+        Character in = 0x100;
+        String inStr = Character.toString(in);
+        // FIXME I don't know vb...
+        // String expected = "chrw(0x100)";
+        String result;
+
+            result = vbScriptCodec.encode(EMPTY_CHAR_ARRAY, inStr);
+        // this should be escaped
+            assertFalse(inStr.equals(result));
+            // assertEquals(expected,result);
+    }
+
+    public void testCSSEncodeChar()
+    {
+            assertEquals( "\\3c ", cssCodec.encodeCharacter(EMPTY_CHAR_ARRAY, LESS_THAN) );
+    }
+
+    public void testCSSEncodeChar0x100()
+    {
+        Character in = 0x100;
+        String inStr = Character.toString(in);
+        String expected = "\\100 ";
+        String result;
+
+            result = cssCodec.encodeCharacter(EMPTY_CHAR_ARRAY, in);
+        // this should be escaped
+            assertFalse(inStr.equals(result));
+            assertEquals(expected,result);
+    }
+
+    public void testCSSEncodeStr0x100()
+    {
+        Character in = 0x100;
+        String inStr = Character.toString(in);
+        String expected = "\\100 ";
+        String result;
+
+            result = cssCodec.encode(EMPTY_CHAR_ARRAY, inStr);
+        // this should be escaped
+            assertFalse(inStr.equals(result));
+            assertEquals(expected,result);
+    }
+
+    public void testMySQLANSIEncodeChar()
+    {
+            assertEquals( "\'\'", mySQLCodecANSI.encodeCharacter(EMPTY_CHAR_ARRAY, SINGLE_QUOTE));
+    }
+
+    public void testMySQLStandardEncodeChar0x100()
+    {
+        Character in = 0x100;
+        String inStr = Character.toString(in);
+        String expected = "\\" + in;
+        String result;
+
+            result = mySQLCodecStandard.encodeCharacter(EMPTY_CHAR_ARRAY, in);
+        // this should be escaped
+            assertFalse(inStr.equals(result));
+            assertEquals(expected,result);
+    }
+
+    public void testMySQLStandardEncodeStr0x100()
+    {
+        Character in = 0x100;
+        String inStr = Character.toString(in);
+        String expected = "\\" + in;
+        String result;
+
+            result = mySQLCodecStandard.encode(EMPTY_CHAR_ARRAY, inStr);
+        // this should be escaped
+            assertFalse(inStr.equals(result));
+            assertEquals(expected,result);
+    }
+
+    public void testMySQLStandardEncodeChar()
+    {
+            assertEquals( "\\<", mySQLCodecStandard.encodeCharacter(EMPTY_CHAR_ARRAY, LESS_THAN) );
+    }
+
+    public void testOracleEncodeChar()
+    {
+            assertEquals( "\'\'", oracleCodec.encodeCharacter(EMPTY_CHAR_ARRAY, SINGLE_QUOTE) );
+    }
+
+    public void testUnixEncodeChar()
+    {
+            assertEquals( "\\<", unixCodec.encodeCharacter(EMPTY_CHAR_ARRAY, LESS_THAN) );
+    }
+
+    public void testUnixEncodeChar0x100()
+    {
+        Character in = 0x100;
+        String inStr = Character.toString(in);
+        String expected = "\\" + in;
+        String result;
+
+            result = unixCodec.encodeCharacter(EMPTY_CHAR_ARRAY, in);
+        // this should be escaped
+            assertFalse(inStr.equals(result));
+            assertEquals(expected,result);
+    }
+
+    public void testUnixEncodeStr0x100()
+    {
+        Character in = 0x100;
+        String inStr = Character.toString(in);
+        String expected = "\\" + in;
+        String result;
+
+            result = unixCodec.encode(EMPTY_CHAR_ARRAY, inStr);
+        // this should be escaped
+            assertFalse(inStr.equals(result));
+            assertEquals(expected,result);
+    }
+
+    public void testWindowsEncodeChar()
+    {
+            assertEquals( "^<", windowsCodec.encodeCharacter(EMPTY_CHAR_ARRAY, LESS_THAN) );
+    }
+
+    public void testWindowsEncodeChar0x100()
+    {
+        Character in = 0x100;
+        String inStr = Character.toString(in);
+        String expected = "^" + in;
+        String result;
+
+            result = windowsCodec.encodeCharacter(EMPTY_CHAR_ARRAY, in);
+        // this should be escaped
+            assertFalse(inStr.equals(result));
+            assertEquals(expected,result);
+    }
+
+    public void testWindowsEncodeStr0x100()
+    {
+        Character in = 0x100;
+        String inStr = Character.toString(in);
+        String expected = "^" + in;
+        String result;
+
+            result = windowsCodec.encode(EMPTY_CHAR_ARRAY, inStr);
+        // this should be escaped
+            assertFalse(inStr.equals(result));
+            assertEquals(expected,result);
+    }
+
+    public void testHtmlDecodeDecimalEntities()
+    {
+            assertEquals( "test!", htmlCodec.decode("&#116;&#101;&#115;&#116;!") );
+    }
+
+    public void testHtmlDecodeHexEntitites()
+    {
+            assertEquals( "test!", htmlCodec.decode("&#x74;&#x65;&#x73;&#x74;!") );
+    }
+
+    public void testHtmlDecodeInvalidAttribute()
+    {
+            assertEquals( "&jeff;", htmlCodec.decode("&jeff;") );
+    }
+
+    public void testHtmlDecodeAmp()
+    {
+        assertEquals("&", htmlCodec.decode("&amp;"));
+        assertEquals("&X", htmlCodec.decode("&amp;X"));
+        assertEquals("&", htmlCodec.decode("&amp"));
+        assertEquals("&X", htmlCodec.decode("&ampX"));
+    }
+
+    public void testHtmlDecodeLt()
+    {
+        assertEquals("<", htmlCodec.decode("&lt;"));
+        assertEquals("<X", htmlCodec.decode("&lt;X"));
+        assertEquals("<", htmlCodec.decode("&lt"));
+        assertEquals("<X", htmlCodec.decode("&ltX"));
+    }
+
+    public void testHtmlDecodeSup1()
+    {
+        assertEquals("\u00B9", htmlCodec.decode("&sup1;"));
+        assertEquals("\u00B9X", htmlCodec.decode("&sup1;X"));
+        assertEquals("\u00B9", htmlCodec.decode("&sup1"));
+        assertEquals("\u00B9X", htmlCodec.decode("&sup1X"));
+    }
+
+    public void testHtmlDecodeSup2()
+    {
+        assertEquals("\u00B2", htmlCodec.decode("&sup2;"));
+        assertEquals("\u00B2X", htmlCodec.decode("&sup2;X"));
+        assertEquals("\u00B2", htmlCodec.decode("&sup2"));
+        assertEquals("\u00B2X", htmlCodec.decode("&sup2X"));
+    }
+
+    public void testHtmlDecodeSup3()
+    {
+        assertEquals("\u00B3", htmlCodec.decode("&sup3;"));
+        assertEquals("\u00B3X", htmlCodec.decode("&sup3;X"));
+        assertEquals("\u00B3", htmlCodec.decode("&sup3"));
+        assertEquals("\u00B3X", htmlCodec.decode("&sup3X"));
+    }
+
+    public void testHtmlDecodeSup()
+    {
+        assertEquals("\u2283", htmlCodec.decode("&sup;"));
+        assertEquals("\u2283X", htmlCodec.decode("&sup;X"));
+        assertEquals("\u2283", htmlCodec.decode("&sup"));
+        assertEquals("\u2283X", htmlCodec.decode("&supX"));
+    }
+
+    public void testHtmlDecodeSupe()
+    {
+        assertEquals("\u2287", htmlCodec.decode("&supe;"));
+        assertEquals("\u2287X", htmlCodec.decode("&supe;X"));
+        assertEquals("\u2287", htmlCodec.decode("&supe"));
+        assertEquals("\u2287X", htmlCodec.decode("&supeX"));
+    }
+
+    public void testHtmlDecodePi()
+    {
+        assertEquals("\u03C0", htmlCodec.decode("&pi;"));
+        assertEquals("\u03C0X", htmlCodec.decode("&pi;X"));
+        assertEquals("\u03C0", htmlCodec.decode("&pi"));
+        assertEquals("\u03C0X", htmlCodec.decode("&piX"));
+    }
+
+    public void testHtmlDecodePiv()
+    {
+        assertEquals("\u03D6", htmlCodec.decode("&piv;"));
+        assertEquals("\u03D6X", htmlCodec.decode("&piv;X"));
+        assertEquals("\u03D6", htmlCodec.decode("&piv"));
+        assertEquals("\u03D6X", htmlCodec.decode("&pivX"));
+    }
+
+    public void testHtmlDecodeTheta()
+    {
+        assertEquals("\u03B8", htmlCodec.decode("&theta;"));
+        assertEquals("\u03B8X", htmlCodec.decode("&theta;X"));
+        assertEquals("\u03B8", htmlCodec.decode("&theta"));
+        assertEquals("\u03B8X", htmlCodec.decode("&thetaX"));
+    }
+
+    public void testHtmlDecodeThetasym()
+    {
+        assertEquals("\u03D1", htmlCodec.decode("&thetasym;"));
+        assertEquals("\u03D1X", htmlCodec.decode("&thetasym;X"));
+        assertEquals("\u03D1", htmlCodec.decode("&thetasym"));
+        assertEquals("\u03D1X", htmlCodec.decode("&thetasymX"));
+    }
+
+    public void testPercentDecode()
+    {
+            assertEquals( "<", percentCodec.decode("%3c") );
+    }
+
+    public void testJavaScriptDecodeBackSlashHex()
+    {
+            assertEquals( "<", javaScriptCodec.decode("\\x3c") );
+    }
+
+    public void testVBScriptDecode()
+    {
+            assertEquals( "<", vbScriptCodec.decode("\"<") );
+    }
+
+    public void testCSSDecode()
+    {
+            assertEquals("<", cssCodec.decode("\\<") );
+    }
+
+    public void testCSSDecodeHexNoSpace()
+    {
+            assertEquals("Axyz", cssCodec.decode("\\41xyz") );
+    }
+
+    public void testCSSDecodeZeroHexNoSpace()
+    {
+            assertEquals("Aabc", cssCodec.decode("\\000041abc") );
+    }
+
+    public void testCSSDecodeHexSpace()
+    {
+            assertEquals("Aabc", cssCodec.decode("\\41 abc") );
+    }
+
+    public void testCSSDecodeNL()
+    {
+            assertEquals("abcxyz", cssCodec.decode("abc\\\nxyz") );
+    }
+
+    public void testCSSDecodeCRNL()
+    {
+            assertEquals("abcxyz", cssCodec.decode("abc\\\r\nxyz") );
+    }
+
+    public void testMySQLANSIDecode()
+    {
+            assertEquals( "\'", mySQLCodecANSI.decode("\'\'") );
+    }
+
+    public void testMySQLStandardDecode()
+    {
+            assertEquals( "<", mySQLCodecStandard.decode("\\<") );
+    }
+
+    public void testOracleDecode()
+    {
+            assertEquals( "\'", oracleCodec.decode("\'\'") );
+    }
+
+    public void testUnixDecode()
+    {
+            assertEquals( "<", unixCodec.decode("\\<") );
+    }
 
         public void testWindowsDecode()
-	{
-        	assertEquals( "<", windowsCodec.decode("^<") );
-	}
-	
-	public void testHtmlDecodeCharLessThan()
-	{
-		Integer value = htmlCodec.decodeCharacter(new PushBackSequenceImpl("&lt;"));
-		assertEquals(new Integer(60), value);
-		StringBuilder sb = new StringBuilder().appendCodePoint(value);
+    {
+            assertEquals( "<", windowsCodec.decode("^<") );
+    }
+
+    public void testHtmlDecodeCharLessThan()
+    {
+        Integer value = htmlCodec.decodeCharacter(new PushBackSequenceImpl("&lt;"));
+        assertEquals(new Integer(60), value);
+        StringBuilder sb = new StringBuilder().appendCodePoint(value);
         assertEquals( LESS_THAN.toString(), sb.toString());
-	}
+    }
 
-	public void testPercentDecodeChar()
-	{
-        	assertEquals( LESS_THAN, percentCodec.decodeCharacter(new PushbackString("%3c") ));
-	}
+    public void testPercentDecodeChar()
+    {
+            assertEquals( LESS_THAN, percentCodec.decodeCharacter(new PushbackString("%3c") ));
+    }
 
         public void testJavaScriptDecodeCharBackSlashHex()
-	{
-        	assertEquals( LESS_THAN, javaScriptCodec.decodeCharacter(new PushbackString("\\x3c") ));
-	}
-        
-	public void testVBScriptDecodeChar()
-	{
-        	assertEquals( LESS_THAN, vbScriptCodec.decodeCharacter(new PushbackString("\"<") ));
-	}
-
-	public void testCSSDecodeCharBackSlashHex()
-	{
-        	assertEquals( LESS_THAN, cssCodec.decodeCharacter(new PushbackString("\\3c") ));
-	}
-
-	public void testMySQLANSIDecodCharQuoteQuote()
-	{
-        	assertEquals( SINGLE_QUOTE, mySQLCodecANSI.decodeCharacter(new PushbackString("\'\'") ));
-	}
+    {
+            assertEquals( LESS_THAN, javaScriptCodec.decodeCharacter(new PushbackString("\\x3c") ));
+    }
+
+    public void testVBScriptDecodeChar()
+    {
+            assertEquals( LESS_THAN, vbScriptCodec.decodeCharacter(new PushbackString("\"<") ));
+    }
+
+    public void testCSSDecodeCharBackSlashHex()
+    {
+            assertEquals( LESS_THAN, cssCodec.decodeCharacter(new PushbackString("\\3c") ));
+    }
+
+    public void testMySQLANSIDecodCharQuoteQuote()
+    {
+            assertEquals( SINGLE_QUOTE, mySQLCodecANSI.decodeCharacter(new PushbackString("\'\'") ));
+    }
 
         public void testMySQLStandardDecodeCharBackSlashLessThan()
-	{
-        	assertEquals( LESS_THAN, mySQLCodecStandard.decodeCharacter(new PushbackString("\\<") ));
-	}
+    {
+            assertEquals( LESS_THAN, mySQLCodecStandard.decodeCharacter(new PushbackString("\\<") ));
+    }
 
-	public void testOracleDecodeCharBackSlashLessThan()
-	{
-        	assertEquals( SINGLE_QUOTE, oracleCodec.decodeCharacter(new PushbackString("\'\'") ));
-	}
+    public void testOracleDecodeCharBackSlashLessThan()
+    {
+            assertEquals( SINGLE_QUOTE, oracleCodec.decodeCharacter(new PushbackString("\'\'") ));
+    }
 
         public void testUnixDecodeCharBackSlashLessThan()
-	{
-        	assertEquals( LESS_THAN, unixCodec.decodeCharacter(new PushbackString("\\<") ));
-	}
+    {
+            assertEquals( LESS_THAN, unixCodec.decodeCharacter(new PushbackString("\\<") ));
+    }
 
         public void testWindowsDecodeCharCarrotLessThan()
-	{
-        	assertEquals( LESS_THAN, windowsCodec.decodeCharacter(new PushbackString("^<") ));
-	}
+    {
+            assertEquals( LESS_THAN, windowsCodec.decodeCharacter(new PushbackString("^<") ));
+    }
 }
diff --git a/src/test/java/org/owasp/esapi/codecs/CSSCodecTest.java b/src/test/java/org/owasp/esapi/codecs/CSSCodecTest.java
index 8d5fb54..ea04aaf 100644
--- a/src/test/java/org/owasp/esapi/codecs/CSSCodecTest.java
+++ b/src/test/java/org/owasp/esapi/codecs/CSSCodecTest.java
@@ -5,29 +5,29 @@ import static org.junit.Assert.assertEquals;
 import org.junit.Test;
 
 public class CSSCodecTest {
-	private static final char[] IMMUNE_STUB = new char[0];
-	/** Unit In Test*/
-	private CSSCodec uit = new CSSCodec();
-	
-	@Test
+    private static final char[] IMMUNE_STUB = new char[0];
+    /** Unit In Test*/
+    private CSSCodec uit = new CSSCodec();
+
+    @Test
     public void testCSSTripletLeadString() {
-    	assertEquals("rgb(255,255,255)\\21 ", uit.encode(IMMUNE_STUB, "rgb(255,255,255)!"));
-    	assertEquals("rgb(25%,25%,25%)\\21 ", uit.encode(IMMUNE_STUB, "rgb(25%,25%,25%)!"));
+        assertEquals("rgb(255,255,255)\\21 ", uit.encode(IMMUNE_STUB, "rgb(255,255,255)!"));
+        assertEquals("rgb(25%,25%,25%)\\21 ", uit.encode(IMMUNE_STUB, "rgb(25%,25%,25%)!"));
     }
-	@Test
+    @Test
     public void testCSSTripletTailString() {
-    	assertEquals("\\24 field\\3d rgb(255,255,255)\\21 ", uit.encode(IMMUNE_STUB, "$field=rgb(255,255,255)!"));
-    	assertEquals("\\24 field\\3d rgb(25%,25%,25%)\\21 ", uit.encode(IMMUNE_STUB, "$field=rgb(25%,25%,25%)!"));
+        assertEquals("\\24 field\\3d rgb(255,255,255)\\21 ", uit.encode(IMMUNE_STUB, "$field=rgb(255,255,255)!"));
+        assertEquals("\\24 field\\3d rgb(25%,25%,25%)\\21 ", uit.encode(IMMUNE_STUB, "$field=rgb(25%,25%,25%)!"));
     }
-	@Test
+    @Test
     public void testCSSTripletStringPart() {
-    	assertEquals("\\24 field\\3d rgb(255,255,255)\\21 ", uit.encode(IMMUNE_STUB, "$field=rgb(255,255,255)!"));
-    	assertEquals("\\24 field\\3d rgb(25%,25%,25%)\\21 ", uit.encode(IMMUNE_STUB, "$field=rgb(25%,25%,25%)!"));
+        assertEquals("\\24 field\\3d rgb(255,255,255)\\21 ", uit.encode(IMMUNE_STUB, "$field=rgb(255,255,255)!"));
+        assertEquals("\\24 field\\3d rgb(25%,25%,25%)\\21 ", uit.encode(IMMUNE_STUB, "$field=rgb(25%,25%,25%)!"));
     }
-	@Test
+    @Test
     public void testCSSTripletStringMultiPart() {
-    	assertEquals("\\24 field\\3d rgb(255,255,255)\\21 \\20 \\24 field\\3d rgb(255,255,255)\\21 ", uit.encode(IMMUNE_STUB, "$field=rgb(255,255,255)! $field=rgb(255,255,255)!"));
-    	assertEquals("\\24 field\\3d rgb(25%,25%,25%)\\21 \\20 \\24 field\\3d rgb(25%,25%,25%)\\21 ", uit.encode(IMMUNE_STUB, "$field=rgb(25%,25%,25%)! $field=rgb(25%,25%,25%)!"));
-    	assertEquals("\\24 field\\3d rgb(255,255,255)\\21 \\20 \\24 field\\3d rgb(25%,25%,25%)\\21 ", uit.encode(IMMUNE_STUB, "$field=rgb(255,255,255)! $field=rgb(25%,25%,25%)!"));
+        assertEquals("\\24 field\\3d rgb(255,255,255)\\21 \\20 \\24 field\\3d rgb(255,255,255)\\21 ", uit.encode(IMMUNE_STUB, "$field=rgb(255,255,255)! $field=rgb(255,255,255)!"));
+        assertEquals("\\24 field\\3d rgb(25%,25%,25%)\\21 \\20 \\24 field\\3d rgb(25%,25%,25%)\\21 ", uit.encode(IMMUNE_STUB, "$field=rgb(25%,25%,25%)! $field=rgb(25%,25%,25%)!"));
+        assertEquals("\\24 field\\3d rgb(255,255,255)\\21 \\20 \\24 field\\3d rgb(25%,25%,25%)\\21 ", uit.encode(IMMUNE_STUB, "$field=rgb(255,255,255)! $field=rgb(25%,25%,25%)!"));
     }
 }
diff --git a/src/test/java/org/owasp/esapi/codecs/CodecImmunityTest.java b/src/test/java/org/owasp/esapi/codecs/CodecImmunityTest.java
index 9a3b880..ef7d9a0 100644
--- a/src/test/java/org/owasp/esapi/codecs/CodecImmunityTest.java
+++ b/src/test/java/org/owasp/esapi/codecs/CodecImmunityTest.java
@@ -17,7 +17,7 @@ import org.owasp.esapi.codecs.*;
 /**
  * Parameterized test to verify that the Immunity parameter for a codec
  * encode/decode event works as expected on a series of special characters.
- *  
+ *
  * @author jeremiah.j.stacey@gmail.com
  * @since 2.1.0.1
  *
@@ -100,7 +100,7 @@ public class CodecImmunityTest {
     }
 
     private static Collection<Object[]> fullCharacterCodecValidation(Collection<AbstractCodec> codecs) {
-        char[] holyCowTesting = StringUtilities.union(EncoderConstants.CHAR_ALPHANUMERICS, EncoderConstants.CHAR_SPECIALS); 
+        char[] holyCowTesting = StringUtilities.union(EncoderConstants.CHAR_ALPHANUMERICS, EncoderConstants.CHAR_SPECIALS);
         Collection<Object[]> params = new ArrayList<Object[]>();
         for (Codec codec: codecs) {
             params.addAll(buildImmunitiyValidation(codec, holyCowTesting, "Full_ALPHA_AND_SPECIALS"));
@@ -118,7 +118,7 @@ public class CodecImmunityTest {
         this.string = toTest;
         /**
          * The Immunity character array is every character in the String we're testing.
-         * 
+         *
          */
         this.immunityList = toTest.toCharArray();
     }
diff --git a/src/test/java/org/owasp/esapi/codecs/HTMLEntityCodecTest.java b/src/test/java/org/owasp/esapi/codecs/HTMLEntityCodecTest.java
index c810316..070e28a 100644
--- a/src/test/java/org/owasp/esapi/codecs/HTMLEntityCodecTest.java
+++ b/src/test/java/org/owasp/esapi/codecs/HTMLEntityCodecTest.java
@@ -5,47 +5,47 @@ import static org.junit.Assert.assertEquals;
 import org.junit.Test;
 
 public class HTMLEntityCodecTest {
-	Codec<Integer> codec = new HTMLEntityCodec();
-	
-	@Test
-	public void testEntityDecoding(){
-		assertEquals("<", codec.decode("&lt;"));
+    Codec<Integer> codec = new HTMLEntityCodec();
+
+    @Test
+    public void testEntityDecoding(){
+        assertEquals("<", codec.decode("&lt;"));
         assertEquals( "<", codec.decode("&LT"));
         assertEquals( "<", codec.decode("&lt;"));
         assertEquals( "<", codec.decode("&LT;"));
-	}
-	
-	@Test
-	public void test32BitCJK(){
-		String s = "𡘾𦴩𥻂";
-		String expected = "&#x2163e;&#x26d29;&#x25ec2;";
-		String bad = "&#xd845;&#xde3e;&#xd85b;&#xdd29;&#xd857;&#xdec2;";
-		assertEquals(false, expected.equals(bad));
-		assertEquals(expected, codec.encode(new char[0], s));
-	}
-	
-	@Test
-	public void test32BitCJKMixedWithBmp(){
-		String s = "𡘾𦴩<𥻂";
-		String expected = "&#x2163e;&#x26d29;&lt;&#x25ec2;";
-		String bad = "&#xd845;&#xde3e;&#xd85b;&#xdd29;&#xd857;&#xdec2;";
-		assertEquals(false, expected.equals(bad));
-		assertEquals(expected, codec.encode(new char[0], s));
-	}
-	
-	@Test
-	public void testDecodeforChars(){
-		String s = "!@$%()=+{}[]";
-		String expected = "!@$%()=+{}[]";
-		assertEquals(expected, codec.decode(s));
-	}
-	
-	@Test
-	public void testMixedBmpAndNonBmp(){
-		String nonBMP = new String(new int[]{0x2f804}, 0, 1);
-		String bmp = "<a";
-		String expected = "&lt;a&#x2f804;";
-		String input = bmp + nonBMP;
-		assertEquals(expected, codec.encode(new char[0], input));
-	}
+    }
+
+    @Test
+    public void test32BitCJK(){
+        String s = "𡘾𦴩𥻂";
+        String expected = "&#x2163e;&#x26d29;&#x25ec2;";
+        String bad = "&#xd845;&#xde3e;&#xd85b;&#xdd29;&#xd857;&#xdec2;";
+        assertEquals(false, expected.equals(bad));
+        assertEquals(expected, codec.encode(new char[0], s));
+    }
+
+    @Test
+    public void test32BitCJKMixedWithBmp(){
+        String s = "𡘾𦴩<𥻂";
+        String expected = "&#x2163e;&#x26d29;&lt;&#x25ec2;";
+        String bad = "&#xd845;&#xde3e;&#xd85b;&#xdd29;&#xd857;&#xdec2;";
+        assertEquals(false, expected.equals(bad));
+        assertEquals(expected, codec.encode(new char[0], s));
+    }
+
+    @Test
+    public void testDecodeforChars(){
+        String s = "!@$%()=+{}[]";
+        String expected = "!@$%()=+{}[]";
+        assertEquals(expected, codec.decode(s));
+    }
+
+    @Test
+    public void testMixedBmpAndNonBmp(){
+        String nonBMP = new String(new int[]{0x2f804}, 0, 1);
+        String bmp = "<a";
+        String expected = "&lt;a&#x2f804;";
+        String input = bmp + nonBMP;
+        assertEquals(expected, codec.encode(new char[0], input));
+    }
 }
diff --git a/src/test/java/org/owasp/esapi/codecs/HashTrieTest.java b/src/test/java/org/owasp/esapi/codecs/HashTrieTest.java
index b2db910..9b35a04 100644
--- a/src/test/java/org/owasp/esapi/codecs/HashTrieTest.java
+++ b/src/test/java/org/owasp/esapi/codecs/HashTrieTest.java
@@ -13,201 +13,201 @@ import junit.framework.TestSuite;
 
 public class HashTrieTest extends TestCase
 {
-	private static final Class<HashTrieTest> CLASS = HashTrieTest.class;
-
-	public HashTrieTest(String testName)
-	{
-		super(testName);
-	}
-
-	public void testSingleInsertLookup()
-	{
-		HashTrie<Boolean> trie = new HashTrie<Boolean>();
-
-		trie.put("true", Boolean.TRUE);
-		assertEquals(Boolean.TRUE, trie.get("true"));
-		assertNull(trie.get("not there"));
-		assertNull(trie.get("tru"));
-		assertNull(trie.get("trueX"));
-		assertEquals("true".length(), trie.getMaxKeyLength());
-	}
-
-	public void testEmpty()
-	{
-		HashTrie<Boolean> trie = new HashTrie<Boolean>();
-		assertNull(trie.get("true"));
-		assertNull(trie.get("false"));
-		assertNull(trie.get(""));
-		assertTrue(trie.getMaxKeyLength()<0);
-	}
-
-	public void testTwoInsertLookup()
-	{
-		HashTrie<Boolean> trie = new HashTrie<Boolean>();
-
-		trie.put("true", Boolean.TRUE);
-		trie.put("false", Boolean.FALSE);
-		assertEquals(Boolean.TRUE, trie.get("true"));
-		assertEquals(Boolean.FALSE, trie.get("false"));
-		assertEquals("false".length(),trie.getMaxKeyLength());
-	}
-
-	public void testMatchingPrefix()
-	{
-		HashTrie<Boolean> trie = new HashTrie<Boolean>();
-
-		trie.put("pretrue", Boolean.TRUE);
-		trie.put("prefalse", Boolean.FALSE);
-		assertEquals(Boolean.TRUE, trie.get("pretrue"));
-		assertEquals(Boolean.FALSE, trie.get("prefalse"));
-	}
-
-	public void testPrefixIsValidKey()
-	{
-		HashTrie<Boolean> trie = new HashTrie<Boolean>();
-
-		trie.put("pre", Boolean.TRUE);
-		trie.put("prefalse", Boolean.FALSE);
-		assertEquals(Boolean.TRUE, trie.get("pre"));
-		assertEquals(Boolean.FALSE, trie.get("prefalse"));
-	}
-
-	public void testDuplicateAdd()
-	{
-		HashTrie<Boolean> trie = new HashTrie<Boolean>();
-
-		assertNull(trie.put("dup", Boolean.TRUE));
-		assertTrue(trie.put("dup", Boolean.FALSE));
-		assertFalse(trie.get("dup"));
-	}
-
-	public void testTwoInsertLongestLookup()
-	{
-		HashTrie<Boolean> trie = new HashTrie<Boolean>();
-		Entry<CharSequence,Boolean> entry;
-
-		trie.put("true", Boolean.TRUE);
-		trie.put("true idea", Boolean.TRUE);
-		trie.put("false", Boolean.FALSE);
-
-		assertNotNull((entry = trie.getLongestMatch("true")));
-		assertEquals("true", entry.getKey());
-		assertTrue(entry.getValue());
-
-		assertNotNull((entry = trie.getLongestMatch("false")));
-		assertEquals("false", entry.getKey());
-		assertFalse(entry.getValue());
-
-		assertNotNull((entry = trie.getLongestMatch("truer")));
-		assertEquals("true", entry.getKey());
-		assertTrue(entry.getValue());
-
-		assertNotNull((entry = trie.getLongestMatch("true to form")));
-		assertEquals("true", entry.getKey());
-		assertTrue(entry.getValue());
-
-		assertNotNull((entry = trie.getLongestMatch("false result")));
-		assertEquals("false", entry.getKey());
-		assertFalse(entry.getValue());
-
-		assertNull(trie.getLongestMatch("not there"));
-		assertNull(trie.getLongestMatch("tru"));
-		assertNull(trie.getLongestMatch("fals"));
-	}
-
-	public void testContainsKey()
-	{
-		HashTrie<Boolean> trie = new HashTrie<Boolean>();
-
-		trie.put("true", Boolean.TRUE);
-		trie.put("false", Boolean.FALSE);
-		assertTrue(trie.containsKey("true"));
-		assertTrue(trie.containsKey("false"));
-		assertFalse(trie.containsKey("not there"));
-	}
-
-	public void testContainsValue()
-	{
-		HashTrie<Integer> trie = new HashTrie<Integer>();
-
-		trie.put("one", 1);
-		trie.put("two", 2);
-		assertTrue(trie.containsValue(1));
-		assertTrue(trie.containsValue(2));
-		assertFalse(trie.containsValue(3));
-	}
-
-	public void testKeySet()
-	{
-		HashTrie<Boolean> trie = new HashTrie<Boolean>();
-		HashSet<CharSequence> expected = new HashSet<CharSequence>(2);
-
-		expected.add("true");
-		expected.add("false");
-		trie.put("true", Boolean.TRUE);
-		trie.put("false", Boolean.FALSE);
-		assertEquals(expected,trie.keySet());
-	}
-
-	public void testValues()
-	{
-		HashTrie<Boolean> trie = new HashTrie<Boolean>();
-		ArrayList<Boolean> actual;
-		ArrayList<Boolean> expected = new ArrayList<Boolean>(2);
-
-		expected.add(Boolean.TRUE);
-		expected.add(Boolean.FALSE);
-		trie.put("true", Boolean.TRUE);
-		trie.put("false", Boolean.FALSE);
-		actual = new ArrayList<Boolean>(trie.values());
-		Collections.sort(actual);
-		Collections.sort(expected);
-		assertEquals(expected,actual);
-	}
-
-	public void testEntrySet()
-	{
-		HashTrie<Boolean> trie = new HashTrie<Boolean>();
-		HashMap<CharSequence,Boolean> equivMap = new HashMap<CharSequence,Boolean>(2);
-
-		equivMap.put("true",Boolean.TRUE);
-		equivMap.put("false",Boolean.FALSE);
-		trie.put("true", Boolean.TRUE);
-		trie.put("false", Boolean.FALSE);
-		assertEquals(equivMap.entrySet(),trie.entrySet());
-	}
-
-	public void testEquals()
-	{
-		HashTrie<Boolean> trie = new HashTrie<Boolean>();
-		HashMap<CharSequence,Boolean> equivMap = new HashMap<CharSequence,Boolean>(2);
-
-		equivMap.put("true",Boolean.TRUE);
-		equivMap.put("false",Boolean.FALSE);
-		trie.put("true", Boolean.TRUE);
-		trie.put("false", Boolean.FALSE);
-		assertTrue(trie.equals(equivMap));
-	}
-
-	public void testHashCode()
-	{
-		HashTrie<Boolean> trie = new HashTrie<Boolean>();
-		HashMap<CharSequence,Boolean> equivMap = new HashMap<CharSequence,Boolean>(2);
-
-		equivMap.put("true",Boolean.TRUE);
-		equivMap.put("false",Boolean.FALSE);
-		trie.put("true", Boolean.TRUE);
-		trie.put("false", Boolean.FALSE);
-		assertEquals(equivMap.hashCode(),trie.hashCode());
-	}
-
-	/**
-	 * Create a test suite with just this test.
-	 * @return A test swuite with just this test.
-	 */
-	public static Test suite()
-	{
-		TestSuite suite = new TestSuite(CLASS);
-		return suite;
-	}
+    private static final Class<HashTrieTest> CLASS = HashTrieTest.class;
+
+    public HashTrieTest(String testName)
+    {
+        super(testName);
+    }
+
+    public void testSingleInsertLookup()
+    {
+        HashTrie<Boolean> trie = new HashTrie<Boolean>();
+
+        trie.put("true", Boolean.TRUE);
+        assertEquals(Boolean.TRUE, trie.get("true"));
+        assertNull(trie.get("not there"));
+        assertNull(trie.get("tru"));
+        assertNull(trie.get("trueX"));
+        assertEquals("true".length(), trie.getMaxKeyLength());
+    }
+
+    public void testEmpty()
+    {
+        HashTrie<Boolean> trie = new HashTrie<Boolean>();
+        assertNull(trie.get("true"));
+        assertNull(trie.get("false"));
+        assertNull(trie.get(""));
+        assertTrue(trie.getMaxKeyLength()<0);
+    }
+
+    public void testTwoInsertLookup()
+    {
+        HashTrie<Boolean> trie = new HashTrie<Boolean>();
+
+        trie.put("true", Boolean.TRUE);
+        trie.put("false", Boolean.FALSE);
+        assertEquals(Boolean.TRUE, trie.get("true"));
+        assertEquals(Boolean.FALSE, trie.get("false"));
+        assertEquals("false".length(),trie.getMaxKeyLength());
+    }
+
+    public void testMatchingPrefix()
+    {
+        HashTrie<Boolean> trie = new HashTrie<Boolean>();
+
+        trie.put("pretrue", Boolean.TRUE);
+        trie.put("prefalse", Boolean.FALSE);
+        assertEquals(Boolean.TRUE, trie.get("pretrue"));
+        assertEquals(Boolean.FALSE, trie.get("prefalse"));
+    }
+
+    public void testPrefixIsValidKey()
+    {
+        HashTrie<Boolean> trie = new HashTrie<Boolean>();
+
+        trie.put("pre", Boolean.TRUE);
+        trie.put("prefalse", Boolean.FALSE);
+        assertEquals(Boolean.TRUE, trie.get("pre"));
+        assertEquals(Boolean.FALSE, trie.get("prefalse"));
+    }
+
+    public void testDuplicateAdd()
+    {
+        HashTrie<Boolean> trie = new HashTrie<Boolean>();
+
+        assertNull(trie.put("dup", Boolean.TRUE));
+        assertTrue(trie.put("dup", Boolean.FALSE));
+        assertFalse(trie.get("dup"));
+    }
+
+    public void testTwoInsertLongestLookup()
+    {
+        HashTrie<Boolean> trie = new HashTrie<Boolean>();
+        Entry<CharSequence,Boolean> entry;
+
+        trie.put("true", Boolean.TRUE);
+        trie.put("true idea", Boolean.TRUE);
+        trie.put("false", Boolean.FALSE);
+
+        assertNotNull((entry = trie.getLongestMatch("true")));
+        assertEquals("true", entry.getKey());
+        assertTrue(entry.getValue());
+
+        assertNotNull((entry = trie.getLongestMatch("false")));
+        assertEquals("false", entry.getKey());
+        assertFalse(entry.getValue());
+
+        assertNotNull((entry = trie.getLongestMatch("truer")));
+        assertEquals("true", entry.getKey());
+        assertTrue(entry.getValue());
+
+        assertNotNull((entry = trie.getLongestMatch("true to form")));
+        assertEquals("true", entry.getKey());
+        assertTrue(entry.getValue());
+
+        assertNotNull((entry = trie.getLongestMatch("false result")));
+        assertEquals("false", entry.getKey());
+        assertFalse(entry.getValue());
+
+        assertNull(trie.getLongestMatch("not there"));
+        assertNull(trie.getLongestMatch("tru"));
+        assertNull(trie.getLongestMatch("fals"));
+    }
+
+    public void testContainsKey()
+    {
+        HashTrie<Boolean> trie = new HashTrie<Boolean>();
+
+        trie.put("true", Boolean.TRUE);
+        trie.put("false", Boolean.FALSE);
+        assertTrue(trie.containsKey("true"));
+        assertTrue(trie.containsKey("false"));
+        assertFalse(trie.containsKey("not there"));
+    }
+
+    public void testContainsValue()
+    {
+        HashTrie<Integer> trie = new HashTrie<Integer>();
+
+        trie.put("one", 1);
+        trie.put("two", 2);
+        assertTrue(trie.containsValue(1));
+        assertTrue(trie.containsValue(2));
+        assertFalse(trie.containsValue(3));
+    }
+
+    public void testKeySet()
+    {
+        HashTrie<Boolean> trie = new HashTrie<Boolean>();
+        HashSet<CharSequence> expected = new HashSet<CharSequence>(2);
+
+        expected.add("true");
+        expected.add("false");
+        trie.put("true", Boolean.TRUE);
+        trie.put("false", Boolean.FALSE);
+        assertEquals(expected,trie.keySet());
+    }
+
+    public void testValues()
+    {
+        HashTrie<Boolean> trie = new HashTrie<Boolean>();
+        ArrayList<Boolean> actual;
+        ArrayList<Boolean> expected = new ArrayList<Boolean>(2);
+
+        expected.add(Boolean.TRUE);
+        expected.add(Boolean.FALSE);
+        trie.put("true", Boolean.TRUE);
+        trie.put("false", Boolean.FALSE);
+        actual = new ArrayList<Boolean>(trie.values());
+        Collections.sort(actual);
+        Collections.sort(expected);
+        assertEquals(expected,actual);
+    }
+
+    public void testEntrySet()
+    {
+        HashTrie<Boolean> trie = new HashTrie<Boolean>();
+        HashMap<CharSequence,Boolean> equivMap = new HashMap<CharSequence,Boolean>(2);
+
+        equivMap.put("true",Boolean.TRUE);
+        equivMap.put("false",Boolean.FALSE);
+        trie.put("true", Boolean.TRUE);
+        trie.put("false", Boolean.FALSE);
+        assertEquals(equivMap.entrySet(),trie.entrySet());
+    }
+
+    public void testEquals()
+    {
+        HashTrie<Boolean> trie = new HashTrie<Boolean>();
+        HashMap<CharSequence,Boolean> equivMap = new HashMap<CharSequence,Boolean>(2);
+
+        equivMap.put("true",Boolean.TRUE);
+        equivMap.put("false",Boolean.FALSE);
+        trie.put("true", Boolean.TRUE);
+        trie.put("false", Boolean.FALSE);
+        assertTrue(trie.equals(equivMap));
+    }
+
+    public void testHashCode()
+    {
+        HashTrie<Boolean> trie = new HashTrie<Boolean>();
+        HashMap<CharSequence,Boolean> equivMap = new HashMap<CharSequence,Boolean>(2);
+
+        equivMap.put("true",Boolean.TRUE);
+        equivMap.put("false",Boolean.FALSE);
+        trie.put("true", Boolean.TRUE);
+        trie.put("false", Boolean.FALSE);
+        assertEquals(equivMap.hashCode(),trie.hashCode());
+    }
+
+    /**
+     * Create a test suite with just this test.
+     * @return A test swuite with just this test.
+     */
+    public static Test suite()
+    {
+        TestSuite suite = new TestSuite(CLASS);
+        return suite;
+    }
 }
diff --git a/src/test/java/org/owasp/esapi/codecs/MySQLCodecTest.java b/src/test/java/org/owasp/esapi/codecs/MySQLCodecTest.java
index 04e5785..f6cca06 100644
--- a/src/test/java/org/owasp/esapi/codecs/MySQLCodecTest.java
+++ b/src/test/java/org/owasp/esapi/codecs/MySQLCodecTest.java
@@ -17,7 +17,7 @@ import org.powermock.reflect.Whitebox;
 /**
  * Tests to show {@link MySQLCodec} with {@link Mode#ANSI}
  * comply with the OWASP Escaping recommendations
- * 
+ *
  * https://www.owasp.org/index.php/SQL_Injection_Prevention_Cheat_Sheet#MySQL_Escaping
  *
  */
@@ -65,7 +65,7 @@ public class MySQLCodecTest {
     /**
      * ANSI
      * Test showing that for characters up to 256, the only encoded value is the single tick.
-     * 
+     *
      * when the single tick is encoded, it is updated to be double tick.  All other characters remain unchanged.
      */
     @Test
@@ -93,7 +93,7 @@ public class MySQLCodecTest {
     public void testAnsiEncodeWithImmuneSet() {
         //The only value that is encoded is single tick. The immunity list does not impact normal capability in ANSI mode
         char[] immuneChars = new char[] {15, 91,150, 255};
-        
+
         for (char refChar : immuneChars) {
             int ref = refChar;
             String charAsString = "" + refChar;
@@ -165,12 +165,12 @@ public class MySQLCodecTest {
 
         }
     }
-    
+
     @Test
     public void testStandardEncodeWithImmuneSet() {
         //These values normally fall under the encodeNonAlphaNumeric test content.
         char[] immuneChars = new char[] {15, 91,150, 255};
-        
+
         for (char refChar : immuneChars) {
             int ref = refChar;
             String charAsString = "" + refChar;
@@ -199,7 +199,7 @@ public class MySQLCodecTest {
             Matcher<String> encodeExpect = new IsEqual<>(expected);
             Matcher<String> decodeExpect = new IsEqual<>(charAsString);
             errorCollector.checkThat(encodeMsg, uitMySqlStandard.encode(EMPTY_CHAR_ARRAY, charAsString), encodeExpect);
-            errorCollector.checkThat(decodeMsg, uitMySqlStandard.decode(expected), decodeExpect);   
+            errorCollector.checkThat(decodeMsg, uitMySqlStandard.decode(expected), decodeExpect);
         }
     }
 
@@ -210,16 +210,16 @@ public class MySQLCodecTest {
     public void testAnsiDecodePushbackSequenceNullFirstElementReturnsNull() {
         PushbackSequence<Character> mockPushback = Mockito.mock(PushbackSequence.class);
         Mockito.when(mockPushback.next()).thenReturn(null);
-        
+
         Character decChar = uitAnsi.decodeCharacter(mockPushback);
         Assert.assertNull(decChar);
-        
+
         Mockito.verify(mockPushback, Mockito.times(1)).mark();
         Mockito.verify(mockPushback, Mockito.times(1)).next();
         Mockito.verify(mockPushback, Mockito.times(1)).reset();
-        
+
     }
-    
+
     /**
      * If the first character is a single tick, and the second character is null, null is expected
      */
@@ -227,16 +227,16 @@ public class MySQLCodecTest {
     public void testAnsiDecodePushbackSequenceNullSecondElementReturnsNull() {
         PushbackSequence<Character> mockPushback = Mockito.mock(PushbackSequence.class);
         Mockito.when(mockPushback.next()).thenReturn('\'').thenReturn(null);
-        
+
         Character decChar = uitAnsi.decodeCharacter(mockPushback);
         Assert.assertNull(decChar);
-        
+
         Mockito.verify(mockPushback, Mockito.times(1)).mark();
         Mockito.verify(mockPushback, Mockito.times(2)).next();
         Mockito.verify(mockPushback, Mockito.times(1)).reset();
-        
+
     }
-    
+
     /**
      * If the first character is a single tick and the second character is NOT a single tick (escaped tick), then null is expected.
      */
@@ -244,14 +244,14 @@ public class MySQLCodecTest {
     public void testAnsiDecodePushbackSequenceNonTickSecondElmentReturnsNull() {
         PushbackSequence<Character> mockPushback = Mockito.mock(PushbackSequence.class);
         Mockito.when(mockPushback.next()).thenReturn('\'').thenReturn('A');
-        
+
         Character decChar = uitAnsi.decodeCharacter(mockPushback);
         Assert.assertNull(decChar);
-        
+
         Mockito.verify(mockPushback, Mockito.times(1)).mark();
         Mockito.verify(mockPushback, Mockito.times(2)).next();
         Mockito.verify(mockPushback, Mockito.times(1)).reset();
-        
+
     }
     /**
      * If two single ticks are read in sequence, a single tick is expected.
@@ -260,14 +260,14 @@ public class MySQLCodecTest {
     public void testAnsiDecodePushbackSequenceReturnsSingleTick() {
         PushbackSequence<Character> mockPushback = Mockito.mock(PushbackSequence.class);
         Mockito.when(mockPushback.next()).thenReturn('\'').thenReturn('\'');
-        
+
         Character decChar = uitAnsi.decodeCharacter(mockPushback);
         Assert.assertEquals('\'', decChar.charValue());
-        
+
         Mockito.verify(mockPushback, Mockito.times(1)).mark();
         Mockito.verify(mockPushback, Mockito.times(2)).next();
         Mockito.verify(mockPushback, Mockito.times(0)).reset();
-        
+
     }
 
     /**
@@ -277,16 +277,16 @@ public class MySQLCodecTest {
     public void testAnsiDecodePushbackSequenceNonTickFirstElementReturnsNull() {
         PushbackSequence<Character> mockPushback = Mockito.mock(PushbackSequence.class);
         Mockito.when(mockPushback.next()).thenReturn('A');
-        
+
         Character decChar = uitAnsi.decodeCharacter(mockPushback);
         Assert.assertNull(decChar);
-        
+
         Mockito.verify(mockPushback, Mockito.times(1)).mark();
         Mockito.verify(mockPushback, Mockito.times(1)).next();
         Mockito.verify(mockPushback, Mockito.times(1)).reset();
-        
+
     }
-    
+
     /**
      * If the first character is null, null is expected
      */
@@ -294,14 +294,14 @@ public class MySQLCodecTest {
     public void testStandardDecodePushbackSequenceNullFirstElementReturnsNull() {
         PushbackSequence<Character> mockPushback = Mockito.mock(PushbackSequence.class);
         Mockito.when(mockPushback.next()).thenReturn(null);
-        
+
         Character decChar = uitMySqlStandard.decodeCharacter(mockPushback);
         Assert.assertNull(decChar);
-        
+
         Mockito.verify(mockPushback, Mockito.times(1)).mark();
         Mockito.verify(mockPushback, Mockito.times(1)).next();
         Mockito.verify(mockPushback, Mockito.times(1)).reset();
-        
+
     }
     /**
      * If the first character is a backslash, and the second character is null, null is expected
@@ -310,37 +310,37 @@ public class MySQLCodecTest {
     public void testStandardDecodePushbackSequenceNullSecondElementReturnsNull() {
         PushbackSequence<Character> mockPushback = Mockito.mock(PushbackSequence.class);
         Mockito.when(mockPushback.next()).thenReturn('\\').thenReturn(null);
-        
+
         Character decChar = uitMySqlStandard.decodeCharacter(mockPushback);
         Assert.assertNull(decChar);
-        
+
         Mockito.verify(mockPushback, Mockito.times(1)).mark();
         Mockito.verify(mockPushback, Mockito.times(2)).next();
         Mockito.verify(mockPushback, Mockito.times(1)).reset();
-        
+
     }
-    
+
     @Test
     public void testCreateAnsiByInt() {
         MySQLCodec codec = new MySQLCodec(MySQLCodec.ANSI_MODE);
         Object configMode = Whitebox.getInternalState(codec, "mode");
         Assert.assertEquals(Mode.ANSI, configMode);
     }
-    
+
     @Test
     public void testCreateStandardByInt() {
         MySQLCodec codec = new MySQLCodec(MySQLCodec.MYSQL_MODE);
         Object configMode = Whitebox.getInternalState(codec, "mode");
         Assert.assertEquals(Mode.STANDARD, configMode);
     }
-    
+
     @Test
     public void testCreateUnsupportedModeByInt() {
         exEx.expect(IllegalArgumentException.class);
         String message = String.format("No Mode for %s. Valid references are MySQLStandard: %s or ANSI: %s", Integer.MIN_VALUE, MySQLCodec.MYSQL_MODE, MySQLCodec.ANSI_MODE);
         exEx.expectMessage(message);
         new MySQLCodec(Integer.MIN_VALUE);
-       
+
     }
     private static class InclusiveRangePair {
         private final int upperInclusive;
diff --git a/src/test/java/org/owasp/esapi/codecs/PercentCodecTest.java b/src/test/java/org/owasp/esapi/codecs/PercentCodecTest.java
index c1b2b7a..5cc9f26 100644
--- a/src/test/java/org/owasp/esapi/codecs/PercentCodecTest.java
+++ b/src/test/java/org/owasp/esapi/codecs/PercentCodecTest.java
@@ -5,12 +5,12 @@ import static org.junit.Assert.assertEquals;
 import org.junit.Test;
 
 public class PercentCodecTest {
-	
-	@Test
-	public void testPercentDecode(){
-		Codec codec = new PercentCodec();
-		
-		String expected = " ";
-		assertEquals(expected, codec.decode("%20"));
-	}
+
+    @Test
+    public void testPercentDecode(){
+        Codec codec = new PercentCodec();
+
+        String expected = " ";
+        assertEquals(expected, codec.decode("%20"));
+    }
 }
diff --git a/src/test/java/org/owasp/esapi/codecs/PushBackStringTest.java b/src/test/java/org/owasp/esapi/codecs/PushBackStringTest.java
index 2a4ed84..1f7ad61 100644
--- a/src/test/java/org/owasp/esapi/codecs/PushBackStringTest.java
+++ b/src/test/java/org/owasp/esapi/codecs/PushBackStringTest.java
@@ -6,36 +6,36 @@ import org.junit.Test;
 
 public class PushBackStringTest {
 
-	@Test
-	public void testPushbackString() {
-		PushbackSequence<Character> pbs = new PushbackString("012345");
-		
-		pbs.mark();
-		assertEquals(0, pbs.index());
-		Character first = pbs.next();
-		
-		System.out.println("0x" + Integer.toHexString(first));
-		
-		assertEquals("0", new StringBuilder().appendCodePoint(first).toString());
-	}
-	
-	@Test
-	public void testPushbackSequence() {
-		AbstractPushbackSequence<Integer> pbs = new PushBackSequenceImpl("&#49;2345");
-		
-		pbs.mark();
-		assertEquals(0, pbs.index());
-		Integer first = pbs.next();
-		
-		System.out.println("0x" + Integer.toHexString(first));
-		
-		assertEquals("&", new StringBuilder().appendCodePoint(first).toString());
-		
-		Integer second = pbs.next();
-		
-		if(second == '#'){
-			System.out.printf("[%d]:[%d]\n", second, (int) '#');
-			
-		}
-	}
+    @Test
+    public void testPushbackString() {
+        PushbackSequence<Character> pbs = new PushbackString("012345");
+
+        pbs.mark();
+        assertEquals(0, pbs.index());
+        Character first = pbs.next();
+
+        System.out.println("0x" + Integer.toHexString(first));
+
+        assertEquals("0", new StringBuilder().appendCodePoint(first).toString());
+    }
+
+    @Test
+    public void testPushbackSequence() {
+        AbstractPushbackSequence<Integer> pbs = new PushBackSequenceImpl("&#49;2345");
+
+        pbs.mark();
+        assertEquals(0, pbs.index());
+        Integer first = pbs.next();
+
+        System.out.println("0x" + Integer.toHexString(first));
+
+        assertEquals("&", new StringBuilder().appendCodePoint(first).toString());
+
+        Integer second = pbs.next();
+
+        if(second == '#'){
+            System.out.printf("[%d]:[%d]\n", second, (int) '#');
+
+        }
+    }
 }
diff --git a/src/test/java/org/owasp/esapi/codecs/XMLEntityCodecTest.java b/src/test/java/org/owasp/esapi/codecs/XMLEntityCodecTest.java
index 10424c6..801d33f 100644
--- a/src/test/java/org/owasp/esapi/codecs/XMLEntityCodecTest.java
+++ b/src/test/java/org/owasp/esapi/codecs/XMLEntityCodecTest.java
@@ -1,15 +1,15 @@
 /**
  * OWASP Enterprise Security API (ESAPI)
- * 
+ *
  * This file is part of the Open Web Application Security Project (OWASP)
  * Enterprise Security API (ESAPI) project. For details, please see
  * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
  *
  * Copyright (c) 2009 - The OWASP Foundation
- * 
+ *
  * The ESAPI is published by OWASP under the BSD license. You should read and accept the
  * LICENSE before you use, modify, and/or redistribute this software.
- * 
+ *
  */
 package org.owasp.esapi.codecs;
 
@@ -25,229 +25,229 @@ import junit.framework.TestSuite;
 
 public class XMLEntityCodecTest extends TestCase
 {
-	private static final char[] EMPTY_CHAR_ARRAY = new char[0];
-	private static final String ALPHA_NUMERIC_STR = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
-	private static final String UNENCODED_STR = ALPHA_NUMERIC_STR + " \t";
-	private static final Set<Character> UNENCODED_SET = CollectionsUtil.strToUnmodifiableSet(UNENCODED_STR);
-	private XMLEntityCodec codec = null;
-
-	protected void setUp()
-	{
-		codec = new XMLEntityCodec();
-	}
-
-	protected void tearDown()
-	{
-		codec = null;
-	}
-
-	public void testEncodeUnencoded()
-	{
-		StringBuilder sb = new StringBuilder("AB_YZ");
-		String str;
-
-		for(char ch : UNENCODED_SET)
-		{
-			sb.setCharAt(2,ch);
-			str = sb.toString();
-			assertEquals(str, codec.encode(EMPTY_CHAR_ARRAY, str));
-		}
-	}
-
-	public void testEncodeOthers()
-	{
-		StringBuilder inSb = new StringBuilder("AB_YZ");
-		StringBuilder outSb = new StringBuilder("AB&#x");
-		String in;
-		String expected;
-		String result;
-		int outSbBaseLen = outSb.length();
-		String out;
-
-		for(int c=Character.MIN_VALUE;c<=Character.MAX_VALUE;c++)
-		{
-			char ch = (char)c;
-			if(UNENCODED_SET.contains(ch))
-				continue;
-			inSb.setCharAt(2,ch);
-			in = inSb.toString();
-			outSb.append(Integer.toHexString(c));
-			outSb.append(";YZ");
-			expected = outSb.toString();
-			result = codec.encode(EMPTY_CHAR_ARRAY,in);
-			assertEquals(expected, result);
-			outSb.setLength(outSbBaseLen);
-		}
-	}
-
-	public void testDecodeUnencoded()
-	{
-		StringBuilder sb = new StringBuilder("AB_YZ");
-		String str;
-
-		for(char ch : UNENCODED_SET)
-		{
-			sb.setCharAt(2,ch);
-			str = sb.toString();
-			assertEquals(str, codec.decode(str));
-		}
-	}
-
-	public void testDecodeHex()
-	{
-		StringBuilder expectedSb = new StringBuilder("AB_YZ");
-		StringBuilder inSb = new StringBuilder("AB&#x");
-		String in;
-		String expected;
-		String result;
-		int inSbBaseLen = inSb.length();
-
-		for(int c=Character.MIN_VALUE;c<=Character.MAX_VALUE;c++)
-		{
-			char ch = (char)c;
-			expectedSb.setCharAt(2,ch);
-			expected = expectedSb.toString();
-			inSb.append(Integer.toHexString(c));
-			inSb.append(";YZ");
-			in = inSb.toString();
-			result = codec.decode(in);
-			assertEquals(expected, result);
-			inSb.setLength(inSbBaseLen);
-		}
-	}
-
-	public void testDecodeDec()
-	{
-		StringBuilder expectedSb = new StringBuilder("AB_YZ");
-		StringBuilder inSb = new StringBuilder("AB&#");
-		String in;
-		String expected;
-		String result;
-		int inSbBaseLen = inSb.length();
-
-		for(int c=Character.MIN_VALUE;c<=Character.MAX_VALUE;c++)
-		{
-			char ch = (char)c;
-			expectedSb.setCharAt(2,ch);
-			expected = expectedSb.toString();
-			inSb.append(Integer.toString(c));
-			inSb.append(";YZ");
-			in = inSb.toString();
-			result = codec.decode(in);
-			assertEquals(expected, result);
-			inSb.setLength(inSbBaseLen);
-		}
-	}
-
-	public void testDecodeLt()
-	{
-		String in = "AB&lt;YZ";
-		String expected = "AB<YZ";
-		String result = codec.decode(in);
-		assertEquals(expected,result);
-	}
-
-	public void testDecodeGt()
-	{
-		String in = "AB&gt;YZ";
-		String expected = "AB>YZ";
-		String result = codec.decode(in);
-		assertEquals(expected,result);
-	}
-
-	public void testDecodeAmp()
-	{
-		String in = "AB&amp;YZ";
-		String expected = "AB&YZ";
-		String result = codec.decode(in);
-		assertEquals(expected,result);
-	}
-
-	public void testDecodeApos()
-	{
-		String in = "AB&apos;YZ";
-		String expected = "AB'YZ";
-		String result = codec.decode(in);
-		assertEquals(expected,result);
-	}
-
-	public void testDecodeQuot()
-	{
-		String in = "AB&quot;YZ";
-		String expected = "AB\"YZ";
-		String result = codec.decode(in);
-		assertEquals(expected,result);
-	}
-
-	public void testDecodeNamedTail()
-	{
-		String in = "AB&quot;";
-		String expected = "AB\"";
-		String result = codec.decode(in);
-		assertEquals(expected,result);
-	}
-
-	public void testDecodeNamedHead()
-	{
-		String in = "&quot;YZ";
-		String expected = "\"YZ";
-		String result = codec.decode(in);
-		assertEquals(expected,result);
-	}
-
-	public void testDecodeNamedLone()
-	{
-		String in = "&quot;";
-		String expected = "\"";
-		String result = codec.decode(in);
-		assertEquals(expected,result);
-	}
-
-	public void testDecodeNamedNoSemiColonTail()
-	{
-		String in = "AB&quot";
-		String expected = in;
-		String result = codec.decode(in);
-		assertEquals(expected,result);
-	}
-
-	public void testDecodeNamedNoSemiColonHead()
-	{
-		String in = "&quotYZ";
-		String expected = in;
-		String result = codec.decode(in);
-		assertEquals(expected,result);
-	}
-
-	public void testDecodeNamedNoSemiColonLone()
-	{
-		String in = "&quot";
-		String expected = in;
-		String result = codec.decode(in);
-		assertEquals(expected,result);
-	}
-
-	public void testDecodeNamedInvalidTail()
-	{
-		String in = "AB&pound;";
-		String expected = in;
-		String result = codec.decode(in);
-		assertEquals(expected,result);
-	}
-
-	public void testDecodeNamedInvalidHead()
-	{
-		String in = "&pound;YZ";
-		String expected = in;
-		String result = codec.decode(in);
-		assertEquals(expected,result);
-	}
-
-	public void testDecodeNamedInvalidLone()
-	{
-		String in = "&pound;";
-		String expected = in;
-		String result = codec.decode(in);
-		assertEquals(expected,result);
-	}
+    private static final char[] EMPTY_CHAR_ARRAY = new char[0];
+    private static final String ALPHA_NUMERIC_STR = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
+    private static final String UNENCODED_STR = ALPHA_NUMERIC_STR + " \t";
+    private static final Set<Character> UNENCODED_SET = CollectionsUtil.strToUnmodifiableSet(UNENCODED_STR);
+    private XMLEntityCodec codec = null;
+
+    protected void setUp()
+    {
+        codec = new XMLEntityCodec();
+    }
+
+    protected void tearDown()
+    {
+        codec = null;
+    }
+
+    public void testEncodeUnencoded()
+    {
+        StringBuilder sb = new StringBuilder("AB_YZ");
+        String str;
+
+        for(char ch : UNENCODED_SET)
+        {
+            sb.setCharAt(2,ch);
+            str = sb.toString();
+            assertEquals(str, codec.encode(EMPTY_CHAR_ARRAY, str));
+        }
+    }
+
+    public void testEncodeOthers()
+    {
+        StringBuilder inSb = new StringBuilder("AB_YZ");
+        StringBuilder outSb = new StringBuilder("AB&#x");
+        String in;
+        String expected;
+        String result;
+        int outSbBaseLen = outSb.length();
+        String out;
+
+        for(int c=Character.MIN_VALUE;c<=Character.MAX_VALUE;c++)
+        {
+            char ch = (char)c;
+            if(UNENCODED_SET.contains(ch))
+                continue;
+            inSb.setCharAt(2,ch);
+            in = inSb.toString();
+            outSb.append(Integer.toHexString(c));
+            outSb.append(";YZ");
+            expected = outSb.toString();
+            result = codec.encode(EMPTY_CHAR_ARRAY,in);
+            assertEquals(expected, result);
+            outSb.setLength(outSbBaseLen);
+        }
+    }
+
+    public void testDecodeUnencoded()
+    {
+        StringBuilder sb = new StringBuilder("AB_YZ");
+        String str;
+
+        for(char ch : UNENCODED_SET)
+        {
+            sb.setCharAt(2,ch);
+            str = sb.toString();
+            assertEquals(str, codec.decode(str));
+        }
+    }
+
+    public void testDecodeHex()
+    {
+        StringBuilder expectedSb = new StringBuilder("AB_YZ");
+        StringBuilder inSb = new StringBuilder("AB&#x");
+        String in;
+        String expected;
+        String result;
+        int inSbBaseLen = inSb.length();
+
+        for(int c=Character.MIN_VALUE;c<=Character.MAX_VALUE;c++)
+        {
+            char ch = (char)c;
+            expectedSb.setCharAt(2,ch);
+            expected = expectedSb.toString();
+            inSb.append(Integer.toHexString(c));
+            inSb.append(";YZ");
+            in = inSb.toString();
+            result = codec.decode(in);
+            assertEquals(expected, result);
+            inSb.setLength(inSbBaseLen);
+        }
+    }
+
+    public void testDecodeDec()
+    {
+        StringBuilder expectedSb = new StringBuilder("AB_YZ");
+        StringBuilder inSb = new StringBuilder("AB&#");
+        String in;
+        String expected;
+        String result;
+        int inSbBaseLen = inSb.length();
+
+        for(int c=Character.MIN_VALUE;c<=Character.MAX_VALUE;c++)
+        {
+            char ch = (char)c;
+            expectedSb.setCharAt(2,ch);
+            expected = expectedSb.toString();
+            inSb.append(Integer.toString(c));
+            inSb.append(";YZ");
+            in = inSb.toString();
+            result = codec.decode(in);
+            assertEquals(expected, result);
+            inSb.setLength(inSbBaseLen);
+        }
+    }
+
+    public void testDecodeLt()
+    {
+        String in = "AB&lt;YZ";
+        String expected = "AB<YZ";
+        String result = codec.decode(in);
+        assertEquals(expected,result);
+    }
+
+    public void testDecodeGt()
+    {
+        String in = "AB&gt;YZ";
+        String expected = "AB>YZ";
+        String result = codec.decode(in);
+        assertEquals(expected,result);
+    }
+
+    public void testDecodeAmp()
+    {
+        String in = "AB&amp;YZ";
+        String expected = "AB&YZ";
+        String result = codec.decode(in);
+        assertEquals(expected,result);
+    }
+
+    public void testDecodeApos()
+    {
+        String in = "AB&apos;YZ";
+        String expected = "AB'YZ";
+        String result = codec.decode(in);
+        assertEquals(expected,result);
+    }
+
+    public void testDecodeQuot()
+    {
+        String in = "AB&quot;YZ";
+        String expected = "AB\"YZ";
+        String result = codec.decode(in);
+        assertEquals(expected,result);
+    }
+
+    public void testDecodeNamedTail()
+    {
+        String in = "AB&quot;";
+        String expected = "AB\"";
+        String result = codec.decode(in);
+        assertEquals(expected,result);
+    }
+
+    public void testDecodeNamedHead()
+    {
+        String in = "&quot;YZ";
+        String expected = "\"YZ";
+        String result = codec.decode(in);
+        assertEquals(expected,result);
+    }
+
+    public void testDecodeNamedLone()
+    {
+        String in = "&quot;";
+        String expected = "\"";
+        String result = codec.decode(in);
+        assertEquals(expected,result);
+    }
+
+    public void testDecodeNamedNoSemiColonTail()
+    {
+        String in = "AB&quot";
+        String expected = in;
+        String result = codec.decode(in);
+        assertEquals(expected,result);
+    }
+
+    public void testDecodeNamedNoSemiColonHead()
+    {
+        String in = "&quotYZ";
+        String expected = in;
+        String result = codec.decode(in);
+        assertEquals(expected,result);
+    }
+
+    public void testDecodeNamedNoSemiColonLone()
+    {
+        String in = "&quot";
+        String expected = in;
+        String result = codec.decode(in);
+        assertEquals(expected,result);
+    }
+
+    public void testDecodeNamedInvalidTail()
+    {
+        String in = "AB&pound;";
+        String expected = in;
+        String result = codec.decode(in);
+        assertEquals(expected,result);
+    }
+
+    public void testDecodeNamedInvalidHead()
+    {
+        String in = "&pound;YZ";
+        String expected = in;
+        String result = codec.decode(in);
+        assertEquals(expected,result);
+    }
+
+    public void testDecodeNamedInvalidLone()
+    {
+        String in = "&pound;";
+        String expected = in;
+        String result = codec.decode(in);
+        assertEquals(expected,result);
+    }
 }
diff --git a/src/test/java/org/owasp/esapi/codecs/abstraction/AbstractCodecCharacterTest.java b/src/test/java/org/owasp/esapi/codecs/abstraction/AbstractCodecCharacterTest.java
index aa72083..6e77f5a 100644
--- a/src/test/java/org/owasp/esapi/codecs/abstraction/AbstractCodecCharacterTest.java
+++ b/src/test/java/org/owasp/esapi/codecs/abstraction/AbstractCodecCharacterTest.java
@@ -35,7 +35,7 @@ import org.owasp.esapi.codecs.PushbackString;
  */
 @RunWith(Parameterized.class)
 public abstract class AbstractCodecCharacterTest {
-    
+
     /** Test Data Tuple.*/
     protected static class CodecCharacterTestTuple {
         /** Codec reference to be tested.*/
@@ -48,7 +48,7 @@ public abstract class AbstractCodecCharacterTest {
         public Character decodedValue;
         /** Optional field to override the toString value of this tuple. */
         public String description;
-        
+
         /**Default public constructor.*/
         public CodecCharacterTestTuple() { /* No Op*/ }
         /** {@inheritDoc}*/
@@ -58,46 +58,46 @@ public abstract class AbstractCodecCharacterTest {
         }
     }
 
-    
+
     protected final Codec codec;
     protected final String input;
     protected final char[] encodeImmune;
     protected final Character decodedValue;
-    
+
     public AbstractCodecCharacterTest(CodecCharacterTestTuple tuple) {
         this.codec = tuple.codec;
         this.input = tuple.input;
         this.decodedValue = tuple.decodedValue;
         this.encodeImmune = tuple.encodeImmune;
     }
-    
+
     /** Checks that the input value matches the result of the codec encoding the decoded value.  */
     @Test
     public void testEncodeCharacter() {
         assertEquals(input, codec.encodeCharacter(encodeImmune, decodedValue));
     }
-    
+
     /** Checks encoding the character as a String.
      * <br/>
      * If the decoded value is in the immunity list, the the decoded value should be returned from the encode call.
-     * Otherwise, input is expected as the return. 
+     * Otherwise, input is expected as the return.
      */
     @Test
     public void testEncode() {
         String expected = Arrays.asList(encodeImmune).contains(decodedValue) ? decodedValue.toString() : input;
         assertEquals(expected, codec.encode(encodeImmune, decodedValue.toString()));
     }
-    
+
     /**  Checks that decoding the input value yields the decodedValue.*/
     @Test
     public void testDecode() {
          assertEquals(decodedValue.toString(), codec.decode(input));
     }
-    
+
     /** Checks that the encoded input String is correctly decoded to the single decodedValue character reference.*/
     @Test
     public void testDecodePushbackSequence() {
         assertEquals(decodedValue, codec.decodeCharacter(new PushbackString(input)));
     }
-    
+
 }
diff --git a/src/test/java/org/owasp/esapi/codecs/abstraction/AbstractCodecStringTest.java b/src/test/java/org/owasp/esapi/codecs/abstraction/AbstractCodecStringTest.java
index cf48dcf..b3a8b9a 100644
--- a/src/test/java/org/owasp/esapi/codecs/abstraction/AbstractCodecStringTest.java
+++ b/src/test/java/org/owasp/esapi/codecs/abstraction/AbstractCodecStringTest.java
@@ -32,7 +32,7 @@ import org.owasp.esapi.codecs.Codec;
  */
 @RunWith(Parameterized.class)
 public abstract class AbstractCodecStringTest {
-   
+
     protected static class CodecStringTestTuple {
         /** Codec reference to be tested.*/
         public Codec codec;
@@ -44,10 +44,10 @@ public abstract class AbstractCodecStringTest {
         public String decodedValue;
         /** Optional field to override the toString value of this tuple. */
         public String description;
-        
+
         /**Default public constructor.*/
         public CodecStringTestTuple() { /* No Op*/ }
-        
+
         /** {@inheritDoc}*/
         @Override
         public String toString() {
@@ -58,25 +58,25 @@ public abstract class AbstractCodecStringTest {
     private final String input;
     private final char[] encodeImmune;
     private final String decodedValue;
-    
+
     public AbstractCodecStringTest(CodecStringTestTuple tuple) {
         this.codec = tuple.codec;
         this.input = tuple.input;
         this.decodedValue = tuple.decodedValue;
         this.encodeImmune = tuple.encodeImmune;
     }
-    
+
 
     /** Checks that when the input is decoded using the specified codec, that the return matches the expected decoded value.*/
     @Test
     public void testDecode() {
         assertEquals(decodedValue, codec.decode(input));
     }
-  
+
     /** Checks that when the decoded value is encoded (using immunity), that the return matches the provided input.*/
     @Test
     public void testEncode() {
         assertEquals(input, codec.encode(encodeImmune, decodedValue));
     }
-    
+
 }
diff --git a/src/test/java/org/owasp/esapi/codecs/percent/PercentCodecCharacterTest.java b/src/test/java/org/owasp/esapi/codecs/percent/PercentCodecCharacterTest.java
index 7d4425d..f80f771 100644
--- a/src/test/java/org/owasp/esapi/codecs/percent/PercentCodecCharacterTest.java
+++ b/src/test/java/org/owasp/esapi/codecs/percent/PercentCodecCharacterTest.java
@@ -29,7 +29,7 @@ import org.owasp.esapi.codecs.abstraction.AbstractCodecCharacterTest;
 
 /**
  *  Codec validation focused on the PercentCodec Character-based api.
- *  
+ *
  */
 public class PercentCodecCharacterTest extends AbstractCodecCharacterTest {
     @Parameters(name = "{0}")
diff --git a/src/test/java/org/owasp/esapi/codecs/percent/PercentCodecKnownIssuesTest.java b/src/test/java/org/owasp/esapi/codecs/percent/PercentCodecKnownIssuesTest.java
index ac8c6d6..2150708 100644
--- a/src/test/java/org/owasp/esapi/codecs/percent/PercentCodecKnownIssuesTest.java
+++ b/src/test/java/org/owasp/esapi/codecs/percent/PercentCodecKnownIssuesTest.java
@@ -26,7 +26,7 @@ import org.owasp.esapi.codecs.PercentCodec;
  * the author to move the test to an appropriate Test file and update the functionality to a working expectation.
  */
 public class PercentCodecKnownIssuesTest {
-    
+
     private PercentCodec codec = new PercentCodec();
 
     /**
@@ -39,18 +39,18 @@ public class PercentCodecKnownIssuesTest {
     public void failsUTF16Conversions() {
         //This should be 195
         int incorrectDecodeExpect = 196;
-        
+
         char[] encodeImmune = PERCENT_CODEC_IMMUNE;
         String decodedValue = ""+(char) 0x100;
         String input = "%C4%80";
 
         String actualDecodeChar = codec.decode(input);
         int actualChar = (int)actualDecodeChar.charAt(0);
-        
+
         assertEquals(incorrectDecodeExpect, actualChar);
-        
+
         //This works as expected.
         assertEquals(input, codec.encode(encodeImmune, decodedValue));
     }
-    
+
 }
diff --git a/src/test/java/org/owasp/esapi/codecs/percent/PercentCodecStringTest.java b/src/test/java/org/owasp/esapi/codecs/percent/PercentCodecStringTest.java
index edec023..57277b1 100644
--- a/src/test/java/org/owasp/esapi/codecs/percent/PercentCodecStringTest.java
+++ b/src/test/java/org/owasp/esapi/codecs/percent/PercentCodecStringTest.java
@@ -24,7 +24,7 @@ import org.owasp.esapi.codecs.abstraction.AbstractCodecStringTest;
 
 /**
  *  Codec validation focused on the PercentCodec String-based api.
- *  
+ *
  */
 public class PercentCodecStringTest extends AbstractCodecStringTest {
     public static final char[] PERCENT_CODEC_IMMUNE;
@@ -32,7 +32,7 @@ public class PercentCodecStringTest extends AbstractCodecStringTest {
     static {
         /*
          * The percent codec contains a unique immune character set which include letters and numbers that will not be transformed.
-         * 
+         *
          * It is being replicated here to allow the test to reasonably expect the correct state back.
          */
         List<Character> immune = new ArrayList<>();
@@ -45,9 +45,9 @@ public class PercentCodecStringTest extends AbstractCodecStringTest {
         for (int index = 65 ; index < 91; index ++) {
             Character capsChar = (char)index;
             immune.add(capsChar);
-            immune.add(Character.toLowerCase(capsChar));            
+            immune.add(Character.toLowerCase(capsChar));
         }
-        
+
         PERCENT_CODEC_IMMUNE = new char[immune.size()];
         for (int index = 0; index < immune.size(); index++) {
             PERCENT_CODEC_IMMUNE[index] = immune.get(index).charValue();
@@ -58,7 +58,7 @@ public class PercentCodecStringTest extends AbstractCodecStringTest {
     public static Collection<Object[]> buildTests() {
         Collection<Object[]> tests = new ArrayList<>();
         List<CodecStringTestTuple> tuples = new ArrayList<>();
-        
+
         tuples.add(newTuple("%3C", "<"));
         tuples.add(newTuple("%00", Character.MIN_VALUE));
         tuples.add(newTuple("%3D", '='));
@@ -67,7 +67,7 @@ public class PercentCodecStringTest extends AbstractCodecStringTest {
         for (char c : PERCENT_CODEC_IMMUNE) {
             tuples.add(newTuple(Character.toString(c), c));
         }
-        
+
         for (CodecStringTestTuple tuple : tuples) {
             tests.add(new Object[] { tuple });
         }
diff --git a/src/test/java/org/owasp/esapi/codecs/ref/EncodingPatternPreservationTest.java b/src/test/java/org/owasp/esapi/codecs/ref/EncodingPatternPreservationTest.java
index 390f538..59701c5 100644
--- a/src/test/java/org/owasp/esapi/codecs/ref/EncodingPatternPreservationTest.java
+++ b/src/test/java/org/owasp/esapi/codecs/ref/EncodingPatternPreservationTest.java
@@ -7,73 +7,73 @@ import org.junit.Test;
 import static org.junit.Assert.*;
 
 public class EncodingPatternPreservationTest {
-	
-	@Test
-	public void testReplaceAndRestore() {
-		Pattern numberRegex = Pattern.compile("(ABC)");
-		EncodingPatternPreservation epp = new EncodingPatternPreservation(numberRegex);
-		String origStr = "12 ABC 34 DEF 56 G 7";
-		String replacedStr = epp.captureAndReplaceMatches(origStr);
-		
-		assertEquals("12 EncodingPatternPreservation 34 DEF 56 G 7", replacedStr);
-		
-		String restored = epp.restoreOriginalContent(replacedStr);
-		assertEquals(origStr, restored);
-	}
-	
-	@Test
-	public void testReplaceMultipleAndRestore() {
-		Pattern numberRegex = Pattern.compile("(ABC)");
-		EncodingPatternPreservation epp = new EncodingPatternPreservation(numberRegex);
-		String origStr = "12 ABC 34 ABC 56 G 7 ABC8";
-		String replacedStr = epp.captureAndReplaceMatches(origStr);
-		
-		assertEquals("12 EncodingPatternPreservation 34 EncodingPatternPreservation 56 G 7 EncodingPatternPreservation8", replacedStr);
-		
-		String restored = epp.restoreOriginalContent(replacedStr);
-		assertEquals(origStr, restored);
-	}
-	
-	@Test
-	public void testSetMarker() {
-		Pattern numberRegex = Pattern.compile("(ABC)");
-		EncodingPatternPreservation epp = new EncodingPatternPreservation(numberRegex);
-		epp.setReplacementMarker(EncodingPatternPreservationTest.class.getSimpleName());
-		
-		String origStr = "12 ABC 34 DEF 56 G 7";
-		String replacedStr = epp.captureAndReplaceMatches(origStr);
-		
-		assertEquals("12 EncodingPatternPreservationTest 34 DEF 56 G 7", replacedStr);
-		
-		String restored = epp.restoreOriginalContent(replacedStr);
-		assertEquals(origStr, restored);
-	}
-	
-	@Test (expected = IllegalStateException.class)
-	public void testSetMarkerExceptionNoReset() {
-		Pattern numberRegex = Pattern.compile("(ABC)");
-		EncodingPatternPreservation epp = new EncodingPatternPreservation(numberRegex);
-		String origStr = "12 ABC 34 DEF 56 G 7";
-		epp.captureAndReplaceMatches(origStr);
-		//This allows the + case to be illustrated
-		epp.reset();
-		
-		//And the exception case.
-		epp.captureAndReplaceMatches(origStr);
-		epp.setReplacementMarker(EncodingPatternPreservationTest.class.getSimpleName());
-	}
-	
-	@Test (expected = IllegalStateException.class)
-	public void testReplaceExceptionNoReset() {
-		Pattern numberRegex = Pattern.compile("(ABC)");
-		EncodingPatternPreservation epp = new EncodingPatternPreservation(numberRegex);
-		String origStr = "12 ABC 34 DEF 56 G 7";
-		epp.captureAndReplaceMatches(origStr);
-		//This allows the + case to be illustrated
-		epp.reset();
-		
-		//And the exception case.
-		epp.captureAndReplaceMatches(origStr);
-		epp.captureAndReplaceMatches(origStr);
-	}
+
+    @Test
+    public void testReplaceAndRestore() {
+        Pattern numberRegex = Pattern.compile("(ABC)");
+        EncodingPatternPreservation epp = new EncodingPatternPreservation(numberRegex);
+        String origStr = "12 ABC 34 DEF 56 G 7";
+        String replacedStr = epp.captureAndReplaceMatches(origStr);
+
+        assertEquals("12 EncodingPatternPreservation 34 DEF 56 G 7", replacedStr);
+
+        String restored = epp.restoreOriginalContent(replacedStr);
+        assertEquals(origStr, restored);
+    }
+
+    @Test
+    public void testReplaceMultipleAndRestore() {
+        Pattern numberRegex = Pattern.compile("(ABC)");
+        EncodingPatternPreservation epp = new EncodingPatternPreservation(numberRegex);
+        String origStr = "12 ABC 34 ABC 56 G 7 ABC8";
+        String replacedStr = epp.captureAndReplaceMatches(origStr);
+
+        assertEquals("12 EncodingPatternPreservation 34 EncodingPatternPreservation 56 G 7 EncodingPatternPreservation8", replacedStr);
+
+        String restored = epp.restoreOriginalContent(replacedStr);
+        assertEquals(origStr, restored);
+    }
+
+    @Test
+    public void testSetMarker() {
+        Pattern numberRegex = Pattern.compile("(ABC)");
+        EncodingPatternPreservation epp = new EncodingPatternPreservation(numberRegex);
+        epp.setReplacementMarker(EncodingPatternPreservationTest.class.getSimpleName());
+
+        String origStr = "12 ABC 34 DEF 56 G 7";
+        String replacedStr = epp.captureAndReplaceMatches(origStr);
+
+        assertEquals("12 EncodingPatternPreservationTest 34 DEF 56 G 7", replacedStr);
+
+        String restored = epp.restoreOriginalContent(replacedStr);
+        assertEquals(origStr, restored);
+    }
+
+    @Test (expected = IllegalStateException.class)
+    public void testSetMarkerExceptionNoReset() {
+        Pattern numberRegex = Pattern.compile("(ABC)");
+        EncodingPatternPreservation epp = new EncodingPatternPreservation(numberRegex);
+        String origStr = "12 ABC 34 DEF 56 G 7";
+        epp.captureAndReplaceMatches(origStr);
+        //This allows the + case to be illustrated
+        epp.reset();
+
+        //And the exception case.
+        epp.captureAndReplaceMatches(origStr);
+        epp.setReplacementMarker(EncodingPatternPreservationTest.class.getSimpleName());
+    }
+
+    @Test (expected = IllegalStateException.class)
+    public void testReplaceExceptionNoReset() {
+        Pattern numberRegex = Pattern.compile("(ABC)");
+        EncodingPatternPreservation epp = new EncodingPatternPreservation(numberRegex);
+        String origStr = "12 ABC 34 DEF 56 G 7";
+        epp.captureAndReplaceMatches(origStr);
+        //This allows the + case to be illustrated
+        epp.reset();
+
+        //And the exception case.
+        epp.captureAndReplaceMatches(origStr);
+        epp.captureAndReplaceMatches(origStr);
+    }
 }
diff --git a/src/test/java/org/owasp/esapi/configuration/EsapiPropertyManagerTest.java b/src/test/java/org/owasp/esapi/configuration/EsapiPropertyManagerTest.java
index b8aa156..507f33c 100644
--- a/src/test/java/org/owasp/esapi/configuration/EsapiPropertyManagerTest.java
+++ b/src/test/java/org/owasp/esapi/configuration/EsapiPropertyManagerTest.java
@@ -31,17 +31,17 @@ public class EsapiPropertyManagerTest {
 
     @BeforeClass
     public static void captureEsapiConfigurations() {
-    	DEVTEAM_CFG = System.getProperty(EsapiConfiguration.DEVTEAM_ESAPI_CFG.getConfigName(),"");
-    	OPSTEAM_CFG = System.getProperty(EsapiConfiguration.OPSTEAM_ESAPI_CFG.getConfigName(),"");
+        DEVTEAM_CFG = System.getProperty(EsapiConfiguration.DEVTEAM_ESAPI_CFG.getConfigName(),"");
+        OPSTEAM_CFG = System.getProperty(EsapiConfiguration.OPSTEAM_ESAPI_CFG.getConfigName(),"");
     }
-    
+
     @AfterClass
     public static void restoreEsapiConfigurations() {
-    	 System.setProperty(EsapiConfiguration.DEVTEAM_ESAPI_CFG.getConfigName(), DEVTEAM_CFG);
+         System.setProperty(EsapiConfiguration.DEVTEAM_ESAPI_CFG.getConfigName(), DEVTEAM_CFG);
          System.setProperty(EsapiConfiguration.OPSTEAM_ESAPI_CFG.getConfigName(), OPSTEAM_CFG);
     }
 
-    
+
     @Before
     public void init() {
         System.setProperty(EsapiConfiguration.DEVTEAM_ESAPI_CFG.getConfigName(), "");
@@ -422,20 +422,20 @@ public class EsapiPropertyManagerTest {
 
     @Test
     public void testExpectFileNotFoundException() {
-    	// given
-    	System.setProperty(EsapiConfiguration.DEVTEAM_ESAPI_CFG.getConfigName(), noSuchFile);
-
-    	// when
-    	try {
-    		testPropertyManager = new EsapiPropertyManager();
-    	} catch (IOException e) {
-    		if ( e instanceof FileNotFoundException ) {
-    			return;
-    		} else {
-    			fail("testExpectFileNotFoundException(): Was expecting FileNotFoundException for IOException. Exception:" + e);
-    		}
-    	}
-
-    	fail("Did not throw expected IOException for property file " + noSuchFile);
+        // given
+        System.setProperty(EsapiConfiguration.DEVTEAM_ESAPI_CFG.getConfigName(), noSuchFile);
+
+        // when
+        try {
+            testPropertyManager = new EsapiPropertyManager();
+        } catch (IOException e) {
+            if ( e instanceof FileNotFoundException ) {
+                return;
+            } else {
+                fail("testExpectFileNotFoundException(): Was expecting FileNotFoundException for IOException. Exception:" + e);
+            }
+        }
+
+        fail("Did not throw expected IOException for property file " + noSuchFile);
     }
 }
diff --git a/src/test/java/org/owasp/esapi/configuration/StandardEsapiPropertyLoaderTest.java b/src/test/java/org/owasp/esapi/configuration/StandardEsapiPropertyLoaderTest.java
index da20835..0806446 100644
--- a/src/test/java/org/owasp/esapi/configuration/StandardEsapiPropertyLoaderTest.java
+++ b/src/test/java/org/owasp/esapi/configuration/StandardEsapiPropertyLoaderTest.java
@@ -26,17 +26,17 @@ public class StandardEsapiPropertyLoaderTest {
 
     @BeforeClass
     public static void captureEsapiConfigurations() {
-    	DEVTEAM_CFG = System.getProperty(EsapiConfiguration.DEVTEAM_ESAPI_CFG.getConfigName(),"");
-    	OPSTEAM_CFG = System.getProperty(EsapiConfiguration.OPSTEAM_ESAPI_CFG.getConfigName(),"");
+        DEVTEAM_CFG = System.getProperty(EsapiConfiguration.DEVTEAM_ESAPI_CFG.getConfigName(),"");
+        OPSTEAM_CFG = System.getProperty(EsapiConfiguration.OPSTEAM_ESAPI_CFG.getConfigName(),"");
     }
-    
+
     @AfterClass
     public static void restoreEsapiConfigurations() {
-    	 System.setProperty(EsapiConfiguration.DEVTEAM_ESAPI_CFG.getConfigName(), DEVTEAM_CFG);
+         System.setProperty(EsapiConfiguration.DEVTEAM_ESAPI_CFG.getConfigName(), DEVTEAM_CFG);
          System.setProperty(EsapiConfiguration.OPSTEAM_ESAPI_CFG.getConfigName(), OPSTEAM_CFG);
     }
 
-    
+
     @Before
     public void init() {
         System.setProperty(EsapiConfiguration.DEVTEAM_ESAPI_CFG.getConfigName(), "");
@@ -139,7 +139,7 @@ public class StandardEsapiPropertyLoaderTest {
     public void testGetIntProp() {
         // given
         String propertyKey = "int_property";
-        
+
         // when
         try {
             testPropertyLoader = new StandardEsapiPropertyLoader(filename, priority);
@@ -156,7 +156,7 @@ public class StandardEsapiPropertyLoaderTest {
     public void testIntPropertyNotFound() throws ConfigurationException {
         // given
         String propertyKey = "non-existing-key";
-        
+
         // when
         try {
             testPropertyLoader = new StandardEsapiPropertyLoader(filename, priority);
@@ -189,7 +189,7 @@ public class StandardEsapiPropertyLoaderTest {
         // given
         String propertyKey = "string_property";
         String expectedValue = "test_string_property";
-        
+
         // when
         try {
             testPropertyLoader = new StandardEsapiPropertyLoader(filename, priority);
@@ -197,7 +197,7 @@ public class StandardEsapiPropertyLoaderTest {
             fail( e.getMessage() );
         }
         String propertyValue = testPropertyLoader.getStringProp(propertyKey);
-        
+
         // then
         assertEquals(expectedValue, propertyValue);
     }
@@ -206,7 +206,7 @@ public class StandardEsapiPropertyLoaderTest {
     public void testStringPropertyNotFound() throws ConfigurationException {
         // given
         String propertyKey = "non-existing-key";
-        
+
         // when
         try {
             testPropertyLoader = new StandardEsapiPropertyLoader(filename, priority);
@@ -226,7 +226,7 @@ public class StandardEsapiPropertyLoaderTest {
         int priority = 1;
         String propertyKey = "boolean_property";
         boolean expectedValue = true;
-        
+
         // when
         try {
             testPropertyLoader = new StandardEsapiPropertyLoader(filename, priority);
@@ -234,7 +234,7 @@ public class StandardEsapiPropertyLoaderTest {
             fail( e.getMessage() );
         }
         boolean value = testPropertyLoader.getBooleanProp(propertyKey);
-        
+
         // then
         assertEquals(expectedValue, value);
     }
@@ -282,7 +282,7 @@ public class StandardEsapiPropertyLoaderTest {
                 "esapi" + File.separator + "ESAPI-test.properties";
         int priority = 1;
         String propertyKey = "non-existing-key";
-        
+
         // when
         try {
             testPropertyLoader = new StandardEsapiPropertyLoader(filename, priority);
@@ -317,14 +317,14 @@ public class StandardEsapiPropertyLoaderTest {
                 "esapi" + File.separator + "ESAPI-test.properties";
         int priority = 1;
         String propertyKey = "string_property";
-        
+
         byte[] expectedValue = new byte[0];
         try {
             expectedValue = ESAPI.encoder().decodeFromBase64("test_string_property");
         } catch (IOException e) {
             fail(e.getMessage());
         }
-        
+
         // when
         try {
             testPropertyLoader = new StandardEsapiPropertyLoader(filename, priority);
@@ -332,7 +332,7 @@ public class StandardEsapiPropertyLoaderTest {
             fail( e.getMessage() );
         }
         byte[] value = testPropertyLoader.getByteArrayProp(propertyKey);
-        
+
         // then
         assertEquals(expectedValue, value);
     }
@@ -343,7 +343,7 @@ public class StandardEsapiPropertyLoaderTest {
         String filename = "src" + File.separator + "test" + File.separator + "resources" + File.separator +
                 "esapi" + File.separator + "ESAPI-test.properties";        int priority = 1;
         String propertyKey = "non-existing-key";
-        
+
         // when
         try {
             testPropertyLoader = new StandardEsapiPropertyLoader(filename, priority);
diff --git a/src/test/java/org/owasp/esapi/configuration/XmlEsapiPropertyLoaderTest.java b/src/test/java/org/owasp/esapi/configuration/XmlEsapiPropertyLoaderTest.java
index 472f872..6aecec5 100644
--- a/src/test/java/org/owasp/esapi/configuration/XmlEsapiPropertyLoaderTest.java
+++ b/src/test/java/org/owasp/esapi/configuration/XmlEsapiPropertyLoaderTest.java
@@ -25,13 +25,13 @@ public class XmlEsapiPropertyLoaderTest {
 
     @BeforeClass
     public static void captureEsapiConfigurations() {
-    	DEVTEAM_CFG = System.getProperty(EsapiConfiguration.DEVTEAM_ESAPI_CFG.getConfigName(),"");
-    	OPSTEAM_CFG = System.getProperty(EsapiConfiguration.OPSTEAM_ESAPI_CFG.getConfigName(),"");
+        DEVTEAM_CFG = System.getProperty(EsapiConfiguration.DEVTEAM_ESAPI_CFG.getConfigName(),"");
+        OPSTEAM_CFG = System.getProperty(EsapiConfiguration.OPSTEAM_ESAPI_CFG.getConfigName(),"");
     }
-    
+
     @AfterClass
     public static void restoreEsapiConfigurations() {
-    	 System.setProperty(EsapiConfiguration.DEVTEAM_ESAPI_CFG.getConfigName(), DEVTEAM_CFG);
+         System.setProperty(EsapiConfiguration.DEVTEAM_ESAPI_CFG.getConfigName(), DEVTEAM_CFG);
          System.setProperty(EsapiConfiguration.OPSTEAM_ESAPI_CFG.getConfigName(), OPSTEAM_CFG);
     }
 
diff --git a/src/test/java/org/owasp/esapi/crypto/CipherSpecTest.java b/src/test/java/org/owasp/esapi/crypto/CipherSpecTest.java
index 81cde6a..54c69a5 100644
--- a/src/test/java/org/owasp/esapi/crypto/CipherSpecTest.java
+++ b/src/test/java/org/owasp/esapi/crypto/CipherSpecTest.java
@@ -22,189 +22,189 @@ import org.owasp.esapi.crypto.CipherSpec;
 /** JUnit test to test CipherSpec class. */
 public class CipherSpecTest extends TestCase {
 
-	private Cipher dfltAESCipher = null;
-	private Cipher dfltECBCipher = null;	// will be "AES/ECB/NoPadding";
-	private Cipher dfltOtherCipher = null;
-	private CipherSpec cipherSpec = null;
-	private byte[] myIV = null;
-
-	@Before public void setUp() throws Exception {
-		myIV = Hex.decode( "0x000102030405060708090a0b0c0d0e0f" ); // Any IV to test w/ will do.
-
-		dfltAESCipher   = Cipher.getInstance("AES");
-		dfltECBCipher   = Cipher.getInstance("AES/ECB/NoPadding");
-		dfltOtherCipher = Cipher.getInstance("Blowfish/OFB8/PKCS5Padding");
-
-		assertTrue( dfltAESCipher != null );
-		assertTrue( dfltECBCipher != null );
-		assertTrue( dfltOtherCipher != null );
-
-		cipherSpec = new CipherSpec(dfltOtherCipher);
-		assertTrue( cipherSpec != null );
-	}
-
-	@After public void tearDown() throws Exception {
-    	// none
-	}
-	
-	/** Test CipherSpec(String cipherXform, int keySize, int blockSize, final byte[] iv) */
-	@Test public void testCipherSpecStringIntIntByteArray() {
-		
-		cipherSpec = new CipherSpec( "AES/CBC/NoPadding",  128,  8, myIV);
-		assertTrue( cipherSpec != null );
-		cipherSpec = null;
-		boolean caughtException = false;
-		try {
-				// Invalid cipher xform -- empty
-			cipherSpec = new CipherSpec( "",  128,  8, myIV);
-		} catch( Throwable t ) {
-			caughtException = true;
-		}
-		assertTrue( caughtException && (cipherSpec == null) );
-		caughtException = false;
-		try {
-				// Invalid cipher xform -- missing padding scheme
-			cipherSpec = new CipherSpec("AES/CBC", 128, 8, myIV);
-		} catch( Throwable t ) {
-		    caughtException = true;
-		}
+    private Cipher dfltAESCipher = null;
+    private Cipher dfltECBCipher = null;    // will be "AES/ECB/NoPadding";
+    private Cipher dfltOtherCipher = null;
+    private CipherSpec cipherSpec = null;
+    private byte[] myIV = null;
+
+    @Before public void setUp() throws Exception {
+        myIV = Hex.decode( "0x000102030405060708090a0b0c0d0e0f" ); // Any IV to test w/ will do.
+
+        dfltAESCipher   = Cipher.getInstance("AES");
+        dfltECBCipher   = Cipher.getInstance("AES/ECB/NoPadding");
+        dfltOtherCipher = Cipher.getInstance("Blowfish/OFB8/PKCS5Padding");
+
+        assertTrue( dfltAESCipher != null );
+        assertTrue( dfltECBCipher != null );
+        assertTrue( dfltOtherCipher != null );
+
+        cipherSpec = new CipherSpec(dfltOtherCipher);
+        assertTrue( cipherSpec != null );
+    }
+
+    @After public void tearDown() throws Exception {
+        // none
+    }
+
+    /** Test CipherSpec(String cipherXform, int keySize, int blockSize, final byte[] iv) */
+    @Test public void testCipherSpecStringIntIntByteArray() {
+
+        cipherSpec = new CipherSpec( "AES/CBC/NoPadding",  128,  8, myIV);
+        assertTrue( cipherSpec != null );
+        cipherSpec = null;
+        boolean caughtException = false;
+        try {
+                // Invalid cipher xform -- empty
+            cipherSpec = new CipherSpec( "",  128,  8, myIV);
+        } catch( Throwable t ) {
+            caughtException = true;
+        }
+        assertTrue( caughtException && (cipherSpec == null) );
+        caughtException = false;
+        try {
+                // Invalid cipher xform -- missing padding scheme
+            cipherSpec = new CipherSpec("AES/CBC", 128, 8, myIV);
+        } catch( Throwable t ) {
+            caughtException = true;
+        }
         assertTrue( caughtException && (cipherSpec == null) );
-	}
-
-	/** CipherSpec(final Cipher cipher, int keySize) */
-	@Test public void testCipherSpecCipherInt() {
-    	cipherSpec = new CipherSpec(dfltOtherCipher, 112);
-    	assertTrue( cipherSpec != null );
-    	assertTrue( cipherSpec.getCipherAlgorithm().equals("Blowfish"));
-    	assertTrue( cipherSpec.getCipherMode().equals("OFB8"));
-    	
-    	cipherSpec = new CipherSpec(dfltAESCipher, 256);
-    	assertTrue( cipherSpec != null );
-    	assertTrue( cipherSpec.getCipherAlgorithm().equals("AES"));
-    	assertTrue( cipherSpec.getCipherMode().equals("ECB") );
-    	assertTrue( cipherSpec.getPaddingScheme().equals("NoPadding") );
-    	// System.out.println("testCipherSpecInt(): " + cipherSpec);
-	}
-
-	/** Test CipherSpec(final byte[] iv) */
-	@Test public void testCipherSpecByteArray() {
-		assertTrue( myIV != null );
-		assertTrue( myIV.length > 0 );
-		cipherSpec = new CipherSpec(myIV);
-		assertTrue( cipherSpec.getKeySize() == 
-						ESAPI.securityConfiguration().getEncryptionKeyLength() );
-		assertTrue( cipherSpec.getCipherTransformation().equals(
-						ESAPI.securityConfiguration().getCipherTransformation() ) );
-	}
-
-	/** Test CipherSpec() */
-	@Test public void testCipherSpec() {
-		cipherSpec = new CipherSpec( dfltECBCipher );
-		assertTrue( cipherSpec.getCipherTransformation().equals("AES/ECB/NoPadding") );
-		assertTrue( cipherSpec.getIV() == null );
-	
-		cipherSpec = new CipherSpec(dfltOtherCipher);
-		assertTrue( cipherSpec.getCipherMode().equals("OFB8") );
-	}
-
-	/** Test setCipherTransformation(String cipherXform) */
-	@Test public void testSetCipherTransformation() {
-		cipherSpec = new CipherSpec();
-		cipherSpec.setCipherTransformation("AlgName/Mode/Padding");
-		cipherSpec.getCipherAlgorithm().equals("AlgName/Mode/Padding");
-		
-		try {
-				// Don't use null here as compiling JUnit tests disables assertion
-				// checking so we get a NullPointerException here instead.
-			cipherSpec.setCipherTransformation(""); // Throws IllegalArgumentException
-		} catch (IllegalArgumentException e) {
-			assertTrue(true);	// Doesn't work w/ @Test(expected=IllegalArgumentException.class)
-		}
-	}
-
-	/** Test getCipherTransformation() */
-	@Test public void testGetCipherTransformation() {
-		assertTrue( (new CipherSpec()).getCipherTransformation().equals("AES/CBC/PKCS5Padding") );
-	}
-
-	/** Test setKeySize() */
-	@Test public void testSetKeySize() {
-		assertTrue( (new CipherSpec()).setKeySize(56).getKeySize() == 56 );
-	}
-
-	/** Test getKeySize() */
-	@Test public void testGetKeySize() {
-		assertTrue( (new CipherSpec()).getKeySize() ==
-			ESAPI.securityConfiguration().getEncryptionKeyLength() );
-	}
-
-	/** Test setBlockSize() */
-	@Test public void testSetBlockSize() {
-		try {
-			cipherSpec.setBlockSize(0); // Throws IllegalArgumentException
-		} catch (IllegalArgumentException e) {
-			assertTrue(true);
-		}
-		try {
-			cipherSpec.setBlockSize(-1); // Throws IllegalArgumentException
-		} catch (IllegalArgumentException e) {
-			assertTrue(true);
-		}
-		assertTrue( cipherSpec.setBlockSize(4).getBlockSize() == 4 );
-	}
-
-	/** Test getBlockSize() */
-	@Test public void testGetBlockSize() {
-		assertTrue( cipherSpec.getBlockSize() == 8 );
-	}
-
-	/** Test getCipherAlgorithm() */
-	@Test public void testGetCipherAlgorithm() {
-		assertTrue( cipherSpec.getCipherAlgorithm().equals("Blowfish") );
-	}
-
-	/** Test getCipherMode */
-	@Test public void testGetCipherMode() {
-		assertTrue( cipherSpec.getCipherMode().equals("OFB8") );
-	}
-
-	/** Test getPaddingScheme() */
-	@Test public void testGetPaddingScheme() {
-		assertTrue( cipherSpec.getPaddingScheme().equals("PKCS5Padding") );
-	}
-
-	/** Test setIV() */
-	@Test public void testSetIV() {
-		try {
-			// Test that ECB mode allows a null IV
-			cipherSpec = new CipherSpec(dfltECBCipher);
+    }
+
+    /** CipherSpec(final Cipher cipher, int keySize) */
+    @Test public void testCipherSpecCipherInt() {
+        cipherSpec = new CipherSpec(dfltOtherCipher, 112);
+        assertTrue( cipherSpec != null );
+        assertTrue( cipherSpec.getCipherAlgorithm().equals("Blowfish"));
+        assertTrue( cipherSpec.getCipherMode().equals("OFB8"));
+
+        cipherSpec = new CipherSpec(dfltAESCipher, 256);
+        assertTrue( cipherSpec != null );
+        assertTrue( cipherSpec.getCipherAlgorithm().equals("AES"));
+        assertTrue( cipherSpec.getCipherMode().equals("ECB") );
+        assertTrue( cipherSpec.getPaddingScheme().equals("NoPadding") );
+        // System.out.println("testCipherSpecInt(): " + cipherSpec);
+    }
+
+    /** Test CipherSpec(final byte[] iv) */
+    @Test public void testCipherSpecByteArray() {
+        assertTrue( myIV != null );
+        assertTrue( myIV.length > 0 );
+        cipherSpec = new CipherSpec(myIV);
+        assertTrue( cipherSpec.getKeySize() ==
+                        ESAPI.securityConfiguration().getEncryptionKeyLength() );
+        assertTrue( cipherSpec.getCipherTransformation().equals(
+                        ESAPI.securityConfiguration().getCipherTransformation() ) );
+    }
+
+    /** Test CipherSpec() */
+    @Test public void testCipherSpec() {
+        cipherSpec = new CipherSpec( dfltECBCipher );
+        assertTrue( cipherSpec.getCipherTransformation().equals("AES/ECB/NoPadding") );
+        assertTrue( cipherSpec.getIV() == null );
+
+        cipherSpec = new CipherSpec(dfltOtherCipher);
+        assertTrue( cipherSpec.getCipherMode().equals("OFB8") );
+    }
+
+    /** Test setCipherTransformation(String cipherXform) */
+    @Test public void testSetCipherTransformation() {
+        cipherSpec = new CipherSpec();
+        cipherSpec.setCipherTransformation("AlgName/Mode/Padding");
+        cipherSpec.getCipherAlgorithm().equals("AlgName/Mode/Padding");
+
+        try {
+                // Don't use null here as compiling JUnit tests disables assertion
+                // checking so we get a NullPointerException here instead.
+            cipherSpec.setCipherTransformation(""); // Throws IllegalArgumentException
+        } catch (IllegalArgumentException e) {
+            assertTrue(true);    // Doesn't work w/ @Test(expected=IllegalArgumentException.class)
+        }
+    }
+
+    /** Test getCipherTransformation() */
+    @Test public void testGetCipherTransformation() {
+        assertTrue( (new CipherSpec()).getCipherTransformation().equals("AES/CBC/PKCS5Padding") );
+    }
+
+    /** Test setKeySize() */
+    @Test public void testSetKeySize() {
+        assertTrue( (new CipherSpec()).setKeySize(56).getKeySize() == 56 );
+    }
+
+    /** Test getKeySize() */
+    @Test public void testGetKeySize() {
+        assertTrue( (new CipherSpec()).getKeySize() ==
+            ESAPI.securityConfiguration().getEncryptionKeyLength() );
+    }
+
+    /** Test setBlockSize() */
+    @Test public void testSetBlockSize() {
+        try {
+            cipherSpec.setBlockSize(0); // Throws IllegalArgumentException
+        } catch (IllegalArgumentException e) {
+            assertTrue(true);
+        }
+        try {
+            cipherSpec.setBlockSize(-1); // Throws IllegalArgumentException
+        } catch (IllegalArgumentException e) {
+            assertTrue(true);
+        }
+        assertTrue( cipherSpec.setBlockSize(4).getBlockSize() == 4 );
+    }
+
+    /** Test getBlockSize() */
+    @Test public void testGetBlockSize() {
+        assertTrue( cipherSpec.getBlockSize() == 8 );
+    }
+
+    /** Test getCipherAlgorithm() */
+    @Test public void testGetCipherAlgorithm() {
+        assertTrue( cipherSpec.getCipherAlgorithm().equals("Blowfish") );
+    }
+
+    /** Test getCipherMode */
+    @Test public void testGetCipherMode() {
+        assertTrue( cipherSpec.getCipherMode().equals("OFB8") );
+    }
+
+    /** Test getPaddingScheme() */
+    @Test public void testGetPaddingScheme() {
+        assertTrue( cipherSpec.getPaddingScheme().equals("PKCS5Padding") );
+    }
+
+    /** Test setIV() */
+    @Test public void testSetIV() {
+        try {
+            // Test that ECB mode allows a null IV
+            cipherSpec = new CipherSpec(dfltECBCipher);
             assertTrue( cipherSpec.getCipherMode().equals("ECB") );
-			cipherSpec.setIV(null);
-			assertTrue(true);
-		} catch ( IllegalArgumentException e) {
-			assertFalse("Test failed; unexpected exception", false);
-		}
-		try {
-			// Test that CBC mode does allows a null IV
-			cipherSpec = new CipherSpec(dfltAESCipher);
-			cipherSpec.setIV(null);
-			assertFalse("Test failed; Expected exception not thrown", false);
-		} catch ( IllegalArgumentException e) {
-			assertTrue(true);
-		}
-	}
-
-	/** Test requiresIV() */
-	@Test public void testRequiresIV() {
-		assertTrue( (new CipherSpec(dfltECBCipher)).requiresIV() == false );
-		cipherSpec = new CipherSpec(dfltAESCipher);
-		assertTrue( cipherSpec.getCipherMode().equals("ECB") );
-		assertTrue( cipherSpec.requiresIV() == false );
-		assertTrue( new CipherSpec(dfltOtherCipher).requiresIV() );
-	}
-	
-	/** Test serialization */
-	@Test public void testSerialization() {
+            cipherSpec.setIV(null);
+            assertTrue(true);
+        } catch ( IllegalArgumentException e) {
+            assertFalse("Test failed; unexpected exception", false);
+        }
+        try {
+            // Test that CBC mode does allows a null IV
+            cipherSpec = new CipherSpec(dfltAESCipher);
+            cipherSpec.setIV(null);
+            assertFalse("Test failed; Expected exception not thrown", false);
+        } catch ( IllegalArgumentException e) {
+            assertTrue(true);
+        }
+    }
+
+    /** Test requiresIV() */
+    @Test public void testRequiresIV() {
+        assertTrue( (new CipherSpec(dfltECBCipher)).requiresIV() == false );
+        cipherSpec = new CipherSpec(dfltAESCipher);
+        assertTrue( cipherSpec.getCipherMode().equals("ECB") );
+        assertTrue( cipherSpec.requiresIV() == false );
+        assertTrue( new CipherSpec(dfltOtherCipher).requiresIV() );
+    }
+
+    /** Test serialization */
+    @Test public void testSerialization() {
         String filename = "cipherspec.ser";
         File serializedFile = new File(filename);
         boolean success = false;
@@ -217,7 +217,7 @@ public class CipherSpecTest extends TestCase {
             //       Guess what? We don't care!!!
             serializedFile.delete();
 
-            
+
             cipherSpec = new CipherSpec( "AES/CBC/NoPadding",  128,  8, myIV);
             FileOutputStream fos = new FileOutputStream(filename);
             ObjectOutputStream out = new ObjectOutputStream(fos);
@@ -234,8 +234,8 @@ public class CipherSpecTest extends TestCase {
             // check that cipherSpec and restoredCipherSpec are equal. Just
             // compare them via their string representations.
             assertEquals("Serialized restored CipherSpec differs from saved CipherSpec",
-            			 cipherSpec.toString(), restoredCipherSpec.toString() );
-            
+                         cipherSpec.toString(), restoredCipherSpec.toString() );
+
             success = true;
         } catch(IOException ex) {
             ex.printStackTrace(System.err);
@@ -257,8 +257,8 @@ public class CipherSpecTest extends TestCase {
                 }
             }
         }
-	}
-	
+    }
+
     /**
      * Run all the test cases in this suite.
      * This is to allow running from {@code org.owasp.esapi.AllTests}.
diff --git a/src/test/java/org/owasp/esapi/crypto/CipherTextSerializerTest.java b/src/test/java/org/owasp/esapi/crypto/CipherTextSerializerTest.java
index 9f86b9f..fcf5be7 100644
--- a/src/test/java/org/owasp/esapi/crypto/CipherTextSerializerTest.java
+++ b/src/test/java/org/owasp/esapi/crypto/CipherTextSerializerTest.java
@@ -18,7 +18,7 @@ public class CipherTextSerializerTest {
     private Cipher encryptor = null;
     private IvParameterSpec ivSpec = null;  // Note: FindBugs reports false positive
                                             // about this being unread field. See
-    										// testAsSerializedByteArray().
+                                            // testAsSerializedByteArray().
 
     @BeforeClass
     public static void setUpBeforeClass() throws Exception {
@@ -38,12 +38,12 @@ public class CipherTextSerializerTest {
 
     @After
     public void tearDown() throws Exception {
-    	System.out.flush();
+        System.out.flush();
     }
 
     @Test
     public final void testAsSerializedByteArray() {
-    	System.out.println("CipherTextSerializerTest.testAsSerializedByteArray() ...");
+        System.out.println("CipherTextSerializerTest.testAsSerializedByteArray() ...");
         CipherSpec cipherSpec = new CipherSpec(encryptor, 128);
         cipherSpec.setIV(ivSpec.getIV());
         SecretKey key;
@@ -68,7 +68,7 @@ public class CipherTextSerializerTest {
     @Test
     public final void testAsCipherText() {
         try {
-        	System.out.println("CipherTextSerializerTest.testAsCipherText() ...");
+            System.out.println("CipherTextSerializerTest.testAsCipherText() ...");
             CipherText ct = ESAPI.encryptor().encrypt( new PlainText("Hello") );
             CipherTextSerializer cts = new CipherTextSerializer( ct );
             CipherText result = cts.asCipherText();
diff --git a/src/test/java/org/owasp/esapi/crypto/CipherTextTest.java b/src/test/java/org/owasp/esapi/crypto/CipherTextTest.java
index b3a6b55..5e8b036 100644
--- a/src/test/java/org/owasp/esapi/crypto/CipherTextTest.java
+++ b/src/test/java/org/owasp/esapi/crypto/CipherTextTest.java
@@ -23,193 +23,193 @@ import junit.framework.JUnit4TestAdapter;
 
 public class CipherTextTest {
 
-	private CipherSpec cipherSpec_ = null;
+    private CipherSpec cipherSpec_ = null;
     private Cipher encryptor = null;
     private Cipher decryptor = null;
     private IvParameterSpec ivSpec = null;
     @Rule
     public TemporaryFolder tempFolder = new TemporaryFolder();
-   
-    
-	@Before
-	public void setUp() throws Exception {
+
+
+    @Before
+    public void setUp() throws Exception {
         encryptor = Cipher.getInstance("AES/CBC/PKCS5Padding");
         decryptor = Cipher.getInstance("AES/CBC/PKCS5Padding");
         byte[] ivBytes = null;
         ivBytes = ESAPI.randomizer().getRandomBytes(encryptor.getBlockSize());
         ivSpec = new IvParameterSpec(ivBytes);
-	}
-
-	/** Test the default CTOR */
-	@Test
-	public final void testCipherText() {
-		CipherText ct =  new CipherText();
-
-		cipherSpec_ = new CipherSpec();
-		assertTrue( ct.getCipherTransformation().equals( cipherSpec_.getCipherTransformation()));
-		assertTrue( ct.getBlockSize() == cipherSpec_.getBlockSize() );
-	}
-
-	@Test
-	public final void testCipherTextCipherSpec() {
-		cipherSpec_ = new CipherSpec("DESede/OFB8/NoPadding", 112);
-		CipherText ct = new CipherText( cipherSpec_ );
-		assertTrue( ct.getRawCipherText() == null );
-		assertTrue( ct.getCipherAlgorithm().equals("DESede") );
-		assertTrue( ct.getKeySize() == cipherSpec_.getKeySize() );
-	}
-
-	@Test
-	public final void testCipherTextCipherSpecByteArray()
-	{
-		try {
-			CipherSpec cipherSpec = new CipherSpec(encryptor, 128);
-			cipherSpec.setIV(ivSpec.getIV());
-			SecretKey key =
-				CryptoHelper.generateSecretKey(cipherSpec.getCipherAlgorithm(), 128);
-			encryptor.init(Cipher.ENCRYPT_MODE, key, ivSpec);
-			byte[] raw = encryptor.doFinal("Hello".getBytes("UTF8"));
-			CipherText ct = new CipherText(cipherSpec, raw);
-			assertTrue( ct != null );
-			byte[] ctRaw = ct.getRawCipherText();
-			assertTrue( ctRaw != null );
-			assertArrayEquals(raw, ctRaw);
-			assertTrue( ct.getCipherTransformation().equals(cipherSpec.getCipherTransformation()) );;
-			assertTrue( ct.getCipherAlgorithm().equals(cipherSpec.getCipherAlgorithm()) );
-			assertTrue( ct.getPaddingScheme().equals(cipherSpec.getPaddingScheme()) );
-			assertTrue( ct.getBlockSize() == cipherSpec.getBlockSize() );
-			assertTrue( ct.getKeySize() == cipherSpec.getKeySize() );
-			byte[] ctIV = ct.getIV();
-			byte[] csIV = cipherSpec.getIV();
-			assertArrayEquals(ctIV, csIV);
-		} catch( Exception ex) {
-			// As far as test coverage goes, we really don't want this to be covered.
-			fail("Caught unexpected exception: " + ex.getClass().getName() +
-					    "; exception message was: " + ex.getMessage());
-		}
-	}
-
-
-	@Test
-	public final void testDecryptionUsingCipherText() {
-		try {
-			CipherSpec cipherSpec = new CipherSpec(encryptor, 128);
-			cipherSpec.setIV(ivSpec.getIV());
-			assertTrue( cipherSpec.getIV() != null );
-			assertTrue( cipherSpec.getIV().length > 0 );
-			SecretKey key =
-				CryptoHelper.generateSecretKey(cipherSpec.getCipherAlgorithm(), 128);
-			encryptor.init(Cipher.ENCRYPT_MODE, key, ivSpec);
-			byte[] ctraw = encryptor.doFinal("Hello".getBytes("UTF8"));
-			CipherText ct = new CipherText(cipherSpec, ctraw);
-			assertTrue( ct.getCipherMode().equals("CBC") );
-			assertTrue( ct.requiresIV() ); // CBC mode requires an IV.
-			String b64ctraw = ct.getBase64EncodedRawCipherText();
-			assertTrue( b64ctraw != null);
-			assertArrayEquals( ESAPI.encoder().decodeFromBase64(b64ctraw), ctraw );
-			decryptor.init(Cipher.DECRYPT_MODE, key, new IvParameterSpec(ct.getIV()));
-			byte[] ptraw = decryptor.doFinal(ESAPI.encoder().decodeFromBase64(b64ctraw));
-			assertTrue( ptraw != null );
-			assertTrue( ptraw.length > 0 );
-			String plaintext = new String( ptraw, "UTF-8");
-			assertTrue( plaintext.equals("Hello") );
-			assertArrayEquals( ct.getRawCipherText(), ctraw );
-			
-			byte[] ivAndRaw = ESAPI.encoder().decodeFromBase64( ct.getEncodedIVCipherText() );
-			assertTrue( ivAndRaw.length > ctraw.length );
-			assertTrue( ct.getBlockSize() == ( ivAndRaw.length - ctraw.length ) );
-		} catch( Exception ex) {
-		    // Note: FindBugs reports a false positive here...
-		    //    REC_CATCH_EXCEPTION: Exception is caught when Exception is not thrown
-		    // but exceptions really can be thrown. This probably is because FindBugs
-		    // examines the byte-code rather than the source code. However "fixing" this
-		    // so that it doesn't complain will make the test much more complicated as there
-		    // are about 3 or 4 different exception types.
-		    //
-		    // On a completely different note, as far as test coverage metrics goes,
-			// we really don't care if this is covered or nit as it is not our intent
-		    // to be causing exceptions here.
-			ex.printStackTrace(System.err);
-			fail("Caught unexpected exception: " + ex.getClass().getName() +
-					"; exception message was: " + ex.getMessage());
-		}
-	}
-
-	@Test
-	public final void testMIC() {
-		try {
-			CipherSpec cipherSpec = new CipherSpec(encryptor, 128);
-			cipherSpec.setIV(ivSpec.getIV());
-			SecretKey key =
-				CryptoHelper.generateSecretKey(cipherSpec.getCipherAlgorithm(), 128);
-			encryptor.init(Cipher.ENCRYPT_MODE, key, ivSpec);
-			byte[] ctraw = encryptor.doFinal("Hello".getBytes("UTF8"));
-			CipherText ct = new CipherText(cipherSpec, ctraw);
-			assertTrue( ct.getIV() != null && ct.getIV().length > 0 );
-			SecretKey authKey = CryptoHelper.computeDerivedKey(key, key.getEncoded().length * 8, "authenticity");
-			ct.computeAndStoreMAC( authKey ); 
-			try {
-				ct.setIVandCiphertext(ivSpec.getIV(), ctraw);	// Expected to log & throw.
-			} catch( Exception ex ) {
-				assertTrue( ex instanceof EncryptionException );
-			}
-			try {
-				ct.setCiphertext(ctraw);	// Expected to log and throw message about
-											// not being able to store raw ciphertext.
-			} catch( Exception ex ) {
-				assertTrue( ex instanceof EncryptionException );
-			}
-			decryptor.init(Cipher.DECRYPT_MODE, key, new IvParameterSpec( ct.getIV() ) );
-			byte[] ptraw = decryptor.doFinal( ct.getRawCipherText() );
-			assertTrue( ptraw != null && ptraw.length > 0 );
-			ct.validateMAC( authKey );
-		} catch( Exception ex) {
-			// As far as test coverage goes, we really don't want this to be covered.
-			ex.printStackTrace(System.err);
-			fail("Caught unexpected exception: " + ex.getClass().getName() +
-					"; exception message was: " + ex.getMessage());
-		}
-	}
-
-	/** Test <i>portable</i> serialization. */
-	@Test public final void testPortableSerialization() throws Exception{
-	    System.out.println("CipherTextTest.testPortableSerialization()starting...");
-	    String filename = "ciphertext-portable.ser";
-	    File serializedFile = tempFolder.newFile(filename);
-	  
-
-	    int keySize = 128;
-	    if ( CryptoPolicy.isUnlimitedStrengthCryptoAvailable() ) {
-	        keySize = 256;
-	    }
-	    CipherSpec cipherSpec = new CipherSpec(encryptor, keySize);
-	    cipherSpec.setIV(ivSpec.getIV());
-	    SecretKey key;
-	    try {
-	        key = CryptoHelper.generateSecretKey(cipherSpec.getCipherAlgorithm(), keySize);
-
-	        encryptor.init(Cipher.ENCRYPT_MODE, key, ivSpec);
-	        byte[] raw = encryptor.doFinal("This is my secret message!!!".getBytes("UTF8"));
-	        CipherText ciphertext = new CipherText(cipherSpec, raw);
-		    KeyDerivationFunction kdf = new KeyDerivationFunction( KeyDerivationFunction.PRF_ALGORITHMS.HmacSHA1 );
-	        SecretKey authKey = kdf.computeDerivedKey(key, key.getEncoded().length * 8, "authenticity");
-	        ciphertext.computeAndStoreMAC( authKey );
+    }
+
+    /** Test the default CTOR */
+    @Test
+    public final void testCipherText() {
+        CipherText ct =  new CipherText();
+
+        cipherSpec_ = new CipherSpec();
+        assertTrue( ct.getCipherTransformation().equals( cipherSpec_.getCipherTransformation()));
+        assertTrue( ct.getBlockSize() == cipherSpec_.getBlockSize() );
+    }
+
+    @Test
+    public final void testCipherTextCipherSpec() {
+        cipherSpec_ = new CipherSpec("DESede/OFB8/NoPadding", 112);
+        CipherText ct = new CipherText( cipherSpec_ );
+        assertTrue( ct.getRawCipherText() == null );
+        assertTrue( ct.getCipherAlgorithm().equals("DESede") );
+        assertTrue( ct.getKeySize() == cipherSpec_.getKeySize() );
+    }
+
+    @Test
+    public final void testCipherTextCipherSpecByteArray()
+    {
+        try {
+            CipherSpec cipherSpec = new CipherSpec(encryptor, 128);
+            cipherSpec.setIV(ivSpec.getIV());
+            SecretKey key =
+                CryptoHelper.generateSecretKey(cipherSpec.getCipherAlgorithm(), 128);
+            encryptor.init(Cipher.ENCRYPT_MODE, key, ivSpec);
+            byte[] raw = encryptor.doFinal("Hello".getBytes("UTF8"));
+            CipherText ct = new CipherText(cipherSpec, raw);
+            assertTrue( ct != null );
+            byte[] ctRaw = ct.getRawCipherText();
+            assertTrue( ctRaw != null );
+            assertArrayEquals(raw, ctRaw);
+            assertTrue( ct.getCipherTransformation().equals(cipherSpec.getCipherTransformation()) );;
+            assertTrue( ct.getCipherAlgorithm().equals(cipherSpec.getCipherAlgorithm()) );
+            assertTrue( ct.getPaddingScheme().equals(cipherSpec.getPaddingScheme()) );
+            assertTrue( ct.getBlockSize() == cipherSpec.getBlockSize() );
+            assertTrue( ct.getKeySize() == cipherSpec.getKeySize() );
+            byte[] ctIV = ct.getIV();
+            byte[] csIV = cipherSpec.getIV();
+            assertArrayEquals(ctIV, csIV);
+        } catch( Exception ex) {
+            // As far as test coverage goes, we really don't want this to be covered.
+            fail("Caught unexpected exception: " + ex.getClass().getName() +
+                        "; exception message was: " + ex.getMessage());
+        }
+    }
+
+
+    @Test
+    public final void testDecryptionUsingCipherText() {
+        try {
+            CipherSpec cipherSpec = new CipherSpec(encryptor, 128);
+            cipherSpec.setIV(ivSpec.getIV());
+            assertTrue( cipherSpec.getIV() != null );
+            assertTrue( cipherSpec.getIV().length > 0 );
+            SecretKey key =
+                CryptoHelper.generateSecretKey(cipherSpec.getCipherAlgorithm(), 128);
+            encryptor.init(Cipher.ENCRYPT_MODE, key, ivSpec);
+            byte[] ctraw = encryptor.doFinal("Hello".getBytes("UTF8"));
+            CipherText ct = new CipherText(cipherSpec, ctraw);
+            assertTrue( ct.getCipherMode().equals("CBC") );
+            assertTrue( ct.requiresIV() ); // CBC mode requires an IV.
+            String b64ctraw = ct.getBase64EncodedRawCipherText();
+            assertTrue( b64ctraw != null);
+            assertArrayEquals( ESAPI.encoder().decodeFromBase64(b64ctraw), ctraw );
+            decryptor.init(Cipher.DECRYPT_MODE, key, new IvParameterSpec(ct.getIV()));
+            byte[] ptraw = decryptor.doFinal(ESAPI.encoder().decodeFromBase64(b64ctraw));
+            assertTrue( ptraw != null );
+            assertTrue( ptraw.length > 0 );
+            String plaintext = new String( ptraw, "UTF-8");
+            assertTrue( plaintext.equals("Hello") );
+            assertArrayEquals( ct.getRawCipherText(), ctraw );
+
+            byte[] ivAndRaw = ESAPI.encoder().decodeFromBase64( ct.getEncodedIVCipherText() );
+            assertTrue( ivAndRaw.length > ctraw.length );
+            assertTrue( ct.getBlockSize() == ( ivAndRaw.length - ctraw.length ) );
+        } catch( Exception ex) {
+            // Note: FindBugs reports a false positive here...
+            //    REC_CATCH_EXCEPTION: Exception is caught when Exception is not thrown
+            // but exceptions really can be thrown. This probably is because FindBugs
+            // examines the byte-code rather than the source code. However "fixing" this
+            // so that it doesn't complain will make the test much more complicated as there
+            // are about 3 or 4 different exception types.
+            //
+            // On a completely different note, as far as test coverage metrics goes,
+            // we really don't care if this is covered or nit as it is not our intent
+            // to be causing exceptions here.
+            ex.printStackTrace(System.err);
+            fail("Caught unexpected exception: " + ex.getClass().getName() +
+                    "; exception message was: " + ex.getMessage());
+        }
+    }
+
+    @Test
+    public final void testMIC() {
+        try {
+            CipherSpec cipherSpec = new CipherSpec(encryptor, 128);
+            cipherSpec.setIV(ivSpec.getIV());
+            SecretKey key =
+                CryptoHelper.generateSecretKey(cipherSpec.getCipherAlgorithm(), 128);
+            encryptor.init(Cipher.ENCRYPT_MODE, key, ivSpec);
+            byte[] ctraw = encryptor.doFinal("Hello".getBytes("UTF8"));
+            CipherText ct = new CipherText(cipherSpec, ctraw);
+            assertTrue( ct.getIV() != null && ct.getIV().length > 0 );
+            SecretKey authKey = CryptoHelper.computeDerivedKey(key, key.getEncoded().length * 8, "authenticity");
+            ct.computeAndStoreMAC( authKey );
+            try {
+                ct.setIVandCiphertext(ivSpec.getIV(), ctraw);    // Expected to log & throw.
+            } catch( Exception ex ) {
+                assertTrue( ex instanceof EncryptionException );
+            }
+            try {
+                ct.setCiphertext(ctraw);    // Expected to log and throw message about
+                                            // not being able to store raw ciphertext.
+            } catch( Exception ex ) {
+                assertTrue( ex instanceof EncryptionException );
+            }
+            decryptor.init(Cipher.DECRYPT_MODE, key, new IvParameterSpec( ct.getIV() ) );
+            byte[] ptraw = decryptor.doFinal( ct.getRawCipherText() );
+            assertTrue( ptraw != null && ptraw.length > 0 );
+            ct.validateMAC( authKey );
+        } catch( Exception ex) {
+            // As far as test coverage goes, we really don't want this to be covered.
+            ex.printStackTrace(System.err);
+            fail("Caught unexpected exception: " + ex.getClass().getName() +
+                    "; exception message was: " + ex.getMessage());
+        }
+    }
+
+    /** Test <i>portable</i> serialization. */
+    @Test public final void testPortableSerialization() throws Exception{
+        System.out.println("CipherTextTest.testPortableSerialization()starting...");
+        String filename = "ciphertext-portable.ser";
+        File serializedFile = tempFolder.newFile(filename);
+
+
+        int keySize = 128;
+        if ( CryptoPolicy.isUnlimitedStrengthCryptoAvailable() ) {
+            keySize = 256;
+        }
+        CipherSpec cipherSpec = new CipherSpec(encryptor, keySize);
+        cipherSpec.setIV(ivSpec.getIV());
+        SecretKey key;
+        try {
+            key = CryptoHelper.generateSecretKey(cipherSpec.getCipherAlgorithm(), keySize);
+
+            encryptor.init(Cipher.ENCRYPT_MODE, key, ivSpec);
+            byte[] raw = encryptor.doFinal("This is my secret message!!!".getBytes("UTF8"));
+            CipherText ciphertext = new CipherText(cipherSpec, raw);
+            KeyDerivationFunction kdf = new KeyDerivationFunction( KeyDerivationFunction.PRF_ALGORITHMS.HmacSHA1 );
+            SecretKey authKey = kdf.computeDerivedKey(key, key.getEncoded().length * 8, "authenticity");
+            ciphertext.computeAndStoreMAC( authKey );
 //          System.err.println("Original ciphertext being serialized: " + ciphertext);
-	        byte[] serializedBytes = ciphertext.asPortableSerializedByteArray();
-	        
-	        FileOutputStream fos = new FileOutputStream(serializedFile);
+            byte[] serializedBytes = ciphertext.asPortableSerializedByteArray();
+
+            FileOutputStream fos = new FileOutputStream(serializedFile);
             fos.write(serializedBytes);
                 // Note: FindBugs complains that this test may fail to close
                 // the fos output stream. We don't really care.
             fos.close();
-            
+
             // NOTE: FindBugs complains about this (OS_OPEN_STREAM). It apparently
             //       is too lame to know that 'fis.read()' is a serious side-effect.
             FileInputStream fis = new FileInputStream(serializedFile);
             int avail = fis.available();
             byte[] bytes = new byte[avail];
             fis.read(bytes, 0, avail);
-            
+
             // Sleep one second to prove that the timestamp on the original
             // CipherText object is the one that we use and not just the
             // current time. Only after that, do we restore the serialized bytes.
@@ -217,12 +217,12 @@ public class CipherTextTest {
                 Thread.sleep(1000);
             } catch (InterruptedException e) {
                 ;    // Ignore
-            }       
+            }
             CipherText restoredCipherText = CipherText.fromPortableSerializedBytes(bytes);
 //          System.err.println("Restored ciphertext: " + restoredCipherText);
             assertTrue( ciphertext.equals(restoredCipherText));
-	    } catch (EncryptionException e) {
-	        Assert.fail("Caught EncryptionException: " + e);
+        } catch (EncryptionException e) {
+            Assert.fail("Caught EncryptionException: " + e);
         } catch (FileNotFoundException e) {
             Assert.fail("Caught FileNotFoundException: " + e);
         } catch (IOException e) {
@@ -233,17 +233,17 @@ public class CipherTextTest {
             // FindBugs complains that we are ignoring this return value. We really don't care.
             serializedFile.delete();
         }
-	}
-	
-	/** Test <i>portable</i> serialization for backward compatibility with ESAPI 2.0. */
-	@Test public final void testPortableSerializationBackwardCompatibility() {
-	    System.out.println("testPortableSerializationBackwardCompatibility()starting...");
-	    String filename = "src/test/resources/ESAPI2.0-ciphertext-portable.ser";  // Do NOT remove
-	    File serializedFile = new File(filename);
-
-	    try {
-	    	// String expectedMsg = "This is my secret message!!!";
-            
+    }
+
+    /** Test <i>portable</i> serialization for backward compatibility with ESAPI 2.0. */
+    @Test public final void testPortableSerializationBackwardCompatibility() {
+        System.out.println("testPortableSerializationBackwardCompatibility()starting...");
+        String filename = "src/test/resources/ESAPI2.0-ciphertext-portable.ser";  // Do NOT remove
+        File serializedFile = new File(filename);
+
+        try {
+            // String expectedMsg = "This is my secret message!!!";
+
             // NOTE: FindBugs complains about this (OS_OPEN_STREAM). It apparently
             //       is too lame to know that 'fis.read()' is a serious side-effect.
             FileInputStream fis = new FileInputStream(serializedFile);
@@ -255,8 +255,8 @@ public class CipherTextTest {
             CipherText restoredCipherText = CipherText.fromPortableSerializedBytes(bytes);
             assertTrue( restoredCipherText != null );
             int retrievedKdfVersion = restoredCipherText.getKDFVersion();
-	    } catch (EncryptionException e) {
-	        Assert.fail("Caught EncryptionException: " + e);
+        } catch (EncryptionException e) {
+            Assert.fail("Caught EncryptionException: " + e);
         } catch (FileNotFoundException e) {
             Assert.fail("Caught FileNotFoundException: " + e);
         } catch (IOException e) {
@@ -264,24 +264,24 @@ public class CipherTextTest {
         } catch (Exception e) {
             Assert.fail("Caught Exception: " + e);
         } finally {
-        	; // Do NOT delete the file.
+            ; // Do NOT delete the file.
         }
-	}
-	
-	/** Test Java serialization. */
-	@Test public final void testJavaSerialization() {
+    }
+
+    /** Test Java serialization. */
+    @Test public final void testJavaSerialization() {
         String filename = "ciphertext.ser";
-      
+
         try {
             File serializedFile = tempFolder.newFile(filename);
-            
+
             CipherSpec cipherSpec = new CipherSpec(encryptor, 128);
-			cipherSpec.setIV(ivSpec.getIV());
-			SecretKey key =
-				CryptoHelper.generateSecretKey(cipherSpec.getCipherAlgorithm(), 128);
-			encryptor.init(Cipher.ENCRYPT_MODE, key, ivSpec);
-			byte[] raw = encryptor.doFinal("This is my secret message!!!".getBytes("UTF8"));
-			CipherText ciphertext = new CipherText(cipherSpec, raw);
+            cipherSpec.setIV(ivSpec.getIV());
+            SecretKey key =
+                CryptoHelper.generateSecretKey(cipherSpec.getCipherAlgorithm(), 128);
+            encryptor.init(Cipher.ENCRYPT_MODE, key, ivSpec);
+            byte[] raw = encryptor.doFinal("This is my secret message!!!".getBytes("UTF8"));
+            CipherText ciphertext = new CipherText(cipherSpec, raw);
 
             FileOutputStream fos = new FileOutputStream(serializedFile);
             ObjectOutputStream out = new ObjectOutputStream(fos);
@@ -299,13 +299,13 @@ public class CipherTextTest {
             // multiple checks. (Hmmm... maybe overriding equals() and hashCode()
             // is in order???)
             assertEquals("1: Serialized restored CipherText differs from saved CipherText",
-            			 ciphertext.toString(), restoredCipherText.toString());
+                         ciphertext.toString(), restoredCipherText.toString());
             assertArrayEquals("2: Serialized restored CipherText differs from saved CipherText",
-            			 ciphertext.getIV(), restoredCipherText.getIV());
+                         ciphertext.getIV(), restoredCipherText.getIV());
             assertEquals("3: Serialized restored CipherText differs from saved CipherText",
-            			 ciphertext.getBase64EncodedRawCipherText(),
-            			 restoredCipherText.getBase64EncodedRawCipherText());
-            
+                         ciphertext.getBase64EncodedRawCipherText(),
+                         restoredCipherText.getBase64EncodedRawCipherText());
+
         } catch(IOException ex) {
             ex.printStackTrace(System.err);
             fail("testJavaSerialization(): Unexpected IOException: " + ex);
@@ -313,29 +313,29 @@ public class CipherTextTest {
             ex.printStackTrace(System.err);
             fail("testJavaSerialization(): Unexpected ClassNotFoundException: " + ex);
         } catch (EncryptionException ex) {
-			ex.printStackTrace(System.err);
-			fail("testJavaSerialization(): Unexpected EncryptionException: " + ex);
-		} catch (IllegalBlockSizeException ex) {
-			ex.printStackTrace(System.err);
-			fail("testJavaSerialization(): Unexpected IllegalBlockSizeException: " + ex);
-		} catch (BadPaddingException ex) {
-			ex.printStackTrace(System.err);
-			fail("testJavaSerialization(): Unexpected BadPaddingException: " + ex);
-		} catch (InvalidKeyException ex) {
-			ex.printStackTrace(System.err);
-			fail("testJavaSerialization(): Unexpected InvalidKeyException: " + ex);
-		} catch (InvalidAlgorithmParameterException ex) {
-			ex.printStackTrace(System.err);
-			fail("testJavaSerialization(): Unexpected InvalidAlgorithmParameterException: " + ex);
-		} 
-	}
-	
-	/**
-	 * Run all the test cases in this suite.
-	 * This is to allow running from {@code org.owasp.esapi.AllTests} which
-	 * uses a JUnit 3 test runner.
-	 */
-	public static junit.framework.Test suite() {
-		return new JUnit4TestAdapter(CipherTextTest.class);
-	}
+            ex.printStackTrace(System.err);
+            fail("testJavaSerialization(): Unexpected EncryptionException: " + ex);
+        } catch (IllegalBlockSizeException ex) {
+            ex.printStackTrace(System.err);
+            fail("testJavaSerialization(): Unexpected IllegalBlockSizeException: " + ex);
+        } catch (BadPaddingException ex) {
+            ex.printStackTrace(System.err);
+            fail("testJavaSerialization(): Unexpected BadPaddingException: " + ex);
+        } catch (InvalidKeyException ex) {
+            ex.printStackTrace(System.err);
+            fail("testJavaSerialization(): Unexpected InvalidKeyException: " + ex);
+        } catch (InvalidAlgorithmParameterException ex) {
+            ex.printStackTrace(System.err);
+            fail("testJavaSerialization(): Unexpected InvalidAlgorithmParameterException: " + ex);
+        }
+    }
+
+    /**
+     * Run all the test cases in this suite.
+     * This is to allow running from {@code org.owasp.esapi.AllTests} which
+     * uses a JUnit 3 test runner.
+     */
+    public static junit.framework.Test suite() {
+        return new JUnit4TestAdapter(CipherTextTest.class);
+    }
 }
diff --git a/src/test/java/org/owasp/esapi/crypto/CryptoHelperTest.java b/src/test/java/org/owasp/esapi/crypto/CryptoHelperTest.java
index aa7ae0c..b315867 100644
--- a/src/test/java/org/owasp/esapi/crypto/CryptoHelperTest.java
+++ b/src/test/java/org/owasp/esapi/crypto/CryptoHelperTest.java
@@ -91,7 +91,7 @@ public class CryptoHelperTest {
          * Unfortunately, can't rely no the nanosecond timer because as the
          * Javadoc for System.nanoTime() states, " No guarantees are made
          * about how frequently values change", so this is not very reliable.
-         * 
+         *
          * However, on can uncomment the code and observe that elapsed times
          * are generally less than 10 millionth of a second. I suppose if we
          * declared a large enough epsilon, we could make it work, but it is
@@ -99,7 +99,7 @@ public class CryptoHelperTest {
          * itself that it always goes through all the bits of the byte array
          * if it compares any bits at all.
          */
-        
+
 //        long start, stop, diff;
 
 //        start = System.nanoTime();
@@ -131,13 +131,13 @@ public class CryptoHelperTest {
 //        stop = System.nanoTime();
 //        diff = stop - start;
 //        System.out.println("diff: " + diff + " nanosec");
- 
+
 //        start = System.nanoTime();
         assertFalse(CryptoHelper.arrayCompare(null, ba1));
 //        stop = System.nanoTime();
 //        diff = stop - start;
 //        System.out.println("diff: " + diff + " nanosec");
- 
+
         ba2 = ba1;
 //        start = System.nanoTime();
         assertTrue(CryptoHelper.arrayCompare(ba1, ba2));
@@ -148,28 +148,28 @@ public class CryptoHelperTest {
 
     @Test
     public final void testIsValidKDFVersion() {
-    	assertTrue( CryptoHelper.isValidKDFVersion(20110203, false, false));
-    	assertTrue( CryptoHelper.isValidKDFVersion(20130830, false, false));
-    	assertTrue( CryptoHelper.isValidKDFVersion(33330303, false, false));
-    	assertTrue( CryptoHelper.isValidKDFVersion(99991231, false, false));
-
-    	assertFalse( CryptoHelper.isValidKDFVersion(0, false, false));
-    	assertFalse( CryptoHelper.isValidKDFVersion(99991232, false, false));
-    	assertFalse( CryptoHelper.isValidKDFVersion(20110202, false, false));
-
-    	assertTrue( CryptoHelper.isValidKDFVersion(20110203, true, false));
-    	assertTrue( CryptoHelper.isValidKDFVersion(KeyDerivationFunction.kdfVersion, true, false));
-    	assertFalse( CryptoHelper.isValidKDFVersion(KeyDerivationFunction.kdfVersion + 1, true, false));
-
-    	try {
-        	CryptoHelper.isValidKDFVersion(77777777, true, true);
-        	fail("Failed to CryptoHelper.isValidKDFVersion() failed to throw IllegalArgumentException.");
-    	}
-    	catch (Exception e) {
-    		assertTrue( e instanceof IllegalArgumentException);
-    	}
+        assertTrue( CryptoHelper.isValidKDFVersion(20110203, false, false));
+        assertTrue( CryptoHelper.isValidKDFVersion(20130830, false, false));
+        assertTrue( CryptoHelper.isValidKDFVersion(33330303, false, false));
+        assertTrue( CryptoHelper.isValidKDFVersion(99991231, false, false));
+
+        assertFalse( CryptoHelper.isValidKDFVersion(0, false, false));
+        assertFalse( CryptoHelper.isValidKDFVersion(99991232, false, false));
+        assertFalse( CryptoHelper.isValidKDFVersion(20110202, false, false));
+
+        assertTrue( CryptoHelper.isValidKDFVersion(20110203, true, false));
+        assertTrue( CryptoHelper.isValidKDFVersion(KeyDerivationFunction.kdfVersion, true, false));
+        assertFalse( CryptoHelper.isValidKDFVersion(KeyDerivationFunction.kdfVersion + 1, true, false));
+
+        try {
+            CryptoHelper.isValidKDFVersion(77777777, true, true);
+            fail("Failed to CryptoHelper.isValidKDFVersion() failed to throw IllegalArgumentException.");
+        }
+        catch (Exception e) {
+            assertTrue( e instanceof IllegalArgumentException);
+        }
     }
-    
+
     private void fillByteArray(byte[] ba, byte b) {
         for (int i = 0; i < ba.length; i++) {
             ba[i] = b;
diff --git a/src/test/java/org/owasp/esapi/crypto/CryptoTokenTest.java b/src/test/java/org/owasp/esapi/crypto/CryptoTokenTest.java
index 52c60c6..250cdd4 100644
--- a/src/test/java/org/owasp/esapi/crypto/CryptoTokenTest.java
+++ b/src/test/java/org/owasp/esapi/crypto/CryptoTokenTest.java
@@ -15,7 +15,7 @@ import org.owasp.esapi.errors.EncryptionException;
 import org.owasp.esapi.errors.ValidationException;
 
 public class CryptoTokenTest {
-    
+
     private SecretKey skey1 = null;
     private SecretKey skey2 = null;
 
@@ -58,7 +58,7 @@ public class CryptoTokenTest {
         assertEquals( ctok.getUserAccountName(), CryptoToken.ANONYMOUS_USER);
         assertFalse( ctok.isExpired() );
         long expTime1 = ctok.getExpiration();
-        
+
         CryptoToken ctok2 = null;
         try {
             if ( sk == null ) {
@@ -135,7 +135,7 @@ public class CryptoTokenTest {
 
         assertTrue( ctok.isExpired() );
         assertTrue( ctok2.isExpired() );
-        
+
         try {
             ctok2.updateToken(2);
         } catch (EncryptionException e) {
@@ -201,7 +201,7 @@ public class CryptoTokenTest {
         } catch (ValidationException e) {
             ;   // Success
         }
-        
+
     }
 
     @Test
@@ -245,7 +245,7 @@ public class CryptoTokenTest {
             ;   // Success
         } catch (Exception e) {
             fail("Caught unexpected exception: " + e);
-        }   
+        }
     }
 
 
@@ -262,7 +262,7 @@ public class CryptoTokenTest {
         } catch (Exception e) {
             fail("Caught unexpected exception: " + e);
         }
-        
+
         // Test case where attr name does not match regex "[A-Za-z0-9_.-]+".
         // Expect ValidationException.
         try {
@@ -273,7 +273,7 @@ public class CryptoTokenTest {
         } catch (Exception e) {
             fail("Caught unexpected exception: " + e);
         }
-        
+
         // Test case where attr VALUE is not. Expect ValidationException.
         try {
             ctok.setAttribute("myAttr", null);
@@ -293,7 +293,7 @@ public class CryptoTokenTest {
 
             ctok.setAttribute("complexAttr", complexValue);
             ctok.setAttribute("..--__", ""); // Ugly weird but legal attr name; empty is legal value.
-            
+
             for ( int i = 0; i < attrValues.length; i++ ) {
                 String attrName = "attr" + i;
                 String attrVal  = attrValues[i];
@@ -303,7 +303,7 @@ public class CryptoTokenTest {
 
             String tokenVal = ctok.getToken();
             assertNotNull("tokenVal should not be null", tokenVal);
-            
+
             CryptoToken ctok2 = new CryptoToken(tokenVal);
 
             String weirdAttr = ctok2.getAttribute("..--__");
@@ -337,7 +337,7 @@ public class CryptoTokenTest {
     // public Map<String, String> getAttributes()
     @Test
     public final void testAddandGetAttributes() {
-        CryptoToken ctok = new CryptoToken();       
+        CryptoToken ctok = new CryptoToken();
         Map<String, String> origAttrs = null;
 
         try {
@@ -348,7 +348,7 @@ public class CryptoTokenTest {
             String val = ctok.getAttribute("attr2");
             assertTrue("Attribute map not cloned; crypto token attr changed!",
                        val.equals("value2") );  // Confirm original attr2 did not change
-            
+
             origAttrs.put("attr3", "value3");
             origAttrs.put("attr4", "value4");
             ctok.addAttributes(origAttrs);
@@ -361,11 +361,11 @@ public class CryptoTokenTest {
         } catch (EncryptionException e) {
             fail("Caught unexpected EncryptionException: " + e);
         }
-        
+
         Map<String, String> extractedAttrs = ctok.getAttributes();
         assertTrue("Expected extracted attrs to be equal to original attrs",
                    origAttrs.equals(extractedAttrs));
-                
+
         origAttrs.put("/illegalAttrName/", "someValue");
         try {
             ctok.addAttributes(origAttrs);
@@ -376,7 +376,7 @@ public class CryptoTokenTest {
             e.printStackTrace(System.err);
             fail("Caught unexpected exception: " + e);
         }
-        
+
         origAttrs.clear();
         CryptoToken ctok2 = null;
         try {
@@ -385,7 +385,7 @@ public class CryptoTokenTest {
         } catch (EncryptionException e) {
             fail("Unexpected EncryptionException");
         }
-        
+
         try {
             ctok2.addAttributes(origAttrs);     // Add (empty) attribute map
         } catch (ValidationException e) {
diff --git a/src/test/java/org/owasp/esapi/crypto/ESAPICryptoMACByPassTest.java b/src/test/java/org/owasp/esapi/crypto/ESAPICryptoMACByPassTest.java
index eecc11c..a93ce6c 100644
--- a/src/test/java/org/owasp/esapi/crypto/ESAPICryptoMACByPassTest.java
+++ b/src/test/java/org/owasp/esapi/crypto/ESAPICryptoMACByPassTest.java
@@ -1,7 +1,7 @@
 /*
  * OWASP Enterprise Security API (ESAPI) - Google issue # 306.
  * (i.e., GitHub issue 312).
- * 
+ *
  * This file is part of the Open Web Application Security Project (OWASP)
  * Enterprise Security API (ESAPI) project. For details, please see
  * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
@@ -10,16 +10,16 @@
  * ESAPI is published by OWASP under the new BSD license. You should read
  * and accept the LICENSE before you use, modify, and/or redistribute this
  * software.
- * 
+ *
  * Full credit for this JUnit to illustrate what is now Google Issue # 306
  * goes to Philippe Arteau <philippe.arteau@gmail.com>. Originally
  * published 2013/08/21 to ESAPI-DEV mailing list. Shows that both
  * ESAPI 2.0 and 2.0.1 is vulnerable. Minor tweaks by Kevin W. Wall.
  *
  * Original class name: SignatureByPassTest.
- * 
+ *
  * NOTE: If this test fails, your version of ESAPI is vulnerable (or you have
- * 		 it configured not to require a MAC which you should NOT do).
+ *          it configured not to require a MAC which you should NOT do).
  */
 
 package org.owasp.esapi.crypto;
@@ -49,7 +49,7 @@ public class ESAPICryptoMACByPassTest {
 
     @Before
     public void setUp() throws NoSuchAlgorithmException, InvalidKeySpecException {
-    	; // Do any prerequisite setup here.
+        ; // Do any prerequisite setup here.
     }
 
     @Test
@@ -61,21 +61,21 @@ public class ESAPICryptoMACByPassTest {
         //Encryption with MAC
         String originalMessage = "Cryptography!?!?";
         System.out.printf("Encrypting the message '%s'\n", originalMessage);
-        	// Until there is a better way to do this. But this is much easier
-        	// than having to set up a custom ESAPI.properties file just for
-        	// this test.
-        	//
-        	// NOTE: Philippe Arteau's original exploit used "AES/OFB/NoPadding"
+            // Until there is a better way to do this. But this is much easier
+            // than having to set up a custom ESAPI.properties file just for
+            // this test.
+            //
+            // NOTE: Philippe Arteau's original exploit used "AES/OFB/NoPadding"
             //       so that one could see that the effect of the decryption would
-        	//		 be "Craptography!?!?". However, if you wish to do that, then
-        	//		 you must also change the ESAPI.properties file used by ESAPI
-        	//		 JUnit tests sp that "OFB" is accepted as an allowed cipher
-        	//		 mode. The easiest way to do that (if you are still not convinced)
-        	//		 is to add "OFB" mode to Encryptor.cipher_modes.additional_allowed;
-        	//		 e.g.,  Encryptor.cipher_modes.additional_allowed=CBC,OFB
-        	//
+            //         be "Craptography!?!?". However, if you wish to do that, then
+            //         you must also change the ESAPI.properties file used by ESAPI
+            //         JUnit tests sp that "OFB" is accepted as an allowed cipher
+            //         mode. The easiest way to do that (if you are still not convinced)
+            //         is to add "OFB" mode to Encryptor.cipher_modes.additional_allowed;
+            //         e.g.,  Encryptor.cipher_modes.additional_allowed=CBC,OFB
+            //
         String origCipherXform =
-        	ESAPI.securityConfiguration().setCipherTransformation("AES/CBC/NoPadding");
+            ESAPI.securityConfiguration().setCipherTransformation("AES/CBC/NoPadding");
         CipherText ct = ESAPI.encryptor().encrypt(sk,new PlainText(originalMessage));
 
         //Serialize the ciphertext in order to send it over the wire..
@@ -87,20 +87,20 @@ public class ESAPICryptoMACByPassTest {
         //Decrypt
         CipherText modifierCtObj = CipherText.fromPortableSerializedBytes(modifiedCt);
         try {
-        	ESAPI.securityConfiguration().setCipherTransformation(origCipherXform);
-        		// This decryption should fail by throwing an EncryptionException
-        		// if ESAPI crypto is NOT vulnerable and you never get to the
-        		// subsequent lines in the try block.
+            ESAPI.securityConfiguration().setCipherTransformation(origCipherXform);
+                // This decryption should fail by throwing an EncryptionException
+                // if ESAPI crypto is NOT vulnerable and you never get to the
+                // subsequent lines in the try block.
             PlainText pt = ESAPI.encryptor().decrypt(sk,modifierCtObj);
             System.out.printf("Decrypting to '%s' (probably will look like garbage!)\n", new String(pt.asBytes()));
             System.out.println("This ESAPI version vulnerable to MAC by-pass described in GitHub issue # 312! Upgrade to latest version.");
             fail("This ESAPI version is vulnerable to MAC by-pass described in GitHub issue # 312! Upgrade to latest version.");
         } catch(EncryptionException eex) {
-        	String errMsg = eex.getMessage();
-        		// See private String DECRYPTION_FAILED in JavaEncryptor.
-        	String expectedError = "Decryption failed; see logs for details.";
-        	assertTrue( errMsg.equals(expectedError) );
-        	System.out.println("testMacByPass(): Attempted decryption after MAC tampering failed.");
+            String errMsg = eex.getMessage();
+                // See private String DECRYPTION_FAILED in JavaEncryptor.
+            String expectedError = "Decryption failed; see logs for details.";
+            assertTrue( errMsg.equals(expectedError) );
+            System.out.println("testMacByPass(): Attempted decryption after MAC tampering failed.");
             System.out.println("Fix of issue # 306 successful. Crypto MAC by-pass test failed; exception was: [" + eex + "]");
         }
     }
diff --git a/src/test/java/org/owasp/esapi/crypto/PlainTextTest.java b/src/test/java/org/owasp/esapi/crypto/PlainTextTest.java
index 135b6d8..3f65b26 100644
--- a/src/test/java/org/owasp/esapi/crypto/PlainTextTest.java
+++ b/src/test/java/org/owasp/esapi/crypto/PlainTextTest.java
@@ -10,59 +10,59 @@ import org.junit.Test;
 import org.owasp.esapi.crypto.PlainText;
 
 public class PlainTextTest {
-	
-	private String unicodeStr = "A\u00ea\u00f1\u00fcC";	// I.e., "AêñüC"
-	private String altString  = "AêñüC";				// Same as above.
-	
-	/* NOTE: This test will not work on Windows unless executed under
-	 * Eclipse and the file is stored / treated as a UTF-8 encoded file
-	 * rather than the Windows native OS encoding of Windows-1252 (aka,
-	 * CP-1252). Therefore this test case has a check to not run the test
-	 * unless
-	 *     unicodeStr.equals(altString)
-	 * is true. If not the test is skipped and a message is printed to stderr.
-	 * Jim Manico made an attempt to address this (see private email to
-	 * kevin.w.wall@gmail.com on 11/26/2009, subject "Re: [OWASP-ESAPI] Unit
-	 * Tests Status") to correct this problem by setting some SVN attribute
-	 * to standardize all source files to UTF-8, but not all Subversion clients
-	 * are either honoring this or perhaps Windows just overrides this. Either
-	 * way, this test (which used to be an assertTrue() expression) was
-	 * introduced to account for this.
-	 */
-	@Test
-	public final void testUnicodeString() {
-	    // These 2 strings are *meant* to be equal. If they are not, please
-	    // do *NOT* change the test. It's a Windows thing. Sorry. Change your
-	    // OS instead. ;-)
-	    if ( ! unicodeStr.equals(altString) ) {
-	        System.err.println("Skipping JUnit test case " +
-	                           "PlainTextTest.testUnicodeString() on OS " +
-	                           System.getProperty("os.name") );
-	        return;
-	    }
-		try {
-			byte[] utf8Bytes = unicodeStr.getBytes("UTF-8");
-			PlainText pt1 = new PlainText(unicodeStr);
-			PlainText pt2 = new PlainText(altString);
-			
-			assertTrue( pt1.equals(pt1) );   // Equals self
-			assertFalse( pt1.equals(null) );
-			assertTrue( pt1.equals(pt2) );
-			assertFalse( pt1.equals( unicodeStr ) );
-			assertTrue( pt1.length() == utf8Bytes.length );
-			assertTrue( Arrays.equals(utf8Bytes, pt1.asBytes()) );			
-			assertTrue( pt1.hashCode() == unicodeStr.hashCode() );
-			
-		} catch (UnsupportedEncodingException e) {
-			fail("No UTF-8 byte encoding: " + e);
-			e.printStackTrace(System.err);
-		}
-	}
-	
-	@Test
-	public final void testNullCase() {
-	    int counter = 0;
-	    try {
+
+    private String unicodeStr = "A\u00ea\u00f1\u00fcC";    // I.e., "AêñüC"
+    private String altString  = "AêñüC";                // Same as above.
+
+    /* NOTE: This test will not work on Windows unless executed under
+     * Eclipse and the file is stored / treated as a UTF-8 encoded file
+     * rather than the Windows native OS encoding of Windows-1252 (aka,
+     * CP-1252). Therefore this test case has a check to not run the test
+     * unless
+     *     unicodeStr.equals(altString)
+     * is true. If not the test is skipped and a message is printed to stderr.
+     * Jim Manico made an attempt to address this (see private email to
+     * kevin.w.wall@gmail.com on 11/26/2009, subject "Re: [OWASP-ESAPI] Unit
+     * Tests Status") to correct this problem by setting some SVN attribute
+     * to standardize all source files to UTF-8, but not all Subversion clients
+     * are either honoring this or perhaps Windows just overrides this. Either
+     * way, this test (which used to be an assertTrue() expression) was
+     * introduced to account for this.
+     */
+    @Test
+    public final void testUnicodeString() {
+        // These 2 strings are *meant* to be equal. If they are not, please
+        // do *NOT* change the test. It's a Windows thing. Sorry. Change your
+        // OS instead. ;-)
+        if ( ! unicodeStr.equals(altString) ) {
+            System.err.println("Skipping JUnit test case " +
+                               "PlainTextTest.testUnicodeString() on OS " +
+                               System.getProperty("os.name") );
+            return;
+        }
+        try {
+            byte[] utf8Bytes = unicodeStr.getBytes("UTF-8");
+            PlainText pt1 = new PlainText(unicodeStr);
+            PlainText pt2 = new PlainText(altString);
+
+            assertTrue( pt1.equals(pt1) );   // Equals self
+            assertFalse( pt1.equals(null) );
+            assertTrue( pt1.equals(pt2) );
+            assertFalse( pt1.equals( unicodeStr ) );
+            assertTrue( pt1.length() == utf8Bytes.length );
+            assertTrue( Arrays.equals(utf8Bytes, pt1.asBytes()) );
+            assertTrue( pt1.hashCode() == unicodeStr.hashCode() );
+
+        } catch (UnsupportedEncodingException e) {
+            fail("No UTF-8 byte encoding: " + e);
+            e.printStackTrace(System.err);
+        }
+    }
+
+    @Test
+    public final void testNullCase() {
+        int counter = 0;
+        try {
             byte[] bytes = null;
             PlainText pt = new PlainText(bytes);
             fail("testNullCase(): Expected IllegalArgumentException");
@@ -71,54 +71,54 @@ public class PlainTextTest {
         } catch (Exception e) {
             fail("testNullCase(): Caught unexpected exception: " + e);
         }
-	}
+    }
 
-	@Test
-	public final void testEmptyString() {
-		PlainText mt  = new PlainText("");
-		assertTrue( mt.length() == 0 );
-		byte[] ba = mt.asBytes();
-		assertTrue( ba != null && ba.length == 0 );
-	}
+    @Test
+    public final void testEmptyString() {
+        PlainText mt  = new PlainText("");
+        assertTrue( mt.length() == 0 );
+        byte[] ba = mt.asBytes();
+        assertTrue( ba != null && ba.length == 0 );
+    }
 
-	@Test
-	public final void testOverwrite() {
-		try {
-			byte[] origBytes = unicodeStr.getBytes("UTF-8");
-			PlainText pt = new PlainText(origBytes);
-			assertTrue( pt.toString().equals(unicodeStr) );
-			assertTrue( Arrays.equals(origBytes, pt.asBytes()) );			
-			assertTrue( pt.hashCode() == unicodeStr.hashCode() );
-			
-			int origLen = origBytes.length;
+    @Test
+    public final void testOverwrite() {
+        try {
+            byte[] origBytes = unicodeStr.getBytes("UTF-8");
+            PlainText pt = new PlainText(origBytes);
+            assertTrue( pt.toString().equals(unicodeStr) );
+            assertTrue( Arrays.equals(origBytes, pt.asBytes()) );
+            assertTrue( pt.hashCode() == unicodeStr.hashCode() );
 
-			pt.overwrite();
-	        byte[] overwrittenBytes = pt.asBytes();
-			assertTrue( overwrittenBytes != null );
-			assertFalse( Arrays.equals( origBytes, overwrittenBytes ) );
+            int origLen = origBytes.length;
 
-			// Ensure that ALL the bytes overwritten with '*'.
-			int afterLen = overwrittenBytes.length;
-			assertTrue( origLen == afterLen );
-			int sum = 0;
-			for( int i = 0; i < afterLen; i++ ) {
-			    if ( overwrittenBytes[i] == '*' ) {
-			        sum++;
-			    }
-			}
-			assertTrue( afterLen == sum );
-		} catch (UnsupportedEncodingException e) {
-			fail("No UTF-8 byte encoding: " + e);
-			e.printStackTrace(System.err);
-		}
-	}
+            pt.overwrite();
+            byte[] overwrittenBytes = pt.asBytes();
+            assertTrue( overwrittenBytes != null );
+            assertFalse( Arrays.equals( origBytes, overwrittenBytes ) );
+
+            // Ensure that ALL the bytes overwritten with '*'.
+            int afterLen = overwrittenBytes.length;
+            assertTrue( origLen == afterLen );
+            int sum = 0;
+            for( int i = 0; i < afterLen; i++ ) {
+                if ( overwrittenBytes[i] == '*' ) {
+                    sum++;
+                }
+            }
+            assertTrue( afterLen == sum );
+        } catch (UnsupportedEncodingException e) {
+            fail("No UTF-8 byte encoding: " + e);
+            e.printStackTrace(System.err);
+        }
+    }
 
-	/**
-	 * Run all the test cases in this suite.
-	 * This is to allow running from {@code org.owasp.esapi.AllTests} which
-	 * uses a JUnit 3 test runner.
-	 */
-	public static junit.framework.Test suite() {
-		return new JUnit4TestAdapter(PlainTextTest.class);
-	}
+    /**
+     * Run all the test cases in this suite.
+     * This is to allow running from {@code org.owasp.esapi.AllTests} which
+     * uses a JUnit 3 test runner.
+     */
+    public static junit.framework.Test suite() {
+        return new JUnit4TestAdapter(PlainTextTest.class);
+    }
 }
diff --git a/src/test/java/org/owasp/esapi/crypto/SecurityProviderLoaderTest.java b/src/test/java/org/owasp/esapi/crypto/SecurityProviderLoaderTest.java
index 5db8aeb..441b07b 100644
--- a/src/test/java/org/owasp/esapi/crypto/SecurityProviderLoaderTest.java
+++ b/src/test/java/org/owasp/esapi/crypto/SecurityProviderLoaderTest.java
@@ -32,7 +32,7 @@ import org.owasp.esapi.errors.EncryptionException;
 public class SecurityProviderLoaderTest {
 
     private static boolean HAS_BOUNCY_CASTLE = false;
-    
+
     @BeforeClass
     public static void setUpBeforeClass() {
         try {
@@ -76,7 +76,7 @@ public class SecurityProviderLoaderTest {
                  preferredProvider + "; exception was: " + e);
         }
     }
-    
+
     @Test(expected=NoSuchProviderException.class)
     public final void testNoSuchProviderException() throws NoSuchProviderException {
         SecurityProviderLoader.insertProviderAt("DrBobsSecretSnakeOilElixirCryptoJCE", 5);
@@ -86,7 +86,7 @@ public class SecurityProviderLoaderTest {
     public final void testBogusProviderWithFQCN() throws NoSuchProviderException {
         SecurityProviderLoader.insertProviderAt("com.snakeoil.DrBobsSecretSnakeOilElixirCryptoJCE", 5);
     }
-    
+
     @Test
     public final void testWithBouncyCastle() {
         if ( ! HAS_BOUNCY_CASTLE ) {
@@ -101,7 +101,7 @@ public class SecurityProviderLoaderTest {
         } catch (NoSuchProviderException e) {
             fail("Caught NoSuchProviderException trying to load Bouncy Castle; exception was: " + e);
         }
-        
+
         // First encrypt w/ preferred cipher transformation (AES/CBC/PKCS5Padding).
         try {
             PlainText clearMsg = new PlainText("This is top secret! We are all out of towels!");
@@ -114,7 +114,7 @@ public class SecurityProviderLoaderTest {
             fail("Encryption w/ Bouncy Castle failed with EncryptionException for preferred " +
                  "cipher transformation; exception was: " + e);
         }
-        
+
         // Next, try a "combined mode" cipher mode available in Bouncy Castle.
         String origCipherXform = null;
         try {
diff --git a/src/test/java/org/owasp/esapi/errors/EnterpriseSecurityExceptionTest.java b/src/test/java/org/owasp/esapi/errors/EnterpriseSecurityExceptionTest.java
index bfd9651..a5a6de7 100644
--- a/src/test/java/org/owasp/esapi/errors/EnterpriseSecurityExceptionTest.java
+++ b/src/test/java/org/owasp/esapi/errors/EnterpriseSecurityExceptionTest.java
@@ -1,15 +1,15 @@
 /**
  * OWASP Enterprise Security API (ESAPI)
- * 
+ *
  * This file is part of the Open Web Application Security Project (OWASP)
  * Enterprise Security API (ESAPI) project. For details, please see
  * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
  *
  * Copyright (c) 2007 - The OWASP Foundation
- * 
+ *
  * The ESAPI is published by OWASP under the BSD license. You should read and accept the
  * LICENSE before you use, modify, and/or redistribute this software.
- * 
+ *
  * @author Jeff Williams <a href="http://www.aspectsecurity.com">Aspect Security</a>
  * @created 2007
  */
@@ -39,17 +39,17 @@ import junit.framework.TestSuite;
 
 /**
  * The Class AccessReferenceMapTest.
- * 
+ *
  * @author Jeff Williams (jeff.williams@aspectsecurity.com)
  */
 public class EnterpriseSecurityExceptionTest extends TestCase {
-    
+
     /**
-	 * Instantiates a new access reference map test.
-	 * 
-	 * @param testName
-	 *            the test name
-	 */
+     * Instantiates a new access reference map test.
+     *
+     * @param testName
+     *            the test name
+     */
     public EnterpriseSecurityExceptionTest(String testName) {
         super(testName);
     }
@@ -59,7 +59,7 @@ public class EnterpriseSecurityExceptionTest extends TestCase {
      * @throws Exception
      */
     protected void setUp() throws Exception {
-    	// none
+        // none
     }
 
     /**
@@ -67,24 +67,24 @@ public class EnterpriseSecurityExceptionTest extends TestCase {
      * @throws Exception
      */
     protected void tearDown() throws Exception {
-    	// none
+        // none
     }
 
     /**
-	 * Suite.
-	 * 
-	 * @return the test
-	 */
+     * Suite.
+     *
+     * @return the test
+     */
     public static Test suite() {
         TestSuite suite = new TestSuite(EnterpriseSecurityExceptionTest.class);
         return suite;
     }
 
-    
+
     /**
-	 * Test of update method, of class org.owasp.esapi.AccessReferenceMap.
-	 * 
-	 */
+     * Test of update method, of class org.owasp.esapi.AccessReferenceMap.
+     *
+     */
     public void testExceptions() {
         System.out.println("exceptions");
         EnterpriseSecurityException e = null;
@@ -119,7 +119,7 @@ public class EnterpriseSecurityExceptionTest extends TestCase {
         e = new ValidationException("m1","m2",new Throwable());
         e = new ValidationException("m1","m2","context");
         e = new ValidationException("m1","m2",new Throwable(),"context");
-         
+
         e = new IntegrityException();
         e = new IntegrityException("m1","m2");
         e = new IntegrityException("m1","m2",new Throwable());
@@ -153,5 +153,5 @@ public class EnterpriseSecurityExceptionTest extends TestCase {
         assertEquals( ex.getUserMessage(), "m1" );
         assertEquals( ex.getLogMessage(), "m2" );
     }
-    
+
 }
diff --git a/src/test/java/org/owasp/esapi/filters/ClickjackFilterTest.java b/src/test/java/org/owasp/esapi/filters/ClickjackFilterTest.java
index 272dafb..369e3f8 100644
--- a/src/test/java/org/owasp/esapi/filters/ClickjackFilterTest.java
+++ b/src/test/java/org/owasp/esapi/filters/ClickjackFilterTest.java
@@ -1,15 +1,15 @@
 /**
  * OWASP Enterprise Security API (ESAPI)
- * 
+ *
  * This file is part of the Open Web Application Security Project (OWASP)
  * Enterprise Security API (ESAPI) project. For details, please see
  * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
  *
  * Copyright (c) 2007 - The OWASP Foundation
- * 
+ *
  * The ESAPI is published by OWASP under the BSD license. You should read and accept the
  * LICENSE before you use, modify, and/or redistribute this software.
- * 
+ *
  * @author Jeff Williams <a href="http://www.aspectsecurity.com">Aspect Security</a>
  * @created 2007
  */
@@ -32,15 +32,15 @@ import org.owasp.esapi.http.MockHttpServletResponse;
 
 /**
  * The Class ClickjackFilterTest.
- * 
+ *
  * @author Jeff Williams (jeff.williams@aspectsecurity.com)
  */
 public class ClickjackFilterTest extends TestCase {
-    
+
     /**
-	 * @param testName
-	 *            the test name
-	 */
+     * @param testName
+     *            the test name
+     */
     public ClickjackFilterTest(String testName) {
         super(testName);
     }
@@ -50,7 +50,7 @@ public class ClickjackFilterTest extends TestCase {
      * @throws Exception
      */
     protected void setUp() throws Exception {
-    	// none
+        // none
     }
 
     /**
@@ -58,45 +58,45 @@ public class ClickjackFilterTest extends TestCase {
      * @throws Exception
      */
     protected void tearDown() throws Exception {
-    	// none
+        // none
     }
 
     /**
-	 * Suite.
-	 * 
-	 * @return the test
-	 */
+     * Suite.
+     *
+     * @return the test
+     */
     public static Test suite() {
         TestSuite suite = new TestSuite(ClickjackFilterTest.class);
         return suite;
     }
 
-    
+
     /**
-	 * Test of update method, of class org.owasp.esapi.AccessReferenceMap.
+     * Test of update method, of class org.owasp.esapi.AccessReferenceMap.
      * @throws Exception
      */
     public void testFilter() throws Exception {
         System.out.println("ClickjackFilter");
 
         Map map = new HashMap();
-    	FilterConfig mfc = new MockFilterConfig( map );
-    	ClickjackFilter filter = new ClickjackFilter();        
-    	filter.init( mfc );
-   	    MockHttpServletRequest request = new MockHttpServletRequest();
-		
-		// the mock filter chain writes the requested URI to the response body
-		MockFilterChain chain = new MockFilterChain();
+        FilterConfig mfc = new MockFilterConfig( map );
+        ClickjackFilter filter = new ClickjackFilter();
+        filter.init( mfc );
+           MockHttpServletRequest request = new MockHttpServletRequest();
+
+        // the mock filter chain writes the requested URI to the response body
+        MockFilterChain chain = new MockFilterChain();
 
         URL url = new URL( "http://www.example.com/index.jsp" );
-		System.out.println( "\nTest request: " + url );
+        System.out.println( "\nTest request: " + url );
         request = new MockHttpServletRequest( url );
-    	MockHttpServletResponse response = new MockHttpServletResponse();
-    	try {
-        	filter.doFilter(request, response, chain);
+        MockHttpServletResponse response = new MockHttpServletResponse();
+        try {
+            filter.doFilter(request, response, chain);
         } catch( Exception e ) {
-        	e.printStackTrace();
-        	fail();
+            e.printStackTrace();
+            fail();
         }
         String header = response.getHeader( "X-FRAME-OPTIONS");
         System.out.println(">>>" + header );
diff --git a/src/test/java/org/owasp/esapi/filters/SafeRequestTest.java b/src/test/java/org/owasp/esapi/filters/SafeRequestTest.java
index db2f0d7..11e45b6 100644
--- a/src/test/java/org/owasp/esapi/filters/SafeRequestTest.java
+++ b/src/test/java/org/owasp/esapi/filters/SafeRequestTest.java
@@ -1,15 +1,15 @@
 /**
  * OWASP Enterprise Security API (ESAPI)
- * 
+ *
  * This file is part of the Open Web Application Security Project (OWASP)
  * Enterprise Security API (ESAPI) project. For details, please see
  * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
  *
  * Copyright (c) 2007 - The OWASP Foundation
- * 
+ *
  * The ESAPI is published by OWASP under the BSD license. You should read and accept the
  * LICENSE before you use, modify, and/or redistribute this software.
- * 
+ *
  * @author Jeff Williams <a href="http://www.aspectsecurity.com">Aspect Security</a>
  * @created 2007
  */
@@ -24,117 +24,117 @@ import org.owasp.esapi.http.MockHttpServletRequest;
 
 /**
  * The Class SafeRequestTest.
- * 
+ *
  * @author Jeff Williams (jeff.williams@aspectsecurity.com)
  */
 public class SafeRequestTest extends TestCase {
 
-	/**
-	 * Instantiates a new access controller test.
-	 * 
-	 * @param testName
-	 *            the test name
-	 * @throws Exception
-	 */
-	public SafeRequestTest(String testName) throws Exception {
-		super(testName);
-	}
-
-	/**
-	 * {@inheritDoc}
-	 *
-	 * @throws Exception
-	 */
-	protected void setUp() throws Exception {
-	}
-
-	/**
-	 * {@inheritDoc}
-	 *
-	 * @throws Exception
-	 */
-	protected void tearDown() throws Exception {
-		// none
-	}
-
-	/**
-	 * Suite.
-	 * 
-	 * @return the test
-	 */
-	public static Test suite() {
-		TestSuite suite = new TestSuite(SafeRequestTest.class);
-		return suite;
-	}
-
-	/**
-	 *
-	 */
-	public void testGetRequestParameters() {
-		System.out.println( "getRequestParameters");
-		MockHttpServletRequest request = new MockHttpServletRequest();
-		request.addParameter( "one","1" );
-		request.addParameter( "two","2" );
-		request.addParameter( "one","3" );
-		request.addParameter( "one","4" );
-		SecurityWrapperRequest safeRequest = new SecurityWrapperRequest( request );
-		String[] params = safeRequest.getParameterValues("one");
-		String out = "";
-		for (int i = 0; i < params.length; i++ ) out += params[i];
-		assertEquals( "134", out );
-	}
-
-	public void testGetQueryStringNull()
-	{
-		MockHttpServletRequest req = new MockHttpServletRequest();
-		SecurityWrapperRequest wrappedReq;
-
-		req.setQueryString(null);
-		wrappedReq = new SecurityWrapperRequest(req);
-		assertNull(wrappedReq.getQueryString());
-	}
-
-	// Test to ensure null-value contract defined by ServletRequest.getParameterNames(String) is met.
-	public void testGetParameterValuesReturnsNullWhenParameterDoesNotExistInRequest() {
-		MockHttpServletRequest request = new MockHttpServletRequest();
-		request.clearParameters();
- 
-		final String paramName = "nonExistentParameter";
-		assertNull(request.getParameterValues(paramName));
-
-		SecurityWrapperRequest safeRequest = new SecurityWrapperRequest(request);
-		assertNull("Expecting null value to be returned for non-existent parameter.", safeRequest.getParameterValues(paramName));
-	}
-
-	public void testGetParameterValuesReturnsCorrectValueWhenParameterExistsInRequest() {
-		MockHttpServletRequest request = new MockHttpServletRequest();
-		request.clearParameters();
-
-		final String paramName = "existentParameter";
-		final String paramValue = "foobar";
-		request.addParameter(paramName, paramValue);
-		assertTrue(request.getParameterValues(paramName)[0].equals(paramValue));
-
-		SecurityWrapperRequest safeRequest = new SecurityWrapperRequest(request);
-		final String actualParamValue = safeRequest.getParameterValues(paramName)[0];
-		assertEquals(paramValue, actualParamValue);
-	}
-
-	public void testGetParameterValuesReturnsCorrectValuesWhenParameterExistsMultipleTimesInRequest() {
-		MockHttpServletRequest request = new MockHttpServletRequest();
-		request.clearParameters();
-
-		final String paramName = "existentParameter";
-		final String paramValue_0 = "foobar";
-		final String paramValue_1 = "barfoo";
-		request.addParameter(paramName, paramValue_0);
-		request.addParameter(paramName, paramValue_1);
-		assertTrue(request.getParameterValues(paramName)[0].equals(paramValue_0));
-		assertTrue(request.getParameterValues(paramName)[1].equals(paramValue_1));
-
-		SecurityWrapperRequest safeRequest = new SecurityWrapperRequest(request);
-		final String[] actualParamValues = safeRequest.getParameterValues(paramName);
-		assertEquals(paramValue_0, actualParamValues[0]);
-		assertEquals(paramValue_1, actualParamValues[1]);
-	}
+    /**
+     * Instantiates a new access controller test.
+     *
+     * @param testName
+     *            the test name
+     * @throws Exception
+     */
+    public SafeRequestTest(String testName) throws Exception {
+        super(testName);
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * @throws Exception
+     */
+    protected void setUp() throws Exception {
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * @throws Exception
+     */
+    protected void tearDown() throws Exception {
+        // none
+    }
+
+    /**
+     * Suite.
+     *
+     * @return the test
+     */
+    public static Test suite() {
+        TestSuite suite = new TestSuite(SafeRequestTest.class);
+        return suite;
+    }
+
+    /**
+     *
+     */
+    public void testGetRequestParameters() {
+        System.out.println( "getRequestParameters");
+        MockHttpServletRequest request = new MockHttpServletRequest();
+        request.addParameter( "one","1" );
+        request.addParameter( "two","2" );
+        request.addParameter( "one","3" );
+        request.addParameter( "one","4" );
+        SecurityWrapperRequest safeRequest = new SecurityWrapperRequest( request );
+        String[] params = safeRequest.getParameterValues("one");
+        String out = "";
+        for (int i = 0; i < params.length; i++ ) out += params[i];
+        assertEquals( "134", out );
+    }
+
+    public void testGetQueryStringNull()
+    {
+        MockHttpServletRequest req = new MockHttpServletRequest();
+        SecurityWrapperRequest wrappedReq;
+
+        req.setQueryString(null);
+        wrappedReq = new SecurityWrapperRequest(req);
+        assertNull(wrappedReq.getQueryString());
+    }
+
+    // Test to ensure null-value contract defined by ServletRequest.getParameterNames(String) is met.
+    public void testGetParameterValuesReturnsNullWhenParameterDoesNotExistInRequest() {
+        MockHttpServletRequest request = new MockHttpServletRequest();
+        request.clearParameters();
+
+        final String paramName = "nonExistentParameter";
+        assertNull(request.getParameterValues(paramName));
+
+        SecurityWrapperRequest safeRequest = new SecurityWrapperRequest(request);
+        assertNull("Expecting null value to be returned for non-existent parameter.", safeRequest.getParameterValues(paramName));
+    }
+
+    public void testGetParameterValuesReturnsCorrectValueWhenParameterExistsInRequest() {
+        MockHttpServletRequest request = new MockHttpServletRequest();
+        request.clearParameters();
+
+        final String paramName = "existentParameter";
+        final String paramValue = "foobar";
+        request.addParameter(paramName, paramValue);
+        assertTrue(request.getParameterValues(paramName)[0].equals(paramValue));
+
+        SecurityWrapperRequest safeRequest = new SecurityWrapperRequest(request);
+        final String actualParamValue = safeRequest.getParameterValues(paramName)[0];
+        assertEquals(paramValue, actualParamValue);
+    }
+
+    public void testGetParameterValuesReturnsCorrectValuesWhenParameterExistsMultipleTimesInRequest() {
+        MockHttpServletRequest request = new MockHttpServletRequest();
+        request.clearParameters();
+
+        final String paramName = "existentParameter";
+        final String paramValue_0 = "foobar";
+        final String paramValue_1 = "barfoo";
+        request.addParameter(paramName, paramValue_0);
+        request.addParameter(paramName, paramValue_1);
+        assertTrue(request.getParameterValues(paramName)[0].equals(paramValue_0));
+        assertTrue(request.getParameterValues(paramName)[1].equals(paramValue_1));
+
+        SecurityWrapperRequest safeRequest = new SecurityWrapperRequest(request);
+        final String[] actualParamValues = safeRequest.getParameterValues(paramName);
+        assertEquals(paramValue_0, actualParamValues[0]);
+        assertEquals(paramValue_1, actualParamValues[1]);
+    }
 }
diff --git a/src/test/java/org/owasp/esapi/filters/SecurityWrapperRequestTest.java b/src/test/java/org/owasp/esapi/filters/SecurityWrapperRequestTest.java
index 03b776d..40c9d36 100644
--- a/src/test/java/org/owasp/esapi/filters/SecurityWrapperRequestTest.java
+++ b/src/test/java/org/owasp/esapi/filters/SecurityWrapperRequestTest.java
@@ -22,8 +22,7 @@ import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
-// A hack for now; eventually, I plan to move this into a new org.owasp.esapi.PropNames class. -kww
-import static org.owasp.esapi.reference.DefaultSecurityConfiguration.DISABLE_INTRUSION_DETECTION;
+import static org.owasp.esapi.PropNames.DISABLE_INTRUSION_DETECTION;
 
 import javax.servlet.http.Cookie;
 import javax.servlet.http.HttpServletRequest;
@@ -61,13 +60,13 @@ import org.powermock.modules.junit4.PowerMockRunner;
 @PrepareForTest(ESAPI.class)
 public class SecurityWrapperRequestTest {
     protected static final String ESAPI_VALIDATOR_GETTER_METHOD_NAME = "validator";
-	protected static final String ESAPI_GET_LOGGER_METHOD_NAME = "getLogger";
-	protected static final String ESAPY_SECURITY_CONFIGURATION_GETTER_METHOD_NAME = "securityConfiguration";
+    protected static final String ESAPI_GET_LOGGER_METHOD_NAME = "getLogger";
+    protected static final String ESAPY_SECURITY_CONFIGURATION_GETTER_METHOD_NAME = "securityConfiguration";
     protected static final String SECURITY_CONFIGURATION_QUERY_STRING_LENGTH_KEY_NAME = "HttpUtilities.URILENGTH";
     protected static final String SECURITY_CONFIGURATION_PARAMETER_STRING_LENGTH_KEY_NAME = "HttpUtilities.httpQueryParamValueLength";
     private static final String SECURITY_CONFIGURATION_HEADER_NAME_LENGTH_KEY_NAME = "HttpUtilities.MaxHeaderNameSize";
     private static final String SECURITY_CONFIGURATION_HEADER_VALUE_LENGTH_KEY_NAME = "HttpUtilities.MaxHeaderValueSize";
-    
+
     protected static final int SECURITY_CONFIGURATION_TEST_LENGTH = 255;
 
     private static final String QUERY_STRING_CANONCALIZE_TYPE_KEY = "HTTPQueryString";
@@ -76,7 +75,7 @@ public class SecurityWrapperRequestTest {
     private static final String COOKIE_VALUE_TYPE_KEY = "HTTPCookieValue";
     private static final String COOKIE_DOMAIN_TYPE_KEY = "HTTPHeaderValue";
     private static final String COOKIE_PATH_TYPE_KEY = "HTTPHeaderValue";
-  
+
     @Rule
     public TestName testName = new TestName();
 
@@ -88,7 +87,7 @@ public class SecurityWrapperRequestTest {
     private SecurityConfiguration mockSecConfig;
     @Mock
     private Logger mockLogger;
-    
+
     private String testQueryValue;
     private String testParameterName;
     private String testParameterValue;
@@ -102,19 +101,19 @@ public class SecurityWrapperRequestTest {
         PowerMockito.when(ESAPI.class, ESAPI_VALIDATOR_GETTER_METHOD_NAME).thenReturn(mockValidator);
         PowerMockito.when(ESAPI.class, ESAPI_GET_LOGGER_METHOD_NAME, "SecurityWrapperRequest").thenReturn(mockLogger);
         PowerMockito.when(ESAPI.class, ESAPY_SECURITY_CONFIGURATION_GETTER_METHOD_NAME).thenReturn(mockSecConfig);
-        //Is intrusion detection disabled?  A:  Yes, it is off.  
+        //Is intrusion detection disabled?  A:  Yes, it is off.
         //This logic is confusing:  True, the value is False...
         Mockito.when( mockSecConfig.getBooleanProp( DISABLE_INTRUSION_DETECTION ) ).thenReturn(true);
-        
+
         testQueryValue = testName.getMethodName() + "_query_value";
-        
+
         testParameterName = testName.getMethodName() + "_parameter_name";
-        testParameterValue = testName.getMethodName() + "_parameter_value";  
+        testParameterValue = testName.getMethodName() + "_parameter_value";
         testValueCanonical = testName.getMethodName() + "_value_canonical";
         testValidatorType = testName.getMethodName() + "_validator_type";
         testMaximumLength = testName.getMethodName().length();
     }
-    
+
     /**
      * Workflow test for happy-path getQueryString. Asserts delegation calls and parameters to delegate
      * behaviors.
@@ -140,7 +139,7 @@ public class SecurityWrapperRequestTest {
     }
 
     /**
-     * Test for getQueryString when validation throws an Exception. 
+     * Test for getQueryString when validation throws an Exception.
      * <br/>
      * Asserts delegation calls and parameters to delegate behaviors.
      */
@@ -161,7 +160,7 @@ public class SecurityWrapperRequestTest {
             .isEmpty());
 
         validatorTester.verify(testQueryValue, QUERY_STRING_CANONCALIZE_TYPE_KEY, SECURITY_CONFIGURATION_TEST_LENGTH, true);
-        
+
         verify(mockSecConfig, times(1)).getIntProp(SECURITY_CONFIGURATION_QUERY_STRING_LENGTH_KEY_NAME);
         verify(mockRequest, times(1)).getQueryString();
     }
@@ -169,7 +168,7 @@ public class SecurityWrapperRequestTest {
     public void testGetParameterString() throws Exception{
         ValidatorTestContainer validatorTester = new ValidatorTestContainer(mockValidator);
         validatorTester.getValidInputReturns(testValueCanonical);
-        
+
         PowerMockito.when(mockSecConfig.getIntProp(SECURITY_CONFIGURATION_PARAMETER_STRING_LENGTH_KEY_NAME)).thenReturn(
                 SECURITY_CONFIGURATION_TEST_LENGTH);
 
@@ -178,9 +177,9 @@ public class SecurityWrapperRequestTest {
         SecurityWrapperRequest request = new SecurityWrapperRequest(mockRequest);
         String rval = request.getParameter(testParameterName);
         assertEquals(testValueCanonical, rval);
-        
+
         validatorTester.verify(testParameterValue, PARAMETER_STRING_CANONCALIZE_TYPE_KEY, SECURITY_CONFIGURATION_TEST_LENGTH, true);
-        
+
         verify(mockSecConfig, times(1)).getIntProp(SECURITY_CONFIGURATION_PARAMETER_STRING_LENGTH_KEY_NAME);
         verify(mockRequest, times(1)).getParameter(testParameterName);
     }
@@ -197,18 +196,18 @@ public class SecurityWrapperRequestTest {
         SecurityWrapperRequest request = new SecurityWrapperRequest(mockRequest);
         String rval = request.getParameter(testParameterName, false);
         assertEquals(testValueCanonical, rval);
-        
+
         validatorTester.verify(testParameterValue, PARAMETER_STRING_CANONCALIZE_TYPE_KEY, SECURITY_CONFIGURATION_TEST_LENGTH, false);
-        
+
         verify(mockSecConfig, times(1)).getIntProp(SECURITY_CONFIGURATION_PARAMETER_STRING_LENGTH_KEY_NAME);
         verify(mockRequest, times(1)).getParameter(testParameterName);
     }
-    
+
     @Test
     public void testGetParameterStringBooleanInt() throws Exception{
         ValidatorTestContainer validatorTester = new ValidatorTestContainer(mockValidator);
         validatorTester.getValidInputReturns(testValueCanonical);
-        
+
         PowerMockito.when(mockRequest.getParameter(testParameterName)).thenReturn(testParameterValue);
 
         SecurityWrapperRequest request = new SecurityWrapperRequest(mockRequest);
@@ -219,13 +218,13 @@ public class SecurityWrapperRequestTest {
 
         verify(mockRequest, times(1)).getParameter(testParameterName);
     }
-    
+
     @Test
     public void testGetParameterStringBooleanIntString() throws Exception{
         ValidatorTestContainer validatorTester = new ValidatorTestContainer(mockValidator);
         validatorTester.getValidInputReturns(testValueCanonical);
-      
-        
+
+
         PowerMockito.when(mockRequest.getParameter(testParameterName)).thenReturn(testParameterValue);
 
         SecurityWrapperRequest request = new SecurityWrapperRequest(mockRequest);
@@ -233,16 +232,16 @@ public class SecurityWrapperRequestTest {
         assertEquals(testValueCanonical, rval);
 
         validatorTester.verify(testParameterValue, testValidatorType, testMaximumLength, false);
-     
+
         verify(mockRequest, times(1)).getParameter(testParameterName);
     }
 
-    
+
     @Test
     public void testGetParameterStringNullEvalPassthrough() throws Exception{
         ValidatorTestContainer validatorTester = new ValidatorTestContainer(mockValidator);
         validatorTester.getValidInputReturns(null);
-        
+
         PowerMockito.when(mockSecConfig.getIntProp(SECURITY_CONFIGURATION_PARAMETER_STRING_LENGTH_KEY_NAME)).thenReturn(
                 SECURITY_CONFIGURATION_TEST_LENGTH);
 
@@ -251,7 +250,7 @@ public class SecurityWrapperRequestTest {
         SecurityWrapperRequest request = new SecurityWrapperRequest(mockRequest);
         String rval = request.getParameter(testParameterName);
         assertNull(rval);
-        
+
         validatorTester.verify(testParameterValue, PARAMETER_STRING_CANONCALIZE_TYPE_KEY, SECURITY_CONFIGURATION_TEST_LENGTH, true);
 
         verify(mockSecConfig, times(1)).getIntProp(SECURITY_CONFIGURATION_PARAMETER_STRING_LENGTH_KEY_NAME);
@@ -262,7 +261,7 @@ public class SecurityWrapperRequestTest {
     public void testGetParameterStringBooleanNullEvalPassthrough() throws Exception{
         ValidatorTestContainer validatorTester = new ValidatorTestContainer(mockValidator);
         validatorTester.getValidInputReturns(null);
-        
+
         PowerMockito.when(mockSecConfig.getIntProp(SECURITY_CONFIGURATION_PARAMETER_STRING_LENGTH_KEY_NAME)).thenReturn(
                 SECURITY_CONFIGURATION_TEST_LENGTH);
 
@@ -271,34 +270,34 @@ public class SecurityWrapperRequestTest {
         SecurityWrapperRequest request = new SecurityWrapperRequest(mockRequest);
         String rval = request.getParameter(testParameterName, false);
         assertNull(rval);
-        
+
         validatorTester.verify(testParameterValue, PARAMETER_STRING_CANONCALIZE_TYPE_KEY, SECURITY_CONFIGURATION_TEST_LENGTH, false);
 
         verify(mockSecConfig, times(1)).getIntProp(SECURITY_CONFIGURATION_PARAMETER_STRING_LENGTH_KEY_NAME);
         verify(mockRequest, times(1)).getParameter(testParameterName);
     }
-    
+
     @Test
     public void testGetParameterStringBooleanIntNullEvalPassthrough() throws Exception{
         ValidatorTestContainer validatorTester = new ValidatorTestContainer(mockValidator);
         validatorTester.getValidInputReturns(null);
-        
+
         PowerMockito.when(mockRequest.getParameter(testParameterName)).thenReturn(testParameterValue);
 
         SecurityWrapperRequest request = new SecurityWrapperRequest(mockRequest);
         String rval = request.getParameter(testParameterName, false, testMaximumLength);
         assertNull(rval);
-        
+
         validatorTester.verify(testParameterValue, PARAMETER_STRING_CANONCALIZE_TYPE_KEY, testMaximumLength, false);
 
         verify(mockRequest, times(1)).getParameter(testParameterName);
     }
-    
+
     @Test
     public void testGetParameterStringBooleanIntStringNullEvalPassthrough() throws Exception{
         ValidatorTestContainer validatorTester = new ValidatorTestContainer(mockValidator);
         validatorTester.getValidInputReturns(null);
-        
+
         PowerMockito.when(mockRequest.getParameter(testParameterName)).thenReturn(testParameterValue);
 
         SecurityWrapperRequest request = new SecurityWrapperRequest(mockRequest);
@@ -308,12 +307,12 @@ public class SecurityWrapperRequestTest {
 
         verify(mockRequest, times(1)).getParameter(testParameterName);
     }
-    
+
     @Test
     public void testGetParameterStringNullOnException() throws Exception{
         ValidatorTestContainer validatorTester = new ValidatorTestContainer(mockValidator);
         validatorTester.getValidInputThrows();
-        
+
         PowerMockito.when(mockSecConfig.getIntProp(SECURITY_CONFIGURATION_PARAMETER_STRING_LENGTH_KEY_NAME)).thenReturn(
                 SECURITY_CONFIGURATION_TEST_LENGTH);
 
@@ -324,18 +323,18 @@ public class SecurityWrapperRequestTest {
         assertNull(rval);
 
         validatorTester.verify(testParameterValue, PARAMETER_STRING_CANONCALIZE_TYPE_KEY, SECURITY_CONFIGURATION_TEST_LENGTH, true);
-        
+
         verify(mockSecConfig, times(1)).getIntProp(SECURITY_CONFIGURATION_PARAMETER_STRING_LENGTH_KEY_NAME);
         verify(mockRequest, times(1)).getParameter(testParameterName);
     }
-    
-    
+
+
 
     @Test
     public void testGetParameterStringBooleanNullOnException() throws Exception{
         ValidatorTestContainer validatorTester = new ValidatorTestContainer(mockValidator);
         validatorTester.getValidInputThrows();
-        
+
         PowerMockito.when(mockSecConfig.getIntProp(SECURITY_CONFIGURATION_PARAMETER_STRING_LENGTH_KEY_NAME)).thenReturn(
                 SECURITY_CONFIGURATION_TEST_LENGTH);
 
@@ -344,28 +343,28 @@ public class SecurityWrapperRequestTest {
         SecurityWrapperRequest request = new SecurityWrapperRequest(mockRequest);
         String rval = request.getParameter(testParameterName, false);
         assertNull(rval);
-        
+
         validatorTester.verify(testParameterValue, PARAMETER_STRING_CANONCALIZE_TYPE_KEY, SECURITY_CONFIGURATION_TEST_LENGTH, false);
-    
+
         verify(mockSecConfig, times(1)).getIntProp(SECURITY_CONFIGURATION_PARAMETER_STRING_LENGTH_KEY_NAME);
         verify(mockRequest, times(1)).getParameter(testParameterName);
     }
-    
+
     @Test
     public void testGetParameterStringBooleanIntNullOnException() throws Exception{
         ValidatorTestContainer validatorTester = new ValidatorTestContainer(mockValidator);
         validatorTester.getValidInputThrows();
-        
+
         PowerMockito.when(mockRequest.getParameter(testParameterName)).thenReturn(testParameterValue);
 
         SecurityWrapperRequest request = new SecurityWrapperRequest(mockRequest);
         String rval = request.getParameter(testParameterName, false, testMaximumLength);
         assertNull(rval);
-        
+
         validatorTester.verify(testParameterValue, PARAMETER_STRING_CANONCALIZE_TYPE_KEY, testMaximumLength, false);
         verify(mockRequest, times(1)).getParameter(testParameterName);
     }
-    
+
     @Test
     public void testGetParameterStringBooleanIntStringNullOnException() throws Exception{
         ValidatorTestContainer validatorTester = new ValidatorTestContainer(mockValidator);
@@ -376,228 +375,228 @@ public class SecurityWrapperRequestTest {
         SecurityWrapperRequest request = new SecurityWrapperRequest(mockRequest);
         String rval = request.getParameter(testParameterName, false, testMaximumLength, testValidatorType);
         assertNull(rval);
-        
+
         validatorTester.verify(testParameterValue, testValidatorType, testMaximumLength, false);
-       
+
         verify(mockRequest, times(1)).getParameter(testParameterName);
     }
-    
+
     @Test
     public void testGetCookie() throws Exception {
-    	PowerMockito.when(mockSecConfig.getIntProp(SECURITY_CONFIGURATION_HEADER_NAME_LENGTH_KEY_NAME)).thenReturn(
-    			SECURITY_CONFIGURATION_TEST_LENGTH);
-    	PowerMockito.when(mockSecConfig.getIntProp(SECURITY_CONFIGURATION_HEADER_VALUE_LENGTH_KEY_NAME)).thenReturn(
-    			SECURITY_CONFIGURATION_TEST_LENGTH);
-
-    	Cookie ck1 = new Cookie(testName.getMethodName(), testName.getMethodName()+ "-VALUE");
-    	ck1.setMaxAge(999);
-    	ck1.setDomain(testName.getMethodName() + "-DOMAIN");
-    	ck1.setPath(testName.getMethodName() + "-URI");
-
-    	Cookie[] stubCookies = new Cookie[] {ck1};
-    	PowerMockito.when(mockRequest.getCookies()).thenReturn(stubCookies);
-
-    	PowerMockito.when(mockValidator.getValidInput(anyString(), eq(ck1.getName()), eq(COOKIE_NAME_TYPE_KEY), eq(SECURITY_CONFIGURATION_TEST_LENGTH), eq(false))).thenReturn(ck1.getName());
-    	PowerMockito.when(mockValidator.getValidInput(anyString(), eq(ck1.getValue()),eq(COOKIE_VALUE_TYPE_KEY), eq(SECURITY_CONFIGURATION_TEST_LENGTH), eq(true))).thenReturn(ck1.getValue());
-    	PowerMockito.when(mockValidator.getValidInput(anyString(), eq(ck1.getDomain()),eq(COOKIE_DOMAIN_TYPE_KEY), eq(SECURITY_CONFIGURATION_TEST_LENGTH), eq(false))).thenReturn(ck1.getDomain());
-    	PowerMockito.when(mockValidator.getValidInput(anyString(), eq(ck1.getPath()), eq(COOKIE_PATH_TYPE_KEY), eq(SECURITY_CONFIGURATION_TEST_LENGTH), eq(false))).thenReturn(ck1.getPath());
-
-    	SecurityWrapperRequest request = new SecurityWrapperRequest(mockRequest);
-    	Cookie[] cookies = request.getCookies();
-    	assertNotEquals(stubCookies, cookies);
-    	assertEquals(1, cookies.length);
-    	Cookie resultCookie = cookies[0];
-    	assertNotEquals(ck1, resultCookie);
-    	assertEquals(ck1.getName(), resultCookie.getName());
-    	assertEquals(ck1.getValue(), resultCookie.getValue());
-    	assertEquals(ck1.getDomain(), resultCookie.getDomain());
-    	assertEquals(ck1.getPath(), resultCookie.getPath());
-    	assertEquals(ck1.getMaxAge(), resultCookie.getMaxAge());
-
-    	Mockito.verify(mockValidator, times(1)).getValidInput(anyString(), ArgumentMatchers.eq(ck1.getName()), ArgumentMatchers.eq(COOKIE_NAME_TYPE_KEY), ArgumentMatchers.eq(SECURITY_CONFIGURATION_TEST_LENGTH), ArgumentMatchers.eq(false));
-    	Mockito.verify(mockValidator, times(1)).getValidInput(anyString(), ArgumentMatchers.eq(ck1.getValue()), ArgumentMatchers.eq(COOKIE_VALUE_TYPE_KEY), ArgumentMatchers.eq(SECURITY_CONFIGURATION_TEST_LENGTH), ArgumentMatchers.eq(true));
-    	Mockito.verify(mockValidator, times(1)).getValidInput(anyString(), ArgumentMatchers.eq(ck1.getDomain()), ArgumentMatchers.eq(COOKIE_DOMAIN_TYPE_KEY), ArgumentMatchers.eq(SECURITY_CONFIGURATION_TEST_LENGTH), ArgumentMatchers.eq(false));
-    	Mockito.verify(mockValidator, times(1)).getValidInput(anyString(), ArgumentMatchers.eq(ck1.getPath()), ArgumentMatchers.eq(COOKIE_PATH_TYPE_KEY), ArgumentMatchers.eq(SECURITY_CONFIGURATION_TEST_LENGTH), ArgumentMatchers.eq(false));
+        PowerMockito.when(mockSecConfig.getIntProp(SECURITY_CONFIGURATION_HEADER_NAME_LENGTH_KEY_NAME)).thenReturn(
+                SECURITY_CONFIGURATION_TEST_LENGTH);
+        PowerMockito.when(mockSecConfig.getIntProp(SECURITY_CONFIGURATION_HEADER_VALUE_LENGTH_KEY_NAME)).thenReturn(
+                SECURITY_CONFIGURATION_TEST_LENGTH);
+
+        Cookie ck1 = new Cookie(testName.getMethodName(), testName.getMethodName()+ "-VALUE");
+        ck1.setMaxAge(999);
+        ck1.setDomain(testName.getMethodName() + "-DOMAIN");
+        ck1.setPath(testName.getMethodName() + "-URI");
+
+        Cookie[] stubCookies = new Cookie[] {ck1};
+        PowerMockito.when(mockRequest.getCookies()).thenReturn(stubCookies);
+
+        PowerMockito.when(mockValidator.getValidInput(anyString(), eq(ck1.getName()), eq(COOKIE_NAME_TYPE_KEY), eq(SECURITY_CONFIGURATION_TEST_LENGTH), eq(false))).thenReturn(ck1.getName());
+        PowerMockito.when(mockValidator.getValidInput(anyString(), eq(ck1.getValue()),eq(COOKIE_VALUE_TYPE_KEY), eq(SECURITY_CONFIGURATION_TEST_LENGTH), eq(true))).thenReturn(ck1.getValue());
+        PowerMockito.when(mockValidator.getValidInput(anyString(), eq(ck1.getDomain()),eq(COOKIE_DOMAIN_TYPE_KEY), eq(SECURITY_CONFIGURATION_TEST_LENGTH), eq(false))).thenReturn(ck1.getDomain());
+        PowerMockito.when(mockValidator.getValidInput(anyString(), eq(ck1.getPath()), eq(COOKIE_PATH_TYPE_KEY), eq(SECURITY_CONFIGURATION_TEST_LENGTH), eq(false))).thenReturn(ck1.getPath());
+
+        SecurityWrapperRequest request = new SecurityWrapperRequest(mockRequest);
+        Cookie[] cookies = request.getCookies();
+        assertNotEquals(stubCookies, cookies);
+        assertEquals(1, cookies.length);
+        Cookie resultCookie = cookies[0];
+        assertNotEquals(ck1, resultCookie);
+        assertEquals(ck1.getName(), resultCookie.getName());
+        assertEquals(ck1.getValue(), resultCookie.getValue());
+        assertEquals(ck1.getDomain(), resultCookie.getDomain());
+        assertEquals(ck1.getPath(), resultCookie.getPath());
+        assertEquals(ck1.getMaxAge(), resultCookie.getMaxAge());
+
+        Mockito.verify(mockValidator, times(1)).getValidInput(anyString(), ArgumentMatchers.eq(ck1.getName()), ArgumentMatchers.eq(COOKIE_NAME_TYPE_KEY), ArgumentMatchers.eq(SECURITY_CONFIGURATION_TEST_LENGTH), ArgumentMatchers.eq(false));
+        Mockito.verify(mockValidator, times(1)).getValidInput(anyString(), ArgumentMatchers.eq(ck1.getValue()), ArgumentMatchers.eq(COOKIE_VALUE_TYPE_KEY), ArgumentMatchers.eq(SECURITY_CONFIGURATION_TEST_LENGTH), ArgumentMatchers.eq(true));
+        Mockito.verify(mockValidator, times(1)).getValidInput(anyString(), ArgumentMatchers.eq(ck1.getDomain()), ArgumentMatchers.eq(COOKIE_DOMAIN_TYPE_KEY), ArgumentMatchers.eq(SECURITY_CONFIGURATION_TEST_LENGTH), ArgumentMatchers.eq(false));
+        Mockito.verify(mockValidator, times(1)).getValidInput(anyString(), ArgumentMatchers.eq(ck1.getPath()), ArgumentMatchers.eq(COOKIE_PATH_TYPE_KEY), ArgumentMatchers.eq(SECURITY_CONFIGURATION_TEST_LENGTH), ArgumentMatchers.eq(false));
     }
-    
+
     @Test
     public void testGetCookieNullDomainPath() throws Exception {
-    	PowerMockito.when(mockSecConfig.getIntProp(SECURITY_CONFIGURATION_HEADER_NAME_LENGTH_KEY_NAME)).thenReturn(
-    			SECURITY_CONFIGURATION_TEST_LENGTH);
-    	PowerMockito.when(mockSecConfig.getIntProp(SECURITY_CONFIGURATION_HEADER_VALUE_LENGTH_KEY_NAME)).thenReturn(
-    			SECURITY_CONFIGURATION_TEST_LENGTH);
-
-    	Cookie ck1 = new Cookie(testName.getMethodName(), testName.getMethodName()+ "-VALUE");
-    	ck1.setMaxAge(999);
-    	//Domain and Path are left null
-
-    	Cookie[] stubCookies = new Cookie[] {ck1};
-    	PowerMockito.when(mockRequest.getCookies()).thenReturn(stubCookies);
-
-    	PowerMockito.when(mockValidator.getValidInput(anyString(), eq(ck1.getName()), eq(COOKIE_NAME_TYPE_KEY), eq(SECURITY_CONFIGURATION_TEST_LENGTH), eq(false))).thenReturn(ck1.getName());
-    	PowerMockito.when(mockValidator.getValidInput(anyString(), eq(ck1.getValue()),eq(COOKIE_VALUE_TYPE_KEY), eq(SECURITY_CONFIGURATION_TEST_LENGTH), eq(true))).thenReturn(ck1.getValue());
-
-    	SecurityWrapperRequest request = new SecurityWrapperRequest(mockRequest);
-    	Cookie[] cookies = request.getCookies();
-    	assertNotEquals(stubCookies, cookies);
-    	assertEquals(1, cookies.length);
-    	Cookie resultCookie1 = cookies[0];
-    	
-    	assertNotEquals(ck1, resultCookie1);
-    	assertEquals(ck1.getName(), resultCookie1.getName());
-    	assertEquals(ck1.getValue(), resultCookie1.getValue());
-    	assertEquals(ck1.getDomain(), resultCookie1.getDomain());
-    	assertEquals(ck1.getPath(), resultCookie1.getPath());
-    	assertEquals(ck1.getMaxAge(), resultCookie1.getMaxAge());
-
-    	Mockito.verify(mockValidator, times(1)).getValidInput(anyString(), ArgumentMatchers.eq(ck1.getName()), ArgumentMatchers.eq(COOKIE_NAME_TYPE_KEY), ArgumentMatchers.eq(SECURITY_CONFIGURATION_TEST_LENGTH), ArgumentMatchers.eq(false));
-    	Mockito.verify(mockValidator, times(1)).getValidInput(anyString(), ArgumentMatchers.eq(ck1.getValue()), ArgumentMatchers.eq(COOKIE_VALUE_TYPE_KEY), ArgumentMatchers.eq(SECURITY_CONFIGURATION_TEST_LENGTH), ArgumentMatchers.eq(true));
-    	Mockito.verify(mockValidator, times(0)).getValidInput(anyString(), ArgumentMatchers.eq(ck1.getDomain()), ArgumentMatchers.eq(COOKIE_DOMAIN_TYPE_KEY), ArgumentMatchers.eq(SECURITY_CONFIGURATION_TEST_LENGTH), ArgumentMatchers.eq(false));
-    	Mockito.verify(mockValidator, times(0)).getValidInput(anyString(), ArgumentMatchers.eq(ck1.getPath()), ArgumentMatchers.eq(COOKIE_PATH_TYPE_KEY), ArgumentMatchers.eq(SECURITY_CONFIGURATION_TEST_LENGTH), ArgumentMatchers.eq(false));
+        PowerMockito.when(mockSecConfig.getIntProp(SECURITY_CONFIGURATION_HEADER_NAME_LENGTH_KEY_NAME)).thenReturn(
+                SECURITY_CONFIGURATION_TEST_LENGTH);
+        PowerMockito.when(mockSecConfig.getIntProp(SECURITY_CONFIGURATION_HEADER_VALUE_LENGTH_KEY_NAME)).thenReturn(
+                SECURITY_CONFIGURATION_TEST_LENGTH);
+
+        Cookie ck1 = new Cookie(testName.getMethodName(), testName.getMethodName()+ "-VALUE");
+        ck1.setMaxAge(999);
+        //Domain and Path are left null
+
+        Cookie[] stubCookies = new Cookie[] {ck1};
+        PowerMockito.when(mockRequest.getCookies()).thenReturn(stubCookies);
+
+        PowerMockito.when(mockValidator.getValidInput(anyString(), eq(ck1.getName()), eq(COOKIE_NAME_TYPE_KEY), eq(SECURITY_CONFIGURATION_TEST_LENGTH), eq(false))).thenReturn(ck1.getName());
+        PowerMockito.when(mockValidator.getValidInput(anyString(), eq(ck1.getValue()),eq(COOKIE_VALUE_TYPE_KEY), eq(SECURITY_CONFIGURATION_TEST_LENGTH), eq(true))).thenReturn(ck1.getValue());
+
+        SecurityWrapperRequest request = new SecurityWrapperRequest(mockRequest);
+        Cookie[] cookies = request.getCookies();
+        assertNotEquals(stubCookies, cookies);
+        assertEquals(1, cookies.length);
+        Cookie resultCookie1 = cookies[0];
+
+        assertNotEquals(ck1, resultCookie1);
+        assertEquals(ck1.getName(), resultCookie1.getName());
+        assertEquals(ck1.getValue(), resultCookie1.getValue());
+        assertEquals(ck1.getDomain(), resultCookie1.getDomain());
+        assertEquals(ck1.getPath(), resultCookie1.getPath());
+        assertEquals(ck1.getMaxAge(), resultCookie1.getMaxAge());
+
+        Mockito.verify(mockValidator, times(1)).getValidInput(anyString(), ArgumentMatchers.eq(ck1.getName()), ArgumentMatchers.eq(COOKIE_NAME_TYPE_KEY), ArgumentMatchers.eq(SECURITY_CONFIGURATION_TEST_LENGTH), ArgumentMatchers.eq(false));
+        Mockito.verify(mockValidator, times(1)).getValidInput(anyString(), ArgumentMatchers.eq(ck1.getValue()), ArgumentMatchers.eq(COOKIE_VALUE_TYPE_KEY), ArgumentMatchers.eq(SECURITY_CONFIGURATION_TEST_LENGTH), ArgumentMatchers.eq(true));
+        Mockito.verify(mockValidator, times(0)).getValidInput(anyString(), ArgumentMatchers.eq(ck1.getDomain()), ArgumentMatchers.eq(COOKIE_DOMAIN_TYPE_KEY), ArgumentMatchers.eq(SECURITY_CONFIGURATION_TEST_LENGTH), ArgumentMatchers.eq(false));
+        Mockito.verify(mockValidator, times(0)).getValidInput(anyString(), ArgumentMatchers.eq(ck1.getPath()), ArgumentMatchers.eq(COOKIE_PATH_TYPE_KEY), ArgumentMatchers.eq(SECURITY_CONFIGURATION_TEST_LENGTH), ArgumentMatchers.eq(false));
     }
-    
+
     @Test
     public void testGetCookieNullRequestCookies() {
-    	          PowerMockito.when(mockRequest.getParameter(testParameterName)).thenReturn(testParameterValue);
+                  PowerMockito.when(mockRequest.getParameter(testParameterName)).thenReturn(testParameterValue);
           PowerMockito.when(mockRequest.getCookies()).thenReturn(null);
           SecurityWrapperRequest request = new SecurityWrapperRequest(mockRequest);
           Cookie[] cookies = request.getCookies();
           assertEquals(0, cookies.length);
     }
-    
+
     @Test
     public void testGetCookieSkipOnBadName() throws Exception {
-    	PowerMockito.when(mockSecConfig.getIntProp(SECURITY_CONFIGURATION_HEADER_NAME_LENGTH_KEY_NAME)).thenReturn(
-    			SECURITY_CONFIGURATION_TEST_LENGTH);
-    	PowerMockito.when(mockSecConfig.getIntProp(SECURITY_CONFIGURATION_HEADER_VALUE_LENGTH_KEY_NAME)).thenReturn(
-    			SECURITY_CONFIGURATION_TEST_LENGTH);
-
-    	Answer<String> exceptionAnswer = new ValidatorTestContainer(mockValidator).throwException();
-    
-    	Cookie ck1 = new Cookie(testName.getMethodName(), testName.getMethodName()+ "-VALUE");
-    	ck1.setMaxAge(999);
-    	ck1.setDomain(testName.getMethodName() + "-DOMAIN");
-    	ck1.setPath(testName.getMethodName() + "-URI");
-
-    	Cookie[] stubCookies = new Cookie[] {ck1};
-    	PowerMockito.when(mockRequest.getCookies()).thenReturn(stubCookies);
-    	
-    	PowerMockito.when(mockValidator.getValidInput(anyString(), eq(ck1.getName()), eq(COOKIE_NAME_TYPE_KEY), eq(SECURITY_CONFIGURATION_TEST_LENGTH), eq(false))).thenAnswer(exceptionAnswer);
-
-    	SecurityWrapperRequest request = new SecurityWrapperRequest(mockRequest);
-    	Cookie[] cookies = request.getCookies();
-    	assertNotEquals(stubCookies, cookies);
-    	assertEquals(0, cookies.length);
-
-    	Mockito.verify(mockValidator, times(1)).getValidInput(anyString(), ArgumentMatchers.eq(ck1.getName()), ArgumentMatchers.eq(COOKIE_NAME_TYPE_KEY), ArgumentMatchers.eq(SECURITY_CONFIGURATION_TEST_LENGTH), ArgumentMatchers.eq(false));
-    	Mockito.verify(mockValidator, times(0)).getValidInput(anyString(), ArgumentMatchers.eq(ck1.getValue()), ArgumentMatchers.eq(COOKIE_VALUE_TYPE_KEY), ArgumentMatchers.eq(SECURITY_CONFIGURATION_TEST_LENGTH), ArgumentMatchers.eq(true));
-    	Mockito.verify(mockValidator, times(0)).getValidInput(anyString(), ArgumentMatchers.eq(ck1.getDomain()), ArgumentMatchers.eq(COOKIE_DOMAIN_TYPE_KEY), ArgumentMatchers.eq(SECURITY_CONFIGURATION_TEST_LENGTH), ArgumentMatchers.eq(false));
-    	Mockito.verify(mockValidator, times(0)).getValidInput(anyString(), ArgumentMatchers.eq(ck1.getPath()), ArgumentMatchers.eq(COOKIE_PATH_TYPE_KEY), ArgumentMatchers.eq(SECURITY_CONFIGURATION_TEST_LENGTH), ArgumentMatchers.eq(false));
-    	
-    	//I would have liked to verify the logging occurred, but it's giving me trouble at this time.
+        PowerMockito.when(mockSecConfig.getIntProp(SECURITY_CONFIGURATION_HEADER_NAME_LENGTH_KEY_NAME)).thenReturn(
+                SECURITY_CONFIGURATION_TEST_LENGTH);
+        PowerMockito.when(mockSecConfig.getIntProp(SECURITY_CONFIGURATION_HEADER_VALUE_LENGTH_KEY_NAME)).thenReturn(
+                SECURITY_CONFIGURATION_TEST_LENGTH);
+
+        Answer<String> exceptionAnswer = new ValidatorTestContainer(mockValidator).throwException();
+
+        Cookie ck1 = new Cookie(testName.getMethodName(), testName.getMethodName()+ "-VALUE");
+        ck1.setMaxAge(999);
+        ck1.setDomain(testName.getMethodName() + "-DOMAIN");
+        ck1.setPath(testName.getMethodName() + "-URI");
+
+        Cookie[] stubCookies = new Cookie[] {ck1};
+        PowerMockito.when(mockRequest.getCookies()).thenReturn(stubCookies);
+
+        PowerMockito.when(mockValidator.getValidInput(anyString(), eq(ck1.getName()), eq(COOKIE_NAME_TYPE_KEY), eq(SECURITY_CONFIGURATION_TEST_LENGTH), eq(false))).thenAnswer(exceptionAnswer);
+
+        SecurityWrapperRequest request = new SecurityWrapperRequest(mockRequest);
+        Cookie[] cookies = request.getCookies();
+        assertNotEquals(stubCookies, cookies);
+        assertEquals(0, cookies.length);
+
+        Mockito.verify(mockValidator, times(1)).getValidInput(anyString(), ArgumentMatchers.eq(ck1.getName()), ArgumentMatchers.eq(COOKIE_NAME_TYPE_KEY), ArgumentMatchers.eq(SECURITY_CONFIGURATION_TEST_LENGTH), ArgumentMatchers.eq(false));
+        Mockito.verify(mockValidator, times(0)).getValidInput(anyString(), ArgumentMatchers.eq(ck1.getValue()), ArgumentMatchers.eq(COOKIE_VALUE_TYPE_KEY), ArgumentMatchers.eq(SECURITY_CONFIGURATION_TEST_LENGTH), ArgumentMatchers.eq(true));
+        Mockito.verify(mockValidator, times(0)).getValidInput(anyString(), ArgumentMatchers.eq(ck1.getDomain()), ArgumentMatchers.eq(COOKIE_DOMAIN_TYPE_KEY), ArgumentMatchers.eq(SECURITY_CONFIGURATION_TEST_LENGTH), ArgumentMatchers.eq(false));
+        Mockito.verify(mockValidator, times(0)).getValidInput(anyString(), ArgumentMatchers.eq(ck1.getPath()), ArgumentMatchers.eq(COOKIE_PATH_TYPE_KEY), ArgumentMatchers.eq(SECURITY_CONFIGURATION_TEST_LENGTH), ArgumentMatchers.eq(false));
+
+        //I would have liked to verify the logging occurred, but it's giving me trouble at this time.
     }
-    
+
     @Test
     public void testGetCookieSkipOnBadValue() throws Exception {
-    	PowerMockito.when(mockSecConfig.getIntProp(SECURITY_CONFIGURATION_HEADER_NAME_LENGTH_KEY_NAME)).thenReturn(
-    			SECURITY_CONFIGURATION_TEST_LENGTH);
-    	PowerMockito.when(mockSecConfig.getIntProp(SECURITY_CONFIGURATION_HEADER_VALUE_LENGTH_KEY_NAME)).thenReturn(
-    			SECURITY_CONFIGURATION_TEST_LENGTH);
-
-    	Answer<String> exceptionAnswer = new ValidatorTestContainer(mockValidator).throwException();
-
-    	Cookie ck1 = new Cookie(testName.getMethodName(), testName.getMethodName()+ "-VALUE");
-    	ck1.setMaxAge(999);
-    	ck1.setDomain(testName.getMethodName() + "-DOMAIN");
-    	ck1.setPath(testName.getMethodName() + "-URI");
-
-    	Cookie[] stubCookies = new Cookie[] {ck1};
-    	PowerMockito.when(mockRequest.getCookies()).thenReturn(stubCookies);
-    	
-    	PowerMockito.when(mockValidator.getValidInput(anyString(), eq(ck1.getName()), eq(COOKIE_NAME_TYPE_KEY), eq(SECURITY_CONFIGURATION_TEST_LENGTH), eq(true))).thenReturn(ck1.getName());
-    	PowerMockito.when(mockValidator.getValidInput(anyString(), eq(ck1.getValue()),eq(COOKIE_VALUE_TYPE_KEY), eq(SECURITY_CONFIGURATION_TEST_LENGTH), eq(true))).thenAnswer(exceptionAnswer);
-
-    	SecurityWrapperRequest request = new SecurityWrapperRequest(mockRequest);
-    	Cookie[] cookies = request.getCookies();
-    	assertNotEquals(stubCookies, cookies);
-    	assertEquals(0, cookies.length);
-
-    	Mockito.verify(mockValidator, times(1)).getValidInput(anyString(), ArgumentMatchers.eq(ck1.getName()), ArgumentMatchers.eq(COOKIE_NAME_TYPE_KEY), ArgumentMatchers.eq(SECURITY_CONFIGURATION_TEST_LENGTH), ArgumentMatchers.eq(false));
-    	Mockito.verify(mockValidator, times(1)).getValidInput(anyString(), ArgumentMatchers.eq(ck1.getValue()), ArgumentMatchers.eq(COOKIE_VALUE_TYPE_KEY), ArgumentMatchers.eq(SECURITY_CONFIGURATION_TEST_LENGTH), ArgumentMatchers.eq(true));
-    	Mockito.verify(mockValidator, times(0)).getValidInput(anyString(), ArgumentMatchers.eq(ck1.getDomain()), ArgumentMatchers.eq(COOKIE_DOMAIN_TYPE_KEY), ArgumentMatchers.eq(SECURITY_CONFIGURATION_TEST_LENGTH), ArgumentMatchers.eq(false));
-    	Mockito.verify(mockValidator, times(0)).getValidInput(anyString(), ArgumentMatchers.eq(ck1.getPath()), ArgumentMatchers.eq(COOKIE_PATH_TYPE_KEY), ArgumentMatchers.eq(SECURITY_CONFIGURATION_TEST_LENGTH), ArgumentMatchers.eq(false));
-    	
-    	//I would have liked to verify the logging occurred, but it's giving me trouble at this time.
+        PowerMockito.when(mockSecConfig.getIntProp(SECURITY_CONFIGURATION_HEADER_NAME_LENGTH_KEY_NAME)).thenReturn(
+                SECURITY_CONFIGURATION_TEST_LENGTH);
+        PowerMockito.when(mockSecConfig.getIntProp(SECURITY_CONFIGURATION_HEADER_VALUE_LENGTH_KEY_NAME)).thenReturn(
+                SECURITY_CONFIGURATION_TEST_LENGTH);
+
+        Answer<String> exceptionAnswer = new ValidatorTestContainer(mockValidator).throwException();
+
+        Cookie ck1 = new Cookie(testName.getMethodName(), testName.getMethodName()+ "-VALUE");
+        ck1.setMaxAge(999);
+        ck1.setDomain(testName.getMethodName() + "-DOMAIN");
+        ck1.setPath(testName.getMethodName() + "-URI");
+
+        Cookie[] stubCookies = new Cookie[] {ck1};
+        PowerMockito.when(mockRequest.getCookies()).thenReturn(stubCookies);
+
+        PowerMockito.when(mockValidator.getValidInput(anyString(), eq(ck1.getName()), eq(COOKIE_NAME_TYPE_KEY), eq(SECURITY_CONFIGURATION_TEST_LENGTH), eq(true))).thenReturn(ck1.getName());
+        PowerMockito.when(mockValidator.getValidInput(anyString(), eq(ck1.getValue()),eq(COOKIE_VALUE_TYPE_KEY), eq(SECURITY_CONFIGURATION_TEST_LENGTH), eq(true))).thenAnswer(exceptionAnswer);
+
+        SecurityWrapperRequest request = new SecurityWrapperRequest(mockRequest);
+        Cookie[] cookies = request.getCookies();
+        assertNotEquals(stubCookies, cookies);
+        assertEquals(0, cookies.length);
+
+        Mockito.verify(mockValidator, times(1)).getValidInput(anyString(), ArgumentMatchers.eq(ck1.getName()), ArgumentMatchers.eq(COOKIE_NAME_TYPE_KEY), ArgumentMatchers.eq(SECURITY_CONFIGURATION_TEST_LENGTH), ArgumentMatchers.eq(false));
+        Mockito.verify(mockValidator, times(1)).getValidInput(anyString(), ArgumentMatchers.eq(ck1.getValue()), ArgumentMatchers.eq(COOKIE_VALUE_TYPE_KEY), ArgumentMatchers.eq(SECURITY_CONFIGURATION_TEST_LENGTH), ArgumentMatchers.eq(true));
+        Mockito.verify(mockValidator, times(0)).getValidInput(anyString(), ArgumentMatchers.eq(ck1.getDomain()), ArgumentMatchers.eq(COOKIE_DOMAIN_TYPE_KEY), ArgumentMatchers.eq(SECURITY_CONFIGURATION_TEST_LENGTH), ArgumentMatchers.eq(false));
+        Mockito.verify(mockValidator, times(0)).getValidInput(anyString(), ArgumentMatchers.eq(ck1.getPath()), ArgumentMatchers.eq(COOKIE_PATH_TYPE_KEY), ArgumentMatchers.eq(SECURITY_CONFIGURATION_TEST_LENGTH), ArgumentMatchers.eq(false));
+
+        //I would have liked to verify the logging occurred, but it's giving me trouble at this time.
     }
 
     @Test
     public void testGetCookieSkipOnBadDomain() throws Exception {
-    	PowerMockito.when(mockSecConfig.getIntProp(SECURITY_CONFIGURATION_HEADER_NAME_LENGTH_KEY_NAME)).thenReturn(
-    			SECURITY_CONFIGURATION_TEST_LENGTH);
-    	PowerMockito.when(mockSecConfig.getIntProp(SECURITY_CONFIGURATION_HEADER_VALUE_LENGTH_KEY_NAME)).thenReturn(
-    			SECURITY_CONFIGURATION_TEST_LENGTH);
-
-    	Answer<String> exceptionAnswer = new ValidatorTestContainer(mockValidator).throwException();
-    
-    	Cookie ck1 = new Cookie(testName.getMethodName(), testName.getMethodName()+ "-VALUE");
-    	ck1.setMaxAge(999);
-    	ck1.setDomain(testName.getMethodName() + "-DOMAIN");
-    	ck1.setPath(testName.getMethodName() + "-URI");
-
-    	Cookie[] stubCookies = new Cookie[] {ck1};
-    	PowerMockito.when(mockRequest.getCookies()).thenReturn(stubCookies);
-    	
-    	PowerMockito.when(mockValidator.getValidInput(anyString(), eq(ck1.getName()), eq(COOKIE_NAME_TYPE_KEY), eq(SECURITY_CONFIGURATION_TEST_LENGTH), eq(false))).thenReturn(ck1.getName());
+        PowerMockito.when(mockSecConfig.getIntProp(SECURITY_CONFIGURATION_HEADER_NAME_LENGTH_KEY_NAME)).thenReturn(
+                SECURITY_CONFIGURATION_TEST_LENGTH);
+        PowerMockito.when(mockSecConfig.getIntProp(SECURITY_CONFIGURATION_HEADER_VALUE_LENGTH_KEY_NAME)).thenReturn(
+                SECURITY_CONFIGURATION_TEST_LENGTH);
+
+        Answer<String> exceptionAnswer = new ValidatorTestContainer(mockValidator).throwException();
+
+        Cookie ck1 = new Cookie(testName.getMethodName(), testName.getMethodName()+ "-VALUE");
+        ck1.setMaxAge(999);
+        ck1.setDomain(testName.getMethodName() + "-DOMAIN");
+        ck1.setPath(testName.getMethodName() + "-URI");
+
+        Cookie[] stubCookies = new Cookie[] {ck1};
+        PowerMockito.when(mockRequest.getCookies()).thenReturn(stubCookies);
+
+        PowerMockito.when(mockValidator.getValidInput(anyString(), eq(ck1.getName()), eq(COOKIE_NAME_TYPE_KEY), eq(SECURITY_CONFIGURATION_TEST_LENGTH), eq(false))).thenReturn(ck1.getName());
        PowerMockito.when(mockValidator.getValidInput(anyString(), eq(ck1.getValue()),eq(COOKIE_VALUE_TYPE_KEY), eq(SECURITY_CONFIGURATION_TEST_LENGTH), eq(true))).thenReturn(ck1.getValue());
-   	PowerMockito.when(mockValidator.getValidInput(anyString(), eq(ck1.getDomain()),eq(COOKIE_DOMAIN_TYPE_KEY), eq(SECURITY_CONFIGURATION_TEST_LENGTH), eq(false))).thenAnswer(exceptionAnswer);
-
-    	SecurityWrapperRequest request = new SecurityWrapperRequest(mockRequest);
-    	Cookie[] cookies = request.getCookies();
-    	assertNotEquals(stubCookies, cookies);
-    	assertEquals(0, cookies.length);
-
-    	Mockito.verify(mockValidator, times(1)).getValidInput(anyString(), ArgumentMatchers.eq(ck1.getName()), ArgumentMatchers.eq(COOKIE_NAME_TYPE_KEY), ArgumentMatchers.eq(SECURITY_CONFIGURATION_TEST_LENGTH), ArgumentMatchers.eq(false));
-    	Mockito.verify(mockValidator, times(1)).getValidInput(anyString(), ArgumentMatchers.eq(ck1.getValue()), ArgumentMatchers.eq(COOKIE_VALUE_TYPE_KEY), ArgumentMatchers.eq(SECURITY_CONFIGURATION_TEST_LENGTH), ArgumentMatchers.eq(true));
-    	Mockito.verify(mockValidator, times(1)).getValidInput(anyString(), ArgumentMatchers.eq(ck1.getDomain()), ArgumentMatchers.eq(COOKIE_DOMAIN_TYPE_KEY), ArgumentMatchers.eq(SECURITY_CONFIGURATION_TEST_LENGTH), ArgumentMatchers.eq(false));
-    	Mockito.verify(mockValidator, times(0)).getValidInput(anyString(), ArgumentMatchers.eq(ck1.getPath()), ArgumentMatchers.eq(COOKIE_PATH_TYPE_KEY), ArgumentMatchers.eq(SECURITY_CONFIGURATION_TEST_LENGTH), ArgumentMatchers.eq(false));
-    	
-    	//I would have liked to verify the logging occurred, but it's giving me trouble at this time.
+       PowerMockito.when(mockValidator.getValidInput(anyString(), eq(ck1.getDomain()),eq(COOKIE_DOMAIN_TYPE_KEY), eq(SECURITY_CONFIGURATION_TEST_LENGTH), eq(false))).thenAnswer(exceptionAnswer);
+
+        SecurityWrapperRequest request = new SecurityWrapperRequest(mockRequest);
+        Cookie[] cookies = request.getCookies();
+        assertNotEquals(stubCookies, cookies);
+        assertEquals(0, cookies.length);
+
+        Mockito.verify(mockValidator, times(1)).getValidInput(anyString(), ArgumentMatchers.eq(ck1.getName()), ArgumentMatchers.eq(COOKIE_NAME_TYPE_KEY), ArgumentMatchers.eq(SECURITY_CONFIGURATION_TEST_LENGTH), ArgumentMatchers.eq(false));
+        Mockito.verify(mockValidator, times(1)).getValidInput(anyString(), ArgumentMatchers.eq(ck1.getValue()), ArgumentMatchers.eq(COOKIE_VALUE_TYPE_KEY), ArgumentMatchers.eq(SECURITY_CONFIGURATION_TEST_LENGTH), ArgumentMatchers.eq(true));
+        Mockito.verify(mockValidator, times(1)).getValidInput(anyString(), ArgumentMatchers.eq(ck1.getDomain()), ArgumentMatchers.eq(COOKIE_DOMAIN_TYPE_KEY), ArgumentMatchers.eq(SECURITY_CONFIGURATION_TEST_LENGTH), ArgumentMatchers.eq(false));
+        Mockito.verify(mockValidator, times(0)).getValidInput(anyString(), ArgumentMatchers.eq(ck1.getPath()), ArgumentMatchers.eq(COOKIE_PATH_TYPE_KEY), ArgumentMatchers.eq(SECURITY_CONFIGURATION_TEST_LENGTH), ArgumentMatchers.eq(false));
+
+        //I would have liked to verify the logging occurred, but it's giving me trouble at this time.
     }
-    
+
 
     @Test
     public void testGetCookieSkipOnBadPath() throws Exception {
-    	PowerMockito.when(mockSecConfig.getIntProp(SECURITY_CONFIGURATION_HEADER_NAME_LENGTH_KEY_NAME)).thenReturn(
-    			SECURITY_CONFIGURATION_TEST_LENGTH);
-    	PowerMockito.when(mockSecConfig.getIntProp(SECURITY_CONFIGURATION_HEADER_VALUE_LENGTH_KEY_NAME)).thenReturn(
-    			SECURITY_CONFIGURATION_TEST_LENGTH);
-
-    	Answer<String> exceptionAnswer = new ValidatorTestContainer(mockValidator).throwException();
-    
-    	Cookie ck1 = new Cookie(testName.getMethodName(), testName.getMethodName()+ "-VALUE");
-    	ck1.setMaxAge(999);
-    	ck1.setDomain(testName.getMethodName() + "-DOMAIN");
-    	ck1.setPath(testName.getMethodName() + "-URI");
-
-    	Cookie[] stubCookies = new Cookie[] {ck1};
-    	PowerMockito.when(mockRequest.getCookies()).thenReturn(stubCookies);
-    	
-    	PowerMockito.when(mockValidator.getValidInput(anyString(), eq(ck1.getName()), eq(COOKIE_NAME_TYPE_KEY), eq(SECURITY_CONFIGURATION_TEST_LENGTH), eq(false))).thenReturn(ck1.getName());
-    	PowerMockito.when(mockValidator.getValidInput(anyString(), eq(ck1.getValue()),eq(COOKIE_VALUE_TYPE_KEY), eq(SECURITY_CONFIGURATION_TEST_LENGTH), eq(true))).thenReturn(ck1.getValue());
-    	PowerMockito.when(mockValidator.getValidInput(anyString(), eq(ck1.getDomain()),eq(COOKIE_DOMAIN_TYPE_KEY), eq(SECURITY_CONFIGURATION_TEST_LENGTH), eq(false))).thenReturn(ck1.getDomain());
-    	PowerMockito.when(mockValidator.getValidInput(anyString(), eq(ck1.getPath()), eq(COOKIE_PATH_TYPE_KEY), eq(SECURITY_CONFIGURATION_TEST_LENGTH), eq(false))).thenAnswer(exceptionAnswer);
-
-    	SecurityWrapperRequest request = new SecurityWrapperRequest(mockRequest);
-    	Cookie[] cookies = request.getCookies();
-    	assertNotEquals(stubCookies, cookies);
-    	assertEquals(0, cookies.length);
-
-    	Mockito.verify(mockValidator, times(1)).getValidInput(anyString(), ArgumentMatchers.eq(ck1.getName()), ArgumentMatchers.eq(COOKIE_NAME_TYPE_KEY), ArgumentMatchers.eq(SECURITY_CONFIGURATION_TEST_LENGTH), ArgumentMatchers.eq(false));
-    	Mockito.verify(mockValidator, times(1)).getValidInput(anyString(), ArgumentMatchers.eq(ck1.getValue()), ArgumentMatchers.eq(COOKIE_VALUE_TYPE_KEY), ArgumentMatchers.eq(SECURITY_CONFIGURATION_TEST_LENGTH), ArgumentMatchers.eq(true));
-    	Mockito.verify(mockValidator, times(1)).getValidInput(anyString(), ArgumentMatchers.eq(ck1.getDomain()), ArgumentMatchers.eq(COOKIE_DOMAIN_TYPE_KEY), ArgumentMatchers.eq(SECURITY_CONFIGURATION_TEST_LENGTH), ArgumentMatchers.eq(false));
-    	Mockito.verify(mockValidator, times(1)).getValidInput(anyString(), ArgumentMatchers.eq(ck1.getPath()), ArgumentMatchers.eq(COOKIE_PATH_TYPE_KEY), ArgumentMatchers.eq(SECURITY_CONFIGURATION_TEST_LENGTH), ArgumentMatchers.eq(false));
-    	
-    	//I would have liked to verify the logging occurred, but it's giving me trouble at this time.
+        PowerMockito.when(mockSecConfig.getIntProp(SECURITY_CONFIGURATION_HEADER_NAME_LENGTH_KEY_NAME)).thenReturn(
+                SECURITY_CONFIGURATION_TEST_LENGTH);
+        PowerMockito.when(mockSecConfig.getIntProp(SECURITY_CONFIGURATION_HEADER_VALUE_LENGTH_KEY_NAME)).thenReturn(
+                SECURITY_CONFIGURATION_TEST_LENGTH);
+
+        Answer<String> exceptionAnswer = new ValidatorTestContainer(mockValidator).throwException();
+
+        Cookie ck1 = new Cookie(testName.getMethodName(), testName.getMethodName()+ "-VALUE");
+        ck1.setMaxAge(999);
+        ck1.setDomain(testName.getMethodName() + "-DOMAIN");
+        ck1.setPath(testName.getMethodName() + "-URI");
+
+        Cookie[] stubCookies = new Cookie[] {ck1};
+        PowerMockito.when(mockRequest.getCookies()).thenReturn(stubCookies);
+
+        PowerMockito.when(mockValidator.getValidInput(anyString(), eq(ck1.getName()), eq(COOKIE_NAME_TYPE_KEY), eq(SECURITY_CONFIGURATION_TEST_LENGTH), eq(false))).thenReturn(ck1.getName());
+        PowerMockito.when(mockValidator.getValidInput(anyString(), eq(ck1.getValue()),eq(COOKIE_VALUE_TYPE_KEY), eq(SECURITY_CONFIGURATION_TEST_LENGTH), eq(true))).thenReturn(ck1.getValue());
+        PowerMockito.when(mockValidator.getValidInput(anyString(), eq(ck1.getDomain()),eq(COOKIE_DOMAIN_TYPE_KEY), eq(SECURITY_CONFIGURATION_TEST_LENGTH), eq(false))).thenReturn(ck1.getDomain());
+        PowerMockito.when(mockValidator.getValidInput(anyString(), eq(ck1.getPath()), eq(COOKIE_PATH_TYPE_KEY), eq(SECURITY_CONFIGURATION_TEST_LENGTH), eq(false))).thenAnswer(exceptionAnswer);
+
+        SecurityWrapperRequest request = new SecurityWrapperRequest(mockRequest);
+        Cookie[] cookies = request.getCookies();
+        assertNotEquals(stubCookies, cookies);
+        assertEquals(0, cookies.length);
+
+        Mockito.verify(mockValidator, times(1)).getValidInput(anyString(), ArgumentMatchers.eq(ck1.getName()), ArgumentMatchers.eq(COOKIE_NAME_TYPE_KEY), ArgumentMatchers.eq(SECURITY_CONFIGURATION_TEST_LENGTH), ArgumentMatchers.eq(false));
+        Mockito.verify(mockValidator, times(1)).getValidInput(anyString(), ArgumentMatchers.eq(ck1.getValue()), ArgumentMatchers.eq(COOKIE_VALUE_TYPE_KEY), ArgumentMatchers.eq(SECURITY_CONFIGURATION_TEST_LENGTH), ArgumentMatchers.eq(true));
+        Mockito.verify(mockValidator, times(1)).getValidInput(anyString(), ArgumentMatchers.eq(ck1.getDomain()), ArgumentMatchers.eq(COOKIE_DOMAIN_TYPE_KEY), ArgumentMatchers.eq(SECURITY_CONFIGURATION_TEST_LENGTH), ArgumentMatchers.eq(false));
+        Mockito.verify(mockValidator, times(1)).getValidInput(anyString(), ArgumentMatchers.eq(ck1.getPath()), ArgumentMatchers.eq(COOKIE_PATH_TYPE_KEY), ArgumentMatchers.eq(SECURITY_CONFIGURATION_TEST_LENGTH), ArgumentMatchers.eq(false));
+
+        //I would have liked to verify the logging occurred, but it's giving me trouble at this time.
     }
 
     /**
@@ -611,8 +610,8 @@ public class SecurityWrapperRequestTest {
         private ArgumentCaptor<Integer> lengthCapture = ArgumentCaptor.forClass(Integer.class);
         private ArgumentCaptor<Boolean> allowNullCapture = ArgumentCaptor.forClass(Boolean.class);
         private Validator validator;
-        
-        
+
+
         public ValidatorTestContainer(Validator validatorRef) {
             this.validator = validatorRef;
         }
@@ -624,7 +623,7 @@ public class SecurityWrapperRequestTest {
                 }
             };
         }
-        
+
         public Answer<String> returnResult(final String result) {
             return new Answer<String>() {
                 @Override
@@ -636,11 +635,11 @@ public class SecurityWrapperRequestTest {
         public void getValidInputReturns(String response) throws Exception {
             setupFor(returnResult(response));
         }
-       
+
         public void getValidInputThrows() throws Exception {
             setupFor(throwException());
         }
-       
+
         public void setupFor(Answer<String> answer) throws Exception {
             String context = anyString();
             String input = inputCapture.capture();
@@ -650,7 +649,7 @@ public class SecurityWrapperRequestTest {
 
             PowerMockito.when(validator.getValidInput(context, input, type, length, allowNull)).thenAnswer(answer);
         }
-              
+
         public void verify(String input, String type, int maxLen, boolean allowNull) throws Exception {
             String actualInput = inputCapture.getValue();
             String actualType = typeCapture.getValue();
@@ -661,7 +660,7 @@ public class SecurityWrapperRequestTest {
             assertEquals(type, actualType);
             assertTrue(maxLen == actualLength);
             assertEquals(allowNull, actualAllowNull);
-            
+
             Mockito.verify(validator, times(1)).getValidInput(anyString(), ArgumentMatchers.eq(input), ArgumentMatchers.eq(type), ArgumentMatchers.eq(maxLen), ArgumentMatchers.eq(allowNull));
         }
     }
diff --git a/src/test/java/org/owasp/esapi/filters/SecurityWrapperResponseTest.java b/src/test/java/org/owasp/esapi/filters/SecurityWrapperResponseTest.java
index 499da87..f7b74c6 100644
--- a/src/test/java/org/owasp/esapi/filters/SecurityWrapperResponseTest.java
+++ b/src/test/java/org/owasp/esapi/filters/SecurityWrapperResponseTest.java
@@ -6,7 +6,7 @@ import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
-import static org.owasp.esapi.reference.DefaultSecurityConfiguration.DISABLE_INTRUSION_DETECTION;
+import static org.owasp.esapi.PropNames.DISABLE_INTRUSION_DETECTION;
 
 import javax.servlet.http.Cookie;
 import javax.servlet.http.HttpServletResponse;
@@ -66,7 +66,7 @@ public class SecurityWrapperResponseTest {
             PowerMockito.when(ESAPI.class, SecurityWrapperRequestTest.ESAPI_VALIDATOR_GETTER_METHOD_NAME).thenReturn(mockValidator);
             PowerMockito.when(ESAPI.class, SecurityWrapperRequestTest.ESAPI_GET_LOGGER_METHOD_NAME, "SecurityWrapperResponse").thenReturn(mockLogger);
             PowerMockito.when(ESAPI.class, SecurityWrapperRequestTest.ESAPY_SECURITY_CONFIGURATION_GETTER_METHOD_NAME).thenReturn(mockSecConfig);
-            //Is intrusion detection disabled?  A:  Yes, it is off.  
+            //Is intrusion detection disabled?  A:  Yes, it is off.
             //This logic is confusing:  True, the value is False...
             Mockito.when( mockSecConfig.getBooleanProp( DISABLE_INTRUSION_DETECTION ) ).thenReturn(true);
 
@@ -104,7 +104,7 @@ public class SecurityWrapperResponseTest {
         verify(mockSecConfig, times(1)).getIntProp(SEC_CTX_MAX_HEADER_NAME_SIZE_ATTR);
         verify(mockSecConfig, times(1)).getIntProp(SEC_CTX_MAX_HEADER_VALUE_SIZE_ATTR);
         verify(mockResponse, times(1)).setHeader(validateNameResponse, validateValueResponse);
-        verify(mockLogger,times(0)).warning(ArgumentMatchers.any(org.owasp.esapi.Logger.EventType.class), anyString(), ArgumentMatchers.any(Exception.class));      
+        verify(mockLogger,times(0)).warning(ArgumentMatchers.any(org.owasp.esapi.Logger.EventType.class), anyString(), ArgumentMatchers.any(Exception.class));
     }
 
     @Test
@@ -261,7 +261,7 @@ public class SecurityWrapperResponseTest {
         verify(mockSecConfig, times(1)).getIntProp(SEC_CTX_MAX_HEADER_VALUE_SIZE_ATTR);
         verify(mockResponse, times(0)).setHeader(anyString(), anyString());
         verify(mockLogger, times(0)).warning(ArgumentMatchers.any(org.owasp.esapi.Logger.EventType.class),anyString(),
-                ArgumentMatchers.any(Exception.class)); 
+                ArgumentMatchers.any(Exception.class));
     }
 
     @Test
@@ -300,7 +300,7 @@ public class SecurityWrapperResponseTest {
         verify(mockSecConfig, times(1)).getIntProp(SEC_CTX_MAX_HEADER_VALUE_SIZE_ATTR);
         verify(mockResponse, times(0)).setHeader(anyString(), anyString());
         verify(mockLogger, times(0)).warning(ArgumentMatchers.any(org.owasp.esapi.Logger.EventType.class),anyString(),
-                ArgumentMatchers.any(Exception.class));   
+                ArgumentMatchers.any(Exception.class));
     }
 
     @Test
@@ -372,7 +372,7 @@ public class SecurityWrapperResponseTest {
         verify(mockSecConfig, times(1)).getIntProp(SEC_CTX_MAX_HEADER_NAME_SIZE_ATTR);
         verify(mockSecConfig, times(1)).getIntProp(SEC_CTX_MAX_HEADER_VALUE_SIZE_ATTR);
         verify(mockResponse, times(1)).addHeader(validateNameResponse, validateValueResponse);
-        verify(mockLogger,times(0)).warning(ArgumentMatchers.any(org.owasp.esapi.Logger.EventType.class), anyString(), ArgumentMatchers.any(Exception.class));      
+        verify(mockLogger,times(0)).warning(ArgumentMatchers.any(org.owasp.esapi.Logger.EventType.class), anyString(), ArgumentMatchers.any(Exception.class));
     }
 
     @Test
@@ -529,7 +529,7 @@ public class SecurityWrapperResponseTest {
         verify(mockSecConfig, times(1)).getIntProp(SEC_CTX_MAX_HEADER_VALUE_SIZE_ATTR);
         verify(mockResponse, times(0)).addHeader(anyString(), anyString());
         verify(mockLogger, times(0)).warning(ArgumentMatchers.any(org.owasp.esapi.Logger.EventType.class),anyString(),
-                ArgumentMatchers.any(Exception.class)); 
+                ArgumentMatchers.any(Exception.class));
     }
 
     @Test
@@ -568,7 +568,7 @@ public class SecurityWrapperResponseTest {
         verify(mockSecConfig, times(1)).getIntProp(SEC_CTX_MAX_HEADER_VALUE_SIZE_ATTR);
         verify(mockResponse, times(0)).addHeader(anyString(), anyString());
         verify(mockLogger, times(0)).warning(ArgumentMatchers.any(org.owasp.esapi.Logger.EventType.class),anyString(),
-                ArgumentMatchers.any(Exception.class));   
+                ArgumentMatchers.any(Exception.class));
     }
 
     @Test
@@ -665,7 +665,7 @@ public class SecurityWrapperResponseTest {
 
     @Test
     public void testAddHeaderInvalidValueLength(){
-        //refactor this to use a spy. 
+        //refactor this to use a spy.
         HttpServletResponse servResp = mock(HttpServletResponse.class);
         SecurityWrapperResponse resp = new SecurityWrapperResponse(servResp);
         SecurityWrapperResponse spyResp = spy(resp);
@@ -722,9 +722,9 @@ public class SecurityWrapperResponseTest {
 
         /*
          * We're indirectly testing our class.  Since it ultimately
-         * delegates to HttpServletResponse.addHeader, we're actually 
+         * delegates to HttpServletResponse.addHeader, we're actually
          * validating that our test method constructs a header with the
-         * expected properties.  This implicitly tests the 
+         * expected properties.  This implicitly tests the
          * createCookieHeader method as well.
          */
         verify(servResp, times(1)).addHeader("Set-Cookie", "Foo=aaaaaaaaaa; Max-Age=5000; Secure; HttpOnly");
diff --git a/src/test/java/org/owasp/esapi/http/MockFilterChain.java b/src/test/java/org/owasp/esapi/http/MockFilterChain.java
index 06951ef..c00927e 100644
--- a/src/test/java/org/owasp/esapi/http/MockFilterChain.java
+++ b/src/test/java/org/owasp/esapi/http/MockFilterChain.java
@@ -1,15 +1,15 @@
 /**
  * OWASP Enterprise Security API (ESAPI)
- * 
+ *
  * This file is part of the Open Web Application Security Project (OWASP)
  * Enterprise Security API (ESAPI) project. For details, please see
  * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
  *
  * Copyright (c) 2007 - The OWASP Foundation
- * 
+ *
  * The ESAPI is published by OWASP under the BSD license. You should read and accept the
  * LICENSE before you use, modify, and/or redistribute this software.
- * 
+ *
  * @author Jeff Williams <a href="http://www.aspectsecurity.com">Aspect Security</a>
  * @created 2007
  */
@@ -38,9 +38,9 @@ public class MockFilterChain implements FilterChain {
      * @throws javax.servlet.ServletException
      */
     public void doFilter( ServletRequest request, ServletResponse response ) throws IOException, ServletException {
-    	System.out.println( "CHAIN received " + request.getClass().getName() + " and is issuing " + response.getClass().getName() );
-       	response.getOutputStream().println( "   This is the body of a response for " +  ((HttpServletRequest)request).getRequestURI() );
-           	((HttpServletResponse)response).addCookie( new Cookie( "name", "value" ) );
+        System.out.println( "CHAIN received " + request.getClass().getName() + " and is issuing " + response.getClass().getName() );
+           response.getOutputStream().println( "   This is the body of a response for " +  ((HttpServletRequest)request).getRequestURI() );
+               ((HttpServletResponse)response).addCookie( new Cookie( "name", "value" ) );
     }
 
 }
diff --git a/src/test/java/org/owasp/esapi/http/MockFilterConfig.java b/src/test/java/org/owasp/esapi/http/MockFilterConfig.java
index b7715a4..7f350f9 100644
--- a/src/test/java/org/owasp/esapi/http/MockFilterConfig.java
+++ b/src/test/java/org/owasp/esapi/http/MockFilterConfig.java
@@ -1,15 +1,15 @@
 /**
  * OWASP Enterprise Security API (ESAPI)
- * 
+ *
  * This file is part of the Open Web Application Security Project (OWASP)
  * Enterprise Security API (ESAPI) project. For details, please see
  * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
  *
  * Copyright (c) 2007 - The OWASP Foundation
- * 
+ *
  * The ESAPI is published by OWASP under the BSD license. You should read and accept the
  * LICENSE before you use, modify, and/or redistribute this software.
- * 
+ *
  * @author Jeff Williams <a href="http://www.aspectsecurity.com">Aspect Security</a>
  * @created 2007
  */
@@ -27,14 +27,14 @@ import javax.servlet.ServletContext;
  * to pass information to a filter during initialization.
  */
 public class MockFilterConfig implements FilterConfig {
-	private Map map;
+    private Map map;
+
+    public MockFilterConfig( Map map ) {
+        this.map = map;
+    }
 
-	public MockFilterConfig( Map map ) {
-		this.map = map;
-	}
-	
     public String getFilterName() {
-    	return "mock";
+        return "mock";
     }
 
     /**
@@ -42,7 +42,7 @@ public class MockFilterConfig implements FilterConfig {
      * is executing.
      */
     public ServletContext getServletContext() {
-    	return new MockServletContext();
+        return new MockServletContext();
     }
 
     /**
@@ -51,7 +51,7 @@ public class MockFilterConfig implements FilterConfig {
      * the parameter does not exist.
      */
     public String getInitParameter(String name) {
-    	return (String)map.get( name );
+        return (String)map.get( name );
     }
 
     /**
@@ -61,6 +61,6 @@ public class MockFilterConfig implements FilterConfig {
      * no initialization parameters.
      */
     public Enumeration getInitParameterNames() {
-    	return Collections.enumeration( map.keySet() );
+        return Collections.enumeration( map.keySet() );
     }
 }
diff --git a/src/test/java/org/owasp/esapi/http/MockHttpServletRequest.java b/src/test/java/org/owasp/esapi/http/MockHttpServletRequest.java
index d085b7c..d64b005 100644
--- a/src/test/java/org/owasp/esapi/http/MockHttpServletRequest.java
+++ b/src/test/java/org/owasp/esapi/http/MockHttpServletRequest.java
@@ -1,15 +1,15 @@
 /**
  * OWASP Enterprise Security API (ESAPI)
- * 
+ *
  * This file is part of the Open Web Application Security Project (OWASP)
  * Enterprise Security API (ESAPI) project. For details, please see
  * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
  *
  * Copyright (c) 2007 - The OWASP Foundation
- * 
+ *
  * The ESAPI is published by OWASP under the BSD license. You should read and accept the
  * LICENSE before you use, modify, and/or redistribute this software.
- * 
+ *
  * @author Jeff Williams <a href="http://www.aspectsecurity.com">Aspect Security</a>
  * @created 2007
  */
@@ -51,632 +51,632 @@ import javax.servlet.http.Part;
 
 /**
  * The Class MockHttpServletRequest.
- * 
+ *
  * @author jwilliams
  */
 public class MockHttpServletRequest implements HttpServletRequest
 {
-	private static final String HDR_CONTENT_TYPE = "Content-Type";
-	private static final String[] EMPTY_STRING_ARRAY = new String[0];
-
-	/** The requestDispatcher */
-	private RequestDispatcher requestDispatcher = new MockRequestDispatcher();
-
-	/** The session. */
-	private MockHttpSession session = null;
-
-	/** The cookies. */
-	private ArrayList<Cookie> cookies = new ArrayList<Cookie>();
-
-	/** The parameters. */
-	private Map<String,String[]> parameters = new HashMap<String,String[]>();
-
-	/** The headers. */
-	private Map<String,List<String>> headers = new HashMap<String,List<String>>();
-
-	private byte[] body;
-
-	private String scheme = "https";
-
-	private String remoteHost = "64.14.103.52";
-
-	private String serverHost = "64.14.103.52";
-
-	private String uri = "/test";
-
-	private String queryString = "pid=1&qid=test";
-
-	private String method = "POST";
-
-	private Map<String,Object> attrs = new HashMap<String,Object>();
-
-	public MockHttpServletRequest() {
-	}
-
-	public MockHttpServletRequest(String uri, byte[] body) {
-		this.body = body;
-		this.uri = uri;
-	}
-
-	public MockHttpServletRequest( URL url ) {
-		scheme = url.getProtocol();
-		serverHost = url.getHost();
-		uri = url.getPath();
-	}
-
-	public String getAuthType() {
-		return null;
-	}
-
-	public String getContextPath() {
-		return null;
-	}
-
-	/**
-	 * Adds the parameter.
-	 * 
-	 * @param name the name
-	 * @param value the value
-	 */
-	public void addParameter(String name, String value) {
-		String[] old = parameters.get(name);
-		if ( old == null ) {
-			old = new String[0];
-		}
-		String[] updated = new String[old.length + 1];
-		for ( int i = 0; i < old.length; i++ ) updated[i] = old[i];
-		updated[old.length] = value;
-		parameters.put(name, updated);
-	}
-
-	/**
-	 * removeParameter removes the parameter name from the parameters map if it exists
-	 *  
-	 * @param name
-	 * 			parameter name to be removed
-	 */
-	public void removeParameter( String name ) {
-		parameters.remove( name );
-	}
-
-	/**
-	 * Adds the header.
-	 * 
-	 * @param name the name
-	 * @param value the value
-	 */
-	public void addHeader(String name, String value)
-	{
-		List<String> values;
-
-		if((values = headers.get(name))==null)
-		{
-			values = new ArrayList<String>();
-			headers.put(name, values);
-		}
-		values.add(value);
-	}
-
-	/**
-	 * Set a header replacing any previous value(s).
-	 * @param name the header name
-	 * @param value the header value
-	 */
-	public void setHeader(String name, String value)
-	{
-		List<String> values = new ArrayList<String>();
-
-		values.add(value);
-		headers.put(name,values);
-	}
-
-	/**
-	 * Sets the cookies.
-	 * 
-	 * @param list the new cookies
-	 */
-	public void setCookies(ArrayList<Cookie> list) {
-		cookies = list;
-	}
-
-	public void setCookie(String name, String value ) {
-		Cookie c = new Cookie( name, value );
-		cookies.add( c );
-	}
-
-	public boolean clearCookie(String name) {
-		return cookies.remove(name);
-	}
-
-	public void clearCookies() {
-		cookies.clear();
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	public Cookie[] getCookies() {
-		if ( cookies.isEmpty() ) return null;
-		return cookies.toArray(new Cookie[0]);
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	public long getDateHeader(String name) {
-		try {
-			Date date = SimpleDateFormat.getDateTimeInstance().parse( getParameter( name ) );
-			return date.getTime(); // TODO needs to be HTTP format
-		} catch( ParseException e ) {
-			return 0;
-		}
-	}
-
-	/**
-	 * {@inheritDoc}
-	 * @param name 
-	 * @return The requested header value.
-	 */
-	public String getHeader(String name) {
-		List<String> values;
-
-		if((values = headers.get(name))==null)
-			return null;
-		if(values.size() == 0)
-			return null;
-		return values.get(0);
-	}
-
-	/**
-	 * {@inheritDoc}
-	 * @return Enumeration of header names as strings
-	 */
-	public Enumeration<String> getHeaderNames()
-	{
-		return Collections.enumeration(headers.keySet());
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	public Enumeration<String> getHeaders(String name) {
-		Vector<String> v = new Vector<String>();
-		v.add( getHeader( name ) );
-		return v.elements();
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	public int getIntHeader(String name) {
-
-		return 0;
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	public String getMethod() {
-		return method;
-	}
-
-	public void setMethod( String value ) {
-		method = value;
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	public String getPathInfo() {
-
-		return null;
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	public String getPathTranslated() {
-
-		return null;
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	public String getQueryString() {
-		return queryString;
-	}
-
-	/**
-	 * Set the query string to return.
-	 * @param str The query string to return.
-	 */
-	public void setQueryString(String str)
-	{
-		this.queryString = str;
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	public String getRemoteUser() {
-
-		return null;
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	public String getRequestURI() {
-		return uri;
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	public StringBuffer getRequestURL() {
-		return new StringBuffer( getScheme() + "://" + this.getServerName() + getRequestURI() + "?" + getQueryString() );
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	public String getRequestedSessionId() {
-
-		return null;
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	public String getServletPath() {
-
-		return null;
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	public HttpSession getSession() {
-		if (session != null) {
-			return getSession(false);
-		}
-		return getSession(true);
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	public HttpSession getSession(boolean create) {
-		if (session == null && create) {
-			session = new MockHttpSession();
-		} else if (session != null && session.getInvalidated()) {
-			session = new MockHttpSession();
-		}
-		return session;
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	public Principal getUserPrincipal() {
-
-		return null;
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	public boolean isRequestedSessionIdFromCookie() {
-
-		return false;
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	public boolean isRequestedSessionIdFromURL() {
-
-		return false;
-	}
-
-	/**
-	 * {@inheritDoc}
-	 * @deprecated
-	 */
-	@Deprecated
-	public boolean isRequestedSessionIdFromUrl() {
-
-		return false;
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	public boolean isRequestedSessionIdValid() {
-
-		return false;
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	public boolean isUserInRole(String role) {
-
-		return false;
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	public Object getAttribute(String name) {
-		return attrs.get(name);
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	public Enumeration<String> getAttributeNames() {
-		return Collections.enumeration(attrs.keySet());
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	public String getCharacterEncoding() {
-
-		return null;
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	public int getContentLength() {
-		return body.length;
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	public String getContentType() {
-		return getHeader(HDR_CONTENT_TYPE);
-	}
-
-	public void setContentType( String value ) {
-		setHeader(HDR_CONTENT_TYPE, value);
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	public ServletInputStream getInputStream() throws IOException {
-		return new MockServletInputStream(body);
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	public String getLocalAddr() {
-		return "10.1.43.6";
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	public String getLocalName() {
-		return "www.domain.com";
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	public int getLocalPort() {
-		return 80;
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	public Locale getLocale() {
-		return null;
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	public Enumeration<Locale> getLocales() {
-		return null;
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	public String getParameter(String name) {
-		String[] values = parameters.get(name);
-		if ( values == null ) return null;
-		return values[0];
-	}
-
-	public void clearParameter(String name) {
-		parameters.remove( name );
-	}
-
-	public void clearParameters() {
-		parameters.clear();
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	public Map<String, String[]> getParameterMap() {
-		return parameters;
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	public Enumeration<String> getParameterNames() {
-		return Collections.enumeration(parameters.keySet());
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	public String[] getParameterValues(String name) {
-		return parameters.get(name);
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	public String getProtocol() {
-		return "HTTP/1.1";
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	public BufferedReader getReader() throws IOException {
-
-		return null;
-	}
-
-	/**
-	 * {@inheritDoc}
-	 * @deprecated
-	 */
-	@Deprecated
-	public String getRealPath(String path) {
-
-		return null;
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	public String getRemoteAddr() {
-		return remoteHost;
-	}
-
-	public void setRemoteAddr(String remoteHost) {
-		this.remoteHost = remoteHost;
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	public String getRemoteHost() {
-		return remoteHost;
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	public int getRemotePort() {
-
-		return 0;
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	public RequestDispatcher getRequestDispatcher(String path) {
-		return requestDispatcher;
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	public String getScheme() {
-		return scheme;
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	public String getServerName() {
-		return serverHost;
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	public int getServerPort() {
-		return 80;
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	public boolean isSecure() {
-		return scheme.equals( "https" );
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	public void removeAttribute(String name) {
-		attrs.remove(name);
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	public void setAttribute(String name, Object o) {
-		attrs.put(name,o);
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	public void setCharacterEncoding(String env) throws UnsupportedEncodingException {
-
-	}
-
-	public void setRequestURI(String uri) throws UnsupportedEncodingException {
-		this.uri = uri;
-	}
-
-	public void setRequestURL(String url) throws UnsupportedEncodingException {
-		// get the scheme
-		int p = url.indexOf( ":" );
-		this.scheme = url.substring( 0, p );
-
-		// get the queryString
-		int q = url.indexOf( "?" );
-		if ( q != -1 )
-		{
-			queryString = url.substring( q+1 );
-			url = url.substring( 0, q );
-		}
-		else
-			queryString = null;
-	}
-
-	public void setScheme( String scheme ) {
-		this.scheme = scheme;
-	}
-
-	public void dump()
-	{
-		String[] names;
-
-		System.out.println();
-		System.out.println( "  " + this.getMethod() + " " + this.getRequestURL() );
-
-		names = headers.keySet().toArray(EMPTY_STRING_ARRAY);
-		Arrays.sort(names);	// make debugging a bit easier...
-		for (String name : names)
-			for(String value : headers.get(name))
-				System.out.println( "  " + name + ": " + value);
-		names = parameters.keySet().toArray(EMPTY_STRING_ARRAY);
-		Arrays.sort(names);
-		for (String name : names) {
-			for(String value : parameters.get(name))
-				System.out.println( "  " + name + "=" + value);
-		}
-		System.out.println( "\n" );
-	}
+    private static final String HDR_CONTENT_TYPE = "Content-Type";
+    private static final String[] EMPTY_STRING_ARRAY = new String[0];
+
+    /** The requestDispatcher */
+    private RequestDispatcher requestDispatcher = new MockRequestDispatcher();
+
+    /** The session. */
+    private MockHttpSession session = null;
+
+    /** The cookies. */
+    private ArrayList<Cookie> cookies = new ArrayList<Cookie>();
+
+    /** The parameters. */
+    private Map<String,String[]> parameters = new HashMap<String,String[]>();
+
+    /** The headers. */
+    private Map<String,List<String>> headers = new HashMap<String,List<String>>();
+
+    private byte[] body;
+
+    private String scheme = "https";
+
+    private String remoteHost = "64.14.103.52";
+
+    private String serverHost = "64.14.103.52";
+
+    private String uri = "/test";
+
+    private String queryString = "pid=1&qid=test";
+
+    private String method = "POST";
+
+    private Map<String,Object> attrs = new HashMap<String,Object>();
+
+    public MockHttpServletRequest() {
+    }
+
+    public MockHttpServletRequest(String uri, byte[] body) {
+        this.body = body;
+        this.uri = uri;
+    }
+
+    public MockHttpServletRequest( URL url ) {
+        scheme = url.getProtocol();
+        serverHost = url.getHost();
+        uri = url.getPath();
+    }
+
+    public String getAuthType() {
+        return null;
+    }
+
+    public String getContextPath() {
+        return null;
+    }
+
+    /**
+     * Adds the parameter.
+     *
+     * @param name the name
+     * @param value the value
+     */
+    public void addParameter(String name, String value) {
+        String[] old = parameters.get(name);
+        if ( old == null ) {
+            old = new String[0];
+        }
+        String[] updated = new String[old.length + 1];
+        for ( int i = 0; i < old.length; i++ ) updated[i] = old[i];
+        updated[old.length] = value;
+        parameters.put(name, updated);
+    }
+
+    /**
+     * removeParameter removes the parameter name from the parameters map if it exists
+     *
+     * @param name
+     *             parameter name to be removed
+     */
+    public void removeParameter( String name ) {
+        parameters.remove( name );
+    }
+
+    /**
+     * Adds the header.
+     *
+     * @param name the name
+     * @param value the value
+     */
+    public void addHeader(String name, String value)
+    {
+        List<String> values;
+
+        if((values = headers.get(name))==null)
+        {
+            values = new ArrayList<String>();
+            headers.put(name, values);
+        }
+        values.add(value);
+    }
+
+    /**
+     * Set a header replacing any previous value(s).
+     * @param name the header name
+     * @param value the header value
+     */
+    public void setHeader(String name, String value)
+    {
+        List<String> values = new ArrayList<String>();
+
+        values.add(value);
+        headers.put(name,values);
+    }
+
+    /**
+     * Sets the cookies.
+     *
+     * @param list the new cookies
+     */
+    public void setCookies(ArrayList<Cookie> list) {
+        cookies = list;
+    }
+
+    public void setCookie(String name, String value ) {
+        Cookie c = new Cookie( name, value );
+        cookies.add( c );
+    }
+
+    public boolean clearCookie(String name) {
+        return cookies.remove(name);
+    }
+
+    public void clearCookies() {
+        cookies.clear();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public Cookie[] getCookies() {
+        if ( cookies.isEmpty() ) return null;
+        return cookies.toArray(new Cookie[0]);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public long getDateHeader(String name) {
+        try {
+            Date date = SimpleDateFormat.getDateTimeInstance().parse( getParameter( name ) );
+            return date.getTime(); // TODO needs to be HTTP format
+        } catch( ParseException e ) {
+            return 0;
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     * @param name
+     * @return The requested header value.
+     */
+    public String getHeader(String name) {
+        List<String> values;
+
+        if((values = headers.get(name))==null)
+            return null;
+        if(values.size() == 0)
+            return null;
+        return values.get(0);
+    }
+
+    /**
+     * {@inheritDoc}
+     * @return Enumeration of header names as strings
+     */
+    public Enumeration<String> getHeaderNames()
+    {
+        return Collections.enumeration(headers.keySet());
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public Enumeration<String> getHeaders(String name) {
+        Vector<String> v = new Vector<String>();
+        v.add( getHeader( name ) );
+        return v.elements();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public int getIntHeader(String name) {
+
+        return 0;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public String getMethod() {
+        return method;
+    }
+
+    public void setMethod( String value ) {
+        method = value;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public String getPathInfo() {
+
+        return null;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public String getPathTranslated() {
+
+        return null;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public String getQueryString() {
+        return queryString;
+    }
+
+    /**
+     * Set the query string to return.
+     * @param str The query string to return.
+     */
+    public void setQueryString(String str)
+    {
+        this.queryString = str;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public String getRemoteUser() {
+
+        return null;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public String getRequestURI() {
+        return uri;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public StringBuffer getRequestURL() {
+        return new StringBuffer( getScheme() + "://" + this.getServerName() + getRequestURI() + "?" + getQueryString() );
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public String getRequestedSessionId() {
+
+        return null;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public String getServletPath() {
+
+        return null;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public HttpSession getSession() {
+        if (session != null) {
+            return getSession(false);
+        }
+        return getSession(true);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public HttpSession getSession(boolean create) {
+        if (session == null && create) {
+            session = new MockHttpSession();
+        } else if (session != null && session.getInvalidated()) {
+            session = new MockHttpSession();
+        }
+        return session;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public Principal getUserPrincipal() {
+
+        return null;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isRequestedSessionIdFromCookie() {
+
+        return false;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isRequestedSessionIdFromURL() {
+
+        return false;
+    }
+
+    /**
+     * {@inheritDoc}
+     * @deprecated
+     */
+    @Deprecated
+    public boolean isRequestedSessionIdFromUrl() {
+
+        return false;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isRequestedSessionIdValid() {
+
+        return false;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isUserInRole(String role) {
+
+        return false;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public Object getAttribute(String name) {
+        return attrs.get(name);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public Enumeration<String> getAttributeNames() {
+        return Collections.enumeration(attrs.keySet());
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public String getCharacterEncoding() {
+
+        return null;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public int getContentLength() {
+        return body.length;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public String getContentType() {
+        return getHeader(HDR_CONTENT_TYPE);
+    }
+
+    public void setContentType( String value ) {
+        setHeader(HDR_CONTENT_TYPE, value);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public ServletInputStream getInputStream() throws IOException {
+        return new MockServletInputStream(body);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public String getLocalAddr() {
+        return "10.1.43.6";
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public String getLocalName() {
+        return "www.domain.com";
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public int getLocalPort() {
+        return 80;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public Locale getLocale() {
+        return null;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public Enumeration<Locale> getLocales() {
+        return null;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public String getParameter(String name) {
+        String[] values = parameters.get(name);
+        if ( values == null ) return null;
+        return values[0];
+    }
+
+    public void clearParameter(String name) {
+        parameters.remove( name );
+    }
+
+    public void clearParameters() {
+        parameters.clear();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public Map<String, String[]> getParameterMap() {
+        return parameters;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public Enumeration<String> getParameterNames() {
+        return Collections.enumeration(parameters.keySet());
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public String[] getParameterValues(String name) {
+        return parameters.get(name);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public String getProtocol() {
+        return "HTTP/1.1";
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public BufferedReader getReader() throws IOException {
+
+        return null;
+    }
+
+    /**
+     * {@inheritDoc}
+     * @deprecated
+     */
+    @Deprecated
+    public String getRealPath(String path) {
+
+        return null;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public String getRemoteAddr() {
+        return remoteHost;
+    }
+
+    public void setRemoteAddr(String remoteHost) {
+        this.remoteHost = remoteHost;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public String getRemoteHost() {
+        return remoteHost;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public int getRemotePort() {
+
+        return 0;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public RequestDispatcher getRequestDispatcher(String path) {
+        return requestDispatcher;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public String getScheme() {
+        return scheme;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public String getServerName() {
+        return serverHost;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public int getServerPort() {
+        return 80;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isSecure() {
+        return scheme.equals( "https" );
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void removeAttribute(String name) {
+        attrs.remove(name);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void setAttribute(String name, Object o) {
+        attrs.put(name,o);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void setCharacterEncoding(String env) throws UnsupportedEncodingException {
+
+    }
+
+    public void setRequestURI(String uri) throws UnsupportedEncodingException {
+        this.uri = uri;
+    }
+
+    public void setRequestURL(String url) throws UnsupportedEncodingException {
+        // get the scheme
+        int p = url.indexOf( ":" );
+        this.scheme = url.substring( 0, p );
+
+        // get the queryString
+        int q = url.indexOf( "?" );
+        if ( q != -1 )
+        {
+            queryString = url.substring( q+1 );
+            url = url.substring( 0, q );
+        }
+        else
+            queryString = null;
+    }
+
+    public void setScheme( String scheme ) {
+        this.scheme = scheme;
+    }
+
+    public void dump()
+    {
+        String[] names;
+
+        System.out.println();
+        System.out.println( "  " + this.getMethod() + " " + this.getRequestURL() );
+
+        names = headers.keySet().toArray(EMPTY_STRING_ARRAY);
+        Arrays.sort(names);    // make debugging a bit easier...
+        for (String name : names)
+            for(String value : headers.get(name))
+                System.out.println( "  " + name + ": " + value);
+        names = parameters.keySet().toArray(EMPTY_STRING_ARRAY);
+        Arrays.sort(names);
+        for (String name : names) {
+            for(String value : parameters.get(name))
+                System.out.println( "  " + name + "=" + value);
+        }
+        System.out.println( "\n" );
+    }
 
     @Override
     public boolean authenticate(HttpServletResponse hsr) throws IOException, ServletException {
@@ -738,19 +738,19 @@ public class MockHttpServletRequest implements HttpServletRequest
         throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
     }
 
-	@Override
-	public long getContentLengthLong() {
-		throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
-	}
+    @Override
+    public long getContentLengthLong() {
+        throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
+    }
 
-	@Override
-	public String changeSessionId() {
-		throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
-	}
+    @Override
+    public String changeSessionId() {
+        throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
+    }
 
-	@Override
-	public <T extends HttpUpgradeHandler> T upgrade(Class<T> handlerClass) throws IOException, ServletException {
-		throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
-	}
+    @Override
+    public <T extends HttpUpgradeHandler> T upgrade(Class<T> handlerClass) throws IOException, ServletException {
+        throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
+    }
 
 }
diff --git a/src/test/java/org/owasp/esapi/http/MockHttpServletResponse.java b/src/test/java/org/owasp/esapi/http/MockHttpServletResponse.java
index fa341db..fadfe13 100644
--- a/src/test/java/org/owasp/esapi/http/MockHttpServletResponse.java
+++ b/src/test/java/org/owasp/esapi/http/MockHttpServletResponse.java
@@ -1,15 +1,15 @@
 /**
  * OWASP Enterprise Security API (ESAPI)
- * 
+ *
  * This file is part of the Open Web Application Security Project (OWASP)
  * Enterprise Security API (ESAPI) project. For details, please see
  * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
  *
  * Copyright (c) 2007 - The OWASP Foundation
- * 
+ *
  * The ESAPI is published by OWASP under the BSD license. You should read and accept the
  * LICENSE before you use, modify, and/or redistribute this software.
- * 
+ *
  * @author Jeff Williams <a href="http://www.aspectsecurity.com">Aspect Security</a>
  * @created 2007
  */
@@ -32,358 +32,358 @@ import org.owasp.esapi.ESAPI;
 
 /**
  * The Class MockHttpServletResponse.
- * 
+ *
  * @author jwilliams
  */
 public class MockHttpServletResponse implements HttpServletResponse {
 
-	/** The cookies. */
-	List<Cookie> cookies = new ArrayList<Cookie>();
-
-	/** The header names. */
-	List<String> headerNames = new ArrayList<String>();
-
-	/** The header values. */
-	List<String> headerValues = new ArrayList<String>();
-
-	/** The status. */
-	int status = 200;
-
-	StringBuffer body = new StringBuffer();
-
-	String contentType = "text/html; charset=ISO-8895-1";
-
-	public String getBody() {
-		return body.toString();
-	}
-	
-	/**
-	 * {@inheritDoc}
-	 */
-	public void addCookie(Cookie cookie) {
-		cookies.add(cookie);
-	}
-
-	public List<Cookie> getCookies() {
-		return cookies;
-	}
-
-	public Cookie getCookie(String name) {
-		Iterator<Cookie> i = cookies.iterator();
-		while (i.hasNext()) {
-			Cookie c = i.next();
-			if (c.getName().equals(name)) {
-				return c;
-			}
-		}
-		return null;
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	public void addDateHeader(String name, long date) {
-		headerNames.add(name);
-		headerValues.add("" + date);
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	public void addHeader(String name, String value) {
-		headerNames.add(name);
-		headerValues.add(value);
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	public void addIntHeader(String name, int value) {
-		headerNames.add(name);
-		headerValues.add("" + value);
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	public boolean containsHeader(String name) {
-		return headerNames.contains(name);
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	public String getHeader(String name) {
-		int index = headerNames.indexOf(name);
-		if (index != -1) {
-			return headerValues.get(index);
-		}
-		return null;
-	}
-
-	/**
-	 * Gets the header names.
-	 * 
-	 * @return the header names
-	 */
-	public List<String> getHeaderNames() {
-		return headerNames;
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	public String encodeRedirectURL(String url) {
-		return null;
-	}
-
-	/**
-	 * {@inheritDoc}
-	 * @deprecated
-	 */
-	@Deprecated
-	public String encodeRedirectUrl(String url) {
-		return null;
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	public String encodeURL(String url) {
-		String enc = url;
-		try { enc = ESAPI.encoder().encodeForURL(url);
-		} catch( Exception e ) {}
-		return enc;
-	}
-
-	/**
-	 * {@inheritDoc}
-	 * @deprecated
-	 */
-	@Deprecated
-	public String encodeUrl(String url) {
-		return encodeURL( url );
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	public void sendError(int sc) throws IOException {
-		status = sc;
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	public void sendError(int sc, String msg) throws IOException {
-		status = sc;
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	public void sendRedirect(String location) throws IOException {
-		status = HttpServletResponse.SC_MOVED_PERMANENTLY;
-		body = new StringBuffer( "Redirect to " + location );
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	public void setDateHeader(String name, long date) {
-		headerNames.add(name);
-		headerValues.add("" + date);
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	public void setHeader(String name, String value) {
-		headerNames.add(name);
-		headerValues.add(value);
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	public void setIntHeader(String name, int value) {
-		headerNames.add(name);
-		headerValues.add("" + value);
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	public void setStatus(int sc) {
-		status = sc;
-	}
-
-	/**
-	 * Gets the status.
-	 * 
-	 * @return the status
-	 */
-	public int getStatus() {
-		return status;
-	}
-
-	/**
-	 * {@inheritDoc}
-	 * @deprecated
-	 */
-	@Deprecated
-	public void setStatus(int sc, String sm) {
-		status = sc;
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	public void flushBuffer() throws IOException {
-
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	public int getBufferSize() {
-		return body.length();
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	public String getCharacterEncoding() {
-		return "UTF-8";
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	public String getContentType() {
-		return contentType;
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	public Locale getLocale() {
-
-		return null;
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	public ServletOutputStream getOutputStream() throws IOException {
-		return new ServletOutputStream() {
-			public void write(int b) throws IOException {
-				body.append((char)b);
-			}
-
-			@Override
-			public boolean isReady() {
-				return false;
-			}
-
-			@Override
-			public void setWriteListener(WriteListener writeListener) {
-				//NO-OP
-			}
-		};
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	public PrintWriter getWriter() throws IOException {
-		return new PrintWriter( getOutputStream(), true );
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	public boolean isCommitted() {
-
-		return false;
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	public void reset() {
-		body = new StringBuffer();
-		cookies = new ArrayList<Cookie>();
-		headerNames = new ArrayList<String>();
-		headerValues = new ArrayList<String>();
-		status = 200;
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	public void resetBuffer() {
-		body = new StringBuffer();
-	}
-
-	public void setBody( String value ) {
-		body = new StringBuffer( value );
-	}
-	
-	/**
-	 * {@inheritDoc}
-	 */
-	public void setBufferSize(int size) {
-
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	public void setCharacterEncoding(String charset) {
-
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	public void setContentLength(int len) {
-
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	public void setContentType(String type) {
-		contentType = type;
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	public void setLocale(Locale loc) {
-
-	}
-
-	/*
-	 * Dump the response in a semi-readable format close to a real HTTP response on the wire
-	 */
-	public void dump() {
+    /** The cookies. */
+    List<Cookie> cookies = new ArrayList<Cookie>();
+
+    /** The header names. */
+    List<String> headerNames = new ArrayList<String>();
+
+    /** The header values. */
+    List<String> headerValues = new ArrayList<String>();
+
+    /** The status. */
+    int status = 200;
+
+    StringBuffer body = new StringBuffer();
+
+    String contentType = "text/html; charset=ISO-8895-1";
+
+    public String getBody() {
+        return body.toString();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void addCookie(Cookie cookie) {
+        cookies.add(cookie);
+    }
+
+    public List<Cookie> getCookies() {
+        return cookies;
+    }
+
+    public Cookie getCookie(String name) {
+        Iterator<Cookie> i = cookies.iterator();
+        while (i.hasNext()) {
+            Cookie c = i.next();
+            if (c.getName().equals(name)) {
+                return c;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void addDateHeader(String name, long date) {
+        headerNames.add(name);
+        headerValues.add("" + date);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void addHeader(String name, String value) {
+        headerNames.add(name);
+        headerValues.add(value);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void addIntHeader(String name, int value) {
+        headerNames.add(name);
+        headerValues.add("" + value);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean containsHeader(String name) {
+        return headerNames.contains(name);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public String getHeader(String name) {
+        int index = headerNames.indexOf(name);
+        if (index != -1) {
+            return headerValues.get(index);
+        }
+        return null;
+    }
+
+    /**
+     * Gets the header names.
+     *
+     * @return the header names
+     */
+    public List<String> getHeaderNames() {
+        return headerNames;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public String encodeRedirectURL(String url) {
+        return null;
+    }
+
+    /**
+     * {@inheritDoc}
+     * @deprecated
+     */
+    @Deprecated
+    public String encodeRedirectUrl(String url) {
+        return null;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public String encodeURL(String url) {
+        String enc = url;
+        try { enc = ESAPI.encoder().encodeForURL(url);
+        } catch( Exception e ) {}
+        return enc;
+    }
+
+    /**
+     * {@inheritDoc}
+     * @deprecated
+     */
+    @Deprecated
+    public String encodeUrl(String url) {
+        return encodeURL( url );
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void sendError(int sc) throws IOException {
+        status = sc;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void sendError(int sc, String msg) throws IOException {
+        status = sc;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void sendRedirect(String location) throws IOException {
+        status = HttpServletResponse.SC_MOVED_PERMANENTLY;
+        body = new StringBuffer( "Redirect to " + location );
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void setDateHeader(String name, long date) {
+        headerNames.add(name);
+        headerValues.add("" + date);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void setHeader(String name, String value) {
+        headerNames.add(name);
+        headerValues.add(value);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void setIntHeader(String name, int value) {
+        headerNames.add(name);
+        headerValues.add("" + value);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void setStatus(int sc) {
+        status = sc;
+    }
+
+    /**
+     * Gets the status.
+     *
+     * @return the status
+     */
+    public int getStatus() {
+        return status;
+    }
+
+    /**
+     * {@inheritDoc}
+     * @deprecated
+     */
+    @Deprecated
+    public void setStatus(int sc, String sm) {
+        status = sc;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void flushBuffer() throws IOException {
+
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public int getBufferSize() {
+        return body.length();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public String getCharacterEncoding() {
+        return "UTF-8";
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public String getContentType() {
+        return contentType;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public Locale getLocale() {
+
+        return null;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public ServletOutputStream getOutputStream() throws IOException {
+        return new ServletOutputStream() {
+            public void write(int b) throws IOException {
+                body.append((char)b);
+            }
+
+            @Override
+            public boolean isReady() {
+                return false;
+            }
+
+            @Override
+            public void setWriteListener(WriteListener writeListener) {
+                //NO-OP
+            }
+        };
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public PrintWriter getWriter() throws IOException {
+        return new PrintWriter( getOutputStream(), true );
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isCommitted() {
+
+        return false;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void reset() {
+        body = new StringBuffer();
+        cookies = new ArrayList<Cookie>();
+        headerNames = new ArrayList<String>();
+        headerValues = new ArrayList<String>();
+        status = 200;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void resetBuffer() {
+        body = new StringBuffer();
+    }
+
+    public void setBody( String value ) {
+        body = new StringBuffer( value );
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void setBufferSize(int size) {
+
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void setCharacterEncoding(String charset) {
+
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void setContentLength(int len) {
+
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void setContentType(String type) {
+        contentType = type;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void setLocale(Locale loc) {
+
+    }
+
+    /*
+     * Dump the response in a semi-readable format close to a real HTTP response on the wire
+     */
+    public void dump() {
         System.out.println();
-		System.out.println( "  " + this.getStatus() + " " );
+        System.out.println( "  " + this.getStatus() + " " );
         for ( Object name : getHeaderNames() ) System.out.println( "  " + name + "=" + getHeader( (String)name ) );
         System.out.println( "  BODY: " + this.getBody() );
         System.out.println();
-	}
+    }
 
     @Override
     public Collection<String> getHeaders(String string) {
         throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
     }
 
-	@Override
-	public void setContentLengthLong(long len) {
-		throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
-	}
-	
+    @Override
+    public void setContentLengthLong(long len) {
+        throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
+    }
+
 }
diff --git a/src/test/java/org/owasp/esapi/http/MockHttpSession.java b/src/test/java/org/owasp/esapi/http/MockHttpSession.java
index 6e9426a..ef716fe 100644
--- a/src/test/java/org/owasp/esapi/http/MockHttpSession.java
+++ b/src/test/java/org/owasp/esapi/http/MockHttpSession.java
@@ -1,15 +1,15 @@
 /**
  * OWASP Enterprise Security API (ESAPI)
- * 
+ *
  * This file is part of the Open Web Application Security Project (OWASP)
  * Enterprise Security API (ESAPI) project. For details, please see
  * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
  *
  * Copyright (c) 2007 - The OWASP Foundation
- * 
+ *
  * The ESAPI is published by OWASP under the BSD license. You should read and accept the
  * LICENSE before you use, modify, and/or redistribute this software.
- * 
+ *
  * @author Jeff Williams <a href="http://www.aspectsecurity.com">Aspect Security</a>
  * @created 2007
  */
@@ -26,206 +26,206 @@ import javax.servlet.http.HttpSession;
 
 /**
  * The Class MockHttpSession.
- * 
+ *
  * @author jwilliams
  */
 public class MockHttpSession implements HttpSession {
 
-	/** The invalidated. */
-	boolean invalidated = false;
-	
-	/** The creation time. */
-	private long creationTime=new Date().getTime();
-	
-	/** The accessed time. */
-	private long accessedTime=new Date().getTime();
-	
-	/** The count. */
-	private static int count = 1;
-	
-	/** The sessionid. */
-	private int sessionid=count++;
-	
-	/** The attributes. */
-	private Map<String, Object> attributes = new HashMap<String, Object>();
-	
-	/**
-	 * Instantiates a new test HTTP session.
-	 */
-	public MockHttpSession() {
-		// to replace synthetic accessor method
-	}
-	
-	/**
-	 * Instantiates a new test http session.
-	 * 
-	 * @param creationTime
-	 *            the creation time
-	 * @param accessedTime
-	 *            the accessed time
-	 */
-	public MockHttpSession( long creationTime, long accessedTime ) {
-		this.creationTime = creationTime;
-		this.accessedTime = accessedTime;
-	}
+    /** The invalidated. */
+    boolean invalidated = false;
+
+    /** The creation time. */
+    private long creationTime=new Date().getTime();
+
+    /** The accessed time. */
+    private long accessedTime=new Date().getTime();
+
+    /** The count. */
+    private static int count = 1;
+
+    /** The sessionid. */
+    private int sessionid=count++;
+
+    /** The attributes. */
+    private Map<String, Object> attributes = new HashMap<String, Object>();
+
+    /**
+     * Instantiates a new test HTTP session.
+     */
+    public MockHttpSession() {
+        // to replace synthetic accessor method
+    }
+
+    /**
+     * Instantiates a new test http session.
+     *
+     * @param creationTime
+     *            the creation time
+     * @param accessedTime
+     *            the accessed time
+     */
+    public MockHttpSession( long creationTime, long accessedTime ) {
+        this.creationTime = creationTime;
+        this.accessedTime = accessedTime;
+    }
 
     /**
      * {@inheritDoc}
      */
-	public Object getAttribute(String string) {
-		return attributes.get( string );
-	}
+    public Object getAttribute(String string) {
+        return attributes.get( string );
+    }
 
     /**
      * {@inheritDoc}
      */
-	public Enumeration<String> getAttributeNames() {
-		Vector<String> v = new Vector<String>( attributes.keySet() );
-		return v.elements();
-	}
+    public Enumeration<String> getAttributeNames() {
+        Vector<String> v = new Vector<String>( attributes.keySet() );
+        return v.elements();
+    }
 
     /**
      * {@inheritDoc}
      */
-	public long getCreationTime() {
-		return creationTime;
-	}
+    public long getCreationTime() {
+        return creationTime;
+    }
 
     /**
      * {@inheritDoc}
      */
-	public String getId() {
-		return ""+sessionid;
-	}
+    public String getId() {
+        return ""+sessionid;
+    }
 
-	/**
-	 * Gets the invalidated.
-	 * 
-	 * @return the invalidated
-	 */
-	public boolean getInvalidated() {
-		return invalidated;
-	}
+    /**
+     * Gets the invalidated.
+     *
+     * @return the invalidated
+     */
+    public boolean getInvalidated() {
+        return invalidated;
+    }
 
     /**
      * {@inheritDoc}
      */
-	public long getLastAccessedTime() {
-		return accessedTime;
-	}
+    public long getLastAccessedTime() {
+        return accessedTime;
+    }
 
     /**
      * {@inheritDoc}
      */
-	public int getMaxInactiveInterval() {
-		return 0;
-	}
+    public int getMaxInactiveInterval() {
+        return 0;
+    }
 
     /**
      * {@inheritDoc}
      */
-	public ServletContext getServletContext() {
-		return null;
-	}
+    public ServletContext getServletContext() {
+        return null;
+    }
 
     /**
      * {@inheritDoc}
      * @deprecated
      */
         @Deprecated
-	// need the full class here as for whatever stupid reason you can't
-	// seem to @SuppressWarnings{'deprecation'} on the import... *sigh*
-	public javax.servlet.http.HttpSessionContext getSessionContext() {
-		return null;
-	}
+    // need the full class here as for whatever stupid reason you can't
+    // seem to @SuppressWarnings{'deprecation'} on the import... *sigh*
+    public javax.servlet.http.HttpSessionContext getSessionContext() {
+        return null;
+    }
 
     /**
      * {@inheritDoc}
      * @deprecated
      */
-     	@Deprecated
-	public Object getValue(String string) {
-		return null;
-	}
+         @Deprecated
+    public Object getValue(String string) {
+        return null;
+    }
 
     /**
      * {@inheritDoc}
      * @deprecated
      */
-     	@Deprecated
-	public String[] getValueNames() {
-		return null;
-	}
+         @Deprecated
+    public String[] getValueNames() {
+        return null;
+    }
 
     /**
      * {@inheritDoc}
-	 */
-	public void invalidate() {
-		invalidated = true;
-	}
-    
+     */
+    public void invalidate() {
+        invalidated = true;
+    }
+
     /**
      * {@inheritDoc}
      */
-	public boolean isNew() {
-		return true;
-	}
+    public boolean isNew() {
+        return true;
+    }
 
-	/**
+    /**
      * {@inheritDoc}
      * @deprecated
      */
-     	@Deprecated
-	public void putValue(String string, Object object) {
-		setAttribute( string, object );
-	}
+         @Deprecated
+    public void putValue(String string, Object object) {
+        setAttribute( string, object );
+    }
 
     /**
      * {@inheritDoc}
      */
-	public void removeAttribute(String string) {
-		attributes.remove( string );
-	}
+    public void removeAttribute(String string) {
+        attributes.remove( string );
+    }
 
     /**
      * {@inheritDoc}
      * @deprecated
      */
-     	@Deprecated
-	public void removeValue(String string) {
-		removeAttribute( string );
-	}
+         @Deprecated
+    public void removeValue(String string) {
+        removeAttribute( string );
+    }
 
     /**
      * {@inheritDoc}
      */
-	public void setAttribute(String string, Object object) {
-		attributes.put(string, object);
-	}
+    public void setAttribute(String string, Object object) {
+        attributes.put(string, object);
+    }
 
     /**
      * {@inheritDoc}
 =     */
-	public void setMaxInactiveInterval(int i) {
-		// stub
-	}
-	
+    public void setMaxInactiveInterval(int i) {
+        // stub
+    }
+
     /**
      *
      * @param time
      */
     public void setAccessedTime( long time ) {
-		this.accessedTime = time;
-	}
+        this.accessedTime = time;
+    }
+
 
-	
     /**
      *
      * @param time
      */
     public void setCreationTime( long time ) {
-		this.creationTime = time;
-	}
+        this.creationTime = time;
+    }
 
 }
 
diff --git a/src/test/java/org/owasp/esapi/http/MockRequestDispatcher.java b/src/test/java/org/owasp/esapi/http/MockRequestDispatcher.java
index 28f6471..d0117ce 100644
--- a/src/test/java/org/owasp/esapi/http/MockRequestDispatcher.java
+++ b/src/test/java/org/owasp/esapi/http/MockRequestDispatcher.java
@@ -1,15 +1,15 @@
 /**
  * OWASP Enterprise Security API (ESAPI)
- * 
+ *
  * This file is part of the Open Web Application Security Project (OWASP)
  * Enterprise Security API (ESAPI) project. For details, please see
  * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
  *
  * Copyright (c) 2007 - The OWASP Foundation
- * 
+ *
  * The ESAPI is published by OWASP under the BSD license. You should read and accept the
  * LICENSE before you use, modify, and/or redistribute this software.
- * 
+ *
  * @author Jeff Williams <a href="http://www.aspectsecurity.com">Aspect Security</a>
  * @created 2007
  */
@@ -36,9 +36,9 @@ public class MockRequestDispatcher implements RequestDispatcher {
      * @throws java.io.IOException
      */
     public void forward(ServletRequest request, ServletResponse response) throws ServletException, IOException {
-    	System.out.println( "Forwarding" );
+        System.out.println( "Forwarding" );
     }
-    
+
     /**
      *
      * @param request
@@ -47,7 +47,7 @@ public class MockRequestDispatcher implements RequestDispatcher {
      * @throws java.io.IOException
      */
     public void include(ServletRequest request, ServletResponse response) throws ServletException, IOException {
-    	System.out.println( "Including" );
+        System.out.println( "Including" );
     }
 }
 
diff --git a/src/test/java/org/owasp/esapi/http/MockServletContext.java b/src/test/java/org/owasp/esapi/http/MockServletContext.java
index cab828f..0625770 100644
--- a/src/test/java/org/owasp/esapi/http/MockServletContext.java
+++ b/src/test/java/org/owasp/esapi/http/MockServletContext.java
@@ -1,15 +1,15 @@
 /**
  * OWASP Enterprise Security API (ESAPI)
- * 
+ *
  * This file is part of the Open Web Application Security Project (OWASP)
  * Enterprise Security API (ESAPI) project. For details, please see
  * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
  *
  * Copyright (c) 2007 - The OWASP Foundation
- * 
+ *
  * The ESAPI is published by OWASP under the BSD license. You should read and accept the
  * LICENSE before you use, modify, and/or redistribute this software.
- * 
+ *
  * @author Jeff Williams <a href="http://www.aspectsecurity.com">Aspect Security</a>
  * @created 2007
  */
@@ -93,7 +93,7 @@ public class MockServletContext implements ServletContext {
      * @see RequestDispatcher
      */
     public ServletContext getContext(String uripath) {
-    	return null;
+        return null;
     }
 
     /**
@@ -105,7 +105,7 @@ public class MockServletContext implements ServletContext {
      * @return 2
      */
     public int getMajorVersion() {
-    	return 2;
+        return 2;
     }
 
     /**
@@ -115,7 +115,7 @@ public class MockServletContext implements ServletContext {
      * return the integer 4.
      */
     public int getMinorVersion() {
-    	return 4;
+        return 4;
     }
 
     /**
@@ -131,7 +131,7 @@ public class MockServletContext implements ServletContext {
      * @return a <code>String</code> specifying the file's MIME type
      */
     public String getMimeType(String file) {
-    	return "text/html";
+        return "text/html";
     }
 
     /**
@@ -161,7 +161,7 @@ public class MockServletContext implements ServletContext {
      * @since Servlet 2.3
      */
     public Set getResourcePaths(String path) {
-    	return null;
+        return null;
     }
 
     /**
@@ -203,7 +203,7 @@ public class MockServletContext implements ServletContext {
      * the correct form
      */
     public URL getResource(String path) throws MalformedURLException {
-    	return null;
+        return null;
     }
 
     /**
@@ -238,7 +238,7 @@ public class MockServletContext implements ServletContext {
      * specified path
      */
     public InputStream getResourceAsStream(String path) {
-    	return null;
+        return null;
     }
 
     /**
@@ -265,7 +265,7 @@ public class MockServletContext implements ServletContext {
      * @see ServletContext#getContext
      */
     public RequestDispatcher getRequestDispatcher(String path) {
-    	return null;
+        return null;
     }
 
     /**
@@ -294,7 +294,7 @@ public class MockServletContext implements ServletContext {
      * @see ServletConfig#getServletName
      */
     public RequestDispatcher getNamedDispatcher(String name) {
-    	return null;
+        return null;
     }
 
     /**
@@ -312,7 +312,7 @@ public class MockServletContext implements ServletContext {
      */
     @Deprecated
     public Servlet getServlet(String name) throws ServletException {
-    	return null;
+        return null;
     }
 
     /**
@@ -327,7 +327,7 @@ public class MockServletContext implements ServletContext {
      */
     @Deprecated
     public Enumeration getServlets() {
-    	return null;
+        return null;
     }
 
     /**
@@ -342,7 +342,7 @@ public class MockServletContext implements ServletContext {
      */
     @Deprecated
     public Enumeration getServletNames() {
-    	return null;
+        return null;
     }
 
     /**
@@ -354,7 +354,7 @@ public class MockServletContext implements ServletContext {
      * message to be written to the log file
      */
     public void log(String msg) {
-    	ESAPI.getLogger( "MockServletContext" ).warning( Logger.EVENT_FAILURE, msg );
+        ESAPI.getLogger( "MockServletContext" ).warning( Logger.EVENT_FAILURE, msg );
     }
 
     /**
@@ -368,7 +368,7 @@ public class MockServletContext implements ServletContext {
      */
     @Deprecated
     public void log(Exception exception, String msg) {
-    	ESAPI.getLogger( "MockServletContext" ).warning( Logger.EVENT_FAILURE, msg, exception );
+        ESAPI.getLogger( "MockServletContext" ).warning( Logger.EVENT_FAILURE, msg, exception );
     }
 
     /**
@@ -384,7 +384,7 @@ public class MockServletContext implements ServletContext {
      * or exception
      */
     public void log(String message, Throwable throwable) {
-    	ESAPI.getLogger( "MockServletContext" ).warning( Logger.EVENT_FAILURE, message, throwable );
+        ESAPI.getLogger( "MockServletContext" ).warning( Logger.EVENT_FAILURE, message, throwable );
     }
 
     /**
@@ -408,7 +408,7 @@ public class MockServletContext implements ServletContext {
      * or null if the translation cannot be performed
      */
     public String getRealPath(String path) {
-    	return ESAPI.securityConfiguration().getResourceFile( path ).getAbsolutePath();
+        return ESAPI.securityConfiguration().getResourceFile( path ).getAbsolutePath();
     }
 
     /**
@@ -428,7 +428,7 @@ public class MockServletContext implements ServletContext {
      * servlet container name and version number
      */
     public String getServerInfo() {
-    	return null;
+        return null;
     }
 
     /**
@@ -450,7 +450,7 @@ public class MockServletContext implements ServletContext {
      * @see ServletConfig#getInitParameter
      */
     public String getInitParameter(String name) {
-    	return null;
+        return null;
     }
 
     /**
@@ -465,7 +465,7 @@ public class MockServletContext implements ServletContext {
      * @see ServletConfig#getInitParameter
      */
     public Enumeration getInitParameterNames() {
-    	return null;
+        return null;
     }
 
 
@@ -496,7 +496,7 @@ public class MockServletContext implements ServletContext {
      * @see ServletContext#getAttributeNames
      */
     public Object getAttribute(String name) {
-    	return null;
+        return null;
     }
 
     /**
@@ -511,7 +511,7 @@ public class MockServletContext implements ServletContext {
      * @see #getAttribute
      */
     public Enumeration getAttributeNames() {
-    	return null;
+        return null;
     }
 
     /**
@@ -561,7 +561,7 @@ public class MockServletContext implements ServletContext {
      * @since Servlet 2.3
      */
     public String getServletContextName() {
-    	return null;
+        return null;
     }
 
     @Override
@@ -694,8 +694,8 @@ public class MockServletContext implements ServletContext {
         throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
     }
 
-	@Override
-	public String getVirtualServerName() {
-		throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
-	}
+    @Override
+    public String getVirtualServerName() {
+        throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
+    }
 }
\ No newline at end of file
diff --git a/src/test/java/org/owasp/esapi/http/MockServletInputStream.java b/src/test/java/org/owasp/esapi/http/MockServletInputStream.java
index 62ff01c..f54b491 100644
--- a/src/test/java/org/owasp/esapi/http/MockServletInputStream.java
+++ b/src/test/java/org/owasp/esapi/http/MockServletInputStream.java
@@ -1,15 +1,15 @@
 /**
  * OWASP Enterprise Security API (ESAPI)
- * 
+ *
  * This file is part of the Open Web Application Security Project (OWASP)
  * Enterprise Security API (ESAPI) project. For details, please see
  * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
  *
  * Copyright (c) 2007 - The OWASP Foundation
- * 
+ *
  * The ESAPI is published by OWASP under the BSD license. You should read and accept the
  * LICENSE before you use, modify, and/or redistribute this software.
- * 
+ *
  * @author Jeff Williams <a href="http://www.aspectsecurity.com">Aspect Security</a>
  * @created 2007
  */
@@ -40,30 +40,30 @@ public class MockServletInputStream extends ServletInputStream {
 
     /**
      * read
-     * @return the next char from this InputStream 
+     * @return the next char from this InputStream
      * @throws IOException
      */
     public int read() throws IOException {
         if (next < body.length) {
             return body[next++];
         } else {
-        	isDone = true;
+            isDone = true;
             return -1;
         }
     }
 
-	@Override
-	public boolean isFinished() {
-		return isDone;
-	}
+    @Override
+    public boolean isFinished() {
+        return isDone;
+    }
 
-	@Override
-	public boolean isReady() {
-		return false;
-	}
+    @Override
+    public boolean isReady() {
+        return false;
+    }
 
-	@Override
-	public void setReadListener(ReadListener readListener) {
-		//NO_OP
-	}
+    @Override
+    public void setReadListener(ReadListener readListener) {
+        //NO_OP
+    }
 }
diff --git a/src/test/java/org/owasp/esapi/logging/appender/ClientInfoSupplierTest.java b/src/test/java/org/owasp/esapi/logging/appender/ClientInfoSupplierTest.java
index 61c0fba..e3dcd76 100644
--- a/src/test/java/org/owasp/esapi/logging/appender/ClientInfoSupplierTest.java
+++ b/src/test/java/org/owasp/esapi/logging/appender/ClientInfoSupplierTest.java
@@ -30,139 +30,139 @@ import org.powermock.modules.junit4.PowerMockRunner;
 @PrepareForTest({ESAPI.class})
 @PowerMockIgnore("javax.security.*") //Required since User extends javax.security.Principal
 public class ClientInfoSupplierTest {
-	private static final String ESAPI_SESSION_ATTR = "ESAPI_SESSION";
-	
-	@Rule
+    private static final String ESAPI_SESSION_ATTR = "ESAPI_SESSION";
+
+    @Rule
     public TestName testName = new TestName();
-	
-	private HttpServletRequest mockRequest;
-	private HttpSession mockSession;
-	private Authenticator mockAuth;
-	private Randomizer mockRand;
-	private User mockUser;
-	
-	@Before
-	public void before() throws Exception {
-		mockAuth =mock(Authenticator.class); 
-		mockRand =mock(Randomizer.class); 
-		mockRequest =mock(HttpServletRequest.class);
-		mockSession =mock(HttpSession.class);
-		mockUser =mock(User.class);
-		
-		mockStatic(ESAPI.class);
-		when(ESAPI.class, "currentRequest").thenReturn(mockRequest);
-		when(ESAPI.class, "authenticator").thenReturn(mockAuth);
-		when(ESAPI.class, "randomizer").thenReturn(mockRand);
-		
-		when(mockRequest.getSession(false)).thenReturn(mockSession);
-		when(mockSession.getAttribute(ESAPI_SESSION_ATTR)).thenReturn(testName.getMethodName()+ "-SESSION");
-		
-		//Session value generation
-		when(mockRand.getRandomInteger(ArgumentMatchers.anyInt(), ArgumentMatchers.anyInt())).thenReturn(55555);
-		 
-		when(mockUser.getLastHostAddress()).thenReturn(testName.getMethodName() + "-HOST_ADDR");
-		
-	     
-	    when(mockAuth.getCurrentUser()).thenReturn(mockUser);
-	}
-	
-	@Test
-	public void testHappyPath() throws Exception {
-		ClientInfoSupplier cis = new ClientInfoSupplier();
-		cis.setLogClientInfo(true);
-		String result = cis.get();
-		
-		assertEquals(testName.getMethodName() + "-SESSION@"+testName.getMethodName() + "-HOST_ADDR", result);
-		
-		verify(mockAuth,times(1)).getCurrentUser();
-		verify(mockRequest,times(1)).getSession(false);
-		verify(mockSession,times(1)).getAttribute(ESAPI_SESSION_ATTR);
-		verify(mockUser,times(1)).getLastHostAddress();
-		
-		verifyNoMoreInteractions(mockAuth, mockRand, mockRequest, mockSession, mockUser);
-	}
-	
-	@Test
-	public void testLogUserOff() {
-		ClientInfoSupplier cis = new ClientInfoSupplier();
-		cis.setLogClientInfo(false);
-		String result = cis.get();
-		
-		assertTrue(result.isEmpty());
-		
-		verifyNoMoreInteractions(mockAuth, mockRand, mockRequest, mockSession, mockUser);
-	}
-	
-	@Test
-	public void testLogUserNull() {
-		when(mockAuth.getCurrentUser()).thenReturn(null);
-		ClientInfoSupplier cis = new ClientInfoSupplier();
-		cis.setLogClientInfo(true);
-		String result = cis.get();
-		
-		assertEquals(testName.getMethodName()+ "-SESSION@#UNKNOWN_HOST#", result);
-		
-		verify(mockAuth,times(1)).getCurrentUser();
-		verify(mockRequest,times(1)).getSession(false);
-		verify(mockSession,times(1)).getAttribute(ESAPI_SESSION_ATTR);
-		
-		verifyNoMoreInteractions(mockAuth, mockRand, mockRequest, mockSession, mockUser);
-	}
-	
-	@Test
-	public void testNullRequest() throws Exception {
-		when(ESAPI.class, "currentRequest").thenReturn(null);
-		ClientInfoSupplier cis = new ClientInfoSupplier();
-		cis.setLogClientInfo(true);
-		String result = cis.get();
-		
-		//sid is empty when request is null		
-		assertEquals("@"+testName.getMethodName() + "-HOST_ADDR", result);
-		
-		verify(mockAuth,times(1)).getCurrentUser();
-		verify(mockUser,times(1)).getLastHostAddress();
-		
-		verifyNoMoreInteractions(mockAuth, mockRand, mockRequest, mockSession, mockUser);
-	}
-	
-	@Test
-	public void testNullSession() throws Exception {
-		when(mockRequest.getSession(false)).thenReturn(null);
-		ClientInfoSupplier cis = new ClientInfoSupplier();
-		cis.setLogClientInfo(true);
-		String result = cis.get();
-		
-		//sid is empty when session is null		
-		assertEquals("@"+testName.getMethodName() + "-HOST_ADDR", result);
-		
-		
-		verify(mockAuth,times(1)).getCurrentUser();
-		verify(mockRequest,times(1)).getSession(false);
-		verify(mockUser,times(1)).getLastHostAddress();
-		
-		
-		verifyNoMoreInteractions(mockAuth, mockRand, mockRequest, mockSession, mockUser);
-	}
-	
-	
-	
-	@Test
-	public void testNullEsapiSession() throws Exception {
-		when(mockSession.getAttribute(ESAPI_SESSION_ATTR)).thenReturn(null);
-		ClientInfoSupplier cis = new ClientInfoSupplier();
-		cis.setLogClientInfo(true);
-		String result = cis.get();
-		
-		//sid is empty when session is null		
-		assertEquals("55555@"+testName.getMethodName() + "-HOST_ADDR", result);
-		
-		verify(mockAuth,times(1)).getCurrentUser();
-		verify(mockRequest,times(1)).getSession(false);
-		verify(mockSession,times(1)).getAttribute(ESAPI_SESSION_ATTR);
-		verify(mockSession, times(1)).setAttribute(ESAPI_SESSION_ATTR, (""+55555));
-		verify(mockRand, times(1)).getRandomInteger(ArgumentMatchers.anyInt(), ArgumentMatchers.anyInt());
-		verify(mockUser,times(1)).getLastHostAddress();
-		
-		verifyNoMoreInteractions(mockAuth, mockRand, mockRequest, mockSession, mockUser);
-	}
+
+    private HttpServletRequest mockRequest;
+    private HttpSession mockSession;
+    private Authenticator mockAuth;
+    private Randomizer mockRand;
+    private User mockUser;
+
+    @Before
+    public void before() throws Exception {
+        mockAuth =mock(Authenticator.class);
+        mockRand =mock(Randomizer.class);
+        mockRequest =mock(HttpServletRequest.class);
+        mockSession =mock(HttpSession.class);
+        mockUser =mock(User.class);
+
+        mockStatic(ESAPI.class);
+        when(ESAPI.class, "currentRequest").thenReturn(mockRequest);
+        when(ESAPI.class, "authenticator").thenReturn(mockAuth);
+        when(ESAPI.class, "randomizer").thenReturn(mockRand);
+
+        when(mockRequest.getSession(false)).thenReturn(mockSession);
+        when(mockSession.getAttribute(ESAPI_SESSION_ATTR)).thenReturn(testName.getMethodName()+ "-SESSION");
+
+        //Session value generation
+        when(mockRand.getRandomInteger(ArgumentMatchers.anyInt(), ArgumentMatchers.anyInt())).thenReturn(55555);
+
+        when(mockUser.getLastHostAddress()).thenReturn(testName.getMethodName() + "-HOST_ADDR");
+
+
+        when(mockAuth.getCurrentUser()).thenReturn(mockUser);
+    }
+
+    @Test
+    public void testHappyPath() throws Exception {
+        ClientInfoSupplier cis = new ClientInfoSupplier();
+        cis.setLogClientInfo(true);
+        String result = cis.get();
+
+        assertEquals(testName.getMethodName() + "-SESSION@"+testName.getMethodName() + "-HOST_ADDR", result);
+
+        verify(mockAuth,times(1)).getCurrentUser();
+        verify(mockRequest,times(1)).getSession(false);
+        verify(mockSession,times(1)).getAttribute(ESAPI_SESSION_ATTR);
+        verify(mockUser,times(1)).getLastHostAddress();
+
+        verifyNoMoreInteractions(mockAuth, mockRand, mockRequest, mockSession, mockUser);
+    }
+
+    @Test
+    public void testLogUserOff() {
+        ClientInfoSupplier cis = new ClientInfoSupplier();
+        cis.setLogClientInfo(false);
+        String result = cis.get();
+
+        assertTrue(result.isEmpty());
+
+        verifyNoMoreInteractions(mockAuth, mockRand, mockRequest, mockSession, mockUser);
+    }
+
+    @Test
+    public void testLogUserNull() {
+        when(mockAuth.getCurrentUser()).thenReturn(null);
+        ClientInfoSupplier cis = new ClientInfoSupplier();
+        cis.setLogClientInfo(true);
+        String result = cis.get();
+
+        assertEquals(testName.getMethodName()+ "-SESSION@#UNKNOWN_HOST#", result);
+
+        verify(mockAuth,times(1)).getCurrentUser();
+        verify(mockRequest,times(1)).getSession(false);
+        verify(mockSession,times(1)).getAttribute(ESAPI_SESSION_ATTR);
+
+        verifyNoMoreInteractions(mockAuth, mockRand, mockRequest, mockSession, mockUser);
+    }
+
+    @Test
+    public void testNullRequest() throws Exception {
+        when(ESAPI.class, "currentRequest").thenReturn(null);
+        ClientInfoSupplier cis = new ClientInfoSupplier();
+        cis.setLogClientInfo(true);
+        String result = cis.get();
+
+        //sid is empty when request is null
+        assertEquals("@"+testName.getMethodName() + "-HOST_ADDR", result);
+
+        verify(mockAuth,times(1)).getCurrentUser();
+        verify(mockUser,times(1)).getLastHostAddress();
+
+        verifyNoMoreInteractions(mockAuth, mockRand, mockRequest, mockSession, mockUser);
+    }
+
+    @Test
+    public void testNullSession() throws Exception {
+        when(mockRequest.getSession(false)).thenReturn(null);
+        ClientInfoSupplier cis = new ClientInfoSupplier();
+        cis.setLogClientInfo(true);
+        String result = cis.get();
+
+        //sid is empty when session is null
+        assertEquals("@"+testName.getMethodName() + "-HOST_ADDR", result);
+
+
+        verify(mockAuth,times(1)).getCurrentUser();
+        verify(mockRequest,times(1)).getSession(false);
+        verify(mockUser,times(1)).getLastHostAddress();
+
+
+        verifyNoMoreInteractions(mockAuth, mockRand, mockRequest, mockSession, mockUser);
+    }
+
+
+
+    @Test
+    public void testNullEsapiSession() throws Exception {
+        when(mockSession.getAttribute(ESAPI_SESSION_ATTR)).thenReturn(null);
+        ClientInfoSupplier cis = new ClientInfoSupplier();
+        cis.setLogClientInfo(true);
+        String result = cis.get();
+
+        //sid is empty when session is null
+        assertEquals("55555@"+testName.getMethodName() + "-HOST_ADDR", result);
+
+        verify(mockAuth,times(1)).getCurrentUser();
+        verify(mockRequest,times(1)).getSession(false);
+        verify(mockSession,times(1)).getAttribute(ESAPI_SESSION_ATTR);
+        verify(mockSession, times(1)).setAttribute(ESAPI_SESSION_ATTR, (""+55555));
+        verify(mockRand, times(1)).getRandomInteger(ArgumentMatchers.anyInt(), ArgumentMatchers.anyInt());
+        verify(mockUser,times(1)).getLastHostAddress();
+
+        verifyNoMoreInteractions(mockAuth, mockRand, mockRequest, mockSession, mockUser);
+    }
 }
\ No newline at end of file
diff --git a/src/test/java/org/owasp/esapi/logging/appender/EventTypeLogSupplierTest.java b/src/test/java/org/owasp/esapi/logging/appender/EventTypeLogSupplierTest.java
index f86fbbc..f547ce6 100644
--- a/src/test/java/org/owasp/esapi/logging/appender/EventTypeLogSupplierTest.java
+++ b/src/test/java/org/owasp/esapi/logging/appender/EventTypeLogSupplierTest.java
@@ -26,21 +26,21 @@ public class EventTypeLogSupplierTest {
         paramSets.add(new Object[] {Logger.SECURITY_FAILURE,Logger.SECURITY_FAILURE.toString()});
         paramSets.add(new Object[] {Logger.SECURITY_SUCCESS,Logger.SECURITY_SUCCESS.toString()});
         paramSets.add(new Object[] {null, Logger.EVENT_UNSPECIFIED.toString()});
-        
+
         return paramSets;
     }
-    
+
     private final EventType eventType;
     private final String expectedResult;
-    
+
     public EventTypeLogSupplierTest(EventType eventType, String result) {
         this.eventType = eventType;
         this.expectedResult = result;
     }
-	@Test
-	public void testEventTypeLog() {
-		EventTypeLogSupplier supplier = new EventTypeLogSupplier(eventType);
-		assertEquals(expectedResult, supplier.get());
-	}
-	
+    @Test
+    public void testEventTypeLog() {
+        EventTypeLogSupplier supplier = new EventTypeLogSupplier(eventType);
+        assertEquals(expectedResult, supplier.get());
+    }
+
 }
diff --git a/src/test/java/org/owasp/esapi/logging/appender/LogPrefixAppenderTest.java b/src/test/java/org/owasp/esapi/logging/appender/LogPrefixAppenderTest.java
index 186d696..bc733ec 100644
--- a/src/test/java/org/owasp/esapi/logging/appender/LogPrefixAppenderTest.java
+++ b/src/test/java/org/owasp/esapi/logging/appender/LogPrefixAppenderTest.java
@@ -29,7 +29,7 @@ public class LogPrefixAppenderTest {
 
     @Rule
     public TestName testName = new TestName();
-    
+
     private String testLoggerName = testName.getMethodName() + "-LOGGER";
     private String testLogMessage =  testName.getMethodName() + "-MESSAGE";
     private String testApplicationName = testName.getMethodName() + "-APPLICATION_NAME";
@@ -46,7 +46,7 @@ public class LogPrefixAppenderTest {
         uisSpy = spy(new UserInfoSupplier());
         cisSpy = spy(new ClientInfoSupplier());
         sisSpy = spy(new ServerInfoSupplier(testName.getMethodName()));
-        
+
         testLoggerName = testName.getMethodName() + "-LOGGER";
         testLogMessage =  testName.getMethodName() + "-MESSAGE";
         testApplicationName =  testName.getMethodName() + "-APPLICATION_NAME";
@@ -71,7 +71,7 @@ public class LogPrefixAppenderTest {
         verify(sisSpy, times(1)).setLogServerIp(true);
         verify(sisSpy, times(1)).setLogApplicationName(true, testApplicationName);
     }
-    
+
     @Test
     public void testCtrArgFalsePassthroughToDelegates() throws Exception {
         when(etlsSpy.get()).thenReturn(ETL_RESULT);
@@ -92,7 +92,7 @@ public class LogPrefixAppenderTest {
         verify(sisSpy, times(1)).setLogServerIp(false);
         verify(sisSpy, times(1)).setLogApplicationName(false, null);
     }
-    
+
     @Test
     public void testDelegateCtrArgs() throws Exception {
         ArgumentCaptor<EventType> eventTypeCapture = ArgumentCaptor.forClass(EventType.class);
@@ -119,7 +119,7 @@ public class LogPrefixAppenderTest {
     public void testLogContentWhenUserInfoEmpty() throws Exception {
         runTest(ETL_RESULT, EMPTY_RESULT, CIS_RESULT,SIS_RESULT, "[EVENT_TYPE CLIENT_INFO -> SERVER_INFO]");
     }
-    
+
     @Test
     public void testLogContentWhenClientInfoEmptyAndServerInfoEmpty() throws Exception {
         runTest(ETL_RESULT, UIS_RESULT, EMPTY_RESULT,EMPTY_RESULT, "[EVENT_TYPE USER_INFO]");
@@ -139,7 +139,7 @@ public class LogPrefixAppenderTest {
     public void testLogContentWhenServerInfoEmpty() throws Exception {
         runTest(ETL_RESULT, UIS_RESULT, CIS_RESULT, EMPTY_RESULT, "[EVENT_TYPE USER_INFO:CLIENT_INFO]");
     }
-    
+
     @Test
     public void testLogContentWhenUserInfoEmptyAndClientInfoEmptyAndServerInfoEmpty() throws Exception {
         runTest(ETL_RESULT, EMPTY_RESULT, EMPTY_RESULT, EMPTY_RESULT, "[EVENT_TYPE]");
@@ -160,7 +160,7 @@ public class LogPrefixAppenderTest {
         //Since everything is mocked these booleans don't much matter aside from the later verifies
         LogPrefixAppender lpa = new LogPrefixAppender(false, false, false, false, null);
         String result =   lpa.appendTo(testLoggerName, testEventType, testLogMessage);
-        
+
         assertEquals(exResult + " " + testName.getMethodName() + "-MESSAGE", result);
     }
 }
diff --git a/src/test/java/org/owasp/esapi/logging/appender/ServerInfoSupplierTest.java b/src/test/java/org/owasp/esapi/logging/appender/ServerInfoSupplierTest.java
index 5280ecb..db91b80 100644
--- a/src/test/java/org/owasp/esapi/logging/appender/ServerInfoSupplierTest.java
+++ b/src/test/java/org/owasp/esapi/logging/appender/ServerInfoSupplierTest.java
@@ -19,77 +19,77 @@ import org.powermock.modules.junit4.PowerMockRunner;
 @RunWith(PowerMockRunner.class)
 @PrepareForTest({ ESAPI.class })
 public class ServerInfoSupplierTest {
-	@Rule
-	public TestName testName = new TestName();
-
-	private HttpServletRequest request;
-
-	@Before
-	public void buildStaticMocks() throws Exception {
-		request = mock(HttpServletRequest.class);
-		mockStatic(ESAPI.class);
-		when(ESAPI.class, "currentRequest").thenReturn(request);
-	}
-
-	@Test
-	public void verifyFullOutput() {
-		when(request.getLocalAddr()).thenReturn("LOCAL_ADDR");
-		when(request.getLocalPort()).thenReturn(99999);
-
-		ServerInfoSupplier sis = new ServerInfoSupplier(testName.getMethodName());
-		sis.setLogApplicationName(true, testName.getMethodName() + "-APPLICATION");
-		sis.setLogServerIp(true);
-
-		String result = sis.get();
-		assertEquals("LOCAL_ADDR:99999/" + testName.getMethodName() + "-APPLICATION/" + testName.getMethodName(),
-				result);
-	}
-
-	@Test
-	public void verifyOutputNullRequest() throws Exception {
-		when(ESAPI.class, "currentRequest").thenReturn(null);
-		ServerInfoSupplier sis = new ServerInfoSupplier(testName.getMethodName());
-		sis.setLogApplicationName(true, testName.getMethodName() + "-APPLICATION");
-		sis.setLogServerIp(true);
-
-		String result = sis.get();
-		assertEquals("/" + testName.getMethodName() + "-APPLICATION/" + testName.getMethodName(), result);
-	}
-
-	@Test
-	public void verifyOutputNoAppName() {
-		when(request.getLocalAddr()).thenReturn("LOCAL_ADDR");
-		when(request.getLocalPort()).thenReturn(99999);
-
-		ServerInfoSupplier sis = new ServerInfoSupplier(testName.getMethodName());
-		sis.setLogApplicationName(false, null);
-		sis.setLogServerIp(true);
-
-		String result = sis.get();
-		assertEquals("LOCAL_ADDR:99999/" + testName.getMethodName(), result);
-	}
-
-	@Test
-	public void verifyOutputNullAppName() {
-		when(request.getLocalAddr()).thenReturn("LOCAL_ADDR");
-		when(request.getLocalPort()).thenReturn(99999);
-
-		ServerInfoSupplier sis = new ServerInfoSupplier(testName.getMethodName());
-		sis.setLogApplicationName(true, null);
-		sis.setLogServerIp(true);
-
-		String result = sis.get();
-		assertEquals("LOCAL_ADDR:99999/null/" + testName.getMethodName(), result);
-	}
-
-	@Test
-	public void verifyOutputNoServerIp() {
-		ServerInfoSupplier sis = new ServerInfoSupplier(testName.getMethodName());
-		sis.setLogApplicationName(true, testName.getMethodName() + "-APPLICATION");
-		sis.setLogServerIp(false);
-
-		String result = sis.get();
-		assertEquals("/" + testName.getMethodName() + "-APPLICATION/" + testName.getMethodName(), result);
-	}
+    @Rule
+    public TestName testName = new TestName();
+
+    private HttpServletRequest request;
+
+    @Before
+    public void buildStaticMocks() throws Exception {
+        request = mock(HttpServletRequest.class);
+        mockStatic(ESAPI.class);
+        when(ESAPI.class, "currentRequest").thenReturn(request);
+    }
+
+    @Test
+    public void verifyFullOutput() {
+        when(request.getLocalAddr()).thenReturn("LOCAL_ADDR");
+        when(request.getLocalPort()).thenReturn(99999);
+
+        ServerInfoSupplier sis = new ServerInfoSupplier(testName.getMethodName());
+        sis.setLogApplicationName(true, testName.getMethodName() + "-APPLICATION");
+        sis.setLogServerIp(true);
+
+        String result = sis.get();
+        assertEquals("LOCAL_ADDR:99999/" + testName.getMethodName() + "-APPLICATION/" + testName.getMethodName(),
+                result);
+    }
+
+    @Test
+    public void verifyOutputNullRequest() throws Exception {
+        when(ESAPI.class, "currentRequest").thenReturn(null);
+        ServerInfoSupplier sis = new ServerInfoSupplier(testName.getMethodName());
+        sis.setLogApplicationName(true, testName.getMethodName() + "-APPLICATION");
+        sis.setLogServerIp(true);
+
+        String result = sis.get();
+        assertEquals("/" + testName.getMethodName() + "-APPLICATION/" + testName.getMethodName(), result);
+    }
+
+    @Test
+    public void verifyOutputNoAppName() {
+        when(request.getLocalAddr()).thenReturn("LOCAL_ADDR");
+        when(request.getLocalPort()).thenReturn(99999);
+
+        ServerInfoSupplier sis = new ServerInfoSupplier(testName.getMethodName());
+        sis.setLogApplicationName(false, null);
+        sis.setLogServerIp(true);
+
+        String result = sis.get();
+        assertEquals("LOCAL_ADDR:99999/" + testName.getMethodName(), result);
+    }
+
+    @Test
+    public void verifyOutputNullAppName() {
+        when(request.getLocalAddr()).thenReturn("LOCAL_ADDR");
+        when(request.getLocalPort()).thenReturn(99999);
+
+        ServerInfoSupplier sis = new ServerInfoSupplier(testName.getMethodName());
+        sis.setLogApplicationName(true, null);
+        sis.setLogServerIp(true);
+
+        String result = sis.get();
+        assertEquals("LOCAL_ADDR:99999/null/" + testName.getMethodName(), result);
+    }
+
+    @Test
+    public void verifyOutputNoServerIp() {
+        ServerInfoSupplier sis = new ServerInfoSupplier(testName.getMethodName());
+        sis.setLogApplicationName(true, testName.getMethodName() + "-APPLICATION");
+        sis.setLogServerIp(false);
+
+        String result = sis.get();
+        assertEquals("/" + testName.getMethodName() + "-APPLICATION/" + testName.getMethodName(), result);
+    }
 
 }
diff --git a/src/test/java/org/owasp/esapi/logging/appender/UserInfoSupplierTest.java b/src/test/java/org/owasp/esapi/logging/appender/UserInfoSupplierTest.java
index 8ae9dec..f873816 100644
--- a/src/test/java/org/owasp/esapi/logging/appender/UserInfoSupplierTest.java
+++ b/src/test/java/org/owasp/esapi/logging/appender/UserInfoSupplierTest.java
@@ -30,66 +30,66 @@ import org.powermock.modules.junit4.PowerMockRunner;
 @PrepareForTest({ESAPI.class})
 @PowerMockIgnore("javax.security.*") //Required since User extends javax.security.Principal
 public class UserInfoSupplierTest {
-	private static final String ESAPI_SESSION_ATTR = "ESAPI_SESSION";
-	
-	@Rule
+    private static final String ESAPI_SESSION_ATTR = "ESAPI_SESSION";
+
+    @Rule
     public TestName testName = new TestName();
-	
-	private Authenticator mockAuth;
-	private User mockUser;
-	
-	@Before
-	public void before() throws Exception {
-		mockAuth =mock(Authenticator.class); 
-		mockUser =mock(User.class);
-		
-		mockStatic(ESAPI.class);
-		when(ESAPI.class, "authenticator").thenReturn(mockAuth);
-		
-		when(mockUser.getAccountName()).thenReturn(testName.getMethodName() + "-USER");
-		
-	     
-	    when(mockAuth.getCurrentUser()).thenReturn(mockUser);
-	}
-	
-	@Test
-	public void testHappyPath() throws Exception {
-		UserInfoSupplier uis = new UserInfoSupplier();
-		uis.setLogUserInfo(true);
-		String result = uis.get();
-		
-		assertEquals(testName.getMethodName() + "-USER", result);
-		
-		verify(mockAuth,times(1)).getCurrentUser();
-		verify(mockUser,times(1)).getAccountName();
-		
-		verifyNoMoreInteractions(mockAuth, mockUser);
-	}
-	
-	@Test
-	public void testLogUserOff() {
-		UserInfoSupplier uis = new UserInfoSupplier();
-		uis.setLogUserInfo(false);
-		String result = uis.get();
-		
-		assertTrue(result.isEmpty());
-		verify(mockAuth,times(1)).getCurrentUser();
-		
-		verifyNoMoreInteractions(mockAuth, mockUser);
-	}
-	
-	@Test
-	public void testLogUserNull() {
-		when(mockAuth.getCurrentUser()).thenReturn(null);
-		UserInfoSupplier uis = new UserInfoSupplier();
-		uis.setLogUserInfo(true);
-		String result = uis.get();
-		
-		assertEquals("#ANONYMOUS#", result);
-		
-		verify(mockAuth,times(1)).getCurrentUser();
-		
-		verifyNoMoreInteractions(mockAuth,  mockUser);
-	}
-	
+
+    private Authenticator mockAuth;
+    private User mockUser;
+
+    @Before
+    public void before() throws Exception {
+        mockAuth =mock(Authenticator.class);
+        mockUser =mock(User.class);
+
+        mockStatic(ESAPI.class);
+        when(ESAPI.class, "authenticator").thenReturn(mockAuth);
+
+        when(mockUser.getAccountName()).thenReturn(testName.getMethodName() + "-USER");
+
+
+        when(mockAuth.getCurrentUser()).thenReturn(mockUser);
+    }
+
+    @Test
+    public void testHappyPath() throws Exception {
+        UserInfoSupplier uis = new UserInfoSupplier();
+        uis.setLogUserInfo(true);
+        String result = uis.get();
+
+        assertEquals(testName.getMethodName() + "-USER", result);
+
+        verify(mockAuth,times(1)).getCurrentUser();
+        verify(mockUser,times(1)).getAccountName();
+
+        verifyNoMoreInteractions(mockAuth, mockUser);
+    }
+
+    @Test
+    public void testLogUserOff() {
+        UserInfoSupplier uis = new UserInfoSupplier();
+        uis.setLogUserInfo(false);
+        String result = uis.get();
+
+        assertTrue(result.isEmpty());
+        verify(mockAuth,times(1)).getCurrentUser();
+
+        verifyNoMoreInteractions(mockAuth, mockUser);
+    }
+
+    @Test
+    public void testLogUserNull() {
+        when(mockAuth.getCurrentUser()).thenReturn(null);
+        UserInfoSupplier uis = new UserInfoSupplier();
+        uis.setLogUserInfo(true);
+        String result = uis.get();
+
+        assertEquals("#ANONYMOUS#", result);
+
+        verify(mockAuth,times(1)).getCurrentUser();
+
+        verifyNoMoreInteractions(mockAuth,  mockUser);
+    }
+
 }
\ No newline at end of file
diff --git a/src/test/java/org/owasp/esapi/logging/cleaning/CodecLogScrubberTest.java b/src/test/java/org/owasp/esapi/logging/cleaning/CodecLogScrubberTest.java
index 684bab7..8ca7426 100644
--- a/src/test/java/org/owasp/esapi/logging/cleaning/CodecLogScrubberTest.java
+++ b/src/test/java/org/owasp/esapi/logging/cleaning/CodecLogScrubberTest.java
@@ -1,15 +1,15 @@
 /**
  * OWASP Enterprise Security API (ESAPI)
- * 
+ *
  * This file is part of the Open Web Application Security Project (OWASP)
  * Enterprise Security API (ESAPI) project. For details, please see
  * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
  *
  * Copyright (c) 2007 - The OWASP Foundation
- * 
+ *
  * The ESAPI is published by OWASP under the BSD license. You should read and accept the
  * LICENSE before you use, modify, and/or redistribute this software.
- * 
+ *
  * @created 2018
  */
 package org.owasp.esapi.logging.cleaning;
diff --git a/src/test/java/org/owasp/esapi/logging/cleaning/CompositeLogScrubberTest.java b/src/test/java/org/owasp/esapi/logging/cleaning/CompositeLogScrubberTest.java
index bd694d2..fa11554 100644
--- a/src/test/java/org/owasp/esapi/logging/cleaning/CompositeLogScrubberTest.java
+++ b/src/test/java/org/owasp/esapi/logging/cleaning/CompositeLogScrubberTest.java
@@ -1,15 +1,15 @@
 /**
  * OWASP Enterprise Security API (ESAPI)
- * 
+ *
  * This file is part of the Open Web Application Security Project (OWASP)
  * Enterprise Security API (ESAPI) project. For details, please see
  * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
  *
  * Copyright (c) 2007 - The OWASP Foundation
- * 
+ *
  * The ESAPI is published by OWASP under the BSD license. You should read and accept the
  * LICENSE before you use, modify, and/or redistribute this software.
- * 
+ *
  * @created 2018
  */
 package org.owasp.esapi.logging.cleaning;
diff --git a/src/test/java/org/owasp/esapi/logging/cleaning/NewlineLogScrubberTest.java b/src/test/java/org/owasp/esapi/logging/cleaning/NewlineLogScrubberTest.java
index b4c600d..810f3f2 100644
--- a/src/test/java/org/owasp/esapi/logging/cleaning/NewlineLogScrubberTest.java
+++ b/src/test/java/org/owasp/esapi/logging/cleaning/NewlineLogScrubberTest.java
@@ -1,15 +1,15 @@
 /**
  * OWASP Enterprise Security API (ESAPI)
- * 
+ *
  * This file is part of the Open Web Application Security Project (OWASP)
  * Enterprise Security API (ESAPI) project. For details, please see
  * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
  *
  * Copyright (c) 2007 - The OWASP Foundation
- * 
+ *
  * The ESAPI is published by OWASP under the BSD license. You should read and accept the
  * LICENSE before you use, modify, and/or redistribute this software.
- * 
+ *
  * @created 2018
  */
 package org.owasp.esapi.logging.cleaning;
diff --git a/src/test/java/org/owasp/esapi/logging/java/JavaLogBridgeImplTest.java b/src/test/java/org/owasp/esapi/logging/java/JavaLogBridgeImplTest.java
index 3b7e4eb..b2928f4 100644
--- a/src/test/java/org/owasp/esapi/logging/java/JavaLogBridgeImplTest.java
+++ b/src/test/java/org/owasp/esapi/logging/java/JavaLogBridgeImplTest.java
@@ -1,15 +1,15 @@
 /**
  * OWASP Enterprise Security API (ESAPI)
- * 
+ *
  * This file is part of the Open Web Application Security Project (OWASP)
  * Enterprise Security API (ESAPI) project. For details, please see
  * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
  *
  * Copyright (c) 2007 - The OWASP Foundation
- * 
+ *
  * The ESAPI is published by OWASP under the BSD license. You should read and accept the
  * LICENSE before you use, modify, and/or redistribute this software.
- * 
+ *
  * @created 2019
  */
 package org.owasp.esapi.logging.java;
@@ -153,4 +153,10 @@ public class JavaLogBridgeImplTest {
 
     }
 
+    @Test
+    public void testNullEventTypeWorks()
+    {
+        // would throw an exception if the null wasn't handled properly
+        bridge.log(javaLogSpy, Logger.ALL, null, testName.getMethodName());
+    }
 }
diff --git a/src/test/java/org/owasp/esapi/logging/java/JavaLogFactoryTest.java b/src/test/java/org/owasp/esapi/logging/java/JavaLogFactoryTest.java
index 465083d..7938171 100644
--- a/src/test/java/org/owasp/esapi/logging/java/JavaLogFactoryTest.java
+++ b/src/test/java/org/owasp/esapi/logging/java/JavaLogFactoryTest.java
@@ -1,15 +1,15 @@
 /**
  * OWASP Enterprise Security API (ESAPI)
- * 
+ *
  * This file is part of the Open Web Application Security Project (OWASP)
  * Enterprise Security API (ESAPI) project. For details, please see
  * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
  *
  * Copyright (c) 2007 - The OWASP Foundation
- * 
+ *
  * The ESAPI is published by OWASP under the BSD license. You should read and accept the
  * LICENSE before you use, modify, and/or redistribute this software.
- * 
+ *
  * @created 2019
  */
 package org.owasp.esapi.logging.java;
@@ -44,10 +44,63 @@ import org.powermock.modules.junit4.PowerMockRunner;
 public class JavaLogFactoryTest {
     @Rule
     public TestName testName = new TestName();
-    
+
     @Rule
     public ExpectedException exEx = ExpectedException.none();
 
+    @Test
+    public void testLogManagerConfigurationAsClass() throws Exception {
+        String propKey = "java.util.logging.config.class";
+        //If defined, grab the value; otherwise, set to a known value to allow for prop to be cleared.
+        String sysDefault = System.getProperties().stringPropertyNames().contains(propKey) ? System.getProperty(propKey) : testName.getMethodName();
+
+        System.setProperty(propKey, "some.defined.value");
+        LogManager testLogManager = new LogManager() {
+            @Override
+            public void readConfiguration(InputStream ins) throws IOException, SecurityException {
+                throw new IOException(testName.getMethodName());
+            }
+        };
+
+        try {
+            // This would throw an IOException if the LogManager was not being respected since no esapi-java-logging file is specified
+            JavaLogFactory.readLoggerConfiguration(testLogManager);
+        } finally {
+            //Restore original prop values
+            if (testName.getMethodName().equals(sysDefault))
+                System.clearProperty(propKey);
+            else {
+                System.setProperty(propKey, sysDefault);
+            }
+        }
+    }
+
+    @Test
+    public void testLogManagerConfigurationAsFile() throws Exception {
+        String propKey = "java.util.logging.config.file";
+        //If defined, grab the value; otherwise, set to a known value to allow for prop to be cleared.
+        String sysDefault = System.getProperties().stringPropertyNames().contains(propKey) ? System.getProperty(propKey) : testName.getMethodName();
+
+        System.setProperty(propKey, "some.defined.value");
+        LogManager testLogManager = new LogManager() {
+            @Override
+            public void readConfiguration(InputStream ins) throws IOException, SecurityException {
+                throw new IOException(testName.getMethodName());
+            }
+        };
+
+        try {
+            // This would throw an IOException if the LogManager was not being respected since no esapi-java-logging file is specified
+            JavaLogFactory.readLoggerConfiguration(testLogManager);
+        } finally {
+            //Restore original prop values
+            if (testName.getMethodName().equals(sysDefault)) {
+                System.clearProperty(propKey);
+            } else {
+                System.setProperty(propKey, sysDefault);
+            } 
+        }
+    }
     @Test
     public void testConfigurationExceptionOnMissingConfiguration() throws Exception {
         final IOException originException = new IOException(testName.getMethodName());
@@ -61,11 +114,11 @@ public class JavaLogFactoryTest {
 
         exEx.expectMessage("Failed to load esapi-java-logging.properties");
         exEx.expect(ConfigurationException.class);
-       
+
         exEx.expectCause(new CustomMatcher<Throwable>("Check for IOException") {
             @Override
             public boolean matches(Object item) {
-               return item instanceof IOException;
+                return item instanceof IOException;
             }
         });
 
@@ -134,7 +187,7 @@ public class JavaLogFactoryTest {
         Assert.assertTrue(clientInfoCapture.getValue());
         Assert.assertFalse(serverInfoCapture.getValue());
         Assert.assertTrue(logAppNameCapture.getValue());
-        Assert.assertEquals(testName.getMethodName(), appNameCapture.getValue());    	
+        Assert.assertEquals(testName.getMethodName(), appNameCapture.getValue());
     }
 
 
diff --git a/src/test/java/org/owasp/esapi/logging/java/JavaLogLevelHandlersTest.java b/src/test/java/org/owasp/esapi/logging/java/JavaLogLevelHandlersTest.java
index a65e3bf..62c5a1d 100644
--- a/src/test/java/org/owasp/esapi/logging/java/JavaLogLevelHandlersTest.java
+++ b/src/test/java/org/owasp/esapi/logging/java/JavaLogLevelHandlersTest.java
@@ -1,15 +1,15 @@
 /**
  * OWASP Enterprise Security API (ESAPI)
- * 
+ *
  * This file is part of the Open Web Application Security Project (OWASP)
  * Enterprise Security API (ESAPI) project. For details, please see
  * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
  *
  * Copyright (c) 2007 - The OWASP Foundation
- * 
+ *
  * The ESAPI is published by OWASP under the BSD license. You should read and accept the
  * LICENSE before you use, modify, and/or redistribute this software.
- * 
+ *
  * @created 2019
  */
 package org.owasp.esapi.logging.java;
@@ -57,7 +57,7 @@ public class JavaLogLevelHandlersTest {
         Mockito.verify(mockLogger, Mockito.times(1)).log(expectedJavaLevel, testName.getMethodName(), testException);
         Mockito.verifyNoMoreInteractions(mockLogger);
     }
-    
+
     @Test
     public void testWarnDelegation() {
         JavaLogLevelHandlers.WARNING.isEnabled(mockLogger);
diff --git a/src/test/java/org/owasp/esapi/logging/java/JavaLoggerTest.java b/src/test/java/org/owasp/esapi/logging/java/JavaLoggerTest.java
index c7258a8..906bb64 100644
--- a/src/test/java/org/owasp/esapi/logging/java/JavaLoggerTest.java
+++ b/src/test/java/org/owasp/esapi/logging/java/JavaLoggerTest.java
@@ -1,15 +1,15 @@
 /**
  * OWASP Enterprise Security API (ESAPI)
- * 
+ *
  * This file is part of the Open Web Application Security Project (OWASP)
  * Enterprise Security API (ESAPI) project. For details, please see
  * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
  *
  * Copyright (c) 2007 - The OWASP Foundation
- * 
+ *
  * The ESAPI is published by OWASP under the BSD license. You should read and accept the
  * LICENSE before you use, modify, and/or redistribute this software.
- * 
+ *
  * @created 2019
  */
 
diff --git a/src/test/java/org/owasp/esapi/logging/log4j/Log4JLogBridgeImplTest.java b/src/test/java/org/owasp/esapi/logging/log4j/Log4JLogBridgeImplTest.java
deleted file mode 100644
index f3bf415..0000000
--- a/src/test/java/org/owasp/esapi/logging/log4j/Log4JLogBridgeImplTest.java
+++ /dev/null
@@ -1,152 +0,0 @@
-/**
- * OWASP Enterprise Security API (ESAPI)
- * 
- * This file is part of the Open Web Application Security Project (OWASP)
- * Enterprise Security API (ESAPI) project. For details, please see
- * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
- *
- * Copyright (c) 2007 - The OWASP Foundation
- * 
- * The ESAPI is published by OWASP under the BSD license. You should read and accept the
- * LICENSE before you use, modify, and/or redistribute this software.
- * 
- * @created 2019
- */
-package org.owasp.esapi.logging.log4j;
-
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.Map;
-
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.ExpectedException;
-import org.junit.rules.TestName;
-import org.mockito.ArgumentMatchers;
-import org.mockito.Mockito;
-import org.owasp.esapi.Logger;
-import org.owasp.esapi.Logger.EventType;
-import org.owasp.esapi.logging.appender.LogAppender;
-import org.owasp.esapi.logging.cleaning.LogScrubber;
-
-public class Log4JLogBridgeImplTest {
-
-    @Rule
-    public TestName testName = new TestName();
-    @Rule
-    public ExpectedException exEx = ExpectedException.none();
-
-    private LogScrubber mockScrubber = Mockito.mock(LogScrubber.class);
-    private LogAppender mockAppender = Mockito.mock(LogAppender.class);
-    private Log4JLogLevelHandler mockHandler = Mockito.mock(Log4JLogLevelHandler.class);
-    private org.apache.log4j.Logger log4JSpy;
-    private Throwable testEx = new Throwable(testName.getMethodName());
-    private Log4JLogBridge bridge;
-
-    @Before
-    public void setup() {
-        Map<Integer, Log4JLogLevelHandler> levelLookup = new HashMap<>();
-        levelLookup.put(Logger.ALL, mockHandler);
-
-        org.apache.log4j.Logger wrappedLogger =org.apache.log4j.Logger.getLogger(testName.getMethodName());
-        log4JSpy = Mockito.spy(wrappedLogger);
-        bridge = new Log4JLogBridgeImpl(mockAppender, mockScrubber, levelLookup);
-    }
-
-    @Test
-    public void testLogMessageWithUnmappedEsapiLevelThrowsException() {
-        exEx.expect(IllegalArgumentException.class);
-        exEx.expectMessage("Unable to lookup LOG4J level mapping");
-        Map<Integer, Log4JLogLevelHandler> emptyMap = Collections.emptyMap();
-        new Log4JLogBridgeImpl(mockAppender, mockScrubber, emptyMap).log(log4JSpy, 0, Logger.EVENT_UNSPECIFIED, "This Should fail");
-    }
-
-    @Test
-    public void testLogMessageAndExceptionWithUnmappedEsapiLevelThrowsException() {
-        exEx.expect(IllegalArgumentException.class);
-        exEx.expectMessage("Unable to lookup LOG4J level mapping");
-        Map<Integer, Log4JLogLevelHandler> emptyMap = Collections.emptyMap();
-        new Log4JLogBridgeImpl(mockAppender, mockScrubber, emptyMap).log(log4JSpy, 0, Logger.EVENT_UNSPECIFIED, "This Should fail", testEx);
-    }
-
-    @Test
-    public void testLogMessage() {
-        EventType eventType = Logger.EVENT_UNSPECIFIED;
-        String loggerName = testName.getMethodName();
-        String orignMsg = testName.getMethodName();
-        String appendMsg = "[APPEND] " + orignMsg;
-        String cleanMsg = appendMsg + " [CLEANED]";
-
-        //Setup for Appender
-        Mockito.when(mockAppender.appendTo(loggerName, eventType, orignMsg)).thenReturn(appendMsg);
-        //Setup for Scrubber
-        Mockito.when(mockScrubber.cleanMessage(appendMsg)).thenReturn(cleanMsg);
-        //Setup for Delegate Handler
-        Mockito.when(mockHandler.isEnabled(log4JSpy)).thenReturn(true);
-
-        bridge.log(log4JSpy, Logger.ALL, eventType, testName.getMethodName());
-
-        Mockito.verify(mockAppender, Mockito.times(1)).appendTo(loggerName, eventType, testName.getMethodName());
-        Mockito.verify(mockScrubber, Mockito.times(1)).cleanMessage(appendMsg);
-        Mockito.verify(mockHandler, Mockito.times(1)).isEnabled(log4JSpy);
-        Mockito.verify(mockHandler, Mockito.times(0)).log(ArgumentMatchers.any(org.apache.log4j.Logger.class), ArgumentMatchers.any(String.class), ArgumentMatchers.any(Throwable.class));
-        Mockito.verify(mockHandler, Mockito.times(1)).log(ArgumentMatchers.same(log4JSpy), ArgumentMatchers.eq(cleanMsg));
-
-        Mockito.verifyNoMoreInteractions(log4JSpy, mockAppender, mockScrubber,mockHandler);
-    }
-
-    @Test
-    public void testLogErrorMessageWithException() {
-        EventType eventType = Logger.EVENT_UNSPECIFIED;
-        String loggerName = testName.getMethodName();
-        String orignMsg = testName.getMethodName();
-        String appendMsg = "[APPEND] " + orignMsg;
-        String cleanMsg = appendMsg + " [CLEANED]";
-
-        //Setup for Appender
-        Mockito.when(mockAppender.appendTo(loggerName, eventType, orignMsg)).thenReturn(appendMsg);
-        //Setup for Scrubber
-        Mockito.when(mockScrubber.cleanMessage(appendMsg)).thenReturn(cleanMsg);
-        //Setup for Delegate Handler
-        Mockito.when(mockHandler.isEnabled(log4JSpy)).thenReturn(true);
-
-        bridge.log(log4JSpy, Logger.ALL, eventType, testName.getMethodName(), testEx);
-
-        Mockito.verify(mockAppender, Mockito.times(1)).appendTo(loggerName, eventType, testName.getMethodName());
-        Mockito.verify(mockScrubber, Mockito.times(1)).cleanMessage(appendMsg);
-        Mockito.verify(mockHandler, Mockito.times(1)).isEnabled(log4JSpy);
-        Mockito.verify(mockHandler, Mockito.times(0)).log(ArgumentMatchers.any(org.apache.log4j.Logger.class), ArgumentMatchers.any(String.class));
-
-        Mockito.verify(mockHandler, Mockito.times(1)).log(ArgumentMatchers.same(log4JSpy), ArgumentMatchers.eq(cleanMsg), ArgumentMatchers.same(testEx));
-
-        Mockito.verifyNoMoreInteractions(log4JSpy, mockAppender, mockScrubber,mockHandler);
-    }
-
-
-    @Test
-    public void testDisabledLogMessage() {
-        Mockito.when(mockHandler.isEnabled(log4JSpy)).thenReturn(false);
-
-        bridge.log(log4JSpy, Logger.ALL, Logger.EVENT_UNSPECIFIED, testName.getMethodName());
-
-        Mockito.verify(mockHandler, Mockito.times(1)).isEnabled(log4JSpy);
-        Mockito.verify(mockScrubber, Mockito.times(0)).cleanMessage(ArgumentMatchers.anyString());
-        Mockito.verify(mockHandler, Mockito.times(0)).log(ArgumentMatchers.any(org.apache.log4j.Logger.class), ArgumentMatchers.any(String.class));
-        Mockito.verify(mockHandler, Mockito.times(0)).log(ArgumentMatchers.any(org.apache.log4j.Logger.class), ArgumentMatchers.any(String.class), ArgumentMatchers.any(Throwable.class));
-    }
-
-    @Test
-    public void testDisabledErrorLogWithException() {
-        Mockito.when(mockHandler.isEnabled(log4JSpy)).thenReturn(false);
-
-        bridge.log(log4JSpy, Logger.ALL, Logger.EVENT_UNSPECIFIED, testName.getMethodName(), testEx);
-
-        Mockito.verify(mockHandler, Mockito.times(1)).isEnabled(log4JSpy);
-        Mockito.verify(mockScrubber, Mockito.times(0)).cleanMessage(ArgumentMatchers.anyString());
-        Mockito.verify(mockHandler, Mockito.times(0)).log(ArgumentMatchers.any(org.apache.log4j.Logger.class), ArgumentMatchers.any(String.class));
-        Mockito.verify(mockHandler, Mockito.times(0)).log(ArgumentMatchers.any(org.apache.log4j.Logger.class), ArgumentMatchers.any(String.class), ArgumentMatchers.any(Throwable.class));
-
-    }
-
-}
diff --git a/src/test/java/org/owasp/esapi/logging/log4j/Log4JLogFactoryTest.java b/src/test/java/org/owasp/esapi/logging/log4j/Log4JLogFactoryTest.java
deleted file mode 100644
index 3b73789..0000000
--- a/src/test/java/org/owasp/esapi/logging/log4j/Log4JLogFactoryTest.java
+++ /dev/null
@@ -1,108 +0,0 @@
-/**
- * OWASP Enterprise Security API (ESAPI)
- * 
- * This file is part of the Open Web Application Security Project (OWASP)
- * Enterprise Security API (ESAPI) project. For details, please see
- * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
- *
- * Copyright (c) 2007 - The OWASP Foundation
- * 
- * The ESAPI is published by OWASP under the BSD license. You should read and accept the
- * LICENSE before you use, modify, and/or redistribute this software.
- * 
- * @created 2019
- */
-package org.owasp.esapi.logging.log4j;
-
-import java.util.List;
-
-import org.junit.Assert;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.TestName;
-import org.junit.runner.RunWith;
-import org.mockito.ArgumentCaptor;
-import org.owasp.esapi.Logger;
-import org.owasp.esapi.logging.appender.LogAppender;
-import org.owasp.esapi.logging.appender.LogPrefixAppender;
-import org.owasp.esapi.logging.cleaning.CodecLogScrubber;
-import org.owasp.esapi.logging.cleaning.CompositeLogScrubber;
-import org.owasp.esapi.logging.cleaning.LogScrubber;
-import org.owasp.esapi.logging.cleaning.NewlineLogScrubber;
-import org.powermock.api.mockito.PowerMockito;
-import org.powermock.core.classloader.annotations.PrepareForTest;
-import org.powermock.modules.junit4.PowerMockRunner;
-
-@RunWith(PowerMockRunner.class)
-@PrepareForTest (Log4JLogFactory.class)
-public class Log4JLogFactoryTest {
-    @Rule
-    public TestName testName = new TestName();
-
-    @Test
-    public void testCreateLoggerByString() {
-        Logger logger = new Log4JLogFactory().getLogger("test");
-        Assert.assertTrue(logger instanceof Log4JLogger);
-    }
-
-    @Test public void testCreateLoggerByClass() {
-        Logger logger = new Log4JLogFactory().getLogger(Log4JLogBridgeImplTest.class);
-        Assert.assertTrue(logger instanceof Log4JLogger);
-    }
-
-    @Test
-    public void checkScrubberWithEncoding() throws Exception {
-        ArgumentCaptor<List> delegates = ArgumentCaptor.forClass(List.class);
-        PowerMockito.whenNew(CompositeLogScrubber.class).withArguments(delegates.capture()).thenReturn(null);
-
-        //Call to invoke the constructor capture
-        Log4JLogFactory.createLogScrubber(true);
-
-        List<LogScrubber> scrubbers = delegates.getValue();
-        Assert.assertEquals(2, scrubbers.size());
-        Assert.assertTrue(scrubbers.get(0) instanceof NewlineLogScrubber);
-        Assert.assertTrue(scrubbers.get(1) instanceof CodecLogScrubber);
-    }
-
-    @Test
-    public void checkScrubberWithoutEncoding() throws Exception {
-        ArgumentCaptor<List> delegates = ArgumentCaptor.forClass(List.class);
-        PowerMockito.whenNew(CompositeLogScrubber.class).withArguments(delegates.capture()).thenReturn(null);
-
-        //Call to invoke the constructor capture
-        Log4JLogFactory.createLogScrubber(false);
-
-        List<LogScrubber> scrubbers = delegates.getValue();
-        Assert.assertEquals(1, scrubbers.size());
-        Assert.assertTrue(scrubbers.get(0) instanceof NewlineLogScrubber);
-    }
-
-    /**
-     * At this time there are no special considerations or handling for the appender
-     * creation in this scope. It is expected that the arguments to the internal
-     * creation method are passed directly to the constructor of the
-     * LogPrefixAppender with no mutation or additional validation.
-     */
-    @Test
-    public void checkPassthroughAppenderConstruct() throws Exception {
-        LogPrefixAppender stubAppender = new LogPrefixAppender(true, true, true, true, "");
-        ArgumentCaptor<Boolean> userInfoCapture = ArgumentCaptor.forClass(Boolean.class);
-        ArgumentCaptor<Boolean> clientInfoCapture = ArgumentCaptor.forClass(Boolean.class);
-        ArgumentCaptor<Boolean> serverInfoCapture = ArgumentCaptor.forClass(Boolean.class);
-        ArgumentCaptor<Boolean> logAppNameCapture = ArgumentCaptor.forClass(Boolean.class);
-        ArgumentCaptor<String> appNameCapture = ArgumentCaptor.forClass(String.class);
-
-        PowerMockito.whenNew(LogPrefixAppender.class).withArguments(userInfoCapture.capture(), clientInfoCapture.capture(), serverInfoCapture.capture(), logAppNameCapture.capture(), appNameCapture.capture()).thenReturn(stubAppender);
-
-        LogAppender appender = Log4JLogFactory.createLogAppender(true, true, false, true, testName.getMethodName());
-
-        Assert.assertEquals(stubAppender, appender);
-        Assert.assertTrue(userInfoCapture.getValue());
-        Assert.assertTrue(clientInfoCapture.getValue());
-        Assert.assertFalse(serverInfoCapture.getValue());
-        Assert.assertTrue(logAppNameCapture.getValue());
-        Assert.assertEquals(testName.getMethodName(), appNameCapture.getValue());    	
-    }
-
-
-}
diff --git a/src/test/java/org/owasp/esapi/logging/log4j/Log4JLogLevelHandlersTest.java b/src/test/java/org/owasp/esapi/logging/log4j/Log4JLogLevelHandlersTest.java
deleted file mode 100644
index 149617f..0000000
--- a/src/test/java/org/owasp/esapi/logging/log4j/Log4JLogLevelHandlersTest.java
+++ /dev/null
@@ -1,102 +0,0 @@
-/**
- * OWASP Enterprise Security API (ESAPI)
- * 
- * This file is part of the Open Web Application Security Project (OWASP)
- * Enterprise Security API (ESAPI) project. For details, please see
- * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
- *
- * Copyright (c) 2007 - The OWASP Foundation
- * 
- * The ESAPI is published by OWASP under the BSD license. You should read and accept the
- * LICENSE before you use, modify, and/or redistribute this software.
- * 
- * @created 2019
- */
-package org.owasp.esapi.logging.log4j;
-
-import org.apache.log4j.Level;
-import org.apache.log4j.Logger;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.TestName;
-import org.mockito.Mockito;
-import org.owasp.esapi.logging.log4j.Log4JLogLevelHandlers;
-
-public class Log4JLogLevelHandlersTest {
-
-    private Logger mockLogger = Mockito.mock(Logger.class);
-    @Rule
-    public TestName testName = new TestName();
-
-    private Throwable testException = new Throwable("Expected for testing");
-
-    @Test
-    public void testFatalDelegation() {
-        Log4JLogLevelHandlers.FATAL.isEnabled(mockLogger);
-        Log4JLogLevelHandlers.FATAL.log(mockLogger, testName.getMethodName());
-        Log4JLogLevelHandlers.FATAL.log(mockLogger, testName.getMethodName(), testException);
-
-        Mockito.verify(mockLogger, Mockito.times(1)).isEnabledFor(Level.FATAL);
-        Mockito.verify(mockLogger, Mockito.times(1)).log(Level.FATAL, testName.getMethodName());
-        Mockito.verify(mockLogger, Mockito.times(1)).log(Level.FATAL, testName.getMethodName(), testException);
-        Mockito.verifyNoMoreInteractions(mockLogger);
-    }
-
-
-    @Test
-    public void testErrorDelegation() {
-        Log4JLogLevelHandlers.ERROR.isEnabled(mockLogger);
-        Log4JLogLevelHandlers.ERROR.log(mockLogger, testName.getMethodName());
-        Log4JLogLevelHandlers.ERROR.log(mockLogger, testName.getMethodName(), testException);
-
-        Mockito.verify(mockLogger, Mockito.times(1)).isEnabledFor(Level.ERROR);
-        Mockito.verify(mockLogger, Mockito.times(1)).log(Level.ERROR, testName.getMethodName());
-        Mockito.verify(mockLogger, Mockito.times(1)).log(Level.ERROR, testName.getMethodName(), testException);
-        Mockito.verifyNoMoreInteractions(mockLogger);
-    }
-
-    @Test
-    public void testWarnDelegation() {
-        Log4JLogLevelHandlers.WARN.isEnabled(mockLogger);
-        Log4JLogLevelHandlers.WARN.log(mockLogger, testName.getMethodName());
-        Log4JLogLevelHandlers.WARN.log(mockLogger, testName.getMethodName(), testException);
-
-        Mockito.verify(mockLogger, Mockito.times(1)).isEnabledFor(Level.WARN);
-        Mockito.verify(mockLogger, Mockito.times(1)).log(Level.WARN, testName.getMethodName());
-        Mockito.verify(mockLogger, Mockito.times(1)).log(Level.WARN, testName.getMethodName(), testException);
-        Mockito.verifyNoMoreInteractions(mockLogger);
-    }
-    @Test
-    public void testInfoDelegation() {
-        Log4JLogLevelHandlers.INFO.isEnabled(mockLogger);
-        Log4JLogLevelHandlers.INFO.log(mockLogger, testName.getMethodName());
-        Log4JLogLevelHandlers.INFO.log(mockLogger, testName.getMethodName(), testException);
-
-        Mockito.verify(mockLogger, Mockito.times(1)).isEnabledFor(Level.INFO);
-        Mockito.verify(mockLogger, Mockito.times(1)).log(Level.INFO, testName.getMethodName());
-        Mockito.verify(mockLogger, Mockito.times(1)).log(Level.INFO, testName.getMethodName(), testException);
-        Mockito.verifyNoMoreInteractions(mockLogger);
-    }
-    @Test
-    public void testDebugDelegation() {
-        Log4JLogLevelHandlers.DEBUG.isEnabled(mockLogger);
-        Log4JLogLevelHandlers.DEBUG.log(mockLogger, testName.getMethodName());
-        Log4JLogLevelHandlers.DEBUG.log(mockLogger, testName.getMethodName(), testException);
-
-        Mockito.verify(mockLogger, Mockito.times(1)).isEnabledFor(Level.DEBUG);
-        Mockito.verify(mockLogger, Mockito.times(1)).log(Level.DEBUG, testName.getMethodName());
-        Mockito.verify(mockLogger, Mockito.times(1)).log(Level.DEBUG, testName.getMethodName(), testException);
-        Mockito.verifyNoMoreInteractions(mockLogger);
-    }
-    @Test
-    public void testTraceDelegation() {
-        Log4JLogLevelHandlers.TRACE.isEnabled(mockLogger);
-        Log4JLogLevelHandlers.TRACE.log(mockLogger, testName.getMethodName());
-        Log4JLogLevelHandlers.TRACE.log(mockLogger, testName.getMethodName(), testException);
-
-        Mockito.verify(mockLogger, Mockito.times(1)).isEnabledFor(Level.TRACE);
-        Mockito.verify(mockLogger, Mockito.times(1)).log(Level.TRACE, testName.getMethodName());
-        Mockito.verify(mockLogger, Mockito.times(1)).log(Level.TRACE, testName.getMethodName(), testException);
-        Mockito.verifyNoMoreInteractions(mockLogger);
-    }
-}
diff --git a/src/test/java/org/owasp/esapi/logging/log4j/Log4JLoggerFactoryTest.java b/src/test/java/org/owasp/esapi/logging/log4j/Log4JLoggerFactoryTest.java
deleted file mode 100644
index 5d73047..0000000
--- a/src/test/java/org/owasp/esapi/logging/log4j/Log4JLoggerFactoryTest.java
+++ /dev/null
@@ -1,97 +0,0 @@
-/**
- * OWASP Enterprise Security API (ESAPI)
- *
- * This file is part of the Open Web Application Security Project (OWASP)
- * Enterprise Security API (ESAPI) project. For details, please see
- * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
- *
- * Copyright (c) 2007 - The OWASP Foundation
- *
- * The ESAPI is published by OWASP under the BSD license. You should read and accept the
- * LICENSE before you use, modify, and/or redistribute this software.
- *
- * @author Jeff Williams <a href="http://www.aspectsecurity.com">Aspect Security</a>
- * @created 2019
- */
-package org.owasp.esapi.logging.log4j;
-
-import org.apache.log4j.Level;
-import org.apache.log4j.Logger;
-import org.apache.log4j.spi.LoggerRepository;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.TestName;
-import org.junit.runner.RunWith;
-import org.mockito.ArgumentMatchers;
-import org.mockito.Mock;
-import org.mockito.Mockito;
-import org.mockito.junit.MockitoJUnitRunner;
-import org.owasp.esapi.logging.appender.LogAppender;
-import org.owasp.esapi.logging.cleaning.LogScrubber;
-import org.powermock.reflect.Whitebox;
-
-/**
- * Basic test implementation that verifies that the {@link LogAppender} and
- * {@link LogScrubber} references are applied by the {@link Logger} instances
- * created by the {@link Log4JLoggerFactory}.
- * 
- */
-@RunWith(MockitoJUnitRunner.class)
-public class Log4JLoggerFactoryTest {
-    @Mock
-    private LogScrubber scrubber;
-    @Mock
-    private LogAppender appender;
-    @Rule
-    public TestName testName = new TestName();
-
-    private String logMsg = testName.getMethodName() + "-MESSAGE";
-    private Logger logger;
-
-    @Before
-    public void configureStaticFactoryState() {
-        Log4JLoggerFactory factory = new Log4JLoggerFactory();
-        Whitebox.setInternalState(Log4JLoggerFactory.class, "LOG4J_LOG_SCRUBBER", scrubber);
-        Whitebox.setInternalState(Log4JLoggerFactory.class, "LOG4J_LOG_APPENDER", appender);
-
-        Mockito.when(scrubber.cleanMessage(logMsg)).thenReturn(logMsg);
-        Mockito.when(appender.appendTo(testName.getMethodName(), null, logMsg)).thenReturn(logMsg);
-
-        LoggerRepository mockRepo = Mockito.mock(LoggerRepository.class);
-        Mockito.when(mockRepo.isDisabled(ArgumentMatchers.anyInt())).thenReturn(false);
-
-        logger = factory.makeNewLoggerInstance(testName.getMethodName());
-        Whitebox.setInternalState(logger, "repository", mockRepo);
-        logger.setLevel(Level.ALL);
-    }
-
-    @Test
-    public void testLogDebug() {
-        logger.debug(logMsg);
-        Mockito.verify(scrubber, Mockito.times(1)).cleanMessage(logMsg);
-        Mockito.verify(appender, Mockito.times(1)).appendTo(testName.getMethodName(), null, logMsg);
-    }
-
-    @Test
-    public void testLogInfo() {
-        logger.info(logMsg);
-        Mockito.verify(scrubber, Mockito.times(1)).cleanMessage(logMsg);
-        Mockito.verify(appender, Mockito.times(1)).appendTo(testName.getMethodName(), null, logMsg);
-    }
-
-    @Test
-    public void testLogWarn() {
-        logger.warn(logMsg);
-        Mockito.verify(scrubber, Mockito.times(1)).cleanMessage(logMsg);
-        Mockito.verify(appender, Mockito.times(1)).appendTo(testName.getMethodName(), null, logMsg);
-    }
-
-    @Test
-    public void testLogError() {
-        logger.error(logMsg);
-        Mockito.verify(scrubber, Mockito.times(1)).cleanMessage(logMsg);
-        Mockito.verify(appender, Mockito.times(1)).appendTo(testName.getMethodName(), null, logMsg);
-    }
-
-}
diff --git a/src/test/java/org/owasp/esapi/logging/log4j/Log4JLoggerTest.java b/src/test/java/org/owasp/esapi/logging/log4j/Log4JLoggerTest.java
deleted file mode 100644
index 16834f2..0000000
--- a/src/test/java/org/owasp/esapi/logging/log4j/Log4JLoggerTest.java
+++ /dev/null
@@ -1,287 +0,0 @@
-/**
- * OWASP Enterprise Security API (ESAPI)
- * 
- * This file is part of the Open Web Application Security Project (OWASP)
- * Enterprise Security API (ESAPI) project. For details, please see
- * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
- *
- * Copyright (c) 2007 - The OWASP Foundation
- * 
- * The ESAPI is published by OWASP under the BSD license. You should read and accept the
- * LICENSE before you use, modify, and/or redistribute this software.
- * 
- * @created 2019
- */
-
-package org.owasp.esapi.logging.log4j;
-
-import org.junit.Assert;
-import org.junit.Test;
-import org.mockito.Mockito;
-import org.owasp.esapi.Logger;
-import org.owasp.esapi.logging.log4j.Log4JLogBridge;
-import org.owasp.esapi.logging.log4j.Log4JLogger;
-
-public class Log4JLoggerTest {
-
-    private static final String MSG = Log4JLoggerTest.class.getSimpleName();
-
-    private Log4JLogBridge mockBridge = Mockito.mock(Log4JLogBridge.class);
-    private org.apache.log4j.Logger mockLogDelegate = Mockito.mock(org.apache.log4j.Logger.class);
-
-    private Throwable testEx = new Throwable(MSG + "_Exception");
-    private Logger testLogger = new Log4JLogger(mockLogDelegate, mockBridge, Logger.ALL);
-
-    @Test
-    public void testLevelEnablement() {
-        testLogger.setLevel(Logger.INFO);
-
-        Assert.assertTrue(testLogger.isFatalEnabled());
-        Assert.assertTrue(testLogger.isErrorEnabled());
-        Assert.assertTrue(testLogger.isWarningEnabled());
-        Assert.assertTrue(testLogger.isInfoEnabled());
-        Assert.assertFalse(testLogger.isDebugEnabled());
-        Assert.assertFalse(testLogger.isTraceEnabled());
-
-        Assert.assertEquals(Logger.INFO, testLogger.getESAPILevel());
-    }
-
-    @Test
-    public void testAllLevelEnablement() {
-        testLogger.setLevel(Logger.ALL);
-
-        Assert.assertTrue(testLogger.isFatalEnabled());
-        Assert.assertTrue(testLogger.isErrorEnabled());
-        Assert.assertTrue(testLogger.isWarningEnabled());
-        Assert.assertTrue(testLogger.isInfoEnabled());
-        Assert.assertTrue(testLogger.isDebugEnabled());
-        Assert.assertTrue(testLogger.isTraceEnabled());
-    }
-
-    @Test
-    public void testOffLevelEnablement() {
-        testLogger.setLevel(Logger.OFF);
-
-        Assert.assertFalse(testLogger.isFatalEnabled());
-        Assert.assertFalse(testLogger.isErrorEnabled());
-        Assert.assertFalse(testLogger.isWarningEnabled());
-        Assert.assertFalse(testLogger.isInfoEnabled());
-        Assert.assertFalse(testLogger.isDebugEnabled());
-        Assert.assertFalse(testLogger.isTraceEnabled());
-    }
-    @Test
-    public void testFatalWithMessage() {
-        testLogger.fatal(Logger.EVENT_UNSPECIFIED, MSG);
-
-        Mockito.verify(mockBridge, Mockito.times(1)).log(mockLogDelegate, Logger.FATAL, Logger.EVENT_UNSPECIFIED, MSG);
-        Mockito.verifyNoMoreInteractions(mockBridge, mockLogDelegate);
-    }
-    @Test
-    public void testFatalWithMessageAndThrowable() {
-        testLogger.fatal(Logger.EVENT_UNSPECIFIED, MSG, testEx);
-
-        Mockito.verify(mockBridge, Mockito.times(1)).log(mockLogDelegate, Logger.FATAL, Logger.EVENT_UNSPECIFIED, MSG, testEx);
-        Mockito.verifyNoMoreInteractions(mockBridge, mockLogDelegate);
-    }
-
-    @Test
-    public void testFatalWithMessageDisabled() {
-        testLogger.setLevel(Logger.OFF);
-        testLogger.fatal(Logger.EVENT_UNSPECIFIED, MSG);
-
-        Mockito.verify(mockBridge, Mockito.times(0)).log(mockLogDelegate, Logger.FATAL, Logger.EVENT_UNSPECIFIED, MSG, testEx);
-        Mockito.verifyNoMoreInteractions(mockBridge, mockLogDelegate);
-    }
-    @Test
-    public void testFatalWithMessageAndThrowableDisabled() {
-        testLogger.setLevel(Logger.OFF);
-        testLogger.fatal(Logger.EVENT_UNSPECIFIED, MSG, testEx);
-        Mockito.verify(mockBridge, Mockito.times(0)).log(mockLogDelegate, Logger.FATAL, Logger.EVENT_UNSPECIFIED, MSG, testEx);
-        Mockito.verifyNoMoreInteractions(mockBridge, mockLogDelegate);
-    }
-
-    @Test
-    public void testErrorWithMessage() {
-        testLogger.error(Logger.EVENT_UNSPECIFIED, MSG);
-
-        Mockito.verify(mockBridge, Mockito.times(1)).log(mockLogDelegate, Logger.ERROR, Logger.EVENT_UNSPECIFIED, MSG);
-        Mockito.verifyNoMoreInteractions(mockBridge, mockLogDelegate);
-    }
-    @Test
-    public void testErrorWithMessageAndThrowable() {
-        testLogger.error(Logger.EVENT_UNSPECIFIED, MSG, testEx);
-
-        Mockito.verify(mockBridge, Mockito.times(1)).log(mockLogDelegate, Logger.ERROR, Logger.EVENT_UNSPECIFIED, MSG, testEx);
-        Mockito.verifyNoMoreInteractions(mockBridge, mockLogDelegate);
-    }
-
-    @Test
-    public void testErrorWithMessageDisabled() {
-        testLogger.setLevel(Logger.OFF);
-        testLogger.error(Logger.EVENT_UNSPECIFIED, MSG);
-
-        Mockito.verify(mockBridge, Mockito.times(0)).log(mockLogDelegate, Logger.ERROR, Logger.EVENT_UNSPECIFIED, MSG, testEx);
-        Mockito.verifyNoMoreInteractions(mockBridge, mockLogDelegate);
-    }
-    @Test
-    public void testErrorWithMessageAndThrowableDisabled() {
-        testLogger.setLevel(Logger.OFF);
-        testLogger.error(Logger.EVENT_UNSPECIFIED, MSG, testEx);
-        Mockito.verify(mockBridge, Mockito.times(0)).log(mockLogDelegate, Logger.ERROR, Logger.EVENT_UNSPECIFIED, MSG, testEx);
-        Mockito.verifyNoMoreInteractions(mockBridge, mockLogDelegate);
-    }
-
-    @Test
-    public void testWarnWithMessage() {
-        testLogger.warning(Logger.EVENT_UNSPECIFIED, MSG);
-
-        Mockito.verify(mockBridge, Mockito.times(1)).log(mockLogDelegate, Logger.WARNING, Logger.EVENT_UNSPECIFIED, MSG);
-        Mockito.verifyNoMoreInteractions(mockBridge, mockLogDelegate);
-    }
-    @Test
-    public void testWarnWithMessageAndThrowable() {
-        testLogger.warning(Logger.EVENT_UNSPECIFIED, MSG, testEx);
-
-        Mockito.verify(mockBridge, Mockito.times(1)).log(mockLogDelegate, Logger.WARNING, Logger.EVENT_UNSPECIFIED, MSG, testEx);
-        Mockito.verifyNoMoreInteractions(mockBridge, mockLogDelegate);
-    }
-
-    @Test
-    public void testWarnWithMessageDisabled() {
-        testLogger.setLevel(Logger.OFF);
-        testLogger.warning(Logger.EVENT_UNSPECIFIED, MSG);
-
-        Mockito.verify(mockBridge, Mockito.times(0)).log(mockLogDelegate, Logger.WARNING, Logger.EVENT_UNSPECIFIED, MSG, testEx);
-        Mockito.verifyNoMoreInteractions(mockBridge, mockLogDelegate);
-    }
-    @Test
-    public void testWarnWithMessageAndThrowableDisabled() {
-        testLogger.setLevel(Logger.OFF);
-        testLogger.warning(Logger.EVENT_UNSPECIFIED, MSG, testEx);
-        Mockito.verify(mockBridge, Mockito.times(0)).log(mockLogDelegate, Logger.WARNING, Logger.EVENT_UNSPECIFIED, MSG, testEx);
-        Mockito.verifyNoMoreInteractions(mockBridge, mockLogDelegate);
-    }
-
-    @Test
-    public void testInfoWithMessage() {
-        testLogger.info(Logger.EVENT_UNSPECIFIED, MSG);
-
-        Mockito.verify(mockBridge, Mockito.times(1)).log(mockLogDelegate, Logger.INFO, Logger.EVENT_UNSPECIFIED, MSG);
-        Mockito.verifyNoMoreInteractions(mockBridge, mockLogDelegate);
-    }
-    @Test
-    public void testInfoWithMessageAndThrowable() {
-        testLogger.info(Logger.EVENT_UNSPECIFIED, MSG, testEx);
-
-        Mockito.verify(mockBridge, Mockito.times(1)).log(mockLogDelegate, Logger.INFO, Logger.EVENT_UNSPECIFIED, MSG, testEx);
-        Mockito.verifyNoMoreInteractions(mockBridge, mockLogDelegate);
-    }
-
-    @Test
-    public void testInfoWithMessageDisabled() {
-        testLogger.setLevel(Logger.OFF);
-        testLogger.info(Logger.EVENT_UNSPECIFIED, MSG);
-
-        Mockito.verify(mockBridge, Mockito.times(0)).log(mockLogDelegate, Logger.INFO, Logger.EVENT_UNSPECIFIED, MSG, testEx);
-        Mockito.verifyNoMoreInteractions(mockBridge, mockLogDelegate);
-    }
-    @Test
-    public void testInfoWithMessageAndThrowableDisabled() {
-        testLogger.setLevel(Logger.OFF);
-        testLogger.info(Logger.EVENT_UNSPECIFIED, MSG, testEx);
-        Mockito.verify(mockBridge, Mockito.times(0)).log(mockLogDelegate, Logger.INFO, Logger.EVENT_UNSPECIFIED, MSG, testEx);
-        Mockito.verifyNoMoreInteractions(mockBridge, mockLogDelegate);
-    }
-    @Test
-    public void testDebugWithMessage() {
-        testLogger.debug(Logger.EVENT_UNSPECIFIED, MSG);
-
-        Mockito.verify(mockBridge, Mockito.times(1)).log(mockLogDelegate, Logger.DEBUG, Logger.EVENT_UNSPECIFIED, MSG);
-        Mockito.verifyNoMoreInteractions(mockBridge, mockLogDelegate);
-    }
-    @Test
-    public void testDebugWithMessageAndThrowable() {
-        testLogger.debug(Logger.EVENT_UNSPECIFIED, MSG, testEx);
-
-        Mockito.verify(mockBridge, Mockito.times(1)).log(mockLogDelegate, Logger.DEBUG, Logger.EVENT_UNSPECIFIED, MSG, testEx);
-        Mockito.verifyNoMoreInteractions(mockBridge, mockLogDelegate);
-    }
-
-    @Test
-    public void testDebugWithMessageDisabled() {
-        testLogger.setLevel(Logger.OFF);
-        testLogger.debug(Logger.EVENT_UNSPECIFIED, MSG);
-
-        Mockito.verify(mockBridge, Mockito.times(0)).log(mockLogDelegate, Logger.DEBUG, Logger.EVENT_UNSPECIFIED, MSG, testEx);
-        Mockito.verifyNoMoreInteractions(mockBridge, mockLogDelegate);
-    }
-    @Test
-    public void testDebugWithMessageAndThrowableDisabled() {
-        testLogger.setLevel(Logger.OFF);
-        testLogger.debug(Logger.EVENT_UNSPECIFIED, MSG, testEx);
-        Mockito.verify(mockBridge, Mockito.times(0)).log(mockLogDelegate, Logger.DEBUG, Logger.EVENT_UNSPECIFIED, MSG, testEx);
-        Mockito.verifyNoMoreInteractions(mockBridge, mockLogDelegate);
-    }
-
-    @Test
-    public void testTraceWithMessage() {
-        testLogger.trace(Logger.EVENT_UNSPECIFIED, MSG);
-
-        Mockito.verify(mockBridge, Mockito.times(1)).log(mockLogDelegate, Logger.TRACE, Logger.EVENT_UNSPECIFIED, MSG);
-        Mockito.verifyNoMoreInteractions(mockBridge, mockLogDelegate);
-    }
-    @Test
-    public void testTraceWithMessageAndThrowable() {
-        testLogger.trace(Logger.EVENT_UNSPECIFIED, MSG, testEx);
-
-        Mockito.verify(mockBridge, Mockito.times(1)).log(mockLogDelegate, Logger.TRACE, Logger.EVENT_UNSPECIFIED, MSG, testEx);
-        Mockito.verifyNoMoreInteractions(mockBridge, mockLogDelegate);
-    }
-
-    @Test
-    public void testTraceWithMessageDisabled() {
-        testLogger.setLevel(Logger.OFF);
-        testLogger.trace(Logger.EVENT_UNSPECIFIED, MSG);
-
-        Mockito.verify(mockBridge, Mockito.times(0)).log(mockLogDelegate, Logger.TRACE, Logger.EVENT_UNSPECIFIED, MSG, testEx);
-        Mockito.verifyNoMoreInteractions(mockBridge, mockLogDelegate);
-    }
-    @Test
-    public void testTraceWithMessageAndThrowableDisabled() {
-        testLogger.setLevel(Logger.OFF);
-        testLogger.trace(Logger.EVENT_UNSPECIFIED, MSG, testEx);
-        Mockito.verify(mockBridge, Mockito.times(0)).log(mockLogDelegate, Logger.TRACE, Logger.EVENT_UNSPECIFIED, MSG, testEx);
-        Mockito.verifyNoMoreInteractions(mockBridge, mockLogDelegate);
-    }
-
-    @Test
-    public void testAlwaysWithMessage() {
-        testLogger.always(Logger.EVENT_UNSPECIFIED, MSG);
-
-        Mockito.verify(mockBridge, Mockito.times(1)).log(mockLogDelegate, Logger.ALL, Logger.EVENT_UNSPECIFIED, MSG);
-        Mockito.verifyNoMoreInteractions(mockBridge, mockLogDelegate);
-    }
-    @Test
-    public void testAlwaysWithMessageAndThrowable() {
-        testLogger.always(Logger.EVENT_UNSPECIFIED, MSG, testEx);
-
-        Mockito.verify(mockBridge, Mockito.times(1)).log(mockLogDelegate, Logger.ALL, Logger.EVENT_UNSPECIFIED, MSG, testEx);
-        Mockito.verifyNoMoreInteractions(mockBridge, mockLogDelegate);
-    }
-
-    @Test
-    public void testAlwaysWithMessageDisabled() {
-        testLogger.setLevel(Logger.OFF);
-        testLogger.always(Logger.EVENT_UNSPECIFIED, MSG);
-
-        Mockito.verify(mockBridge, Mockito.times(0)).log(mockLogDelegate, Logger.ALL, Logger.EVENT_UNSPECIFIED, MSG, testEx);
-        Mockito.verifyNoMoreInteractions(mockBridge, mockLogDelegate);
-    }
-    @Test
-    public void testAlwaysWithMessageAndThrowableDisabled() {
-        testLogger.setLevel(Logger.OFF);
-        testLogger.always(Logger.EVENT_UNSPECIFIED, MSG, testEx);
-        Mockito.verify(mockBridge, Mockito.times(0)).log(mockLogDelegate, Logger.ALL, Logger.EVENT_UNSPECIFIED, MSG, testEx);
-        Mockito.verifyNoMoreInteractions(mockBridge, mockLogDelegate);
-    }
-}
diff --git a/src/test/java/org/owasp/esapi/logging/slf4j/Slf4JLogBridgeImplTest.java b/src/test/java/org/owasp/esapi/logging/slf4j/Slf4JLogBridgeImplTest.java
index f9586a8..97398d9 100644
--- a/src/test/java/org/owasp/esapi/logging/slf4j/Slf4JLogBridgeImplTest.java
+++ b/src/test/java/org/owasp/esapi/logging/slf4j/Slf4JLogBridgeImplTest.java
@@ -1,15 +1,15 @@
 /**
  * OWASP Enterprise Security API (ESAPI)
- * 
+ *
  * This file is part of the Open Web Application Security Project (OWASP)
  * Enterprise Security API (ESAPI) project. For details, please see
  * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
  *
  * Copyright (c) 2007 - The OWASP Foundation
- * 
+ *
  * The ESAPI is published by OWASP under the BSD license. You should read and accept the
  * LICENSE before you use, modify, and/or redistribute this software.
- * 
+ *
  * @created 2018
  */
 package org.owasp.esapi.logging.slf4j;
@@ -51,6 +51,7 @@ public class Slf4JLogBridgeImplTest {
     public void setup() {
         Map<Integer, Slf4JLogLevelHandler> levelLookup = new HashMap<>();
         levelLookup.put(Logger.ALL, mockHandler);
+        levelLookup.put(Logger.ERROR, mockHandler);
 
         bridge = new Slf4JLogBridgeImpl(mockAppender, mockScrubber, levelLookup);
     }
@@ -62,7 +63,7 @@ public class Slf4JLogBridgeImplTest {
         Map<Integer, Slf4JLogLevelHandler> emptyMap = Collections.emptyMap();
         new Slf4JLogBridgeImpl(mockAppender, mockScrubber, emptyMap).log(mockSlf4JLogger, 0, Logger.EVENT_UNSPECIFIED, "This Should fail");
     }
-    
+
     @Test
     public void testLogMessageAndExceptionWithUnmappedEsapiLevelThrowsException() {
         exEx.expect(IllegalArgumentException.class);
@@ -70,13 +71,13 @@ public class Slf4JLogBridgeImplTest {
         Map<Integer, Slf4JLogLevelHandler> emptyMap = Collections.emptyMap();
         new Slf4JLogBridgeImpl(mockAppender, mockScrubber, emptyMap).log(mockSlf4JLogger, 0, Logger.EVENT_UNSPECIFIED, "This Should fail", testEx);
     }
-    
+
     @Test
     public void testLogMessage() {
-    	EventType eventType = Logger.EVENT_UNSPECIFIED;
-    	String loggerName = testName.getMethodName() + "-LOGGER";
-    	String orignMsg = testName.getMethodName();
-    	String appendMsg = "[APPEND] " + orignMsg;
+        EventType eventType = Logger.EVENT_UNSPECIFIED;
+        String loggerName = testName.getMethodName() + "-LOGGER";
+        String orignMsg = testName.getMethodName();
+        String appendMsg = "[APPEND] " + orignMsg;
         String cleanMsg = appendMsg + " [CLEANED]";
 
         //Setup for Appender
@@ -96,17 +97,17 @@ public class Slf4JLogBridgeImplTest {
         Mockito.verify(mockHandler, Mockito.times(1)).isEnabled(mockSlf4JLogger);
         Mockito.verify(mockHandler, Mockito.times(0)).log(ArgumentMatchers.any(org.slf4j.Logger.class), ArgumentMatchers.any(Marker.class), ArgumentMatchers.any(String.class), ArgumentMatchers.any(Throwable.class));
         Mockito.verify(mockHandler, Mockito.times(1)).log(ArgumentMatchers.same(mockSlf4JLogger), markerCapture.capture(), ArgumentMatchers.eq(cleanMsg));
-     
+
         Assert.assertEquals(Logger.EVENT_UNSPECIFIED.toString(), markerCapture.getValue().getName());
         Mockito.verifyNoMoreInteractions(mockSlf4JLogger, mockAppender, mockScrubber,mockHandler);
     }
 
     @Test
     public void testLogErrorMessageWithException() {
-    	EventType eventType = Logger.EVENT_UNSPECIFIED;
-    	String loggerName = testName.getMethodName() + "-LOGGER";
-    	String orignMsg = testName.getMethodName();
-    	String appendMsg = "[APPEND] " + orignMsg;
+        EventType eventType = Logger.EVENT_UNSPECIFIED;
+        String loggerName = testName.getMethodName() + "-LOGGER";
+        String orignMsg = testName.getMethodName();
+        String appendMsg = "[APPEND] " + orignMsg;
         String cleanMsg = appendMsg + " [CLEANED]";
 
         //Setup for Appender
@@ -127,7 +128,7 @@ public class Slf4JLogBridgeImplTest {
         Mockito.verify(mockHandler, Mockito.times(0)).log(ArgumentMatchers.any(org.slf4j.Logger.class), ArgumentMatchers.any(Marker.class), ArgumentMatchers.any(String.class));
 
         Mockito.verify(mockHandler, Mockito.times(1)).log(ArgumentMatchers.same(mockSlf4JLogger), markerCapture.capture(), ArgumentMatchers.eq(cleanMsg), ArgumentMatchers.same(testEx));
-     
+
         Assert.assertEquals(Logger.EVENT_UNSPECIFIED.toString(), markerCapture.getValue().getName());
         Mockito.verifyNoMoreInteractions(mockSlf4JLogger, mockAppender, mockScrubber,mockHandler);
     }
@@ -158,4 +159,21 @@ public class Slf4JLogBridgeImplTest {
 
     }
 
+
+    @Test
+    public void testNullEventTypeUsesUnspecified() {
+        EventType computedEventType = Logger.EVENT_UNSPECIFIED;
+
+        //Setup for Delegate Handler
+        ArgumentCaptor<Marker> markerCapture = ArgumentCaptor.forClass(Marker.class);
+        Mockito.when(mockHandler.isEnabled(mockSlf4JLogger)).thenReturn(true);
+
+        bridge.log(mockSlf4JLogger, Logger.ALL, null, testName.getMethodName());
+
+        Mockito.verify(mockHandler).log(ArgumentMatchers.any(), markerCapture.capture(), ArgumentMatchers.any());
+        Mockito.verify(mockAppender).appendTo(ArgumentMatchers.any(), ArgumentMatchers.eq(computedEventType), ArgumentMatchers.any());
+
+        Assert.assertEquals(computedEventType.toString(), markerCapture.getValue().getName());
+    }
+
 }
diff --git a/src/test/java/org/owasp/esapi/logging/slf4j/Slf4JLogFactoryTest.java b/src/test/java/org/owasp/esapi/logging/slf4j/Slf4JLogFactoryTest.java
index c392f1d..12a16af 100644
--- a/src/test/java/org/owasp/esapi/logging/slf4j/Slf4JLogFactoryTest.java
+++ b/src/test/java/org/owasp/esapi/logging/slf4j/Slf4JLogFactoryTest.java
@@ -1,15 +1,15 @@
 /**
  * OWASP Enterprise Security API (ESAPI)
- * 
+ *
  * This file is part of the Open Web Application Security Project (OWASP)
  * Enterprise Security API (ESAPI) project. For details, please see
  * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
  *
  * Copyright (c) 2007 - The OWASP Foundation
- * 
+ *
  * The ESAPI is published by OWASP under the BSD license. You should read and accept the
  * LICENSE before you use, modify, and/or redistribute this software.
- * 
+ *
  * @created 2018
  */
 package org.owasp.esapi.logging.slf4j;
@@ -36,53 +36,53 @@ import org.powermock.modules.junit4.PowerMockRunner;
 @RunWith(PowerMockRunner.class)
 @PrepareForTest (Slf4JLogFactory.class)
 public class Slf4JLogFactoryTest {
-	@Rule
+    @Rule
     public TestName testName = new TestName();
-	
+
     @Test
     public void testCreateLoggerByString() {
         Logger logger = new Slf4JLogFactory().getLogger("test");
         Assert.assertTrue(logger instanceof Slf4JLogger);
     }
-    
+
     @Test public void testCreateLoggerByClass() {
         Logger logger = new Slf4JLogFactory().getLogger(Slf4JLogBridgeImplTest.class);
         Assert.assertTrue(logger instanceof Slf4JLogger);
     }
-    
+
     @Test
     public void checkScrubberWithEncoding() throws Exception {
         ArgumentCaptor<List> delegates = ArgumentCaptor.forClass(List.class);
         PowerMockito.whenNew(CompositeLogScrubber.class).withArguments(delegates.capture()).thenReturn(null);
-        
+
         //Call to invoke the constructor capture
         Slf4JLogFactory.createLogScrubber(true);
-        
+
         List<LogScrubber> scrubbers = delegates.getValue();
         Assert.assertEquals(2, scrubbers.size());
         Assert.assertTrue(scrubbers.get(0) instanceof NewlineLogScrubber);
         Assert.assertTrue(scrubbers.get(1) instanceof CodecLogScrubber);
     }
-    
+
     @Test
     public void checkScrubberWithoutEncoding() throws Exception {
         ArgumentCaptor<List> delegates = ArgumentCaptor.forClass(List.class);
         PowerMockito.whenNew(CompositeLogScrubber.class).withArguments(delegates.capture()).thenReturn(null);
-        
+
         //Call to invoke the constructor capture
         Slf4JLogFactory.createLogScrubber(false);
-        
+
         List<LogScrubber> scrubbers = delegates.getValue();
         Assert.assertEquals(1, scrubbers.size());
         Assert.assertTrue(scrubbers.get(0) instanceof NewlineLogScrubber);
     }
-    
+
     /**
-	 * At this time there are no special considerations or handling for the appender
-	 * creation in this scope. It is expected that the arguments to the internal
-	 * creation method are passed directly to the constructor of the
-	 * LogPrefixAppender with no mutation or additional validation.
-	 */
+     * At this time there are no special considerations or handling for the appender
+     * creation in this scope. It is expected that the arguments to the internal
+     * creation method are passed directly to the constructor of the
+     * LogPrefixAppender with no mutation or additional validation.
+     */
     @Test
     public void checkPassthroughAppenderConstruct() throws Exception {
         LogPrefixAppender stubAppender = new LogPrefixAppender(true, true, true, true, "");
@@ -94,15 +94,15 @@ public class Slf4JLogFactoryTest {
 
         PowerMockito.whenNew(LogPrefixAppender.class).withArguments(userInfoCapture.capture(), clientInfoCapture.capture(), serverInfoCapture.capture(), logAppNameCapture.capture(), appNameCapture.capture()).thenReturn(stubAppender);
 
-    	LogAppender appender = Slf4JLogFactory.createLogAppender(true, true, false, true, testName.getMethodName());
-    	
-    	Assert.assertEquals(stubAppender, appender);
-    	Assert.assertTrue(userInfoCapture.getValue());
-    	Assert.assertTrue(clientInfoCapture.getValue());
-    	Assert.assertFalse(serverInfoCapture.getValue());
-    	Assert.assertTrue(logAppNameCapture.getValue());
-    	Assert.assertEquals(testName.getMethodName(), appNameCapture.getValue());    	
+        LogAppender appender = Slf4JLogFactory.createLogAppender(true, true, false, true, testName.getMethodName());
+
+        Assert.assertEquals(stubAppender, appender);
+        Assert.assertTrue(userInfoCapture.getValue());
+        Assert.assertTrue(clientInfoCapture.getValue());
+        Assert.assertFalse(serverInfoCapture.getValue());
+        Assert.assertTrue(logAppNameCapture.getValue());
+        Assert.assertEquals(testName.getMethodName(), appNameCapture.getValue());
     }
-    
-   
+
+
 }
diff --git a/src/test/java/org/owasp/esapi/logging/slf4j/Slf4JLogLevelHandlersTest.java b/src/test/java/org/owasp/esapi/logging/slf4j/Slf4JLogLevelHandlersTest.java
index e5607c4..73e4833 100644
--- a/src/test/java/org/owasp/esapi/logging/slf4j/Slf4JLogLevelHandlersTest.java
+++ b/src/test/java/org/owasp/esapi/logging/slf4j/Slf4JLogLevelHandlersTest.java
@@ -1,15 +1,15 @@
 /**
  * OWASP Enterprise Security API (ESAPI)
- * 
+ *
  * This file is part of the Open Web Application Security Project (OWASP)
  * Enterprise Security API (ESAPI) project. For details, please see
  * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
  *
  * Copyright (c) 2007 - The OWASP Foundation
- * 
+ *
  * The ESAPI is published by OWASP under the BSD license. You should read and accept the
  * LICENSE before you use, modify, and/or redistribute this software.
- * 
+ *
  * @created 2018
  */
 package org.owasp.esapi.logging.slf4j;
diff --git a/src/test/java/org/owasp/esapi/logging/slf4j/Slf4JLoggerTest.java b/src/test/java/org/owasp/esapi/logging/slf4j/Slf4JLoggerTest.java
index 70687f4..77e718d 100644
--- a/src/test/java/org/owasp/esapi/logging/slf4j/Slf4JLoggerTest.java
+++ b/src/test/java/org/owasp/esapi/logging/slf4j/Slf4JLoggerTest.java
@@ -1,15 +1,15 @@
 /**
  * OWASP Enterprise Security API (ESAPI)
- * 
+ *
  * This file is part of the Open Web Application Security Project (OWASP)
  * Enterprise Security API (ESAPI) project. For details, please see
  * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
  *
  * Copyright (c) 2007 - The OWASP Foundation
- * 
+ *
  * The ESAPI is published by OWASP under the BSD license. You should read and accept the
  * LICENSE before you use, modify, and/or redistribute this software.
- * 
+ *
  * @created 2018
  */
 
@@ -21,33 +21,33 @@ import org.mockito.Mockito;
 import org.owasp.esapi.Logger;
 
 public class Slf4JLoggerTest {
-    
+
     private static final String MSG = Slf4JLoggerTest.class.getSimpleName();
-    
+
     private Slf4JLogBridge mockBridge = Mockito.mock(Slf4JLogBridge.class);
     private org.slf4j.Logger mockLogDelegate = Mockito.mock(org.slf4j.Logger.class);
-    
+
     private Throwable testEx = new Throwable(MSG + "_Exception");
     private Logger testLogger = new Slf4JLogger(mockLogDelegate, mockBridge, Logger.ALL);
 
     @Test
     public void testLevelEnablement() {
         testLogger.setLevel(Logger.INFO);
-        
+
         Assert.assertTrue(testLogger.isFatalEnabled());
         Assert.assertTrue(testLogger.isErrorEnabled());
         Assert.assertTrue(testLogger.isWarningEnabled());
         Assert.assertTrue(testLogger.isInfoEnabled());
         Assert.assertFalse(testLogger.isDebugEnabled());
         Assert.assertFalse(testLogger.isTraceEnabled());
-        
+
         Assert.assertEquals(Logger.INFO, testLogger.getESAPILevel());
     }
-    
+
     @Test
     public void testAllLevelEnablement() {
         testLogger.setLevel(Logger.ALL);
-        
+
         Assert.assertTrue(testLogger.isFatalEnabled());
         Assert.assertTrue(testLogger.isErrorEnabled());
         Assert.assertTrue(testLogger.isWarningEnabled());
@@ -59,7 +59,7 @@ public class Slf4JLoggerTest {
     @Test
     public void testOffLevelEnablement() {
         testLogger.setLevel(Logger.OFF);
-        
+
         Assert.assertFalse(testLogger.isFatalEnabled());
         Assert.assertFalse(testLogger.isErrorEnabled());
         Assert.assertFalse(testLogger.isWarningEnabled());
@@ -70,23 +70,23 @@ public class Slf4JLoggerTest {
     @Test
     public void testFatalWithMessage() {
         testLogger.fatal(Logger.EVENT_UNSPECIFIED, MSG);
-        
+
         Mockito.verify(mockBridge, Mockito.times(1)).log(mockLogDelegate, Logger.FATAL, Logger.EVENT_UNSPECIFIED, MSG);
         Mockito.verifyNoMoreInteractions(mockBridge, mockLogDelegate);
     }
     @Test
     public void testFatalWithMessageAndThrowable() {
         testLogger.fatal(Logger.EVENT_UNSPECIFIED, MSG, testEx);
-        
+
         Mockito.verify(mockBridge, Mockito.times(1)).log(mockLogDelegate, Logger.FATAL, Logger.EVENT_UNSPECIFIED, MSG, testEx);
         Mockito.verifyNoMoreInteractions(mockBridge, mockLogDelegate);
     }
-    
+
     @Test
     public void testFatalWithMessageDisabled() {
         testLogger.setLevel(Logger.OFF);
         testLogger.fatal(Logger.EVENT_UNSPECIFIED, MSG);
-        
+
         Mockito.verify(mockBridge, Mockito.times(0)).log(mockLogDelegate, Logger.FATAL, Logger.EVENT_UNSPECIFIED, MSG, testEx);
         Mockito.verifyNoMoreInteractions(mockBridge, mockLogDelegate);
     }
@@ -97,27 +97,27 @@ public class Slf4JLoggerTest {
         Mockito.verify(mockBridge, Mockito.times(0)).log(mockLogDelegate, Logger.FATAL, Logger.EVENT_UNSPECIFIED, MSG, testEx);
         Mockito.verifyNoMoreInteractions(mockBridge, mockLogDelegate);
     }
-    
+
     @Test
     public void testErrorWithMessage() {
         testLogger.error(Logger.EVENT_UNSPECIFIED, MSG);
-        
+
         Mockito.verify(mockBridge, Mockito.times(1)).log(mockLogDelegate, Logger.ERROR, Logger.EVENT_UNSPECIFIED, MSG);
         Mockito.verifyNoMoreInteractions(mockBridge, mockLogDelegate);
     }
     @Test
     public void testErrorWithMessageAndThrowable() {
         testLogger.error(Logger.EVENT_UNSPECIFIED, MSG, testEx);
-        
+
         Mockito.verify(mockBridge, Mockito.times(1)).log(mockLogDelegate, Logger.ERROR, Logger.EVENT_UNSPECIFIED, MSG, testEx);
         Mockito.verifyNoMoreInteractions(mockBridge, mockLogDelegate);
     }
-    
+
     @Test
     public void testErrorWithMessageDisabled() {
         testLogger.setLevel(Logger.OFF);
         testLogger.error(Logger.EVENT_UNSPECIFIED, MSG);
-        
+
         Mockito.verify(mockBridge, Mockito.times(0)).log(mockLogDelegate, Logger.ERROR, Logger.EVENT_UNSPECIFIED, MSG, testEx);
         Mockito.verifyNoMoreInteractions(mockBridge, mockLogDelegate);
     }
@@ -128,27 +128,27 @@ public class Slf4JLoggerTest {
         Mockito.verify(mockBridge, Mockito.times(0)).log(mockLogDelegate, Logger.ERROR, Logger.EVENT_UNSPECIFIED, MSG, testEx);
         Mockito.verifyNoMoreInteractions(mockBridge, mockLogDelegate);
     }
-    
+
     @Test
     public void testWarnWithMessage() {
         testLogger.warning(Logger.EVENT_UNSPECIFIED, MSG);
-        
+
         Mockito.verify(mockBridge, Mockito.times(1)).log(mockLogDelegate, Logger.WARNING, Logger.EVENT_UNSPECIFIED, MSG);
         Mockito.verifyNoMoreInteractions(mockBridge, mockLogDelegate);
     }
     @Test
     public void testWarnWithMessageAndThrowable() {
         testLogger.warning(Logger.EVENT_UNSPECIFIED, MSG, testEx);
-        
+
         Mockito.verify(mockBridge, Mockito.times(1)).log(mockLogDelegate, Logger.WARNING, Logger.EVENT_UNSPECIFIED, MSG, testEx);
         Mockito.verifyNoMoreInteractions(mockBridge, mockLogDelegate);
     }
-    
+
     @Test
     public void testWarnWithMessageDisabled() {
         testLogger.setLevel(Logger.OFF);
         testLogger.warning(Logger.EVENT_UNSPECIFIED, MSG);
-        
+
         Mockito.verify(mockBridge, Mockito.times(0)).log(mockLogDelegate, Logger.WARNING, Logger.EVENT_UNSPECIFIED, MSG, testEx);
         Mockito.verifyNoMoreInteractions(mockBridge, mockLogDelegate);
     }
@@ -159,27 +159,27 @@ public class Slf4JLoggerTest {
         Mockito.verify(mockBridge, Mockito.times(0)).log(mockLogDelegate, Logger.WARNING, Logger.EVENT_UNSPECIFIED, MSG, testEx);
         Mockito.verifyNoMoreInteractions(mockBridge, mockLogDelegate);
     }
-    
+
     @Test
     public void testInfoWithMessage() {
         testLogger.info(Logger.EVENT_UNSPECIFIED, MSG);
-        
+
         Mockito.verify(mockBridge, Mockito.times(1)).log(mockLogDelegate, Logger.INFO, Logger.EVENT_UNSPECIFIED, MSG);
         Mockito.verifyNoMoreInteractions(mockBridge, mockLogDelegate);
     }
     @Test
     public void testInfoWithMessageAndThrowable() {
         testLogger.info(Logger.EVENT_UNSPECIFIED, MSG, testEx);
-        
+
         Mockito.verify(mockBridge, Mockito.times(1)).log(mockLogDelegate, Logger.INFO, Logger.EVENT_UNSPECIFIED, MSG, testEx);
         Mockito.verifyNoMoreInteractions(mockBridge, mockLogDelegate);
     }
-    
+
     @Test
     public void testInfoWithMessageDisabled() {
         testLogger.setLevel(Logger.OFF);
         testLogger.info(Logger.EVENT_UNSPECIFIED, MSG);
-        
+
         Mockito.verify(mockBridge, Mockito.times(0)).log(mockLogDelegate, Logger.INFO, Logger.EVENT_UNSPECIFIED, MSG, testEx);
         Mockito.verifyNoMoreInteractions(mockBridge, mockLogDelegate);
     }
@@ -193,23 +193,23 @@ public class Slf4JLoggerTest {
     @Test
     public void testDebugWithMessage() {
         testLogger.debug(Logger.EVENT_UNSPECIFIED, MSG);
-        
+
         Mockito.verify(mockBridge, Mockito.times(1)).log(mockLogDelegate, Logger.DEBUG, Logger.EVENT_UNSPECIFIED, MSG);
         Mockito.verifyNoMoreInteractions(mockBridge, mockLogDelegate);
     }
     @Test
     public void testDebugWithMessageAndThrowable() {
         testLogger.debug(Logger.EVENT_UNSPECIFIED, MSG, testEx);
-        
+
         Mockito.verify(mockBridge, Mockito.times(1)).log(mockLogDelegate, Logger.DEBUG, Logger.EVENT_UNSPECIFIED, MSG, testEx);
         Mockito.verifyNoMoreInteractions(mockBridge, mockLogDelegate);
     }
-    
+
     @Test
     public void testDebugWithMessageDisabled() {
         testLogger.setLevel(Logger.OFF);
         testLogger.debug(Logger.EVENT_UNSPECIFIED, MSG);
-        
+
         Mockito.verify(mockBridge, Mockito.times(0)).log(mockLogDelegate, Logger.DEBUG, Logger.EVENT_UNSPECIFIED, MSG, testEx);
         Mockito.verifyNoMoreInteractions(mockBridge, mockLogDelegate);
     }
@@ -220,27 +220,27 @@ public class Slf4JLoggerTest {
         Mockito.verify(mockBridge, Mockito.times(0)).log(mockLogDelegate, Logger.DEBUG, Logger.EVENT_UNSPECIFIED, MSG, testEx);
         Mockito.verifyNoMoreInteractions(mockBridge, mockLogDelegate);
     }
-    
+
     @Test
     public void testTraceWithMessage() {
         testLogger.trace(Logger.EVENT_UNSPECIFIED, MSG);
-        
+
         Mockito.verify(mockBridge, Mockito.times(1)).log(mockLogDelegate, Logger.TRACE, Logger.EVENT_UNSPECIFIED, MSG);
         Mockito.verifyNoMoreInteractions(mockBridge, mockLogDelegate);
     }
     @Test
     public void testTraceWithMessageAndThrowable() {
         testLogger.trace(Logger.EVENT_UNSPECIFIED, MSG, testEx);
-        
+
         Mockito.verify(mockBridge, Mockito.times(1)).log(mockLogDelegate, Logger.TRACE, Logger.EVENT_UNSPECIFIED, MSG, testEx);
         Mockito.verifyNoMoreInteractions(mockBridge, mockLogDelegate);
     }
-    
+
     @Test
     public void testTraceWithMessageDisabled() {
         testLogger.setLevel(Logger.OFF);
         testLogger.trace(Logger.EVENT_UNSPECIFIED, MSG);
-        
+
         Mockito.verify(mockBridge, Mockito.times(0)).log(mockLogDelegate, Logger.TRACE, Logger.EVENT_UNSPECIFIED, MSG, testEx);
         Mockito.verifyNoMoreInteractions(mockBridge, mockLogDelegate);
     }
@@ -251,27 +251,27 @@ public class Slf4JLoggerTest {
         Mockito.verify(mockBridge, Mockito.times(0)).log(mockLogDelegate, Logger.TRACE, Logger.EVENT_UNSPECIFIED, MSG, testEx);
         Mockito.verifyNoMoreInteractions(mockBridge, mockLogDelegate);
     }
-    
+
     @Test
     public void testAlwaysWithMessage() {
         testLogger.always(Logger.EVENT_UNSPECIFIED, MSG);
-        
+
         Mockito.verify(mockBridge, Mockito.times(1)).log(mockLogDelegate, Logger.ALL, Logger.EVENT_UNSPECIFIED, MSG);
         Mockito.verifyNoMoreInteractions(mockBridge, mockLogDelegate);
     }
     @Test
     public void testAlwaysWithMessageAndThrowable() {
         testLogger.always(Logger.EVENT_UNSPECIFIED, MSG, testEx);
-        
+
         Mockito.verify(mockBridge, Mockito.times(1)).log(mockLogDelegate, Logger.ALL, Logger.EVENT_UNSPECIFIED, MSG, testEx);
         Mockito.verifyNoMoreInteractions(mockBridge, mockLogDelegate);
     }
-    
+
     @Test
     public void testAlwaysWithMessageDisabled() {
         testLogger.setLevel(Logger.OFF);
         testLogger.always(Logger.EVENT_UNSPECIFIED, MSG);
-        
+
         Mockito.verify(mockBridge, Mockito.times(0)).log(mockLogDelegate, Logger.ALL, Logger.EVENT_UNSPECIFIED, MSG, testEx);
         Mockito.verifyNoMoreInteractions(mockBridge, mockLogDelegate);
     }
diff --git a/src/test/java/org/owasp/esapi/reference/AbstractAccessReferenceMapTest.java b/src/test/java/org/owasp/esapi/reference/AbstractAccessReferenceMapTest.java
index 810a2bf..3d78362 100644
--- a/src/test/java/org/owasp/esapi/reference/AbstractAccessReferenceMapTest.java
+++ b/src/test/java/org/owasp/esapi/reference/AbstractAccessReferenceMapTest.java
@@ -48,7 +48,7 @@ public class AbstractAccessReferenceMapTest {
                         e.printStackTrace();
                     }
 
-                } 
+                }
             }
         };
 
@@ -65,7 +65,7 @@ public class AbstractAccessReferenceMapTest {
 
         Mockito.verify(map,Mockito.times(1)).getUniqueReference();
     }
-    
+
     @Test
     public void verifyNoDuplicateKeysOnUpdateReplace() {
         @SuppressWarnings("unchecked")
@@ -74,26 +74,26 @@ public class AbstractAccessReferenceMapTest {
                 );
         Object indirectObj1 = new Object();
         Object indirectObj2 = new Object();
-        Mockito.when(map.getUniqueReference()).thenReturn(indirectObj1); 
-        
+        Mockito.when(map.getUniqueReference()).thenReturn(indirectObj1);
+
         Object direct1 = new Object();
         Object direct2 = new Object();
-        
+
         map.addDirectReference(direct1);
-        
+
         Mockito.reset(map);
-        
+
         Set<Object> newDirectElements = new HashSet<>();
         newDirectElements.add(direct2);
         newDirectElements.add(direct1);
-        
-        Mockito.when(map.getUniqueReference()).thenReturn(indirectObj1).thenReturn(indirectObj2); 
-        
+
+        Mockito.when(map.getUniqueReference()).thenReturn(indirectObj1).thenReturn(indirectObj2);
+
         map.update(newDirectElements);
-        
+
         //Needs to be called 2 times to get past the first duplicate key. This verifies that we're inserting unique pairs.
         Mockito.verify(map, Mockito.times(2)).getUniqueReference();
-        
+
         Assert.assertEquals(indirectObj1, map.getIndirectReference(direct1));
         Assert.assertEquals(indirectObj2, map.getIndirectReference(direct2));
     }
diff --git a/src/test/java/org/owasp/esapi/reference/AccessControllerTest.java b/src/test/java/org/owasp/esapi/reference/AccessControllerTest.java
index 107c1da..a2c20c2 100644
--- a/src/test/java/org/owasp/esapi/reference/AccessControllerTest.java
+++ b/src/test/java/org/owasp/esapi/reference/AccessControllerTest.java
@@ -1,15 +1,15 @@
 /**
  * OWASP Enterprise Security API (ESAPI)
- * 
+ *
  * This file is part of the Open Web Application Security Project (OWASP)
  * Enterprise Security API (ESAPI) project. For details, please see
  * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
  *
  * Copyright (c) 2007 - The OWASP Foundation
- * 
+ *
  * The ESAPI is published by OWASP under the BSD license. You should read and accept the
  * LICENSE before you use, modify, and/or redistribute this software.
- * 
+ *
  * @author Jeff Williams <a href="http://www.aspectsecurity.com">Aspect Security</a>
  * @created 2007
  */
@@ -28,331 +28,331 @@ import org.owasp.esapi.errors.AccessControlException;
 
 /**
  * The Class AccessControllerTest.
- * 
+ *
  * @author Jeff Williams (jeff.williams@aspectsecurity.com)
  */
 public class AccessControllerTest extends TestCase {
 
-	/**
-	 * Instantiates a new access controller test.
-	 * 
-	 * @param testName
+    /**
+     * Instantiates a new access controller test.
+     *
+     * @param testName
      *            the test name
      * @throws Exception
-	 */
-	public AccessControllerTest(String testName) throws Exception {
-		super(testName);
-		
-		Authenticator authenticator = ESAPI.authenticator();
-		String password = authenticator.generateStrongPassword();
-
-		// create a user with the "user" role for this test
-		User alice = authenticator.getUser("testuser1");
-		if ( alice == null ) {
-			alice = authenticator.createUser( "testuser1", password, password);
-		}
-		alice.addRole("user");		
-
-		// create a user with the "admin" role for this test
-		User bob = authenticator.getUser("testuser2");
-		if ( bob == null ) {
-			bob = authenticator.createUser( "testuser2", password, password);
-		}
-		bob.addRole("admin");
-		
-		// create a user with the "user" and "admin" roles for this test
-		User mitch = authenticator.getUser("testuser3");
-		if ( mitch == null ) {
-			mitch = authenticator.createUser( "testuser3", password, password);
-		}
-		mitch.addRole("admin");
-		mitch.addRole("user");
-	}
+     */
+    public AccessControllerTest(String testName) throws Exception {
+        super(testName);
+
+        Authenticator authenticator = ESAPI.authenticator();
+        String password = authenticator.generateStrongPassword();
+
+        // create a user with the "user" role for this test
+        User alice = authenticator.getUser("testuser1");
+        if ( alice == null ) {
+            alice = authenticator.createUser( "testuser1", password, password);
+        }
+        alice.addRole("user");
+
+        // create a user with the "admin" role for this test
+        User bob = authenticator.getUser("testuser2");
+        if ( bob == null ) {
+            bob = authenticator.createUser( "testuser2", password, password);
+        }
+        bob.addRole("admin");
+
+        // create a user with the "user" and "admin" roles for this test
+        User mitch = authenticator.getUser("testuser3");
+        if ( mitch == null ) {
+            mitch = authenticator.createUser( "testuser3", password, password);
+        }
+        mitch.addRole("admin");
+        mitch.addRole("user");
+    }
 
     /**
      * {@inheritDoc}
      *
      * @throws Exception
      */
-	protected void setUp() throws Exception {
-	}
+    protected void setUp() throws Exception {
+    }
 
     /**
      * {@inheritDoc}
      *
      * @throws Exception
      */
-	protected void tearDown() throws Exception {
-		// none
-	}
-
-	/**
-	 * Suite.
-	 * 
-	 * @return the test
-	 */
-	public static Test suite() {
-		TestSuite suite = new TestSuite(AccessControllerTest.class);
-		return suite;
-	}
+    protected void tearDown() throws Exception {
+        // none
+    }
+
+    /**
+     * Suite.
+     *
+     * @return the test
+     */
+    public static Test suite() {
+        TestSuite suite = new TestSuite(AccessControllerTest.class);
+        return suite;
+    }
 
     /**
      *
      */
     public void testMatchRule() {
-		ESAPI.authenticator().setCurrentUser(null);
-		assertFalse(ESAPI.accessController().isAuthorizedForURL("/nobody"));
-	}
-	
-	/**
-	 * Test of isAuthorizedForURL method, of class
-	 * org.owasp.esapi.AccessController.
+        ESAPI.authenticator().setCurrentUser(null);
+        assertFalse(ESAPI.accessController().isAuthorizedForURL("/nobody"));
+    }
+
+    /**
+     * Test of isAuthorizedForURL method, of class
+     * org.owasp.esapi.AccessController.
      *
      * @throws Exception
      */
-	public void testIsAuthorizedForURL() throws Exception {
-		System.out.println("isAuthorizedForURL");
-		AccessController instance = ESAPI.accessController();
-		Authenticator auth = ESAPI.authenticator();
-		
-		auth.setCurrentUser( auth.getUser("testuser1") );
-		assertFalse(instance.isAuthorizedForURL("/nobody"));
-		assertFalse(instance.isAuthorizedForURL("/test/admin"));
-		assertTrue(instance.isAuthorizedForURL("/test/user"));
-		assertTrue(instance.isAuthorizedForURL("/test/all"));
-		assertFalse(instance.isAuthorizedForURL("/test/none"));
-		assertTrue(instance.isAuthorizedForURL("/test/none/test.gif"));
-		assertFalse(instance.isAuthorizedForURL("/test/none/test.exe"));
-		assertTrue(instance.isAuthorizedForURL("/test/none/test.png"));
-		assertFalse(instance.isAuthorizedForURL("/test/moderator"));
-		assertTrue(instance.isAuthorizedForURL("/test/profile"));
-		assertFalse(instance.isAuthorizedForURL("/upload"));
-
-		auth.setCurrentUser( auth.getUser("testuser2") );
-		assertFalse(instance.isAuthorizedForURL("/nobody"));
-		assertTrue(instance.isAuthorizedForURL("/test/admin"));
-		assertFalse(instance.isAuthorizedForURL("/test/user"));
-		assertTrue(instance.isAuthorizedForURL("/test/all"));
-		assertFalse(instance.isAuthorizedForURL("/test/none"));
-		assertTrue(instance.isAuthorizedForURL("/test/none/test.png"));
-		assertFalse(instance.isAuthorizedForURL("/test/moderator"));
-		assertTrue(instance.isAuthorizedForURL("/test/profile"));
-		assertFalse(instance.isAuthorizedForURL("/upload"));
-		
-		auth.setCurrentUser( auth.getUser("testuser3") );
-		assertFalse(instance.isAuthorizedForURL("/nobody"));
-		assertTrue(instance.isAuthorizedForURL("/test/admin"));
-		assertTrue(instance.isAuthorizedForURL("/test/user"));
-		assertTrue(instance.isAuthorizedForURL("/test/all"));
-		assertFalse(instance.isAuthorizedForURL("/test/none"));
-		assertTrue(instance.isAuthorizedForURL("/test/none/test.png"));
-		assertFalse(instance.isAuthorizedForURL("/test/moderator"));
-		assertTrue(instance.isAuthorizedForURL("/test/profile"));
-		assertFalse(instance.isAuthorizedForURL("/upload"));
-		
-		try {
-			instance.assertAuthorizedForURL("/test/admin");
-			instance.assertAuthorizedForURL( "/nobody" );
-			fail();
-		} catch ( AccessControlException e ) {
-			// expected
-		}
-	}
-
-	/**
-	 * Test of isAuthorizedForFunction method, of class
-	 * org.owasp.esapi.AccessController.
-	 */
-	public void testIsAuthorizedForFunction() {
-		System.out.println("isAuthorizedForFunction");
-		AccessController instance = ESAPI.accessController();
-		Authenticator auth = ESAPI.authenticator();
-		
-		auth.setCurrentUser( auth.getUser("testuser1") );
-		assertTrue(instance.isAuthorizedForFunction("/FunctionA"));
-		assertFalse(instance.isAuthorizedForFunction("/FunctionAdeny"));
-		assertFalse(instance.isAuthorizedForFunction("/FunctionB"));
-		assertFalse(instance.isAuthorizedForFunction("/FunctionBdeny"));
-		assertTrue(instance.isAuthorizedForFunction("/FunctionC"));
-		assertFalse(instance.isAuthorizedForFunction("/FunctionCdeny"));
-
-		auth.setCurrentUser( auth.getUser("testuser2") );
-		assertFalse(instance.isAuthorizedForFunction("/FunctionA"));
-		assertFalse(instance.isAuthorizedForFunction("/FunctionAdeny"));
-		assertTrue(instance.isAuthorizedForFunction("/FunctionB"));
-		assertFalse(instance.isAuthorizedForFunction("/FunctionBdeny"));
-		assertTrue(instance.isAuthorizedForFunction("/FunctionD"));
-		assertFalse(instance.isAuthorizedForFunction("/FunctionDdeny"));
-
-		auth.setCurrentUser( auth.getUser("testuser3") );
-		assertTrue(instance.isAuthorizedForFunction("/FunctionA"));
-		assertFalse(instance.isAuthorizedForFunction("/FunctionAdeny"));
-		assertTrue(instance.isAuthorizedForFunction("/FunctionB"));
-		assertFalse(instance.isAuthorizedForFunction("/FunctionBdeny"));
-		assertTrue(instance.isAuthorizedForFunction("/FunctionC"));
-		assertFalse(instance.isAuthorizedForFunction("/FunctionCdeny"));
-
-		try {
-			instance.assertAuthorizedForFunction("/FunctionA");
-			instance.assertAuthorizedForFunction( "/FunctionDdeny" );
-			fail();
-		} catch ( AccessControlException e ) {
-			// expected
-		}
-	}
-
-	/**
-	 * Test of isAuthorizedForData method, of class
-	 * org.owasp.esapi.AccessController.
-	 */
-	public void testIsAuthorizedForData() {
-		System.out.println("isAuthorizedForData");
-		AccessController instance = ESAPI.accessController();
-		Authenticator auth = ESAPI.authenticator();
-		
-		Class adminR = null;
-		Class adminRW = null;
-		Class userW = null;
-		Class userRW = null;
-		Class anyR = null;
-		Class userAdminR = null;
-		Class userAdminRW = null;
-		Class undefined = null;
-		
-		try{
-			adminR = Class.forName("java.util.ArrayList");
-			adminRW = Class.forName("java.lang.Math");
-			userW = Class.forName("java.util.Date");
-			userRW = Class.forName("java.lang.String");
-			anyR = Class.forName("java.io.BufferedReader");
-			userAdminR = Class.forName("java.util.Random");
-			userAdminRW = Class.forName("javax.crypto.Cipher");
-			undefined = Class.forName("java.io.FileWriter");
-			
-		}catch(ClassNotFoundException cnf){
-			System.out.println("CLASS NOT FOUND.");
-			cnf.printStackTrace();
-		}
-		//test User
-		auth.setCurrentUser( auth.getUser("testuser1") );
-		assertTrue(instance.isAuthorizedForData("read", userRW));
-		assertFalse(instance.isAuthorizedForData("read", undefined));
-		assertFalse(instance.isAuthorizedForData("write", undefined));
-		assertFalse(instance.isAuthorizedForData("read", userW));
-		assertFalse(instance.isAuthorizedForData("read", adminRW));
-		assertTrue(instance.isAuthorizedForData("write", userRW));
-		assertTrue(instance.isAuthorizedForData("write", userW));
-		assertFalse(instance.isAuthorizedForData("write", anyR));
-		assertTrue(instance.isAuthorizedForData("read", anyR));
-		assertTrue(instance.isAuthorizedForData("read", userAdminR));
-		assertTrue(instance.isAuthorizedForData("write", userAdminRW));
-		
-		//test Admin
-		auth.setCurrentUser( auth.getUser("testuser2") );
-		assertTrue(instance.isAuthorizedForData("read", adminRW));
-		assertFalse(instance.isAuthorizedForData("read", undefined));
-		assertFalse(instance.isAuthorizedForData("write", undefined));
-		assertFalse(instance.isAuthorizedForData("read", userRW));
-		assertTrue(instance.isAuthorizedForData("write", adminRW));
-		assertFalse(instance.isAuthorizedForData("write", anyR));
-		assertTrue(instance.isAuthorizedForData("read", anyR));
-		assertTrue(instance.isAuthorizedForData("read", userAdminR));
-		assertTrue(instance.isAuthorizedForData("write", userAdminRW));
-		
-		//test User/Admin
-		auth.setCurrentUser( auth.getUser("testuser3") );
-		assertTrue(instance.isAuthorizedForData("read", userRW));
-		assertFalse(instance.isAuthorizedForData("read", undefined));
-		assertFalse(instance.isAuthorizedForData("write", undefined));
-		assertFalse(instance.isAuthorizedForData("read", userW));
-		assertTrue(instance.isAuthorizedForData("read", adminR));
-		assertTrue(instance.isAuthorizedForData("write", userRW));
-		assertTrue(instance.isAuthorizedForData("write", userW));
-		assertFalse(instance.isAuthorizedForData("write", anyR));
-		assertTrue(instance.isAuthorizedForData("read", anyR));
-		assertTrue(instance.isAuthorizedForData("read", userAdminR));
-		assertTrue(instance.isAuthorizedForData("write", userAdminRW));
-		try {
-			instance.assertAuthorizedForData("read", userRW);
-			instance.assertAuthorizedForData( "write", adminR );
-			fail();
-		} catch ( AccessControlException e ) {
-			// expected
-		}
-		
-	}
-
-	/**
-	 * Test of isAuthorizedForFile method, of class
-	 * org.owasp.esapi.AccessController.
-	 */
-	public void testIsAuthorizedForFile() {
-		System.out.println("isAuthorizedForFile");
-		AccessController instance = ESAPI.accessController();
-		Authenticator auth = ESAPI.authenticator();
-		
-		auth.setCurrentUser( auth.getUser("testuser1") );
-		assertTrue(instance.isAuthorizedForFile("/Dir/File1"));
-		assertFalse(instance.isAuthorizedForFile("/Dir/File2"));
-		assertTrue(instance.isAuthorizedForFile("/Dir/File3"));
-		assertFalse(instance.isAuthorizedForFile("/Dir/ridiculous"));
-
-		auth.setCurrentUser( auth.getUser("testuser2") );
-		assertFalse(instance.isAuthorizedForFile("/Dir/File1"));
-		assertTrue(instance.isAuthorizedForFile("/Dir/File2"));
-		assertTrue(instance.isAuthorizedForFile("/Dir/File4"));
-		assertFalse(instance.isAuthorizedForFile("/Dir/ridiculous"));
-
-		auth.setCurrentUser( auth.getUser("testuser3") );
-		assertTrue(instance.isAuthorizedForFile("/Dir/File1"));
-		assertTrue(instance.isAuthorizedForFile("/Dir/File2"));
-		assertFalse(instance.isAuthorizedForFile("/Dir/File5"));
-		assertFalse(instance.isAuthorizedForFile("/Dir/ridiculous"));
-
-		try {
-			instance.assertAuthorizedForFile("/Dir/File1");
-			instance.assertAuthorizedForFile( "/Dir/File6" );
-			fail();
-		} catch ( AccessControlException e ) {
-			// expected
-		}
-	}
-
-	/**
-	 * Test of isAuthorizedForService method, of class
-	 * org.owasp.esapi.AccessController.
-	 */
-	public void testIsAuthorizedForService() {
-		System.out.println("isAuthorizedForService");
-		AccessController instance = ESAPI.accessController();
-		Authenticator auth = ESAPI.authenticator();
-		
-		auth.setCurrentUser( auth.getUser("testuser1") );
-		assertTrue(instance.isAuthorizedForService("/services/ServiceA"));
-		assertFalse(instance.isAuthorizedForService("/services/ServiceB"));
-		assertTrue(instance.isAuthorizedForService("/services/ServiceC"));
-		
-		assertFalse(instance.isAuthorizedForService("/test/ridiculous"));
-
-		auth.setCurrentUser( auth.getUser("testuser2") );
-		assertFalse(instance.isAuthorizedForService("/services/ServiceA"));
-		assertTrue(instance.isAuthorizedForService("/services/ServiceB"));
-		assertFalse(instance.isAuthorizedForService("/services/ServiceF"));
-		assertFalse(instance.isAuthorizedForService("/test/ridiculous"));
-
-		auth.setCurrentUser( auth.getUser("testuser3") );
-		assertTrue(instance.isAuthorizedForService("/services/ServiceA"));
-		assertTrue(instance.isAuthorizedForService("/services/ServiceB"));
-		assertFalse(instance.isAuthorizedForService("/services/ServiceE"));
-		assertFalse(instance.isAuthorizedForService("/test/ridiculous"));
-
-		try {
-			instance.assertAuthorizedForService("/services/ServiceD");
-			instance.assertAuthorizedForService( "/test/ridiculous" );
-			fail();
-		} catch ( AccessControlException e ) {
-			// expected
-		}
-	}
+    public void testIsAuthorizedForURL() throws Exception {
+        System.out.println("isAuthorizedForURL");
+        AccessController instance = ESAPI.accessController();
+        Authenticator auth = ESAPI.authenticator();
+
+        auth.setCurrentUser( auth.getUser("testuser1") );
+        assertFalse(instance.isAuthorizedForURL("/nobody"));
+        assertFalse(instance.isAuthorizedForURL("/test/admin"));
+        assertTrue(instance.isAuthorizedForURL("/test/user"));
+        assertTrue(instance.isAuthorizedForURL("/test/all"));
+        assertFalse(instance.isAuthorizedForURL("/test/none"));
+        assertTrue(instance.isAuthorizedForURL("/test/none/test.gif"));
+        assertFalse(instance.isAuthorizedForURL("/test/none/test.exe"));
+        assertTrue(instance.isAuthorizedForURL("/test/none/test.png"));
+        assertFalse(instance.isAuthorizedForURL("/test/moderator"));
+        assertTrue(instance.isAuthorizedForURL("/test/profile"));
+        assertFalse(instance.isAuthorizedForURL("/upload"));
+
+        auth.setCurrentUser( auth.getUser("testuser2") );
+        assertFalse(instance.isAuthorizedForURL("/nobody"));
+        assertTrue(instance.isAuthorizedForURL("/test/admin"));
+        assertFalse(instance.isAuthorizedForURL("/test/user"));
+        assertTrue(instance.isAuthorizedForURL("/test/all"));
+        assertFalse(instance.isAuthorizedForURL("/test/none"));
+        assertTrue(instance.isAuthorizedForURL("/test/none/test.png"));
+        assertFalse(instance.isAuthorizedForURL("/test/moderator"));
+        assertTrue(instance.isAuthorizedForURL("/test/profile"));
+        assertFalse(instance.isAuthorizedForURL("/upload"));
+
+        auth.setCurrentUser( auth.getUser("testuser3") );
+        assertFalse(instance.isAuthorizedForURL("/nobody"));
+        assertTrue(instance.isAuthorizedForURL("/test/admin"));
+        assertTrue(instance.isAuthorizedForURL("/test/user"));
+        assertTrue(instance.isAuthorizedForURL("/test/all"));
+        assertFalse(instance.isAuthorizedForURL("/test/none"));
+        assertTrue(instance.isAuthorizedForURL("/test/none/test.png"));
+        assertFalse(instance.isAuthorizedForURL("/test/moderator"));
+        assertTrue(instance.isAuthorizedForURL("/test/profile"));
+        assertFalse(instance.isAuthorizedForURL("/upload"));
+
+        try {
+            instance.assertAuthorizedForURL("/test/admin");
+            instance.assertAuthorizedForURL( "/nobody" );
+            fail();
+        } catch ( AccessControlException e ) {
+            // expected
+        }
+    }
+
+    /**
+     * Test of isAuthorizedForFunction method, of class
+     * org.owasp.esapi.AccessController.
+     */
+    public void testIsAuthorizedForFunction() {
+        System.out.println("isAuthorizedForFunction");
+        AccessController instance = ESAPI.accessController();
+        Authenticator auth = ESAPI.authenticator();
+
+        auth.setCurrentUser( auth.getUser("testuser1") );
+        assertTrue(instance.isAuthorizedForFunction("/FunctionA"));
+        assertFalse(instance.isAuthorizedForFunction("/FunctionAdeny"));
+        assertFalse(instance.isAuthorizedForFunction("/FunctionB"));
+        assertFalse(instance.isAuthorizedForFunction("/FunctionBdeny"));
+        assertTrue(instance.isAuthorizedForFunction("/FunctionC"));
+        assertFalse(instance.isAuthorizedForFunction("/FunctionCdeny"));
+
+        auth.setCurrentUser( auth.getUser("testuser2") );
+        assertFalse(instance.isAuthorizedForFunction("/FunctionA"));
+        assertFalse(instance.isAuthorizedForFunction("/FunctionAdeny"));
+        assertTrue(instance.isAuthorizedForFunction("/FunctionB"));
+        assertFalse(instance.isAuthorizedForFunction("/FunctionBdeny"));
+        assertTrue(instance.isAuthorizedForFunction("/FunctionD"));
+        assertFalse(instance.isAuthorizedForFunction("/FunctionDdeny"));
+
+        auth.setCurrentUser( auth.getUser("testuser3") );
+        assertTrue(instance.isAuthorizedForFunction("/FunctionA"));
+        assertFalse(instance.isAuthorizedForFunction("/FunctionAdeny"));
+        assertTrue(instance.isAuthorizedForFunction("/FunctionB"));
+        assertFalse(instance.isAuthorizedForFunction("/FunctionBdeny"));
+        assertTrue(instance.isAuthorizedForFunction("/FunctionC"));
+        assertFalse(instance.isAuthorizedForFunction("/FunctionCdeny"));
+
+        try {
+            instance.assertAuthorizedForFunction("/FunctionA");
+            instance.assertAuthorizedForFunction( "/FunctionDdeny" );
+            fail();
+        } catch ( AccessControlException e ) {
+            // expected
+        }
+    }
+
+    /**
+     * Test of isAuthorizedForData method, of class
+     * org.owasp.esapi.AccessController.
+     */
+    public void testIsAuthorizedForData() {
+        System.out.println("isAuthorizedForData");
+        AccessController instance = ESAPI.accessController();
+        Authenticator auth = ESAPI.authenticator();
+
+        Class adminR = null;
+        Class adminRW = null;
+        Class userW = null;
+        Class userRW = null;
+        Class anyR = null;
+        Class userAdminR = null;
+        Class userAdminRW = null;
+        Class undefined = null;
+
+        try{
+            adminR = Class.forName("java.util.ArrayList");
+            adminRW = Class.forName("java.lang.Math");
+            userW = Class.forName("java.util.Date");
+            userRW = Class.forName("java.lang.String");
+            anyR = Class.forName("java.io.BufferedReader");
+            userAdminR = Class.forName("java.util.Random");
+            userAdminRW = Class.forName("javax.crypto.Cipher");
+            undefined = Class.forName("java.io.FileWriter");
+
+        }catch(ClassNotFoundException cnf){
+            System.out.println("CLASS NOT FOUND.");
+            cnf.printStackTrace();
+        }
+        //test User
+        auth.setCurrentUser( auth.getUser("testuser1") );
+        assertTrue(instance.isAuthorizedForData("read", userRW));
+        assertFalse(instance.isAuthorizedForData("read", undefined));
+        assertFalse(instance.isAuthorizedForData("write", undefined));
+        assertFalse(instance.isAuthorizedForData("read", userW));
+        assertFalse(instance.isAuthorizedForData("read", adminRW));
+        assertTrue(instance.isAuthorizedForData("write", userRW));
+        assertTrue(instance.isAuthorizedForData("write", userW));
+        assertFalse(instance.isAuthorizedForData("write", anyR));
+        assertTrue(instance.isAuthorizedForData("read", anyR));
+        assertTrue(instance.isAuthorizedForData("read", userAdminR));
+        assertTrue(instance.isAuthorizedForData("write", userAdminRW));
+
+        //test Admin
+        auth.setCurrentUser( auth.getUser("testuser2") );
+        assertTrue(instance.isAuthorizedForData("read", adminRW));
+        assertFalse(instance.isAuthorizedForData("read", undefined));
+        assertFalse(instance.isAuthorizedForData("write", undefined));
+        assertFalse(instance.isAuthorizedForData("read", userRW));
+        assertTrue(instance.isAuthorizedForData("write", adminRW));
+        assertFalse(instance.isAuthorizedForData("write", anyR));
+        assertTrue(instance.isAuthorizedForData("read", anyR));
+        assertTrue(instance.isAuthorizedForData("read", userAdminR));
+        assertTrue(instance.isAuthorizedForData("write", userAdminRW));
+
+        //test User/Admin
+        auth.setCurrentUser( auth.getUser("testuser3") );
+        assertTrue(instance.isAuthorizedForData("read", userRW));
+        assertFalse(instance.isAuthorizedForData("read", undefined));
+        assertFalse(instance.isAuthorizedForData("write", undefined));
+        assertFalse(instance.isAuthorizedForData("read", userW));
+        assertTrue(instance.isAuthorizedForData("read", adminR));
+        assertTrue(instance.isAuthorizedForData("write", userRW));
+        assertTrue(instance.isAuthorizedForData("write", userW));
+        assertFalse(instance.isAuthorizedForData("write", anyR));
+        assertTrue(instance.isAuthorizedForData("read", anyR));
+        assertTrue(instance.isAuthorizedForData("read", userAdminR));
+        assertTrue(instance.isAuthorizedForData("write", userAdminRW));
+        try {
+            instance.assertAuthorizedForData("read", userRW);
+            instance.assertAuthorizedForData( "write", adminR );
+            fail();
+        } catch ( AccessControlException e ) {
+            // expected
+        }
+
+    }
+
+    /**
+     * Test of isAuthorizedForFile method, of class
+     * org.owasp.esapi.AccessController.
+     */
+    public void testIsAuthorizedForFile() {
+        System.out.println("isAuthorizedForFile");
+        AccessController instance = ESAPI.accessController();
+        Authenticator auth = ESAPI.authenticator();
+
+        auth.setCurrentUser( auth.getUser("testuser1") );
+        assertTrue(instance.isAuthorizedForFile("/Dir/File1"));
+        assertFalse(instance.isAuthorizedForFile("/Dir/File2"));
+        assertTrue(instance.isAuthorizedForFile("/Dir/File3"));
+        assertFalse(instance.isAuthorizedForFile("/Dir/ridiculous"));
+
+        auth.setCurrentUser( auth.getUser("testuser2") );
+        assertFalse(instance.isAuthorizedForFile("/Dir/File1"));
+        assertTrue(instance.isAuthorizedForFile("/Dir/File2"));
+        assertTrue(instance.isAuthorizedForFile("/Dir/File4"));
+        assertFalse(instance.isAuthorizedForFile("/Dir/ridiculous"));
+
+        auth.setCurrentUser( auth.getUser("testuser3") );
+        assertTrue(instance.isAuthorizedForFile("/Dir/File1"));
+        assertTrue(instance.isAuthorizedForFile("/Dir/File2"));
+        assertFalse(instance.isAuthorizedForFile("/Dir/File5"));
+        assertFalse(instance.isAuthorizedForFile("/Dir/ridiculous"));
+
+        try {
+            instance.assertAuthorizedForFile("/Dir/File1");
+            instance.assertAuthorizedForFile( "/Dir/File6" );
+            fail();
+        } catch ( AccessControlException e ) {
+            // expected
+        }
+    }
+
+    /**
+     * Test of isAuthorizedForService method, of class
+     * org.owasp.esapi.AccessController.
+     */
+    public void testIsAuthorizedForService() {
+        System.out.println("isAuthorizedForService");
+        AccessController instance = ESAPI.accessController();
+        Authenticator auth = ESAPI.authenticator();
+
+        auth.setCurrentUser( auth.getUser("testuser1") );
+        assertTrue(instance.isAuthorizedForService("/services/ServiceA"));
+        assertFalse(instance.isAuthorizedForService("/services/ServiceB"));
+        assertTrue(instance.isAuthorizedForService("/services/ServiceC"));
+
+        assertFalse(instance.isAuthorizedForService("/test/ridiculous"));
+
+        auth.setCurrentUser( auth.getUser("testuser2") );
+        assertFalse(instance.isAuthorizedForService("/services/ServiceA"));
+        assertTrue(instance.isAuthorizedForService("/services/ServiceB"));
+        assertFalse(instance.isAuthorizedForService("/services/ServiceF"));
+        assertFalse(instance.isAuthorizedForService("/test/ridiculous"));
+
+        auth.setCurrentUser( auth.getUser("testuser3") );
+        assertTrue(instance.isAuthorizedForService("/services/ServiceA"));
+        assertTrue(instance.isAuthorizedForService("/services/ServiceB"));
+        assertFalse(instance.isAuthorizedForService("/services/ServiceE"));
+        assertFalse(instance.isAuthorizedForService("/test/ridiculous"));
+
+        try {
+            instance.assertAuthorizedForService("/services/ServiceD");
+            instance.assertAuthorizedForService( "/test/ridiculous" );
+            fail();
+        } catch ( AccessControlException e ) {
+            // expected
+        }
+    }
 
 }
diff --git a/src/test/java/org/owasp/esapi/reference/AccessReferenceMapTest.java b/src/test/java/org/owasp/esapi/reference/AccessReferenceMapTest.java
index 1a26077..f04655f 100644
--- a/src/test/java/org/owasp/esapi/reference/AccessReferenceMapTest.java
+++ b/src/test/java/org/owasp/esapi/reference/AccessReferenceMapTest.java
@@ -1,15 +1,15 @@
 /**
  * OWASP Enterprise Security API (ESAPI)
- * 
+ *
  * This file is part of the Open Web Application Security Project (OWASP)
  * Enterprise Security API (ESAPI) project. For details, please see
  * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
  *
  * Copyright (c) 2007 - The OWASP Foundation
- * 
+ *
  * The ESAPI is published by OWASP under the BSD license. You should read and accept the
  * LICENSE before you use, modify, and/or redistribute this software.
- * 
+ *
  * @author Jeff Williams <a href="http://www.aspectsecurity.com">Aspect Security</a>
  * @created 2007
  */
@@ -33,17 +33,17 @@ import org.owasp.esapi.errors.EncryptionException;
 
 /**
  * The Class AccessReferenceMapTest.
- * 
+ *
  * @author Jeff Williams (jeff.williams@aspectsecurity.com)
  */
 public class AccessReferenceMapTest extends TestCase {
-    
+
     /**
-	 * Instantiates a new access reference map test.
-	 * 
-	 * @param testName
-	 *            the test name
-	 */
+     * Instantiates a new access reference map test.
+     *
+     * @param testName
+     *            the test name
+     */
     public AccessReferenceMapTest(String testName) {
         super(testName);
     }
@@ -53,7 +53,7 @@ public class AccessReferenceMapTest extends TestCase {
      * @throws Exception
      */
     protected void setUp() throws Exception {
-    	// none
+        // none
     }
 
     /**
@@ -61,139 +61,139 @@ public class AccessReferenceMapTest extends TestCase {
      * @throws Exception
      */
     protected void tearDown() throws Exception {
-    	// none
+        // none
     }
 
     /**
-	 * Suite.
-	 * 
-	 * @return the test
-	 */
+     * Suite.
+     *
+     * @return the test
+     */
     public static Test suite() {
         TestSuite suite = new TestSuite(AccessReferenceMapTest.class);
         return suite;
     }
 
-    
+
     /**
-	 * Test of update method, of class org.owasp.esapi.AccessReferenceMap.
-	 * 
-	 * @throws AuthenticationException
+     * Test of update method, of class org.owasp.esapi.AccessReferenceMap.
+     *
+     * @throws AuthenticationException
      *             the authentication exception
      * @throws EncryptionException
-	 */
+     */
     public void testUpdate() throws AuthenticationException, EncryptionException {
         System.out.println("update");
-    	RandomAccessReferenceMap arm = new RandomAccessReferenceMap();
-    	Authenticator auth = ESAPI.authenticator();
-    	
-    	String pass = auth.generateStrongPassword();
-    	User u = auth.createUser( "armUpdate", pass, pass );
-    	
-    	// test to make sure update returns something
-		arm.update(auth.getUserNames());
-		String indirect = arm.getIndirectReference( u.getAccountName() );
-		if ( indirect == null ) fail();
-		
-		// test to make sure update removes items that are no longer in the list
-		auth.removeUser( u.getAccountName() );
-		arm.update(auth.getUserNames());
-		indirect = arm.getIndirectReference( u.getAccountName() );
-		if ( indirect != null ) fail();
-		
-		// test to make sure old indirect reference is maintained after an update
-		arm.update(auth.getUserNames());
-		String newIndirect = arm.getIndirectReference( u.getAccountName() );
-		assertEquals(indirect, newIndirect);
+        RandomAccessReferenceMap arm = new RandomAccessReferenceMap();
+        Authenticator auth = ESAPI.authenticator();
+
+        String pass = auth.generateStrongPassword();
+        User u = auth.createUser( "armUpdate", pass, pass );
+
+        // test to make sure update returns something
+        arm.update(auth.getUserNames());
+        String indirect = arm.getIndirectReference( u.getAccountName() );
+        if ( indirect == null ) fail();
+
+        // test to make sure update removes items that are no longer in the list
+        auth.removeUser( u.getAccountName() );
+        arm.update(auth.getUserNames());
+        indirect = arm.getIndirectReference( u.getAccountName() );
+        if ( indirect != null ) fail();
+
+        // test to make sure old indirect reference is maintained after an update
+        arm.update(auth.getUserNames());
+        String newIndirect = arm.getIndirectReference( u.getAccountName() );
+        assertEquals(indirect, newIndirect);
     }
-    
-    
+
+
     /**
-	 * Test of iterator method, of class org.owasp.esapi.AccessReferenceMap.
-	 */
+     * Test of iterator method, of class org.owasp.esapi.AccessReferenceMap.
+     */
     public void testIterator() {
         System.out.println("iterator");
-    	RandomAccessReferenceMap arm = new RandomAccessReferenceMap();
+        RandomAccessReferenceMap arm = new RandomAccessReferenceMap();
         Authenticator auth = ESAPI.authenticator();
-        
-		arm.update(auth.getUserNames());
-
-		Iterator i = arm.iterator();
-		while ( i.hasNext() ) {
-			String userName = (String)i.next();
-			User u = auth.getUser( userName );
-			if ( u == null ) fail();
-		}
+
+        arm.update(auth.getUserNames());
+
+        Iterator i = arm.iterator();
+        while ( i.hasNext() ) {
+            String userName = (String)i.next();
+            User u = auth.getUser( userName );
+            if ( u == null ) fail();
+        }
     }
-    
+
     /**
-	 * Test of getIndirectReference method, of class
-	 * org.owasp.esapi.AccessReferenceMap.
-	 */
+     * Test of getIndirectReference method, of class
+     * org.owasp.esapi.AccessReferenceMap.
+     */
     public void testGetIndirectReference() {
         System.out.println("getIndirectReference");
-        
+
         String directReference = "234";
         Set list = new HashSet();
         list.add( "123" );
         list.add( directReference );
         list.add( "345" );
         RandomAccessReferenceMap instance = new RandomAccessReferenceMap( list );
-        
+
         String expResult = directReference;
         String result = instance.getIndirectReference(directReference);
-        assertNotSame(expResult, result);        
+        assertNotSame(expResult, result);
     }
 
     /**
-	 * Test of getDirectReference method, of class
-	 * org.owasp.esapi.AccessReferenceMap.
-	 * 
-	 * @throws AccessControlException
-	 *             the access control exception
-	 */
+     * Test of getDirectReference method, of class
+     * org.owasp.esapi.AccessReferenceMap.
+     *
+     * @throws AccessControlException
+     *             the access control exception
+     */
     public void testGetDirectReference() throws AccessControlException {
         System.out.println("getDirectReference");
-        
+
         String directReference = "234";
         Set list = new HashSet();
         list.add( "123" );
         list.add( directReference );
         list.add( "345" );
         RandomAccessReferenceMap instance = new RandomAccessReferenceMap( list );
-        
+
         String ind = instance.getIndirectReference(directReference);
         String dir = (String)instance.getDirectReference(ind);
         assertEquals(directReference, dir);
         try {
-        	instance.getDirectReference("invalid");
-        	fail();
+            instance.getDirectReference("invalid");
+            fail();
         } catch( AccessControlException e ) {
-        	// success
+            // success
         }
     }
-    
+
     /**
      *
      * @throws org.owasp.esapi.errors.AccessControlException
      */
     public void testAddDirectReference() throws AccessControlException {
         System.out.println("addDirectReference");
-        
+
         String directReference = "234";
         Set list = new HashSet();
         list.add( "123" );
         list.add( directReference );
         list.add( "345" );
         RandomAccessReferenceMap instance = new RandomAccessReferenceMap( list );
-        
+
         String newDirect = instance.addDirectReference("newDirect");
         assertNotNull( newDirect );
         String ind = instance.addDirectReference(directReference);
         String dir = (String)instance.getDirectReference(ind);
         assertEquals(directReference, dir);
-    	String newInd = instance.addDirectReference(directReference);
-    	assertEquals(ind, newInd);
+        String newInd = instance.addDirectReference(directReference);
+        assertEquals(ind, newInd);
     }
 
     /**
@@ -202,22 +202,22 @@ public class AccessReferenceMapTest extends TestCase {
      */
     public void testRemoveDirectReference() throws AccessControlException {
         System.out.println("removeDirectReference");
-        
+
         String directReference = "234";
         Set list = new HashSet();
         list.add( "123" );
         list.add( directReference );
         list.add( "345" );
         RandomAccessReferenceMap instance = new RandomAccessReferenceMap( list );
-        
+
         String indirect = instance.getIndirectReference(directReference);
         assertNotNull(indirect);
         String deleted = instance.removeDirectReference(directReference);
         assertEquals(indirect,deleted);
-    	deleted = instance.removeDirectReference("ridiculous");
-    	assertNull(deleted);
+        deleted = instance.removeDirectReference("ridiculous");
+        assertNull(deleted);
     }
-    
-    
-    
+
+
+
 }
diff --git a/src/test/java/org/owasp/esapi/reference/AuthenticatorTest.java b/src/test/java/org/owasp/esapi/reference/AuthenticatorTest.java
index 7d62b6f..5df1b5c 100644
--- a/src/test/java/org/owasp/esapi/reference/AuthenticatorTest.java
+++ b/src/test/java/org/owasp/esapi/reference/AuthenticatorTest.java
@@ -1,15 +1,15 @@
 /**
  * OWASP Enterprise Security API (ESAPI)
- * 
+ *
  * This file is part of the Open Web Application Security Project (OWASP)
  * Enterprise Security API (ESAPI) project. For details, please see
  * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
  *
  * Copyright (c) 2007 - The OWASP Foundation
- * 
+ *
  * The ESAPI is published by OWASP under the BSD license. You should read and accept the
  * LICENSE before you use, modify, and/or redistribute this software.
- * 
+ *
  * @author Jeff Williams <a href="http://www.aspectsecurity.com">Aspect Security</a>
  * @created 2007
  */
@@ -55,12 +55,12 @@ import org.owasp.esapi.http.MockHttpServletResponse;
 
 /**
  * The Class AuthenticatorTest.
- * 
+ *
  * @author Jeff Williams (jeff.williams@aspectsecurity.com)
  */
 public class AuthenticatorTest {
     private static Authenticator instance;
-    /** 
+    /**
      * User session information is stored on a per-thread basis.  So long as this has potential to run single threaded then we'll maintain a synchronous nature execution.
      * This is done to prevent tests corrupting each others states since all will be executed on a limited set of Threads within the JVM.
      */
@@ -82,7 +82,7 @@ public class AuthenticatorTest {
     public void setup() throws InterruptedException {
         while (!threadIsolation.tryAcquire(500, TimeUnit.MILLISECONDS)) {
             //Spurious Interrupt Guard
-        }       
+        }
     }
 
     @After
@@ -102,20 +102,20 @@ public class AuthenticatorTest {
         }
     }
 
-	
-	/**
-	 * Test of createAccount method, of class org.owasp.esapi.Authenticator.
-	 * 
-	 * @throws AuthenticationException
+
+    /**
+     * Test of createAccount method, of class org.owasp.esapi.Authenticator.
+     *
+     * @throws AuthenticationException
      *             the authentication exception
      * @throws EncryptionException
-	 */
-	@Test public void testCreateUser() throws AuthenticationException, EncryptionException {
-		System.out.println("createUser");
-		String accountName = ESAPI.randomizer().getRandomString(8, EncoderConstants.CHAR_ALPHANUMERICS);
-		String password = instance.generateStrongPassword();
-		User user = instance.createUser(accountName, password, password);
-		assertTrue(user.verifyPassword(password));
+     */
+    @Test public void testCreateUser() throws AuthenticationException, EncryptionException {
+        System.out.println("createUser");
+        String accountName = ESAPI.randomizer().getRandomString(8, EncoderConstants.CHAR_ALPHANUMERICS);
+        String password = instance.generateStrongPassword();
+        User user = instance.createUser(accountName, password, password);
+        assertTrue(user.verifyPassword(password));
         try {
             instance.createUser(accountName, password, password); // duplicate user
             fail();
@@ -147,318 +147,318 @@ public class AuthenticatorTest {
             // success
         }
         try {
-        	String uName = "ea234kEknr";	//sufficiently random password that also works as a username
+            String uName = "ea234kEknr";    //sufficiently random password that also works as a username
             instance.createUser(uName, uName, uName);  // using username as password
             fail();
         } catch (AuthenticationException e) {
             // success
         }
-	}
-
-	/**
-	 * Test of generateStrongPassword method, of class
-	 * org.owasp.esapi.Authenticator.
-	 * 
-	 * @throws AuthenticationException
-	 *             the authentication exception
-	 */
-	@Test public void testGenerateStrongPassword() throws AuthenticationException {
-		System.out.println("generateStrongPassword");		
-		String oldPassword = "iiiiiiiiii";  // i is not allowed in passwords - this prevents failures from containing pieces of old password
-		String newPassword = null;
-		String username = "FictionalEsapiUser";
-		User user = new DefaultUser(username);
-		for (int i = 0; i < 100; i++) {
+    }
+
+    /**
+     * Test of generateStrongPassword method, of class
+     * org.owasp.esapi.Authenticator.
+     *
+     * @throws AuthenticationException
+     *             the authentication exception
+     */
+    @Test public void testGenerateStrongPassword() throws AuthenticationException {
+        System.out.println("generateStrongPassword");
+        String oldPassword = "iiiiiiiiii";  // i is not allowed in passwords - this prevents failures from containing pieces of old password
+        String newPassword = null;
+        String username = "FictionalEsapiUser";
+        User user = new DefaultUser(username);
+        for (int i = 0; i < 100; i++) {
             try {
                 newPassword = instance.generateStrongPassword();
                 instance.verifyPasswordStrength(oldPassword, newPassword, user);
             } catch( AuthenticationException e ) {
-            	System.out.println( "  FAILED >> " + newPassword + " : " + e.getLogMessage());
+                System.out.println( "  FAILED >> " + newPassword + " : " + e.getLogMessage());
                 fail();
             }
-		}
-		try {
-			instance.verifyPasswordStrength("test56^$test", "abcdx56^$sl", user );
-		} catch( AuthenticationException e ) {
-			// expected
-		}
-	}
-
-
-	/**
-	 * Test of getCurrentUser method, of class org.owasp.esapi.Authenticator.
-	 * 
+        }
+        try {
+            instance.verifyPasswordStrength("test56^$test", "abcdx56^$sl", user );
+        } catch( AuthenticationException e ) {
+            // expected
+        }
+    }
+
+
+    /**
+     * Test of getCurrentUser method, of class org.owasp.esapi.Authenticator.
+     *
      *
      * @throws Exception
      */
-	@Test public void testGetCurrentUser() throws Exception {
-		System.out.println("getCurrentUser");
-		String username1 = ESAPI.randomizer().getRandomString(8, EncoderConstants.CHAR_ALPHANUMERICS);
-		String username2 = ESAPI.randomizer().getRandomString(8, EncoderConstants.CHAR_ALPHANUMERICS);
-		User user1 = instance.createUser(username1, "getCurrentUser", "getCurrentUser");
-		User user2 = instance.createUser(username2, "getCurrentUser", "getCurrentUser");		
-		user1.enable();
-	    MockHttpServletRequest request = new MockHttpServletRequest();
-		MockHttpServletResponse response = new MockHttpServletResponse();
+    @Test public void testGetCurrentUser() throws Exception {
+        System.out.println("getCurrentUser");
+        String username1 = ESAPI.randomizer().getRandomString(8, EncoderConstants.CHAR_ALPHANUMERICS);
+        String username2 = ESAPI.randomizer().getRandomString(8, EncoderConstants.CHAR_ALPHANUMERICS);
+        User user1 = instance.createUser(username1, "getCurrentUser", "getCurrentUser");
+        User user2 = instance.createUser(username2, "getCurrentUser", "getCurrentUser");
+        user1.enable();
+        MockHttpServletRequest request = new MockHttpServletRequest();
+        MockHttpServletResponse response = new MockHttpServletResponse();
         ESAPI.httpUtilities().setCurrentHTTP(request, response);
-		user1.loginWithPassword("getCurrentUser");
-		User currentUser = instance.getCurrentUser();
-		assertEquals( currentUser, user1 );
-		instance.setCurrentUser( user2 );
-		assertFalse( currentUser.getAccountName().equals( user2.getAccountName() ) );
-		
-		Runnable echo = new Runnable() {
-			public void run() {
-				User a = null;
-				try {
-					String password = instance.generateStrongPassword();
-					//Create account name using random strings to guarantee uniqueness among running threads.
+        user1.loginWithPassword("getCurrentUser");
+        User currentUser = instance.getCurrentUser();
+        assertEquals( currentUser, user1 );
+        instance.setCurrentUser( user2 );
+        assertFalse( currentUser.getAccountName().equals( user2.getAccountName() ) );
+
+        Runnable echo = new Runnable() {
+            public void run() {
+                User a = null;
+                try {
+                    String password = instance.generateStrongPassword();
+                    //Create account name using random strings to guarantee uniqueness among running threads.
                     String accountName=ESAPI.randomizer().getRandomString(8, EncoderConstants.CHAR_ALPHANUMERICS);
-					a = instance.getUser(accountName);
-					if ( a != null ) {
-					    instance.removeUser(accountName);
-					}
-					a = instance.createUser(accountName, password, password);
-					instance.setCurrentUser(a);
-				} catch (AuthenticationException e) {
-				    //Use ErrorCollector to fail test.
+                    a = instance.getUser(accountName);
+                    if ( a != null ) {
+                        instance.removeUser(accountName);
+                    }
+                    a = instance.createUser(accountName, password, password);
+                    instance.setCurrentUser(a);
+                } catch (AuthenticationException e) {
+                    //Use ErrorCollector to fail test.
                     collector.addError(e);
-				}
-				User b = instance.getCurrentUser();
-				collector.checkThat("Logged in user should equal original user", a.equals(b), new IsEqual<Boolean>(Boolean.TRUE));
-			}
-		};
+                }
+                User b = instance.getCurrentUser();
+                collector.checkThat("Logged in user should equal original user", a.equals(b), new IsEqual<Boolean>(Boolean.TRUE));
+            }
+        };
         ThreadGroup tg = new ThreadGroup("test");
-		for ( int i = 0; i<10; i++ ) {
-			new Thread( tg, echo ).start();
-		}
+        for ( int i = 0; i<10; i++ ) {
+            new Thread( tg, echo ).start();
+        }
         while (tg.activeCount() > 0 ) {
             Thread.sleep(100);
         }
-	}
-
-	/**
-	 * Test of getUser method, of class org.owasp.esapi.Authenticator.
-	 * 
-	 * @throws AuthenticationException
-	 *             the authentication exception
-	 */
-	@Test public void testGetUser() throws AuthenticationException {
-		System.out.println("getUser");
-		String password = instance.generateStrongPassword();
-		String accountName=ESAPI.randomizer().getRandomString(8, EncoderConstants.CHAR_ALPHANUMERICS);
-		instance.createUser(accountName, password, password);
-		assertNotNull(instance.getUser( accountName ));
-		assertNull(instance.getUser( ESAPI.randomizer().getRandomString(8, EncoderConstants.CHAR_ALPHANUMERICS) ));
-	}
-	
+    }
+
+    /**
+     * Test of getUser method, of class org.owasp.esapi.Authenticator.
+     *
+     * @throws AuthenticationException
+     *             the authentication exception
+     */
+    @Test public void testGetUser() throws AuthenticationException {
+        System.out.println("getUser");
+        String password = instance.generateStrongPassword();
+        String accountName=ESAPI.randomizer().getRandomString(8, EncoderConstants.CHAR_ALPHANUMERICS);
+        instance.createUser(accountName, password, password);
+        assertNotNull(instance.getUser( accountName ));
+        assertNull(instance.getUser( ESAPI.randomizer().getRandomString(8, EncoderConstants.CHAR_ALPHANUMERICS) ));
+    }
+
     /**
      *
      * @throws org.owasp.esapi.errors.AuthenticationException
      */
     @Test public void testGetUserFromRememberToken() throws AuthenticationException {
-		System.out.println("getUserFromRememberToken");
-		String password = instance.generateStrongPassword();
-		String accountName=ESAPI.randomizer().getRandomString(8, EncoderConstants.CHAR_ALPHANUMERICS);
-		User user = instance.createUser(accountName, password, password);
-		user.enable();
-		MockHttpServletRequest request = new MockHttpServletRequest();
-		MockHttpServletResponse response = new MockHttpServletResponse();
-		ESAPI.httpUtilities().setCurrentHTTP(request, response);
-		
-		System.out.println("getUserFromRememberToken - expecting failure");
-		request.setCookie( HTTPUtilities.REMEMBER_TOKEN_COOKIE_NAME, "ridiculous" );
-		try {
-			instance.login( request, response );  // wrong cookie will fail
-			fail();
-		} catch( AuthenticationException e ) {
-			// expected
-		}
-
-		System.out.println("getUserFromRememberToken - expecting success");
-		request = new MockHttpServletRequest();
-		ESAPI.httpUtilities().setCurrentHTTP(request, response);
-		ESAPI.authenticator().setCurrentUser(user);
-		String newToken = ESAPI.httpUtilities().setRememberToken(request, response, password, 10000, "test.com", request.getContextPath() );
-		request.setCookie( HTTPUtilities.REMEMBER_TOKEN_COOKIE_NAME, newToken );
+        System.out.println("getUserFromRememberToken");
+        String password = instance.generateStrongPassword();
+        String accountName=ESAPI.randomizer().getRandomString(8, EncoderConstants.CHAR_ALPHANUMERICS);
+        User user = instance.createUser(accountName, password, password);
+        user.enable();
+        MockHttpServletRequest request = new MockHttpServletRequest();
+        MockHttpServletResponse response = new MockHttpServletResponse();
+        ESAPI.httpUtilities().setCurrentHTTP(request, response);
+
+        System.out.println("getUserFromRememberToken - expecting failure");
+        request.setCookie( HTTPUtilities.REMEMBER_TOKEN_COOKIE_NAME, "ridiculous" );
+        try {
+            instance.login( request, response );  // wrong cookie will fail
+            fail();
+        } catch( AuthenticationException e ) {
+            // expected
+        }
+
+        System.out.println("getUserFromRememberToken - expecting success");
+        request = new MockHttpServletRequest();
+        ESAPI.httpUtilities().setCurrentHTTP(request, response);
+        ESAPI.authenticator().setCurrentUser(user);
+        String newToken = ESAPI.httpUtilities().setRememberToken(request, response, password, 10000, "test.com", request.getContextPath() );
+        request.setCookie( HTTPUtilities.REMEMBER_TOKEN_COOKIE_NAME, newToken );
         user.logout();  // logout the current user so we can log them in with the remember cookie
-		User test2 = instance.login( request, response );
-		assertSame( user, test2 );
-	}
-	
-
-	
-	/**
-	 * Test get user from session.
-	 * 
-	 * @throws AuthenticationException
-	 *             the authentication exception
-	 */
-	@Test public void testGetUserFromSession() throws AuthenticationException {
-		System.out.println("getUserFromSession");
-		assumeTrue(instance instanceof FileBasedAuthenticator);
-		String accountName=ESAPI.randomizer().getRandomString(8, EncoderConstants.CHAR_ALPHANUMERICS);
-		String password = instance.generateStrongPassword();
-		User user = instance.createUser(accountName, password, password);
-		user.enable();
-		MockHttpServletRequest request = new MockHttpServletRequest();
-		request.addParameter("username", accountName);
-		request.addParameter("password", password);
-		MockHttpServletResponse response = new MockHttpServletResponse();
-		ESAPI.httpUtilities().setCurrentHTTP( request, response );
-		instance.login( request, response);
-		User test = ((FileBasedAuthenticator)instance).getUserFromSession();
-		assertEquals( user, test );
-	}
-
-	/**
-	 * Test get user names.
-	 * 
-	 * @throws AuthenticationException
-	 *             the authentication exception
-	 */
-	@Test public void testGetUserNames() throws AuthenticationException {
-		System.out.println("getUserNames");
-		String password = instance.generateStrongPassword();
-		String[] testnames = new String[10];
-		for(int i=0;i<testnames.length;i++) {
-			testnames[i] = ESAPI.randomizer().getRandomString(8,EncoderConstants.CHAR_ALPHANUMERICS);
-		}
-		for(int i=0;i<testnames.length;i++) {
-			instance.createUser(testnames[i], password, password);
-		}
-		Set names = instance.getUserNames();
-		for(int i=0;i<testnames.length;i++) {
-			assertTrue(names.contains(testnames[i].toLowerCase()));
-		}
-	}
-	
-	/**
-	 * Test of hashPassword method, of class org.owasp.esapi.Authenticator.
+        User test2 = instance.login( request, response );
+        assertSame( user, test2 );
+    }
+
+
+
+    /**
+     * Test get user from session.
+     *
+     * @throws AuthenticationException
+     *             the authentication exception
+     */
+    @Test public void testGetUserFromSession() throws AuthenticationException {
+        System.out.println("getUserFromSession");
+        assumeTrue(instance instanceof FileBasedAuthenticator);
+        String accountName=ESAPI.randomizer().getRandomString(8, EncoderConstants.CHAR_ALPHANUMERICS);
+        String password = instance.generateStrongPassword();
+        User user = instance.createUser(accountName, password, password);
+        user.enable();
+        MockHttpServletRequest request = new MockHttpServletRequest();
+        request.addParameter("username", accountName);
+        request.addParameter("password", password);
+        MockHttpServletResponse response = new MockHttpServletResponse();
+        ESAPI.httpUtilities().setCurrentHTTP( request, response );
+        instance.login( request, response);
+        User test = ((FileBasedAuthenticator)instance).getUserFromSession();
+        assertEquals( user, test );
+    }
+
+    /**
+     * Test get user names.
+     *
+     * @throws AuthenticationException
+     *             the authentication exception
+     */
+    @Test public void testGetUserNames() throws AuthenticationException {
+        System.out.println("getUserNames");
+        String password = instance.generateStrongPassword();
+        String[] testnames = new String[10];
+        for(int i=0;i<testnames.length;i++) {
+            testnames[i] = ESAPI.randomizer().getRandomString(8,EncoderConstants.CHAR_ALPHANUMERICS);
+        }
+        for(int i=0;i<testnames.length;i++) {
+            instance.createUser(testnames[i], password, password);
+        }
+        Set names = instance.getUserNames();
+        for(int i=0;i<testnames.length;i++) {
+            assertTrue(names.contains(testnames[i].toLowerCase()));
+        }
+    }
+
+    /**
+     * Test of hashPassword method, of class org.owasp.esapi.Authenticator.
      *
      * @throws EncryptionException
      */
-	@Test public void testHashPassword() throws EncryptionException {
-		System.out.println("hashPassword");
-		String username = "Jeff";
-		String password = "test";
-		String result1 = instance.hashPassword(password, username);
-		String result2 = instance.hashPassword(password, username);
-		assertTrue(result1.equals(result2));
-	}
-
-	/**
-	 * Test of login method, of class org.owasp.esapi.Authenticator.
-	 * 
-	 * @throws AuthenticationException
-	 *             the authentication exception
-	 */
-	@Test public void testLogin() throws AuthenticationException {
-		System.out.println("login");
+    @Test public void testHashPassword() throws EncryptionException {
+        System.out.println("hashPassword");
+        String username = "Jeff";
+        String password = "test";
+        String result1 = instance.hashPassword(password, username);
+        String result2 = instance.hashPassword(password, username);
+        assertTrue(result1.equals(result2));
+    }
+
+    /**
+     * Test of login method, of class org.owasp.esapi.Authenticator.
+     *
+     * @throws AuthenticationException
+     *             the authentication exception
+     */
+    @Test public void testLogin() throws AuthenticationException {
+        System.out.println("login");
         String username = ESAPI.randomizer().getRandomString(8, EncoderConstants.CHAR_ALPHANUMERICS);
-		String password = instance.generateStrongPassword();
-		User user = instance.createUser(username, password, password);
-		user.enable();
-		MockHttpServletRequest request = new MockHttpServletRequest();
-		request.addParameter("username", username);
-		request.addParameter("password", password);
-		MockHttpServletResponse response = new MockHttpServletResponse();
-		ESAPI.httpUtilities().setCurrentHTTP(request, response);
-		User test = instance.login( request, response);
-		assertTrue( test.isLoggedIn() );
-		assertSame(user, test);
-	}
-	
-	/**
-	 * Test of removeAccount method, of class org.owasp.esapi.Authenticator.
-	 * 
-	 * @throws Exception
-	 *             the exception
-	 */
-	@Test public void testRemoveUser() throws Exception {
-		System.out.println("removeUser");
-		String accountName = ESAPI.randomizer().getRandomString(8, EncoderConstants.CHAR_ALPHANUMERICS);
-		String password = instance.generateStrongPassword();
-		instance.createUser(accountName, password, password);
-		assertTrue( instance.exists(accountName));
-		instance.removeUser(accountName);
-		assertFalse( instance.exists(accountName));
-	}
-
-	/**
-	 * Test of saveUsers method, of class org.owasp.esapi.Authenticator.
-	 * 
-	 * @throws Exception
-	 *             the exception
-	 */
-	@Test public void testSaveUsers() throws Exception {
-		System.out.println("saveUsers");
-		assumeTrue(instance instanceof FileBasedAuthenticator);
-		String accountName = ESAPI.randomizer().getRandomString(8, EncoderConstants.CHAR_ALPHANUMERICS);
-		String password = instance.generateStrongPassword();
-		instance.createUser(accountName, password, password);
-		((FileBasedAuthenticator)instance).saveUsers();
-		assertNotNull( instance.getUser(accountName) );
-		instance.removeUser(accountName);
-		assertNull( instance.getUser(accountName) );
-	}
-
-	
-	/**
-	 * Test of setCurrentUser method, of class org.owasp.esapi.Authenticator.
-	 * 
-	 * @throws AuthenticationException
-	 *             the authentication exception
-	 * @throws InterruptedException Thrown if test is interrupted while awaiting completion of child threads.
-	 */
-	@Test public void testSetCurrentUser() throws AuthenticationException, InterruptedException {
-		System.out.println("setCurrentUser");
+        String password = instance.generateStrongPassword();
+        User user = instance.createUser(username, password, password);
+        user.enable();
+        MockHttpServletRequest request = new MockHttpServletRequest();
+        request.addParameter("username", username);
+        request.addParameter("password", password);
+        MockHttpServletResponse response = new MockHttpServletResponse();
+        ESAPI.httpUtilities().setCurrentHTTP(request, response);
+        User test = instance.login( request, response);
+        assertTrue( test.isLoggedIn() );
+        assertSame(user, test);
+    }
+
+    /**
+     * Test of removeAccount method, of class org.owasp.esapi.Authenticator.
+     *
+     * @throws Exception
+     *             the exception
+     */
+    @Test public void testRemoveUser() throws Exception {
+        System.out.println("removeUser");
+        String accountName = ESAPI.randomizer().getRandomString(8, EncoderConstants.CHAR_ALPHANUMERICS);
+        String password = instance.generateStrongPassword();
+        instance.createUser(accountName, password, password);
+        assertTrue( instance.exists(accountName));
+        instance.removeUser(accountName);
+        assertFalse( instance.exists(accountName));
+    }
+
+    /**
+     * Test of saveUsers method, of class org.owasp.esapi.Authenticator.
+     *
+     * @throws Exception
+     *             the exception
+     */
+    @Test public void testSaveUsers() throws Exception {
+        System.out.println("saveUsers");
+        assumeTrue(instance instanceof FileBasedAuthenticator);
+        String accountName = ESAPI.randomizer().getRandomString(8, EncoderConstants.CHAR_ALPHANUMERICS);
+        String password = instance.generateStrongPassword();
+        instance.createUser(accountName, password, password);
+        ((FileBasedAuthenticator)instance).saveUsers();
+        assertNotNull( instance.getUser(accountName) );
+        instance.removeUser(accountName);
+        assertNull( instance.getUser(accountName) );
+    }
+
+
+    /**
+     * Test of setCurrentUser method, of class org.owasp.esapi.Authenticator.
+     *
+     * @throws AuthenticationException
+     *             the authentication exception
+     * @throws InterruptedException Thrown if test is interrupted while awaiting completion of child threads.
+     */
+    @Test public void testSetCurrentUser() throws AuthenticationException, InterruptedException {
+        System.out.println("setCurrentUser");
         String user1 = ESAPI.randomizer().getRandomString(8, EncoderConstants.CHAR_UPPERS);
-		String user2 = ESAPI.randomizer().getRandomString(8, EncoderConstants.CHAR_UPPERS);
-		User userOne = instance.createUser(user1, "getCurrentUser", "getCurrentUser");
-		userOne.enable();
-	    MockHttpServletRequest request = new MockHttpServletRequest();
-		MockHttpServletResponse response = new MockHttpServletResponse();
-		ESAPI.httpUtilities().setCurrentHTTP(request, response);
-		userOne.loginWithPassword("getCurrentUser");
-		User currentUser = instance.getCurrentUser();
-		assertEquals( currentUser, userOne );
-		User userTwo = instance.createUser(user2, "getCurrentUser", "getCurrentUser");		
-		instance.setCurrentUser( userTwo );
-		assertFalse( currentUser.getAccountName().equals( userTwo.getAccountName() ) );
-		final CountDownLatch latch = new CountDownLatch(10);
-		Runnable echo = new Runnable() {
-			public void run() {
-				User u=null;
-				try {
-				  //Increase pwd size to guarantee greater than (not "or equal to") 16 strength.  See FileBasedAuthenticator 711-715
+        String user2 = ESAPI.randomizer().getRandomString(8, EncoderConstants.CHAR_UPPERS);
+        User userOne = instance.createUser(user1, "getCurrentUser", "getCurrentUser");
+        userOne.enable();
+        MockHttpServletRequest request = new MockHttpServletRequest();
+        MockHttpServletResponse response = new MockHttpServletResponse();
+        ESAPI.httpUtilities().setCurrentHTTP(request, response);
+        userOne.loginWithPassword("getCurrentUser");
+        User currentUser = instance.getCurrentUser();
+        assertEquals( currentUser, userOne );
+        User userTwo = instance.createUser(user2, "getCurrentUser", "getCurrentUser");
+        instance.setCurrentUser( userTwo );
+        assertFalse( currentUser.getAccountName().equals( userTwo.getAccountName() ) );
+        final CountDownLatch latch = new CountDownLatch(10);
+        Runnable echo = new Runnable() {
+            public void run() {
+                User u=null;
+                try {
+                  //Increase pwd size to guarantee greater than (not "or equal to") 16 strength.  See FileBasedAuthenticator 711-715
                     String password = ESAPI.randomizer().getRandomString(17, EncoderConstants.CHAR_ALPHANUMERICS);
                     String username = ESAPI.randomizer().getRandomString(8, EncoderConstants.CHAR_ALPHANUMERICS);
-					u = instance.createUser(username, password, password);
-					instance.setCurrentUser(u);
-					ESAPI.getLogger("test").info( Logger.SECURITY_SUCCESS, "Got current user" );
-					//If the user isn't removed every subsequent execution will fail because we cannot create a duplicate user of the same name!
+                    u = instance.createUser(username, password, password);
+                    instance.setCurrentUser(u);
+                    ESAPI.getLogger("test").info( Logger.SECURITY_SUCCESS, "Got current user" );
+                    //If the user isn't removed every subsequent execution will fail because we cannot create a duplicate user of the same name!
                     instance.removeUser( u.getAccountName() );
-				} catch (AuthenticationException e) {
-				    collector.addError(e);
+                } catch (AuthenticationException e) {
+                    collector.addError(e);
                 } finally {
                     latch.countDown();
                 }
-			}
-		};
-		for ( int i = 0; i<10; i++ ) {
-			new Thread( echo ).start();
-		}
-		while(!latch.await(500, TimeUnit.MILLISECONDS)) {
-            //Spurious Interrupt Guard. 
+            }
+        };
+        for ( int i = 0; i<10; i++ ) {
+            new Thread( echo ).start();
+        }
+        while(!latch.await(500, TimeUnit.MILLISECONDS)) {
+            //Spurious Interrupt Guard.
         }
-	}
-	
+    }
+
 
 
     /**
      * Test of setCurrentUser method, of class org.owasp.esapi.Authenticator.
-     * 
+     *
      * @throws AuthenticationException
      *             the authentication exception
      */
@@ -482,7 +482,7 @@ public class AuthenticatorTest {
 
     /**
      * Test of setCurrentUser method, of class org.owasp.esapi.Authenticator.
-     * 
+     *
      * @throws AuthenticationException
      *             the authentication exception
      */
@@ -505,10 +505,10 @@ public class AuthenticatorTest {
             // expected
         }
     }
-    
+
     /**
      * Test of setCurrentUser method, of class org.owasp.esapi.Authenticator.
-     * 
+     *
      * @throws AuthenticationException
      *             the authentication exception
      */
@@ -533,7 +533,7 @@ public class AuthenticatorTest {
     }
     /**
      * Test of setCurrentUser method, of class org.owasp.esapi.Authenticator.
-     * 
+     *
      * @throws AuthenticationException
      *             the authentication exception
      */
@@ -559,110 +559,110 @@ public class AuthenticatorTest {
             // expected
         }
     }
-	
-	
-	
-	/**
-	 * Test of validatePasswordStrength method, of class
-	 * org.owasp.esapi.Authenticator.
-	 * 
-	 * @throws AuthenticationException
-	 *             the authentication exception
-	 */
-	@Test public void testValidatePasswordStrength() throws AuthenticationException {
-		System.out.println("validatePasswordStrength");
-        
+
+
+
+    /**
+     * Test of validatePasswordStrength method, of class
+     * org.owasp.esapi.Authenticator.
+     *
+     * @throws AuthenticationException
+     *             the authentication exception
+     */
+    @Test public void testValidatePasswordStrength() throws AuthenticationException {
+        System.out.println("validatePasswordStrength");
+
         String username = "FictionalEsapiUser";
-		User user = new DefaultUser(username);
-
-		// should fail
-		try {
-			instance.verifyPasswordStrength("password", "jeff", user);
-			fail();
-		} catch (AuthenticationException e) {
-			// success
-		}
-		try {
-			instance.verifyPasswordStrength("diff123bang", "same123string", user);
-			fail();
-		} catch (AuthenticationException e) {
-			// success
-		}
-		try {
-			instance.verifyPasswordStrength("password", "JEFF", user);
-			fail();
-		} catch (AuthenticationException e) {
-			// success
-		}
-		try {
-			instance.verifyPasswordStrength("password", "1234", user);
-			fail();
-		} catch (AuthenticationException e) {
-			// success
-		}
-		try {
-			instance.verifyPasswordStrength("password", "password", user);
-			fail();
-		} catch (AuthenticationException e) {
-			// success
-		}
-		try {
-			instance.verifyPasswordStrength("password", "-1", user);
-			fail();
-		} catch (AuthenticationException e) {
-			// success
-		}
-		try {
-			instance.verifyPasswordStrength("password", "password123", user);
-			fail();
-		} catch (AuthenticationException e) {
-			// success
-		}
-		try {
-			instance.verifyPasswordStrength("password", "test123", user);
-			fail();
-		} catch (AuthenticationException e) {
-			// success
-		}
-		//jtm - 11/16/2010 - fix for bug http://code.google.com/p/owasp-esapi-java/issues/detail?id=108
-		try {
-			instance.verifyPasswordStrength("password", "FictionalEsapiUser", user);
-			fail();
-		} catch (AuthenticationException e) {
-			// success
-		}
-		try {
-			instance.verifyPasswordStrength("password", "FICTIONALESAPIUSER", user);
-			fail();
-		} catch (AuthenticationException e) {
-			// success
-		}
-
-		// should pass
-		instance.verifyPasswordStrength("password", "jeffJEFF12!", user);
-		instance.verifyPasswordStrength("password", "super calif ragil istic", user);
-		instance.verifyPasswordStrength("password", "TONYTONYTONYTONY", user);
-		instance.verifyPasswordStrength("password", instance.generateStrongPassword(), user);
+        User user = new DefaultUser(username);
+
+        // should fail
+        try {
+            instance.verifyPasswordStrength("password", "jeff", user);
+            fail();
+        } catch (AuthenticationException e) {
+            // success
+        }
+        try {
+            instance.verifyPasswordStrength("diff123bang", "same123string", user);
+            fail();
+        } catch (AuthenticationException e) {
+            // success
+        }
+        try {
+            instance.verifyPasswordStrength("password", "JEFF", user);
+            fail();
+        } catch (AuthenticationException e) {
+            // success
+        }
+        try {
+            instance.verifyPasswordStrength("password", "1234", user);
+            fail();
+        } catch (AuthenticationException e) {
+            // success
+        }
+        try {
+            instance.verifyPasswordStrength("password", "password", user);
+            fail();
+        } catch (AuthenticationException e) {
+            // success
+        }
+        try {
+            instance.verifyPasswordStrength("password", "-1", user);
+            fail();
+        } catch (AuthenticationException e) {
+            // success
+        }
+        try {
+            instance.verifyPasswordStrength("password", "password123", user);
+            fail();
+        } catch (AuthenticationException e) {
+            // success
+        }
+        try {
+            instance.verifyPasswordStrength("password", "test123", user);
+            fail();
+        } catch (AuthenticationException e) {
+            // success
+        }
+        //jtm - 11/16/2010 - fix for bug http://code.google.com/p/owasp-esapi-java/issues/detail?id=108
+        try {
+            instance.verifyPasswordStrength("password", "FictionalEsapiUser", user);
+            fail();
+        } catch (AuthenticationException e) {
+            // success
+        }
+        try {
+            instance.verifyPasswordStrength("password", "FICTIONALESAPIUSER", user);
+            fail();
+        } catch (AuthenticationException e) {
+            // success
+        }
+
+        // should pass
+        instance.verifyPasswordStrength("password", "jeffJEFF12!", user);
+        instance.verifyPasswordStrength("password", "super calif ragil istic", user);
+        instance.verifyPasswordStrength("password", "TONYTONYTONYTONY", user);
+        instance.verifyPasswordStrength("password", instance.generateStrongPassword(), user);
 
         // chrisisbeef - Issue 65 - http://code.google.com/p/owasp-esapi-java/issues/detail?id=65
         instance.verifyPasswordStrength("password", "b!gbr0ther", user);
-	}
-
-	/**
-	 * Test of exists method, of class org.owasp.esapi.Authenticator.
-	 * 
-	 * @throws Exception
-	 *             the exception
-	 */
-	@Test public void testExists() throws Exception {
-		System.out.println("exists");
-		String accountName = ESAPI.randomizer().getRandomString(8, EncoderConstants.CHAR_ALPHANUMERICS);
-		String password = instance.generateStrongPassword();
-		instance.createUser(accountName, password, password);
-		assertTrue(instance.exists(accountName));
-		instance.removeUser(accountName);
-		assertFalse(instance.exists(accountName));
-	}
+    }
+
+    /**
+     * Test of exists method, of class org.owasp.esapi.Authenticator.
+     *
+     * @throws Exception
+     *             the exception
+     */
+    @Test public void testExists() throws Exception {
+        System.out.println("exists");
+        String accountName = ESAPI.randomizer().getRandomString(8, EncoderConstants.CHAR_ALPHANUMERICS);
+        String password = instance.generateStrongPassword();
+        instance.createUser(accountName, password, password);
+        assertTrue(instance.exists(accountName));
+        instance.removeUser(accountName);
+        assertFalse(instance.exists(accountName));
+    }
 
     /**
      * Test of main method, of class org.owasp.esapi.Authenticator.
@@ -673,7 +673,7 @@ public class AuthenticatorTest {
         String accountName = ESAPI.randomizer().getRandomString(8, EncoderConstants.CHAR_ALPHANUMERICS);
         String password = instance.generateStrongPassword();
         String role = "test";
-        
+
         // test wrong parameters - missing role parameter
         String[] badargs = { accountName, password };
         FileBasedAuthenticator.main( badargs );
@@ -692,6 +692,6 @@ public class AuthenticatorTest {
         assertTrue( u2.isInRole(role));
         assertEquals( instance.hashPassword(password, accountName), ((FileBasedAuthenticator)instance).getHashedPassword(u2) );
     }
-    
-    
+
+
 }
diff --git a/src/test/java/org/owasp/esapi/reference/DefaultSecurityConfigurationTest.java b/src/test/java/org/owasp/esapi/reference/DefaultSecurityConfigurationTest.java
index d0c3e6d..9a80161 100644
--- a/src/test/java/org/owasp/esapi/reference/DefaultSecurityConfigurationTest.java
+++ b/src/test/java/org/owasp/esapi/reference/DefaultSecurityConfigurationTest.java
@@ -16,332 +16,334 @@ import org.owasp.esapi.ESAPI;
 import org.owasp.esapi.Logger;
 import org.owasp.esapi.SecurityConfiguration;
 import org.owasp.esapi.errors.ConfigurationException;
-import org.owasp.esapi.reference.DefaultSecurityConfiguration.DefaultSearchPath;
+import org.owasp.esapi.PropNames.DefaultSearchPath;
+
+import static org.owasp.esapi.PropNames.*;
 
 public class DefaultSecurityConfigurationTest {
 
-	private DefaultSecurityConfiguration createWithProperty(String key, String val) {
-		Properties properties = new Properties();
-		properties.setProperty(key, val);
-		return new DefaultSecurityConfiguration(properties);
-	}
-	
-	@Test
-	public void testGetApplicationName() {
-		final String expected = "ESAPI_UnitTests";
-		DefaultSecurityConfiguration secConf = this.createWithProperty(DefaultSecurityConfiguration.APPLICATION_NAME, expected);
-		assertEquals(expected, secConf.getApplicationName());
-	}
-	
-	@Test
-	public void testGetLogImplementation() {
-		//test the default
-		DefaultSecurityConfiguration secConf = new DefaultSecurityConfiguration(new Properties());
-		assertEquals(DefaultSecurityConfiguration.DEFAULT_LOG_IMPLEMENTATION, secConf.getLogImplementation());
-		
-		final String expected = "TestLogger";
-		secConf = this.createWithProperty(DefaultSecurityConfiguration.LOG_IMPLEMENTATION, expected);
-		assertEquals(expected, secConf.getLogImplementation());
-	}
-	
-	@Test
-	public void testAuthenticationImplementation() {
-		//test the default
-		DefaultSecurityConfiguration secConf = new DefaultSecurityConfiguration(new Properties());
-		assertEquals(DefaultSecurityConfiguration.DEFAULT_AUTHENTICATION_IMPLEMENTATION, secConf.getAuthenticationImplementation());
-		
-		final String expected = "TestAuthentication";
-		secConf = this.createWithProperty(DefaultSecurityConfiguration.AUTHENTICATION_IMPLEMENTATION, expected);
-		assertEquals(expected, secConf.getAuthenticationImplementation());
-	}
-	
-	@Test
-	public void testEncoderImplementation() {
-		//test the default
-		DefaultSecurityConfiguration secConf = new DefaultSecurityConfiguration(new Properties());
-		assertEquals(DefaultSecurityConfiguration.DEFAULT_ENCODER_IMPLEMENTATION, secConf.getEncoderImplementation());
-		
-		final String expected = "TestEncoder";
-		secConf = this.createWithProperty(DefaultSecurityConfiguration.ENCODER_IMPLEMENTATION, expected);
-		assertEquals(expected, secConf.getEncoderImplementation());
-	}
-	
-	@Test
-	public void testAccessControlImplementation() {
-		//test the default
-		DefaultSecurityConfiguration secConf = new DefaultSecurityConfiguration(new Properties());
-		assertEquals(DefaultSecurityConfiguration.DEFAULT_ACCESS_CONTROL_IMPLEMENTATION, secConf.getAccessControlImplementation());
-		
-		final String expected = "TestAccessControl";
-		secConf = this.createWithProperty(DefaultSecurityConfiguration.ACCESS_CONTROL_IMPLEMENTATION, expected);
-		assertEquals(expected, secConf.getAccessControlImplementation());
-	}
-	
-	@Test
-	public void testEncryptionImplementation() {
-		//test the default
-		DefaultSecurityConfiguration secConf = new DefaultSecurityConfiguration(new Properties());
-		assertEquals(DefaultSecurityConfiguration.DEFAULT_ENCRYPTION_IMPLEMENTATION, secConf.getEncryptionImplementation());
-		
-		final String expected = "TestEncryption";
-		secConf = this.createWithProperty(DefaultSecurityConfiguration.ENCRYPTION_IMPLEMENTATION, expected);
-		assertEquals(expected, secConf.getEncryptionImplementation());
-	}
-	
-	@Test
-	public void testIntrusionDetectionImplementation() {
-		//test the default
-		DefaultSecurityConfiguration secConf = new DefaultSecurityConfiguration(new Properties());
-		assertEquals(DefaultSecurityConfiguration.DEFAULT_INTRUSION_DETECTION_IMPLEMENTATION, secConf.getIntrusionDetectionImplementation());
-		
-		final String expected = "TestIntrusionDetection";
-		secConf = this.createWithProperty(DefaultSecurityConfiguration.INTRUSION_DETECTION_IMPLEMENTATION, expected);
-		assertEquals(expected, secConf.getIntrusionDetectionImplementation());
-	}
-	
-	@Test
-	public void testRandomizerImplementation() {
-		//test the default
-		DefaultSecurityConfiguration secConf = new DefaultSecurityConfiguration(new Properties());
-		assertEquals(DefaultSecurityConfiguration.DEFAULT_RANDOMIZER_IMPLEMENTATION, secConf.getRandomizerImplementation());
-		
-		final String expected = "TestRandomizer";
-		secConf = this.createWithProperty(DefaultSecurityConfiguration.RANDOMIZER_IMPLEMENTATION, expected);
-		assertEquals(expected, secConf.getRandomizerImplementation());
-	}
-	
-	@Test
-	public void testExecutorImplementation() {
-		//test the default
-		DefaultSecurityConfiguration secConf = new DefaultSecurityConfiguration(new Properties());
-		assertEquals(DefaultSecurityConfiguration.DEFAULT_EXECUTOR_IMPLEMENTATION, secConf.getExecutorImplementation());
-		
-		final String expected = "TestExecutor";
-		secConf = this.createWithProperty(DefaultSecurityConfiguration.EXECUTOR_IMPLEMENTATION, expected);
-		assertEquals(expected, secConf.getExecutorImplementation());
-	}
-	
-	@Test
-	public void testHTTPUtilitiesImplementation() {
-		//test the default
-		DefaultSecurityConfiguration secConf = new DefaultSecurityConfiguration(new Properties());
-		assertEquals(DefaultSecurityConfiguration.DEFAULT_HTTP_UTILITIES_IMPLEMENTATION, secConf.getHTTPUtilitiesImplementation());
-		
-		final String expected = "TestHTTPUtilities";
-		secConf = this.createWithProperty(DefaultSecurityConfiguration.HTTP_UTILITIES_IMPLEMENTATION, expected);
-		assertEquals(expected, secConf.getHTTPUtilitiesImplementation());
-	}
-	
-	@Test
-	public void testValidationImplementation() {
-		//test the default
-		DefaultSecurityConfiguration secConf = new DefaultSecurityConfiguration(new Properties());
-		assertEquals(DefaultSecurityConfiguration.DEFAULT_VALIDATOR_IMPLEMENTATION, secConf.getValidationImplementation());
-		
-		final String expected = "TestValidation";
-		secConf = this.createWithProperty(DefaultSecurityConfiguration.VALIDATOR_IMPLEMENTATION, expected);
-		assertEquals(expected, secConf.getValidationImplementation());
-	}
-	
-	@Test
-	public void testGetEncryptionKeyLength() {
-		// test the default
-		DefaultSecurityConfiguration secConf = new DefaultSecurityConfiguration(new Properties());
-		assertEquals(128, secConf.getEncryptionKeyLength());
-		
-		final int expected = 256;
-		secConf = this.createWithProperty(DefaultSecurityConfiguration.KEY_LENGTH, String.valueOf(expected));
-		assertEquals(expected, secConf.getEncryptionKeyLength());
-	}
-	
-	@Test
-	public void testGetKDFPseudoRandomFunction() {
-		// test the default
-		DefaultSecurityConfiguration secConf = new DefaultSecurityConfiguration(new Properties());
-		assertEquals("HmacSHA256", secConf.getKDFPseudoRandomFunction());
-		
-		final String expected = "HmacSHA1";
-		secConf = this.createWithProperty(DefaultSecurityConfiguration.KDF_PRF_ALG, expected);
-		assertEquals(expected, secConf.getKDFPseudoRandomFunction());
-	}
-	
-	@Test
-	public void testGetMasterSalt() {
-		try {
-			DefaultSecurityConfiguration secConf = new DefaultSecurityConfiguration(new Properties());
-			secConf.getMasterSalt();
-			fail("Expected Exception not thrown");
-		}
-		catch (ConfigurationException ce) {
-			assertNotNull(ce.getMessage());
-		}
-		
-		final String salt = "53081";
-		final String property = ESAPI.encoder().encodeForBase64(salt.getBytes(), false);
-		Properties properties = new Properties();
-		properties.setProperty(DefaultSecurityConfiguration.MASTER_SALT, property);
-		DefaultSecurityConfiguration secConf = new DefaultSecurityConfiguration(properties);
-		assertEquals(salt, new String(secConf.getMasterSalt()));
-	}
-	
-	@Test
-	public void testGetAllowedExecutables() {
-		DefaultSecurityConfiguration secConf = new DefaultSecurityConfiguration(new Properties());
-		java.util.List<String> allowedExecutables = secConf.getAllowedExecutables();
-		
-		//is this really what should be returned? what about an empty list?
-		assertEquals(1, allowedExecutables.size());
-		assertEquals("", allowedExecutables.get(0));
-		
-		
-		Properties properties = new Properties();
-		properties.setProperty(DefaultSecurityConfiguration.APPROVED_EXECUTABLES, String.valueOf("/bin/bzip2,/bin/diff, /bin/cvs"));
-		secConf = new DefaultSecurityConfiguration(properties);
-		allowedExecutables = secConf.getAllowedExecutables();
-		assertEquals(3, allowedExecutables.size());
-		assertEquals("/bin/bzip2", allowedExecutables.get(0));
-		assertEquals("/bin/diff", allowedExecutables.get(1));
-		
-		//this seems less than optimal, maybe each value should have a trim() done to it
-		//at least we know that this behavior exists, the property should'nt have spaces between values
-		assertEquals(" /bin/cvs", allowedExecutables.get(2));
-	}
-	
-	@Test
-	public void testGetAllowedFileExtensions() {
-		
-		DefaultSecurityConfiguration secConf = new DefaultSecurityConfiguration(new Properties());
-		java.util.List<String> allowedFileExtensions = secConf.getAllowedFileExtensions();
-		assertFalse(allowedFileExtensions.isEmpty());
-		
-		
-		Properties properties = new Properties();
-		properties.setProperty(DefaultSecurityConfiguration.APPROVED_UPLOAD_EXTENSIONS, String.valueOf(".txt,.xml,.html,.png"));
-		secConf = new DefaultSecurityConfiguration(properties);
-		allowedFileExtensions = secConf.getAllowedFileExtensions();
-		assertEquals(4, allowedFileExtensions.size());
-		assertEquals(".html", allowedFileExtensions.get(2));
-	}
-	
-	@Test
-	public void testGetAllowedFileUploadSize() {
-		DefaultSecurityConfiguration secConf = new DefaultSecurityConfiguration(new Properties());
-		//assert that the default is of some reasonable size
-		assertTrue(secConf.getAllowedFileUploadSize() > (1024 * 100));
-		
-		final int expected = (1024 * 1000);
-		secConf = this.createWithProperty(DefaultSecurityConfiguration.MAX_UPLOAD_FILE_BYTES, String.valueOf(expected));
-		assertEquals(expected, secConf.getAllowedFileUploadSize());
-	}
-	
-	@Test
-	public void testGetParameterNames() {
-		//test the default
-		DefaultSecurityConfiguration secConf = new DefaultSecurityConfiguration(new Properties());
-		assertEquals("password", secConf.getPasswordParameterName());
-		assertEquals("username", secConf.getUsernameParameterName());
-		
-		Properties properties = new Properties();
-		properties.setProperty(DefaultSecurityConfiguration.PASSWORD_PARAMETER_NAME, "j_password");
-		properties.setProperty(DefaultSecurityConfiguration.USERNAME_PARAMETER_NAME, "j_username");
-		secConf = new DefaultSecurityConfiguration(properties);
-		assertEquals("j_password", secConf.getPasswordParameterName());
-		assertEquals("j_username", secConf.getUsernameParameterName());
-	}
-	
-	@Test
-	public void testGetEncryptionAlgorithm() {
-		//test the default
-		DefaultSecurityConfiguration secConf = new DefaultSecurityConfiguration(new Properties());
-		assertEquals("AES", secConf.getEncryptionAlgorithm());
-		
-		secConf = this.createWithProperty(DefaultSecurityConfiguration.ENCRYPTION_ALGORITHM, "3DES");
-		assertEquals("3DES", secConf.getEncryptionAlgorithm());
-	}
-	
-	@Test
-	public void testGetCipherXProperties() {
-		DefaultSecurityConfiguration secConf = new DefaultSecurityConfiguration(new Properties());
-		assertEquals("AES/CBC/PKCS5Padding", secConf.getCipherTransformation());
-		//assertEquals("AES/CBC/PKCS5Padding", secConf.getC);
-		
-		Properties properties = new Properties();
-		properties.setProperty(DefaultSecurityConfiguration.CIPHER_TRANSFORMATION_IMPLEMENTATION, "Blowfish/CFB/ISO10126Padding");
-		secConf = new DefaultSecurityConfiguration(properties);
-		assertEquals("Blowfish/CFB/ISO10126Padding", secConf.getCipherTransformation());
-		
-		secConf.setCipherTransformation("DESede/PCBC/PKCS5Padding");
-		assertEquals("DESede/PCBC/PKCS5Padding", secConf.getCipherTransformation());
-		
-		secConf.setCipherTransformation(null);//sets it back to default
-		assertEquals("Blowfish/CFB/ISO10126Padding", secConf.getCipherTransformation());
-	}
-
-	// NOTE: When SecurityConfiguration.getIVType() is finally removed, this test can be as well.
-	@Test
-	public void testIV() {
-		DefaultSecurityConfiguration secConf = new DefaultSecurityConfiguration(new Properties());
-		assertEquals("random", secConf.getIVType());    // Ensure that 'random' is the default type for getIVType().
+    private DefaultSecurityConfiguration createWithProperty(String key, String val) {
+        Properties properties = new Properties();
+        properties.setProperty(key, val);
+        return new DefaultSecurityConfiguration(properties);
+    }
+
+    @Test
+    public void testGetApplicationName() {
+        final String expected = "ESAPI_UnitTests";
+        DefaultSecurityConfiguration secConf = this.createWithProperty(APPLICATION_NAME, expected);
+        assertEquals(expected, secConf.getApplicationName());
+    }
+
+    @Test
+    public void testGetLogImplementation() {
+        //test the default
+        DefaultSecurityConfiguration secConf = new DefaultSecurityConfiguration(new Properties());
+        assertEquals(DEFAULT_LOG_IMPLEMENTATION, secConf.getLogImplementation());
+
+        final String expected = "TestLogger";
+        secConf = this.createWithProperty(LOG_IMPLEMENTATION, expected);
+        assertEquals(expected, secConf.getLogImplementation());
+    }
+
+    @Test
+    public void testAuthenticationImplementation() {
+        //test the default
+        DefaultSecurityConfiguration secConf = new DefaultSecurityConfiguration(new Properties());
+        assertEquals(DEFAULT_AUTHENTICATION_IMPLEMENTATION, secConf.getAuthenticationImplementation());
+
+        final String expected = "TestAuthentication";
+        secConf = this.createWithProperty(AUTHENTICATION_IMPLEMENTATION, expected);
+        assertEquals(expected, secConf.getAuthenticationImplementation());
+    }
+
+    @Test
+    public void testEncoderImplementation() {
+        //test the default
+        DefaultSecurityConfiguration secConf = new DefaultSecurityConfiguration(new Properties());
+        assertEquals(DEFAULT_ENCODER_IMPLEMENTATION, secConf.getEncoderImplementation());
+
+        final String expected = "TestEncoder";
+        secConf = this.createWithProperty(ENCODER_IMPLEMENTATION, expected);
+        assertEquals(expected, secConf.getEncoderImplementation());
+    }
+
+    @Test
+    public void testAccessControlImplementation() {
+        //test the default
+        DefaultSecurityConfiguration secConf = new DefaultSecurityConfiguration(new Properties());
+        assertEquals(DEFAULT_ACCESS_CONTROL_IMPLEMENTATION, secConf.getAccessControlImplementation());
+
+        final String expected = "TestAccessControl";
+        secConf = this.createWithProperty(ACCESS_CONTROL_IMPLEMENTATION, expected);
+        assertEquals(expected, secConf.getAccessControlImplementation());
+    }
+
+    @Test
+    public void testEncryptionImplementation() {
+        //test the default
+        DefaultSecurityConfiguration secConf = new DefaultSecurityConfiguration(new Properties());
+        assertEquals(DEFAULT_ENCRYPTION_IMPLEMENTATION, secConf.getEncryptionImplementation());
+
+        final String expected = "TestEncryption";
+        secConf = this.createWithProperty(ENCRYPTION_IMPLEMENTATION, expected);
+        assertEquals(expected, secConf.getEncryptionImplementation());
+    }
+
+    @Test
+    public void testIntrusionDetectionImplementation() {
+        //test the default
+        DefaultSecurityConfiguration secConf = new DefaultSecurityConfiguration(new Properties());
+        assertEquals(DEFAULT_INTRUSION_DETECTION_IMPLEMENTATION, secConf.getIntrusionDetectionImplementation());
+
+        final String expected = "TestIntrusionDetection";
+        secConf = this.createWithProperty(INTRUSION_DETECTION_IMPLEMENTATION, expected);
+        assertEquals(expected, secConf.getIntrusionDetectionImplementation());
+    }
+
+    @Test
+    public void testRandomizerImplementation() {
+        //test the default
+        DefaultSecurityConfiguration secConf = new DefaultSecurityConfiguration(new Properties());
+        assertEquals(DEFAULT_RANDOMIZER_IMPLEMENTATION, secConf.getRandomizerImplementation());
+
+        final String expected = "TestRandomizer";
+        secConf = this.createWithProperty(RANDOMIZER_IMPLEMENTATION, expected);
+        assertEquals(expected, secConf.getRandomizerImplementation());
+    }
+
+    @Test
+    public void testExecutorImplementation() {
+        //test the default
+        DefaultSecurityConfiguration secConf = new DefaultSecurityConfiguration(new Properties());
+        assertEquals(DEFAULT_EXECUTOR_IMPLEMENTATION, secConf.getExecutorImplementation());
+
+        final String expected = "TestExecutor";
+        secConf = this.createWithProperty(EXECUTOR_IMPLEMENTATION, expected);
+        assertEquals(expected, secConf.getExecutorImplementation());
+    }
+
+    @Test
+    public void testHTTPUtilitiesImplementation() {
+        //test the default
+        DefaultSecurityConfiguration secConf = new DefaultSecurityConfiguration(new Properties());
+        assertEquals(DEFAULT_HTTP_UTILITIES_IMPLEMENTATION, secConf.getHTTPUtilitiesImplementation());
+
+        final String expected = "TestHTTPUtilities";
+        secConf = this.createWithProperty(HTTP_UTILITIES_IMPLEMENTATION, expected);
+        assertEquals(expected, secConf.getHTTPUtilitiesImplementation());
+    }
+
+    @Test
+    public void testValidationImplementation() {
+        //test the default
+        DefaultSecurityConfiguration secConf = new DefaultSecurityConfiguration(new Properties());
+        assertEquals(DEFAULT_VALIDATOR_IMPLEMENTATION, secConf.getValidationImplementation());
+
+        final String expected = "TestValidation";
+        secConf = this.createWithProperty(VALIDATOR_IMPLEMENTATION, expected);
+        assertEquals(expected, secConf.getValidationImplementation());
+    }
+
+    @Test
+    public void testGetEncryptionKeyLength() {
+        // test the default
+        DefaultSecurityConfiguration secConf = new DefaultSecurityConfiguration(new Properties());
+        assertEquals(128, secConf.getEncryptionKeyLength());
+
+        final int expected = 256;
+        secConf = this.createWithProperty(KEY_LENGTH, String.valueOf(expected));
+        assertEquals(expected, secConf.getEncryptionKeyLength());
+    }
+
+    @Test
+    public void testGetKDFPseudoRandomFunction() {
+        // test the default
+        DefaultSecurityConfiguration secConf = new DefaultSecurityConfiguration(new Properties());
+        assertEquals("HmacSHA256", secConf.getKDFPseudoRandomFunction());
+
+        final String expected = "HmacSHA1";
+        secConf = this.createWithProperty(KDF_PRF_ALG, expected);
+        assertEquals(expected, secConf.getKDFPseudoRandomFunction());
+    }
+
+    @Test
+    public void testGetMasterSalt() {
+        try {
+            DefaultSecurityConfiguration secConf = new DefaultSecurityConfiguration(new Properties());
+            secConf.getMasterSalt();
+            fail("Expected Exception not thrown");
+        }
+        catch (ConfigurationException ce) {
+            assertNotNull(ce.getMessage());
+        }
+
+        final String salt = "53081";
+        final String property = ESAPI.encoder().encodeForBase64(salt.getBytes(), false);
+        Properties properties = new Properties();
+        properties.setProperty(MASTER_SALT, property);
+        DefaultSecurityConfiguration secConf = new DefaultSecurityConfiguration(properties);
+        assertEquals(salt, new String(secConf.getMasterSalt()));
+    }
+
+    @Test
+    public void testGetAllowedExecutables() {
+        DefaultSecurityConfiguration secConf = new DefaultSecurityConfiguration(new Properties());
+        java.util.List<String> allowedExecutables = secConf.getAllowedExecutables();
+
+        //is this really what should be returned? what about an empty list?
+        assertEquals(1, allowedExecutables.size());
+        assertEquals("", allowedExecutables.get(0));
+
+
+        Properties properties = new Properties();
+        properties.setProperty(APPROVED_EXECUTABLES, String.valueOf("/bin/bzip2,/bin/diff, /bin/cvs"));
+        secConf = new DefaultSecurityConfiguration(properties);
+        allowedExecutables = secConf.getAllowedExecutables();
+        assertEquals(3, allowedExecutables.size());
+        assertEquals("/bin/bzip2", allowedExecutables.get(0));
+        assertEquals("/bin/diff", allowedExecutables.get(1));
+
+        //this seems less than optimal, maybe each value should have a trim() done to it
+        //at least we know that this behavior exists, the property should'nt have spaces between values
+        assertEquals(" /bin/cvs", allowedExecutables.get(2));
+    }
+
+    @Test
+    public void testGetAllowedFileExtensions() {
+
+        DefaultSecurityConfiguration secConf = new DefaultSecurityConfiguration(new Properties());
+        java.util.List<String> allowedFileExtensions = secConf.getAllowedFileExtensions();
+        assertFalse(allowedFileExtensions.isEmpty());
+
+
+        Properties properties = new Properties();
+        properties.setProperty(APPROVED_UPLOAD_EXTENSIONS, String.valueOf(".txt,.xml,.html,.png"));
+        secConf = new DefaultSecurityConfiguration(properties);
+        allowedFileExtensions = secConf.getAllowedFileExtensions();
+        assertEquals(4, allowedFileExtensions.size());
+        assertEquals(".html", allowedFileExtensions.get(2));
+    }
+
+    @Test
+    public void testGetAllowedFileUploadSize() {
+        DefaultSecurityConfiguration secConf = new DefaultSecurityConfiguration(new Properties());
+        //assert that the default is of some reasonable size
+        assertTrue(secConf.getAllowedFileUploadSize() > (1024 * 100));
+
+        final int expected = (1024 * 1000);
+        secConf = this.createWithProperty(MAX_UPLOAD_FILE_BYTES, String.valueOf(expected));
+        assertEquals(expected, secConf.getAllowedFileUploadSize());
+    }
+
+    @Test
+    public void testGetParameterNames() {
+        //test the default
+        DefaultSecurityConfiguration secConf = new DefaultSecurityConfiguration(new Properties());
+        assertEquals("password", secConf.getPasswordParameterName());
+        assertEquals("username", secConf.getUsernameParameterName());
+
+        Properties properties = new Properties();
+        properties.setProperty(PASSWORD_PARAMETER_NAME, "j_password");
+        properties.setProperty(USERNAME_PARAMETER_NAME, "j_username");
+        secConf = new DefaultSecurityConfiguration(properties);
+        assertEquals("j_password", secConf.getPasswordParameterName());
+        assertEquals("j_username", secConf.getUsernameParameterName());
+    }
+
+    @Test
+    public void testGetEncryptionAlgorithm() {
+        //test the default
+        DefaultSecurityConfiguration secConf = new DefaultSecurityConfiguration(new Properties());
+        assertEquals("AES", secConf.getEncryptionAlgorithm());
+
+        secConf = this.createWithProperty(ENCRYPTION_ALGORITHM, "3DES");
+        assertEquals("3DES", secConf.getEncryptionAlgorithm());
+    }
+
+    @Test
+    public void testGetCipherXProperties() {
+        DefaultSecurityConfiguration secConf = new DefaultSecurityConfiguration(new Properties());
+        assertEquals("AES/CBC/PKCS5Padding", secConf.getCipherTransformation());
+        //assertEquals("AES/CBC/PKCS5Padding", secConf.getC);
+
+        Properties properties = new Properties();
+        properties.setProperty(CIPHER_TRANSFORMATION_IMPLEMENTATION, "Blowfish/CFB/ISO10126Padding");
+        secConf = new DefaultSecurityConfiguration(properties);
+        assertEquals("Blowfish/CFB/ISO10126Padding", secConf.getCipherTransformation());
+
+        secConf.setCipherTransformation("DESede/PCBC/PKCS5Padding");
+        assertEquals("DESede/PCBC/PKCS5Padding", secConf.getCipherTransformation());
+
+        secConf.setCipherTransformation(null);//sets it back to default
+        assertEquals("Blowfish/CFB/ISO10126Padding", secConf.getCipherTransformation());
+    }
+
+    // NOTE: When SecurityConfiguration.getIVType() is finally removed, this test can be as well.
+    @Test
+    public void testIV() {
+        DefaultSecurityConfiguration secConf = new DefaultSecurityConfiguration(new Properties());
+        assertEquals("random", secConf.getIVType());    // Ensure that 'random' is the default type for getIVType().
 
         Properties props = new Properties();
         String ivType = null;
-        props.setProperty(DefaultSecurityConfiguration.IV_TYPE, "fixed");  // No longer supported.
+        props.setProperty(IV_TYPE, "fixed");  // No longer supported.
 
         secConf = new DefaultSecurityConfiguration( props );
-		try {
-			ivType = secConf.getIVType();    // This should now throw a Configuration Exception.
-			fail("Expected ConfigurationException to be thrown for " + DefaultSecurityConfiguration.IV_TYPE + "=" + ivType);
-		}
-		catch (ConfigurationException ce) {
-			assertNotNull(ce.getMessage());
-		}
-		
-		props.setProperty(DefaultSecurityConfiguration.IV_TYPE, "illegal");	// This will just result in a logSpecial message & "random" is returned.
-		secConf = new DefaultSecurityConfiguration(props);
-		ivType = secConf.getIVType();
-		assertEquals(ivType, "random");
-	}
-	
-	@Test
-	public void testGetAllowMultipleEncoding() {
-		DefaultSecurityConfiguration secConf = new DefaultSecurityConfiguration(new Properties());
-		assertFalse(secConf.getAllowMultipleEncoding());
-		
-		secConf = this.createWithProperty(DefaultSecurityConfiguration.ALLOW_MULTIPLE_ENCODING, "yes");
-		assertTrue(secConf.getAllowMultipleEncoding());
-		
-		secConf = this.createWithProperty(DefaultSecurityConfiguration.ALLOW_MULTIPLE_ENCODING, "true");
-		assertTrue(secConf.getAllowMultipleEncoding());
-		
-		secConf = this.createWithProperty(DefaultSecurityConfiguration.ALLOW_MULTIPLE_ENCODING, "no");
-		assertFalse(secConf.getAllowMultipleEncoding());
-	}
-	
-	@Test
-	public void testGetDefaultCanonicalizationCodecs() {
-		DefaultSecurityConfiguration secConf = new DefaultSecurityConfiguration(new Properties());
-		assertFalse(secConf.getDefaultCanonicalizationCodecs().isEmpty());
-		
-		String property = "org.owasp.esapi.codecs.TestCodec1,org.owasp.esapi.codecs.TestCodec2";
-		secConf = this.createWithProperty(DefaultSecurityConfiguration.CANONICALIZATION_CODECS, property);
-		assertTrue(secConf.getDefaultCanonicalizationCodecs().contains("org.owasp.esapi.codecs.TestCodec1"));
-	}
-	
-	@Test
-	public void testGetDisableIntrusionDetection() {
-		DefaultSecurityConfiguration secConf = new DefaultSecurityConfiguration(new Properties());
-		assertFalse(secConf.getDisableIntrusionDetection());
-		
-		secConf = this.createWithProperty(DefaultSecurityConfiguration.DISABLE_INTRUSION_DETECTION, "TRUE");
-		assertTrue(secConf.getDisableIntrusionDetection());
-		
-		secConf = this.createWithProperty(DefaultSecurityConfiguration.DISABLE_INTRUSION_DETECTION, "true");
-		assertTrue(secConf.getDisableIntrusionDetection());
-		
-		secConf = this.createWithProperty(DefaultSecurityConfiguration.DISABLE_INTRUSION_DETECTION, "false");
-		assertFalse(secConf.getDisableIntrusionDetection());
-	}
-	
+        try {
+            ivType = secConf.getIVType();    // This should now throw a Configuration Exception.
+            fail("Expected ConfigurationException to be thrown for " + IV_TYPE + "=" + ivType);
+        }
+        catch (ConfigurationException ce) {
+            assertNotNull(ce.getMessage());
+        }
+
+        props.setProperty(IV_TYPE, "illegal");    // This will just result in a logSpecial message & "random" is returned.
+        secConf = new DefaultSecurityConfiguration(props);
+        ivType = secConf.getIVType();
+        assertEquals(ivType, "random");
+    }
+
+    @Test
+    public void testGetAllowMultipleEncoding() {
+        DefaultSecurityConfiguration secConf = new DefaultSecurityConfiguration(new Properties());
+        assertFalse(secConf.getAllowMultipleEncoding());
+
+        secConf = this.createWithProperty(ALLOW_MULTIPLE_ENCODING, "yes");
+        assertTrue(secConf.getAllowMultipleEncoding());
+
+        secConf = this.createWithProperty(ALLOW_MULTIPLE_ENCODING, "true");
+        assertTrue(secConf.getAllowMultipleEncoding());
+
+        secConf = this.createWithProperty(ALLOW_MULTIPLE_ENCODING, "no");
+        assertFalse(secConf.getAllowMultipleEncoding());
+    }
+
+    @Test
+    public void testGetDefaultCanonicalizationCodecs() {
+        DefaultSecurityConfiguration secConf = new DefaultSecurityConfiguration(new Properties());
+        assertFalse(secConf.getDefaultCanonicalizationCodecs().isEmpty());
+
+        String property = "org.owasp.esapi.codecs.TestCodec1,org.owasp.esapi.codecs.TestCodec2";
+        secConf = this.createWithProperty(CANONICALIZATION_CODECS, property);
+        assertTrue(secConf.getDefaultCanonicalizationCodecs().contains("org.owasp.esapi.codecs.TestCodec1"));
+    }
+
+    @Test
+    public void testGetDisableIntrusionDetection() {
+        DefaultSecurityConfiguration secConf = new DefaultSecurityConfiguration(new Properties());
+        assertFalse(secConf.getDisableIntrusionDetection());
+
+        secConf = this.createWithProperty(DISABLE_INTRUSION_DETECTION, "TRUE");
+        assertTrue(secConf.getDisableIntrusionDetection());
+
+        secConf = this.createWithProperty(DISABLE_INTRUSION_DETECTION, "true");
+        assertTrue(secConf.getDisableIntrusionDetection());
+
+        secConf = this.createWithProperty(DISABLE_INTRUSION_DETECTION, "false");
+        assertFalse(secConf.getDisableIntrusionDetection());
+    }
+
     @Test
     public void testNoSuchPropFile(){
         try {
@@ -357,12 +359,12 @@ public class DefaultSecurityConfigurationTest {
         }
 
     }
-    
-	private String patternOrNull(Pattern p){
-		return null==p?null:p.pattern();
-	}
 
-	@Test
+    private String patternOrNull(Pattern p){
+        return null==p?null:p.pattern();
+    }
+
+    @Test
     public void testRootCPLoading(){
         DefaultSecurityConfiguration secConf = new DefaultSecurityConfiguration("ESAPI-root-cp.properties");
         assertEquals(patternOrNull(secConf.getValidationPattern("Test1")), "ValueFromFile1");
@@ -395,85 +397,85 @@ public class DefaultSecurityConfigurationTest {
     }
 
     @Test
-	public void testValidationsPropertiesFileOptions(){
-		DefaultSecurityConfiguration secConf = new DefaultSecurityConfiguration("ESAPI-SingleValidatorFileChecker.properties");
-		assertEquals(patternOrNull(secConf.getValidationPattern("Test1")), "ValueFromFile1");
-		assertNull(secConf.getValidationPattern("Test2"));
-		assertNull(secConf.getValidationPattern("TestC"));
-		
-		secConf = new DefaultSecurityConfiguration("ESAPI-DualValidatorFileChecker.properties");
-		assertEquals(patternOrNull(secConf.getValidationPattern("Test1")), "ValueFromFile1");
-		assertEquals(patternOrNull(secConf.getValidationPattern("Test2")), "ValueFromFile2");
-		assertNull(secConf.getValidationPattern("TestC"));
-
-		secConf = new DefaultSecurityConfiguration("ESAPI-CommaValidatorFileChecker.properties");
-		assertEquals(patternOrNull(secConf.getValidationPattern("TestC")), "ValueFromCommaFile");
-		assertNull(secConf.getValidationPattern("Test1"));
-		assertNull(secConf.getValidationPattern("Test2"));
-
-		secConf = new DefaultSecurityConfiguration("ESAPI-QuotedValidatorFileChecker.properties");
-		assertEquals(patternOrNull(secConf.getValidationPattern("Test1")), "ValueFromFile1");
-		assertEquals(patternOrNull(secConf.getValidationPattern("Test2")), "ValueFromFile2");
-		assertEquals(patternOrNull(secConf.getValidationPattern("TestC")), "ValueFromCommaFile");
-	}
-	
-	@Test 
-	public void DefaultSearchPathTest(){
-		assertEquals("", DefaultSearchPath.ROOT.value());
-		assertEquals("resourceDirectory/", DefaultSearchPath.RESOURCE_DIRECTORY.value());
-		assertEquals(".esapi/", DefaultSearchPath.DOT_ESAPI.value());
-		assertEquals("esapi/", DefaultSearchPath.ESAPI.value());
-		assertEquals("resources/", DefaultSearchPath.RESOURCES.value());
-		assertEquals("src/main/resources/", DefaultSearchPath.SRC_MAIN_RESOURCES.value());
-	}
-	
-	@Test
-	public void DefaultSearchPathEnumChanges(){
-		int expected = 6;
-		int testValue = DefaultSearchPath.values().length;
-		assertEquals(expected, testValue);
-	}
-	
-	@Test
-	public void defaultPropertiesTest(){
-		SecurityConfiguration sc = ESAPI.securityConfiguration();
-//		# Maximum size of JSESSIONID for the application--the validator regex may have additional values.  
-//		HttpUtilities.HTTPJSESSIONIDLENGTH=50
-		assertEquals(50, sc.getIntProp("HttpUtilities.HTTPJSESSIONIDLENGTH"));
-//		# Maximum length of a URL (see https://stackoverflow.com/questions/417142/what-is-the-maximum-length-of-a-url-in-different-browsers)
-//		HttpUtilities.URILENGTH=2000
-		assertEquals(2000, sc.getIntProp("HttpUtilities.URILENGTH"));
-//		# Maximum length for an http scheme
-//		HttpUtilities.HTTPSCHEMELENGTH=10
-		assertEquals(10, sc.getIntProp("HttpUtilities.HTTPSCHEMELENGTH"));
-//		# Maximum length for an http host
-//		HttpUtilities.HTTPHOSTLENGTH=100
-		assertEquals(100, sc.getIntProp("HttpUtilities.HTTPHOSTLENGTH"));
-//		# Maximum length for an http path
-//		HttpUtilities.HTTPPATHLENGTH=150
-		assertEquals(150, sc.getIntProp("HttpUtilities.HTTPPATHLENGTH"));
-//		#Maximum length for a context path 
-//		HttpUtilities.contextPathLength=150
-		assertEquals(150, sc.getIntProp("HttpUtilities.contextPathLength"));
-//		#Maximum length for an httpServletPath 
-//		HttpUtilities.HTTPSERVLETPATHLENGTH=100
-		assertEquals(100, sc.getIntProp("HttpUtilities.HTTPSERVLETPATHLENGTH"));
-//		#Maximum length for an http query parameter name
-//		HttpUtilities.httpQueryParamNameLength=100
-		assertEquals(100, sc.getIntProp("HttpUtilities.httpQueryParamNameLength"));
-//		#Maximum length for an http query parameter -- old default was 2000, but that's the max length for a URL...
-//		HttpUtilities.httpQueryParamValueLength=500
-		assertEquals(500, sc.getIntProp("HttpUtilities.httpQueryParamValueLength"));
-//		# Maximum size of HTTP header key--the validator regex may have additional values. 
-//		HttpUtilities.MaxHeaderNameSize=256
-		assertEquals(256, sc.getIntProp("HttpUtilities.MaxHeaderNameSize"));
-//		# Maximum size of HTTP header value--the validator regex may have additional values. 
-//		HttpUtilities.MaxHeaderValueSize=4096
-		assertEquals(4096, sc.getIntProp("HttpUtilities.MaxHeaderValueSize"));
-//		# Maximum length of a redirect 
-//		HttpUtilities.maxRedirectLength=512
-		assertEquals(512, sc.getIntProp("HttpUtilities.maxRedirectLength"));
-	}
+    public void testValidationsPropertiesFileOptions(){
+        DefaultSecurityConfiguration secConf = new DefaultSecurityConfiguration("ESAPI-SingleValidatorFileChecker.properties");
+        assertEquals(patternOrNull(secConf.getValidationPattern("Test1")), "ValueFromFile1");
+        assertNull(secConf.getValidationPattern("Test2"));
+        assertNull(secConf.getValidationPattern("TestC"));
+
+        secConf = new DefaultSecurityConfiguration("ESAPI-DualValidatorFileChecker.properties");
+        assertEquals(patternOrNull(secConf.getValidationPattern("Test1")), "ValueFromFile1");
+        assertEquals(patternOrNull(secConf.getValidationPattern("Test2")), "ValueFromFile2");
+        assertNull(secConf.getValidationPattern("TestC"));
+
+        secConf = new DefaultSecurityConfiguration("ESAPI-CommaValidatorFileChecker.properties");
+        assertEquals(patternOrNull(secConf.getValidationPattern("TestC")), "ValueFromCommaFile");
+        assertNull(secConf.getValidationPattern("Test1"));
+        assertNull(secConf.getValidationPattern("Test2"));
+
+        secConf = new DefaultSecurityConfiguration("ESAPI-QuotedValidatorFileChecker.properties");
+        assertEquals(patternOrNull(secConf.getValidationPattern("Test1")), "ValueFromFile1");
+        assertEquals(patternOrNull(secConf.getValidationPattern("Test2")), "ValueFromFile2");
+        assertEquals(patternOrNull(secConf.getValidationPattern("TestC")), "ValueFromCommaFile");
+    }
+
+    @Test
+    public void DefaultSearchPathTest(){
+        assertEquals("", DefaultSearchPath.ROOT.value());
+        assertEquals("resourceDirectory/", DefaultSearchPath.RESOURCE_DIRECTORY.value());
+        assertEquals(".esapi/", DefaultSearchPath.DOT_ESAPI.value());
+        assertEquals("esapi/", DefaultSearchPath.ESAPI.value());
+        assertEquals("resources/", DefaultSearchPath.RESOURCES.value());
+        assertEquals("src/main/resources/", DefaultSearchPath.SRC_MAIN_RESOURCES.value());
+    }
+
+    @Test
+    public void DefaultSearchPathEnumChanges(){
+        int expected = 6;
+        int testValue = DefaultSearchPath.values().length;
+        assertEquals(expected, testValue);
+    }
+
+    @Test
+    public void defaultPropertiesTest(){
+        SecurityConfiguration sc = ESAPI.securityConfiguration();
+//        # Maximum size of JSESSIONID for the application--the validator regex may have additional values.
+//        HttpUtilities.HTTPJSESSIONIDLENGTH=50
+        assertEquals(50, sc.getIntProp("HttpUtilities.HTTPJSESSIONIDLENGTH"));
+//        # Maximum length of a URL (see https://stackoverflow.com/questions/417142/what-is-the-maximum-length-of-a-url-in-different-browsers)
+//        HttpUtilities.URILENGTH=2000
+        assertEquals(2000, sc.getIntProp("HttpUtilities.URILENGTH"));
+//        # Maximum length for an http scheme
+//        HttpUtilities.HTTPSCHEMELENGTH=10
+        assertEquals(10, sc.getIntProp("HttpUtilities.HTTPSCHEMELENGTH"));
+//        # Maximum length for an http host
+//        HttpUtilities.HTTPHOSTLENGTH=100
+        assertEquals(100, sc.getIntProp("HttpUtilities.HTTPHOSTLENGTH"));
+//        # Maximum length for an http path
+//        HttpUtilities.HTTPPATHLENGTH=150
+        assertEquals(150, sc.getIntProp("HttpUtilities.HTTPPATHLENGTH"));
+//        #Maximum length for a context path
+//        HttpUtilities.contextPathLength=150
+        assertEquals(150, sc.getIntProp("HttpUtilities.contextPathLength"));
+//        #Maximum length for an httpServletPath
+//        HttpUtilities.HTTPSERVLETPATHLENGTH=100
+        assertEquals(100, sc.getIntProp("HttpUtilities.HTTPSERVLETPATHLENGTH"));
+//        #Maximum length for an http query parameter name
+//        HttpUtilities.httpQueryParamNameLength=100
+        assertEquals(100, sc.getIntProp("HttpUtilities.httpQueryParamNameLength"));
+//        #Maximum length for an http query parameter -- old default was 2000, but that's the max length for a URL...
+//        HttpUtilities.httpQueryParamValueLength=500
+        assertEquals(500, sc.getIntProp("HttpUtilities.httpQueryParamValueLength"));
+//        # Maximum size of HTTP header key--the validator regex may have additional values.
+//        HttpUtilities.MaxHeaderNameSize=256
+        assertEquals(256, sc.getIntProp("HttpUtilities.MaxHeaderNameSize"));
+//        # Maximum size of HTTP header value--the validator regex may have additional values.
+//        HttpUtilities.MaxHeaderValueSize=4096
+        assertEquals(4096, sc.getIntProp("HttpUtilities.MaxHeaderValueSize"));
+//        # Maximum length of a redirect
+//        HttpUtilities.maxRedirectLength=512
+        assertEquals(512, sc.getIntProp("HttpUtilities.maxRedirectLength"));
+    }
 
     // Test some of the deprecated methods to make sure I didn't screw them up
     // given the double negatives on some these properties.
@@ -482,7 +484,7 @@ public class DefaultSecurityConfigurationTest {
     {
         assertTrue("1: Deprecated (1st) method returns different value than new (2nd) method",
                     ESAPI.securityConfiguration().getDisableIntrusionDetection() ==
-                      ESAPI.securityConfiguration().getBooleanProp( DefaultSecurityConfiguration.DISABLE_INTRUSION_DETECTION )
+                      ESAPI.securityConfiguration().getBooleanProp( DISABLE_INTRUSION_DETECTION )
                   );
         // TODO: add some more tests here for the deprecated replacements.
     }
diff --git a/src/test/java/org/owasp/esapi/reference/DefaultValidaterDateAPITest.java b/src/test/java/org/owasp/esapi/reference/DefaultValidaterDateAPITest.java
index 5e552c5..3322633 100644
--- a/src/test/java/org/owasp/esapi/reference/DefaultValidaterDateAPITest.java
+++ b/src/test/java/org/owasp/esapi/reference/DefaultValidaterDateAPITest.java
@@ -36,9 +36,9 @@ import org.powermock.core.classloader.annotations.PrepareForTest;
 import org.powermock.modules.junit4.PowerMockRunner;
 
 /**
- * This class contains a subsection of tests of the DefaultValidator class 
+ * This class contains a subsection of tests of the DefaultValidator class
  * SPECIFIC TO THE DATE VALIDATION API.
- * 
+ *
  */
 @RunWith(PowerMockRunner.class)
 @PrepareForTest(DefaultValidator.class)
@@ -48,7 +48,7 @@ public class DefaultValidaterDateAPITest {
     @Rule
     public TestName testName = new TestName();
     private String dateString="Input Does not matter in this context";
-    
+
     private ValidationException validationEx;
     private Date testDate = new Date();
     private String contextStr;
@@ -56,109 +56,109 @@ public class DefaultValidaterDateAPITest {
     private DateFormat testFormat = DateFormat.getDateInstance(DateFormat.MEDIUM, Locale.US);
     private DateValidationRule spyDateRule;
     private ValidationErrorList errors = new ValidationErrorList();
-    
+
     private DefaultValidator uit;
-    
-    
+
+
     @Before
     public void setup() throws Exception {
         contextStr = testName.getMethodName();
-        
+
         validationEx = new ValidationException(contextStr, contextStr);
-        
+
         mockEncoder = mock(Encoder.class);
         uit = new DefaultValidator(mockEncoder);
-        
+
         spyDateRule = new DateValidationRule(contextStr, mockEncoder, testFormat);
         spyDateRule = spy(spyDateRule);
         whenNew(DateValidationRule.class).withArguments(anyString(), eq(mockEncoder), eq(testFormat)).thenReturn(spyDateRule);
-        
+
         errors = spy(errors);
         whenNew(ValidationErrorList.class).withNoArguments().thenReturn(errors);
     }
-    
+
     @After
     public void tearDown() {
         verifyNoMoreInteractions(spyDateRule, errors);
     }
-    
+
     @Test
     public void testIsValidDate() {
         doReturn(testDate).when(spyDateRule).sanitize(eq(contextStr), eq(dateString), isA(ValidationErrorList.class));
-        
+
         boolean isValid = uit.isValidDate(contextStr, dateString, testFormat, true);
         Assert.assertTrue("Mock is configured to return a valid date, return should be equally valid.", isValid);
-        
+
         verify(errors, atLeastOnce()).isEmpty();
         verify(errors, times(0)).errors();
         verify(spyDateRule, times(1)).setAllowNull(true);
         verify(spyDateRule, times(1)).sanitize(eq(contextStr), eq(dateString), isA(ValidationErrorList.class));
     }
-    
+
     @Test
     public void testIsValidDateErrorList() {
         doReturn(testDate).when(spyDateRule).sanitize(eq(contextStr), eq(dateString), isA(ValidationErrorList.class));
-        
+
         boolean isValid = uit.isValidDate(contextStr, dateString, testFormat, true, errors);
         Assert.assertTrue("Mock is configured to return a valid date, return should be equally valid.", isValid);
-        
+
         verify(errors, atLeastOnce()).isEmpty();
         verify(errors, times(0)).errors();
         verify(spyDateRule, times(1)).setAllowNull(true);
         verify(spyDateRule, times(1)).sanitize(eq(contextStr), eq(dateString), eq(errors));
     }
-    
+
     @Test
     public void testGetValidDate() throws IntrusionException, ValidationException {
         doReturn(testDate).when(spyDateRule).sanitize(eq(contextStr), eq(dateString), isA(ValidationErrorList.class));
         Date validDate = uit.getValidDate(contextStr, dateString, testFormat, true);
         Assert.assertEquals("ValidDate should match the mock's configured return value", testDate, validDate);
-        
+
         verify(errors, atLeastOnce()).isEmpty();
         verify(errors, times(0)).errors();
         verify(spyDateRule, times(1)).setAllowNull(true);
         verify(spyDateRule, times(1)).sanitize(eq(contextStr), eq(dateString), isA(ValidationErrorList.class));
     }
-    
+
     @Test
     public void testGetValidDateErrorList() {
         doReturn(testDate).when(spyDateRule).sanitize(eq(contextStr), eq(dateString), isA(ValidationErrorList.class));
         Date validDate = uit.getValidDate(contextStr, dateString, testFormat, true, errors);
         Assert.assertEquals("ValidDate should match the mock's configured return value", testDate, validDate);
-        
+
         verify(errors, atLeastOnce()).isEmpty();
         verify(errors, times(0)).errors();
         verify(spyDateRule, times(1)).setAllowNull(true);
         verify(spyDateRule, times(1)).sanitize(eq(contextStr), eq(dateString), eq(errors));
     }
-    
-    
+
+
     @Test
     public void testIsValidDateOnValidationError() {
         doReturn(false).when(errors).isEmpty();
         doReturn(Arrays.asList(validationEx)).when(errors).errors();
-        
+
         doReturn(testDate).when(spyDateRule).sanitize(eq(contextStr), eq(dateString), isA(ValidationErrorList.class));
-        
+
         boolean isValid = uit.isValidDate(contextStr, dateString, testFormat, true);
         Assert.assertFalse("On ValidationException input should be invalid", isValid);
-        
+
         verify(errors, atLeastOnce()).isEmpty();
         verify(errors, times(1)).errors();
         verify(spyDateRule, times(1)).setAllowNull(true);
         verify(spyDateRule, times(1)).sanitize(eq(contextStr), eq(dateString), isA(ValidationErrorList.class));
     }
-    
+
     @Test
     public void testIsValidDateErrorListOnValidationError() {
         doReturn(false).when(errors).isEmpty();
         doReturn(Arrays.asList(validationEx)).when(errors).errors();
-        
+
         doReturn(testDate).when(spyDateRule).sanitize(eq(contextStr), eq(dateString), isA(ValidationErrorList.class));
-        
+
         boolean isValid = uit.isValidDate(contextStr, dateString, testFormat, true, errors);
         Assert.assertFalse("On ValidationException input should be invalid", isValid);
-        
+
         verify(errors, times(2)).isEmpty();
         verify(errors, times(0)).errors();
         verify(spyDateRule, times(1)).setAllowNull(true);
@@ -180,7 +180,7 @@ public class DefaultValidaterDateAPITest {
             verify(spyDateRule, times(1)).sanitize(eq(contextStr), eq(dateString), isA(ValidationErrorList.class));
         }
     }
-    
+
     @Test
     public void testGetValidDateErrorListOnValidationError() {
         doReturn(false).when(errors).isEmpty();
diff --git a/src/test/java/org/owasp/esapi/reference/DefaultValidatorInputStringAPITest.java b/src/test/java/org/owasp/esapi/reference/DefaultValidatorInputStringAPITest.java
index 99e25c4..d62907c 100644
--- a/src/test/java/org/owasp/esapi/reference/DefaultValidatorInputStringAPITest.java
+++ b/src/test/java/org/owasp/esapi/reference/DefaultValidatorInputStringAPITest.java
@@ -37,9 +37,9 @@ import org.powermock.core.classloader.annotations.PrepareForTest;
 import org.powermock.modules.junit4.PowerMockRunner;
 
 /**
- * This class contains a subsection of tests of the DefaultValidator class 
+ * This class contains a subsection of tests of the DefaultValidator class
  * SPECIFIC TO THE INPUT 'STRING' VALIDATION API.
- * 
+ *
  */
 @RunWith(PowerMockRunner.class)
 @PrepareForTest({DefaultValidator.class, ESAPI.class})
@@ -59,52 +59,52 @@ public class DefaultValidatorInputStringAPITest {
     private String contextStr;
     private StringValidationRule spyStringRule;
     private ValidationErrorList errors = new ValidationErrorList();
-    
+
     private DefaultValidator uit;
     private String testValidatorType;
     private String validatorResultString;
     private int testMaximumLength;
-    
+
     @Before
     public void setup() throws Exception {
         contextStr = testName.getMethodName();
         testValidatorType = testName.getMethodName() + "_validator_type";
         validatorResultString = testName.getMethodName() + "_validator_result";
         testMaximumLength = testName.getMethodName().length();
-        
+
         validationEx = new ValidationException(contextStr, contextStr);
-        
+
         mockEncoder = mock(Encoder.class);
         uit = new DefaultValidator(mockEncoder);
-        
+
         //Don't care how the StringValidationRule works, we just care that we forwarded the information as expected.
-        spyStringRule = new StringValidationRule(testValidatorType, mockEncoder); 
+        spyStringRule = new StringValidationRule(testValidatorType, mockEncoder);
         spyStringRule = spy(spyStringRule);
         doNothing().when(spyStringRule).addWhitelistPattern(ArgumentMatchers.<Pattern>any());
         doNothing().when(spyStringRule).setAllowNull(ArgumentMatchers.anyBoolean());
         doNothing().when(spyStringRule).setMaximumLength(ArgumentMatchers.anyInt());
         doReturn(validatorResultString).when(spyStringRule).getValid(ArgumentMatchers.anyString(), ArgumentMatchers.anyString());
         whenNew(StringValidationRule.class).withArguments(eq(testValidatorType), eq(mockEncoder)).thenReturn(spyStringRule);
-        
+
         errors = spy(errors);
         whenNew(ValidationErrorList.class).withNoArguments().thenReturn(errors);
-        
-        
+
+
         PowerMockito.mockStatic(ESAPI.class);
         PowerMockito.when(ESAPI.class, ESAPY_SECURITY_CONFIGURATION_GETTER_METHOD_NAME).thenReturn(mockSecConfig);
-        
-        
+
+
         when(mockSecConfig.getValidationPattern(testValidatorType)).thenReturn(TEST_PATTERN);
-        
+
     }
-    
+
     @After
     public void verifyDelegateCalls() {
         verify(mockSecConfig, times(1)).getValidationPattern(testValidatorType);
-        
+
         PowerMockito.verifyNoMoreInteractions(spyStringRule, mockSecConfig, mockEncoder);
     }
-    
+
     @Test
     public void getValidInputNullAllowedPassthrough() throws Exception {
         String safeValue =  uit.getValidInput(contextStr, testName.getMethodName(), testValidatorType, testMaximumLength, true);
@@ -116,7 +116,7 @@ public class DefaultValidatorInputStringAPITest {
         verify(spyStringRule, times(1)).setCanonicalize(true);
         verify(spyStringRule, times(1)).getValid(contextStr, testName.getMethodName());
     }
-    
+
     @Test
     public void getValidInputNullNotAllowedPassthrough() throws Exception {
         String safeValue =  uit.getValidInput(contextStr, testName.getMethodName(), testValidatorType, testMaximumLength, false);
@@ -128,16 +128,16 @@ public class DefaultValidatorInputStringAPITest {
         verify(spyStringRule, times(1)).setCanonicalize(true);
         verify(spyStringRule, times(1)).getValid(contextStr, testName.getMethodName());
     }
-    
+
     @Test
     public void getValidInputNullPatternThrows() throws Exception {
         exEx.expect(IllegalArgumentException.class);
         exEx.expectMessage(testValidatorType + "] was not set via the ESAPI validation configuration");
         when(mockSecConfig.getValidationPattern(testValidatorType)).thenReturn(null);
-    
+
         uit.getValidInput(contextStr, testName.getMethodName(), testValidatorType, testMaximumLength, true);
     }
-    
+
     @Test
     public void getValidInputValidationExceptionPropagates() throws Exception {
         exEx.expect(Is.is(validationEx));
@@ -154,7 +154,7 @@ public class DefaultValidatorInputStringAPITest {
             verify(spyStringRule, times(1)).getValid(contextStr, testName.getMethodName());
         }
     }
-    
+
     @Test
     public void getValidInputValidationExceptionErrorList() throws Exception {
         ValidationErrorList errorList = new ValidationErrorList();
@@ -171,13 +171,13 @@ public class DefaultValidatorInputStringAPITest {
         verify(spyStringRule, times(1)).setCanonicalize(true);
         verify(spyStringRule, times(1)).getValid(contextStr, testName.getMethodName());
     }
-    
-    
+
+
     @Test
     public void isValidInputNullAllowedPassthrough() throws Exception {
         boolean isValid=  uit.isValidInput(contextStr, testName.getMethodName(), testValidatorType, testMaximumLength, true);
         assertTrue(isValid);
-        
+
         verify(spyStringRule, times(1)).addWhitelistPattern(TEST_PATTERN);
         verify(spyStringRule, times(1)).setAllowNull(true);
         verify(spyStringRule, times(0)).setAllowNull(false);
@@ -185,7 +185,7 @@ public class DefaultValidatorInputStringAPITest {
         verify(spyStringRule, times(1)).setCanonicalize(true);
         verify(spyStringRule, times(1)).getValid(contextStr, testName.getMethodName());
     }
-    
+
     @Test
     public void isValidInputValidationExceptionReturnsFalse() throws Exception {
         doThrow(validationEx).when(spyStringRule).getValid(ArgumentMatchers.anyString(), ArgumentMatchers.anyString());
@@ -198,7 +198,7 @@ public class DefaultValidatorInputStringAPITest {
         verify(spyStringRule, times(1)).setCanonicalize(true);
         verify(spyStringRule, times(1)).getValid(contextStr, testName.getMethodName());
     }
-    
+
     @Test
     public void isValidInputValidationExceptionErrorListReturnsFalse() throws Exception {
         ValidationErrorList errorList = new ValidationErrorList();
@@ -216,7 +216,7 @@ public class DefaultValidatorInputStringAPITest {
         verify(spyStringRule, times(1)).setCanonicalize(true);
         verify(spyStringRule, times(1)).getValid(contextStr, testName.getMethodName());
     }
-    
+
     @Test
     public void canonicalizeSettingPassedThrough() throws Exception {
         String safeValue =  uit.getValidInput(contextStr, testName.getMethodName(), testValidatorType, testMaximumLength, false,false);
diff --git a/src/test/java/org/owasp/esapi/reference/EncoderTest.java b/src/test/java/org/owasp/esapi/reference/EncoderTest.java
index ed04b6d..87a9b6c 100644
--- a/src/test/java/org/owasp/esapi/reference/EncoderTest.java
+++ b/src/test/java/org/owasp/esapi/reference/EncoderTest.java
@@ -1,25 +1,27 @@
 /**
  * OWASP Enterprise Security API (ESAPI)
- * 
+ *
  * This file is part of the Open Web Application Security Project (OWASP)
  * Enterprise Security API (ESAPI) project. For details, please see
  * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
  *
  * Copyright (c) 2007 - The OWASP Foundation
- * 
+ *
  * The ESAPI is published by OWASP under the BSD license. You should read and accept the
  * LICENSE before you use, modify, and/or redistribute this software.
- * 
+ *
  * @author Jeff Williams <a href="http://www.aspectsecurity.com">Aspect Security</a>
  * @created 2007
  */
 package org.owasp.esapi.reference;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
 
 import java.io.IOException;
 import java.io.UnsupportedEncodingException;
 import java.net.URI;
+import java.util.List;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.HashMap;
@@ -36,11 +38,15 @@ import org.owasp.esapi.codecs.Codec;
 import org.owasp.esapi.codecs.HTMLEntityCodec;
 import org.owasp.esapi.codecs.MySQLCodec;
 import org.owasp.esapi.codecs.OracleCodec;
+import org.owasp.esapi.codecs.JSONCodec;
 import org.owasp.esapi.codecs.PushbackString;
 import org.owasp.esapi.codecs.UnixCodec;
 import org.owasp.esapi.codecs.WindowsCodec;
 import org.owasp.esapi.errors.EncodingException;
 import org.owasp.esapi.errors.IntrusionException;
+import org.owasp.esapi.Randomizer;
+import org.owasp.esapi.SecurityConfiguration;
+import org.owasp.esapi.SecurityConfigurationWrapper;
 
 import junit.framework.Test;
 import junit.framework.TestCase;
@@ -48,74 +54,95 @@ import junit.framework.TestSuite;
 
 /**
  * The Class EncoderTest.
- * 
+ *
  * @author Jeff Williams (jeff.williams@aspectsecurity.com)
  */
 public class EncoderTest extends TestCase {
-    
-	private static final String PREFERRED_ENCODING = "UTF-8";
-	
-    /**
-	 * Instantiates a new encoder test.
-	 * 
-	 * @param testName
-	 *            the test name
-	 */
+
+    private static class Conf extends SecurityConfigurationWrapper
+    {
+        private final List<String> codecList;
+
+        /**
+         * @param orig   The original {@code SecurityConfiguration} to use as a basis.
+         *               Generally, that will just be:      {@code ESAPI.securityConfiguration()}
+         * @param codecsList List of {@code Codec}s to replace {@code Encoder.DefaultCodecList}
+         */
+        Conf(SecurityConfiguration orig, List<String> codecList)
+        {
+            super(orig);
+            this.codecList = codecList;
+        }
+
+        @Override
+        public List<String> getDefaultCanonicalizationCodecs()
+        {
+            return codecList;
+        }
+    }
+    private static final String PREFERRED_ENCODING = "UTF-8";
+
+    /**
+     * Instantiates a new encoder test.
+     *
+     * @param testName
+     *            the test name
+     */
     public EncoderTest(String testName) {
         super(testName);
     }
-    
+
     /**
      * {@inheritDoc}
-     * @throws Exception 
+     * @throws Exception
      */
     protected void setUp() throws Exception {
-    	// none
+        // none
     }
-    
+
     /**
      * {@inheritDoc}s
      * @throws Exception
      */
     protected void tearDown() throws Exception {
-    	// none
+        ESAPI.override(null); // Restore
     }
-    
+
     /**
-	 * Suite.
-	 * 
-	 * @return the test
-	 */
+     * Suite.
+     *
+     * @return the test
+     */
     public static Test suite() {
-        TestSuite suite = new TestSuite(EncoderTest.class);        
+        TestSuite suite = new TestSuite(EncoderTest.class);
         return suite;
     }
-    
-	/**
-	 * Test of canonicalize method, of class org.owasp.esapi.Encoder.
-	 * 
-	 * @throws EncodingException
-	 */
-	public void testCanonicalize() throws EncodingException {
-		System.out.println("canonicalize");
+
+    /**
+     * Test of canonicalize method, of class org.owasp.esapi.Encoder.
+     *
+     * @throws EncodingException
+     */
+    public void testCanonicalize() throws EncodingException {
+        System.out.println("canonicalize");
 
         ArrayList<String> list = new ArrayList<String>();
         list.add( "HTMLEntityCodec" );
-	    list.add( "PercentCodec" );
-		Encoder instance = new DefaultEncoder( list );
-		
-		// Test null paths
-		assertEquals( null, instance.canonicalize(null));
-		assertEquals( null, instance.canonicalize(null, true));
-		assertEquals( null, instance.canonicalize(null, false));
-		assertEquals( null, instance.canonicalize(null, true, true));
-		assertEquals( null, instance.canonicalize(null, true, false));
-		assertEquals( null, instance.canonicalize(null, false, true));
-		assertEquals( null, instance.canonicalize(null, false, false));
-		
-		// test exception paths
-		assertEquals( "%", instance.canonicalize("%25", true));
-		assertEquals( "%", instance.canonicalize("%25", false));
+        list.add( "PercentCodec" );
+        Encoder instance = new DefaultEncoder( list );
+
+        // Test null paths
+        assertEquals( null, instance.canonicalize(null));
+        assertEquals( null, instance.canonicalize(null, true));
+        assertEquals( null, instance.canonicalize(null, false));
+        assertEquals( null, instance.canonicalize(null, true, true));
+        assertEquals( null, instance.canonicalize(null, true, false));
+        assertEquals( null, instance.canonicalize(null, false, true));
+        assertEquals( null, instance.canonicalize(null, false, false));
+
+        // test exception paths
+        assertEquals( "%", instance.canonicalize("%25", true));
+        assertEquals( "%", instance.canonicalize("%25", false));
 
         assertEquals( "%", instance.canonicalize("%25"));
         assertEquals( "%F", instance.canonicalize("%25F"));
@@ -127,7 +154,7 @@ public class EncoderTest extends TestCase {
         assertEquals( "<", instance.canonicalize("&LT"));
         assertEquals( "<", instance.canonicalize("&lt;"));
         assertEquals( "<", instance.canonicalize("&LT;"));
-        
+
         assertEquals( "%", instance.canonicalize("&#37;"));
         assertEquals( "%", instance.canonicalize("&#37"));
         assertEquals( "%b", instance.canonicalize("&#37b"));
@@ -214,10 +241,10 @@ public class EncoderTest extends TestCase {
         assertEquals( "<", instance.canonicalize("&LT;"));
         assertEquals( "&", instance.canonicalize("&amp"));
         assertEquals( "〈", instance.canonicalize("&lang"));
-        
+
         assertEquals( "<script>alert(\"hello\");</script>", instance.canonicalize("%3Cscript%3Ealert%28%22hello%22%29%3B%3C%2Fscript%3E") );
         assertEquals( "<script>alert(\"hello\");</script>", instance.canonicalize("%3Cscript&#x3E;alert%28%22hello&#34%29%3B%3C%2Fscript%3E", false) );
-        
+
         // javascript escape syntax
         ArrayList<String> js = new ArrayList<String>();
         js.add( "JavaScriptCodec" );
@@ -235,7 +262,7 @@ public class EncoderTest extends TestCase {
         assertEquals( "\"", instance.canonicalize("\\\""));
         assertEquals( "\\", instance.canonicalize("\\\\"));
         assertEquals( "\\<", instance.canonicalize("\\<"));
-        
+
         assertEquals( "<", instance.canonicalize("\\u003c"));
         assertEquals( "<", instance.canonicalize("\\U003c"));
         assertEquals( "<", instance.canonicalize("\\u003C"));
@@ -261,12 +288,12 @@ public class EncoderTest extends TestCase {
         assertEquals( "<", instance.canonicalize("\\003C"));
         assertEquals( "<", instance.canonicalize("\\0003C"));
         assertEquals( "<", instance.canonicalize("\\00003C"));
-	}
+    }
+
 
-	
     /**
      * Test of canonicalize method, of class org.owasp.esapi.Encoder.
-     * 
+     *
      * @throws EncodingException
      */
     public void testDoubleEncodingCanonicalization() throws EncodingException {
@@ -276,37 +303,37 @@ public class EncoderTest extends TestCase {
         // note these examples use the strict=false flag on canonicalize to allow
         // full decoding without throwing an IntrusionException. Generally, you
         // should use strict mode as allowing double-encoding is an abomination.
-        
+
         // double encoding examples
         assertEquals( "<", instance.canonicalize("&#x26;lt&#59", false )); //double entity
         assertEquals( "\\", instance.canonicalize("%255c", false)); //double percent
         assertEquals( "%", instance.canonicalize("%2525", false)); //double percent
-        
+
         // double encoding with multiple schemes example
         assertEquals( "<", instance.canonicalize("%26lt%3b", false)); //first entity, then percent
         assertEquals( "&", instance.canonicalize("&#x25;26", false)); //first percent, then entity
 
-		//enforce multiple and mixed encoding detection
-		try {
-			instance.canonicalize("%26lt; %26lt; &#X25;3c &#x25;3c %2526lt%253B %2526lt%253B %2526lt%253B", true, true);
-			fail("Multiple and mixed encoding not detected");
-		} catch (IntrusionException ie) {}
+        //enforce multiple and mixed encoding detection
+        try {
+            instance.canonicalize("%26lt; %26lt; &#X25;3c &#x25;3c %2526lt%253B %2526lt%253B %2526lt%253B", true, true);
+            fail("Multiple and mixed encoding not detected");
+        } catch (IntrusionException ie) {}
 
-		//enforce multiple but not mixed encoding detection
-		try {
-			instance.canonicalize("%252525253C", true, false); 
-			fail("Multiple encoding not detected");
-		} catch (IntrusionException ie) {}
+        //enforce multiple but not mixed encoding detection
+        try {
+            instance.canonicalize("%252525253C", true, false);
+            fail("Multiple encoding not detected");
+        } catch (IntrusionException ie) {}
 
-		//enforce mixed but not multiple encoding detection
-		try {
-			instance.canonicalize("%25 %2526 %26#X3c;script&#x3e; &#37;3Cscript%25252525253e", false, true); 
-			fail("Mixed encoding not detected");
-		} catch (IntrusionException ie) {}
+        //enforce mixed but not multiple encoding detection
+        try {
+            instance.canonicalize("%25 %2526 %26#X3c;script&#x3e; &#37;3Cscript%25252525253e", false, true);
+            fail("Mixed encoding not detected");
+        } catch (IntrusionException ie) {}
 
-		//enforce niether mixed nor multiple encoding detection -should canonicalize but not throw an error
-		assertEquals( "< < < < < < <", instance.canonicalize("%26lt; %26lt; &#X25;3c &#x25;3c %2526lt%253B %2526lt%253B %2526lt%253B", 
-															 false, false)); 
+        //enforce niether mixed nor multiple encoding detection -should canonicalize but not throw an error
+        assertEquals( "< < < < < < <", instance.canonicalize("%26lt; %26lt; &#X25;3c &#x25;3c %2526lt%253B %2526lt%253B %2526lt%253B",
+                                                             false, false));
 
         // nested encoding examples
         assertEquals( "<", instance.canonicalize("%253c", false)); //nested encode % with percent
@@ -315,11 +342,11 @@ public class EncoderTest extends TestCase {
         assertEquals( "<", instance.canonicalize("%3%63", false));  //nested encode second nibble with percent
         assertEquals( "<", instance.canonicalize("&&#108;t;", false)); //nested encode l with entity
         assertEquals( "<", instance.canonicalize("%2&#x35;3c", false)); //triple percent, percent, 5 with entity
-        
+
         // nested encoding with multiple schemes examples
         assertEquals( "<", instance.canonicalize("&%6ct;", false)); // nested encode l with percent
-        assertEquals( "<", instance.canonicalize("%&#x33;c", false)); //nested encode 3 with entity            
-        
+        assertEquals( "<", instance.canonicalize("%&#x33;c", false)); //nested encode 3 with entity
+
         // multiple encoding tests
         assertEquals( "% & <script> <script>", instance.canonicalize( "%25 %2526 %26#X3c;script&#x3e; &#37;3Cscript%25252525253e", false ) );
         assertEquals( "< < < < < < <", instance.canonicalize( "%26lt; %26lt; &#X25;3c &#x25;3c %2526lt%253B %2526lt%253B %2526lt%253B", false ) );
@@ -330,7 +357,7 @@ public class EncoderTest extends TestCase {
         } catch( IntrusionException e ) {
             // expected
         }
-        
+
         try {
             assertEquals( "<script", instance.canonicalize("%253Cscript" ) );
         } catch( IntrusionException e ) {
@@ -344,7 +371,7 @@ public class EncoderTest extends TestCase {
     }
 
     /**
-	 * Test of encodeForHTML method, of class org.owasp.esapi.Encoder.
+     * Test of encodeForHTML method, of class org.owasp.esapi.Encoder.
      *
      * @throws Exception
      */
@@ -354,7 +381,7 @@ public class EncoderTest extends TestCase {
         assertEquals(null, instance.encodeForHTML(null));
         // test invalid characters are replaced with spaces
         assertEquals("a&#xfffd;b&#xfffd;c&#xfffd;d&#xfffd;e&#xfffd;f&#x9;g", instance.encodeForHTML("a" + (char)0 + "b" + (char)4 + "c" + (char)128 + "d" + (char)150 + "e" +(char)159 + "f" + (char)9 + "g"));
-        
+
         assertEquals("&lt;script&gt;", instance.encodeForHTML("<script>"));
         assertEquals("&amp;lt&#x3b;script&amp;gt&#x3b;", instance.encodeForHTML("&lt;script&gt;"));
         assertEquals("&#x21;&#x40;&#x24;&#x25;&#x28;&#x29;&#x3d;&#x2b;&#x7b;&#x7d;&#x5b;&#x5d;", instance.encodeForHTML("!@$%()=+{}[]"));
@@ -365,10 +392,10 @@ public class EncoderTest extends TestCase {
         assertEquals("one&amp;two", instance.encodeForHTML("one&two"));
         assertEquals("" + (char)12345 + (char)65533 + (char)1244, "" + (char)12345 + (char)65533 + (char)1244 );
     }
-    
+
     /**
-	 * Test of encodeForHTMLAttribute method, of class org.owasp.esapi.Encoder.
-	 */
+     * Test of encodeForHTMLAttribute method, of class org.owasp.esapi.Encoder.
+     */
     public void testEncodeForHTMLAttribute() {
         System.out.println("encodeForHTMLAttribute");
         Encoder instance = ESAPI.encoder();
@@ -377,8 +404,8 @@ public class EncoderTest extends TestCase {
         assertEquals(",.-_", instance.encodeForHTMLAttribute(",.-_"));
         assertEquals("&#x20;&#x21;&#x40;&#x24;&#x25;&#x28;&#x29;&#x3d;&#x2b;&#x7b;&#x7d;&#x5b;&#x5d;", instance.encodeForHTMLAttribute(" !@$%()=+{}[]"));
     }
-    
-    
+
+
     /**
      *
      */
@@ -391,35 +418,39 @@ public class EncoderTest extends TestCase {
         assertEquals("#f00", instance.encodeForCSS("#f00"));
         assertEquals("#123456", instance.encodeForCSS("#123456"));
         assertEquals("#abcdef", instance.encodeForCSS("#abcdef"));
-        assertEquals("red", instance.encodeForCSS("red"));       
+        assertEquals("red", instance.encodeForCSS("red"));
     }
-    
+
     public void testCSSTripletLeadString() {
-    	Encoder instance = ESAPI.encoder();
-    	assertEquals("rgb(255,255,255)\\21 ", instance.encodeForCSS("rgb(255,255,255)!"));
-    	assertEquals("rgb(25%,25%,25%)\\21 ", instance.encodeForCSS("rgb(25%,25%,25%)!"));
+        System.out.println("CSSTripletLeadString");
+        Encoder instance = ESAPI.encoder();
+        assertEquals("rgb(255,255,255)\\21 ", instance.encodeForCSS("rgb(255,255,255)!"));
+        assertEquals("rgb(25%,25%,25%)\\21 ", instance.encodeForCSS("rgb(25%,25%,25%)!"));
     }
     public void testCSSTripletTailString() {
-		Encoder instance = ESAPI.encoder();
-    	assertEquals("\\24 field\\3d rgb(255,255,255)\\21 ", instance.encodeForCSS("$field=rgb(255,255,255)!"));
-    	assertEquals("\\24 field\\3d rgb(25%,25%,25%)\\21 ", instance.encodeForCSS("$field=rgb(25%,25%,25%)!"));
+        System.out.println("CSSTripletTailString");
+        Encoder instance = ESAPI.encoder();
+        assertEquals("\\24 field\\3d rgb(255,255,255)\\21 ", instance.encodeForCSS("$field=rgb(255,255,255)!"));
+        assertEquals("\\24 field\\3d rgb(25%,25%,25%)\\21 ", instance.encodeForCSS("$field=rgb(25%,25%,25%)!"));
     }
     public void testCSSTripletStringPart() {
-		Encoder instance = ESAPI.encoder();
-    	assertEquals("\\24 field\\3d rgb(255,255,255)\\21 ", instance.encodeForCSS("$field=rgb(255,255,255)!"));
-    	assertEquals("\\24 field\\3d rgb(25%,25%,25%)\\21 ", instance.encodeForCSS("$field=rgb(25%,25%,25%)!"));
+        System.out.println("CSSTripletStringPart");
+        Encoder instance = ESAPI.encoder();
+        assertEquals("\\24 field\\3d rgb(255,255,255)\\21 ", instance.encodeForCSS("$field=rgb(255,255,255)!"));
+        assertEquals("\\24 field\\3d rgb(25%,25%,25%)\\21 ", instance.encodeForCSS("$field=rgb(25%,25%,25%)!"));
     }
     public void testCSSTripletStringMultiPart() {
-		Encoder instance = ESAPI.encoder();
-    	assertEquals("\\24 field\\3d rgb(255,255,255)\\21 \\20 \\24 field\\3d rgb(255,255,255)\\21 ", instance.encodeForCSS("$field=rgb(255,255,255)! $field=rgb(255,255,255)!"));
-    	assertEquals("\\24 field\\3d rgb(25%,25%,25%)\\21 \\20 \\24 field\\3d rgb(25%,25%,25%)\\21 ", instance.encodeForCSS("$field=rgb(25%,25%,25%)! $field=rgb(25%,25%,25%)!"));
-    	assertEquals("\\24 field\\3d rgb(255,255,255)\\21 \\20 \\24 field\\3d rgb(25%,25%,25%)\\21 ", instance.encodeForCSS("$field=rgb(255,255,255)! $field=rgb(25%,25%,25%)!"));
+        System.out.println("CSSTripletMultiPart");
+        Encoder instance = ESAPI.encoder();
+        assertEquals("\\24 field\\3d rgb(255,255,255)\\21 \\20 \\24 field\\3d rgb(255,255,255)\\21 ", instance.encodeForCSS("$field=rgb(255,255,255)! $field=rgb(255,255,255)!"));
+        assertEquals("\\24 field\\3d rgb(25%,25%,25%)\\21 \\20 \\24 field\\3d rgb(25%,25%,25%)\\21 ", instance.encodeForCSS("$field=rgb(25%,25%,25%)! $field=rgb(25%,25%,25%)!"));
+        assertEquals("\\24 field\\3d rgb(255,255,255)\\21 \\20 \\24 field\\3d rgb(25%,25%,25%)\\21 ", instance.encodeForCSS("$field=rgb(255,255,255)! $field=rgb(25%,25%,25%)!"));
     }
-       
-    
+
+
     /**
-	 * Test of encodeForJavaScript method, of class org.owasp.esapi.Encoder.
-	 */
+     * Test of encodeForJavaScript method, of class org.owasp.esapi.Encoder.
+     */
     public void testEncodeForJavascript() {
         System.out.println("encodeForJavascript");
         Encoder instance = ESAPI.encoder();
@@ -438,12 +469,12 @@ public class EncoderTest extends TestCase {
         // assertEquals( "\\\"", instance.encodeForJavaScript("\""));
         // assertEquals( "\\\\", instance.encodeForJavaScript("\\"));
     }
-        
+
     /**
      *
      */
     public void testEncodeForVBScript() {
-        System.out.println("encodeForVBScript");        
+        System.out.println("encodeForVBScript");
         Encoder instance = ESAPI.encoder();
         assertEquals(null, instance.encodeForVBScript(null));
         assertEquals( "chrw(60)&\"script\"&chrw(62)", instance.encodeForVBScript("<script>"));
@@ -453,22 +484,22 @@ public class EncoderTest extends TestCase {
         assertEquals( "test\"&chrw(32)&chrw(60)&chrw(62)&chrw(32)&\"test", instance.encodeForVBScript("test <> test" ));
     }
 
-        
+
     /**
-	 * Test of encodeForXPath method, of class org.owasp.esapi.Encoder.
-	 */
+     * Test of encodeForXPath method, of class org.owasp.esapi.Encoder.
+     */
     public void testEncodeForXPath() {
         System.out.println("encodeForXPath");
         Encoder instance = ESAPI.encoder();
         assertEquals(null, instance.encodeForXPath(null));
         assertEquals("&#x27;or 1&#x3d;1", instance.encodeForXPath("'or 1=1"));
     }
-    
 
-    
+
+
     /**
-	 * Test of encodeForSQL method, of class org.owasp.esapi.Encoder.
-	 */
+     * Test of encodeForSQL method, of class org.owasp.esapi.Encoder.
+     */
     public void testEncodeForSQL() {
         System.out.println("encodeForSQL");
         Encoder instance = ESAPI.encoder();
@@ -476,7 +507,7 @@ public class EncoderTest extends TestCase {
         Codec mySQL1 = new MySQLCodec( MySQLCodec.ANSI_MODE );
         assertEquals("ANSI_MODE", null, instance.encodeForSQL(mySQL1, null));
         assertEquals("ANSI_MODE", "Jeff'' or ''1''=''1", instance.encodeForSQL(mySQL1, "Jeff' or '1'='1"));
-        
+
         Codec mySQL2 = new MySQLCodec( MySQLCodec.MYSQL_MODE );
         assertEquals("MYSQL_MODE", null, instance.encodeForSQL(mySQL2, null));
         assertEquals("MYSQL_MODE", "Jeff\\' or \\'1\\'\\=\\'1", instance.encodeForSQL(mySQL2, "Jeff' or '1'='1"));
@@ -487,16 +518,17 @@ public class EncoderTest extends TestCase {
     }
 
     public void testMySQLANSIModeQuoteInjection() {
+        System.out.println("mySQLANSIModeQuoteInjection");
         Encoder instance = ESAPI.encoder();
         Codec c = new MySQLCodec(MySQLCodec.Mode.ANSI);
         //No special handling is required for double quotes in ANSI_Quotes mode
         assertEquals("MySQL Ansi Quote Injection Bug", "\" or 1=1 -- -", instance.encodeForSQL(c, "\" or 1=1 -- -"));
     }
 
-    
+
     /**
-	 * Test of encodeForLDAP method, of class org.owasp.esapi.Encoder.
-	 */
+     * Test of encodeForLDAP method, of class org.owasp.esapi.Encoder.
+     */
     public void testEncodeForLDAP() {
         System.out.println("encodeForLDAP");
         Encoder instance = ESAPI.encoder();
@@ -505,11 +537,12 @@ public class EncoderTest extends TestCase {
         assertEquals("Zeros", "Hi \\00", instance.encodeForLDAP("Hi \u0000"));
         assertEquals("LDAP Christams Tree", "Hi \\28This\\29 = is \\2a a \\5c test # � � �", instance.encodeForLDAP("Hi (This) = is * a \\ test # � � �"));
         assertEquals("Hi \\28This\\29 =", instance.encodeForLDAP("Hi (This) ="));
+        assertEquals("Forward slash for \\2fMicrosoft\\2f \\2fAD\\2f", instance.encodeForLDAP("Forward slash for /Microsoft/ /AD/"));
     }
-    
+
     /**
-	 * Test of encodeForLDAP method with without encoding wildcard characters, of class org.owasp.esapi.Encoder.
-	 */
+     * Test of encodeForLDAP method with without encoding wildcard characters, of class org.owasp.esapi.Encoder.
+     */
     public void testEncodeForLDAPWithoutEncodingWildcards() {
         System.out.println("encodeForLDAPWithoutEncodingWildcards");
         Encoder instance = ESAPI.encoder();
@@ -517,11 +550,12 @@ public class EncoderTest extends TestCase {
         assertEquals("No special characters to escape", "Hi This is a test #��", instance.encodeForLDAP("Hi This is a test #��", false));
         assertEquals("Zeros", "Hi \\00", instance.encodeForLDAP("Hi \u0000", false));
         assertEquals("LDAP Christams Tree", "Hi \\28This\\29 = is * a \\5c test # � � �", instance.encodeForLDAP("Hi (This) = is * a \\ test # � � �", false));
+        assertEquals("Forward slash for \\2fMicrosoft\\2f \\2fAD\\2f", instance.encodeForLDAP("Forward slash for /Microsoft/ /AD/"));
     }
-    
+
     /**
-	 * Test of encodeForDN method, of class org.owasp.esapi.Encoder.
-	 */
+     * Test of encodeForDN method, of class org.owasp.esapi.Encoder.
+     */
     public void testEncodeForDN() {
         System.out.println("encodeForDN");
         Encoder instance = ESAPI.encoder();
@@ -533,28 +567,33 @@ public class EncoderTest extends TestCase {
         assertEquals("less than greater than", "Hello\\<\\>", instance.encodeForDN("Hello<>"));
         assertEquals("only 3 spaces", "\\  \\ ", instance.encodeForDN("   "));
         assertEquals("Christmas Tree DN", "\\ Hello\\\\ \\+ \\, \\\"World\\\" \\;\\ ", instance.encodeForDN(" Hello\\ + , \"World\" ; "));
+        assertEquals("Forward slash for \\/Microsoft\\/ \\/AD\\/", instance.encodeForDN("Forward slash for /Microsoft/ /AD/"));
     }
-    
+
     /**
-     * Longstanding issue of always lowercasing named HTML entities.  This will be set right now. 
+     * Longstanding issue of always lowercasing named HTML entities.  This will be set right now.
      */
     public void testNamedUpperCaseDecoding(){
-    	String input = "&Uuml;";
-    	String expected = "Ü";
-    	assertEquals(expected, ESAPI.encoder().decodeForHTML(input));
+        System.out.println("namedUpperCaseDecoding");
+        String input = "&Uuml;";
+        String expected = "Ü";
+        assertEquals(expected, ESAPI.encoder().decodeForHTML(input));
     }
-    
+
     public void testEncodeForXMLNull() {
+        System.out.println("encodeFormXMLNull");
         Encoder instance = ESAPI.encoder();
         assertEquals(null, instance.encodeForXML(null));
     }
 
     public void testEncodeForXMLSpace() {
+        System.out.println("encodeFormXMLSpace");
         Encoder instance = ESAPI.encoder();
         assertEquals(" ", instance.encodeForXML(" "));
     }
 
     public void testEncodeForXMLScript() {
+        System.out.println("encodeForXMLScript");
         Encoder instance = ESAPI.encoder();
         assertEquals("&#x3c;script&#x3e;", instance.encodeForXML("<script>"));
     }
@@ -564,50 +603,57 @@ public class EncoderTest extends TestCase {
         Encoder instance = ESAPI.encoder();
         assertEquals(",.-_", instance.encodeForXML(",.-_"));
     }
-    
+
     public void testEncodeForXMLSymbol() {
+        System.out.println("encodeForXMLSymbol");
         Encoder instance = ESAPI.encoder();
         assertEquals("&#x21;&#x40;&#x24;&#x25;&#x28;&#x29;&#x3d;&#x2b;&#x7b;&#x7d;&#x5b;&#x5d;", instance.encodeForXML("!@$%()=+{}[]"));
     }
 
     public void testEncodeForXMLPound() {
-        System.out.println("encodeForXML");
+        System.out.println("encodeForXMLPound");
         Encoder instance = ESAPI.encoder();
         assertEquals("&#xa3;", instance.encodeForXML("\u00A3"));
     }
-    
+
     public void testEncodeForXMLAttributeNull() {
+        System.out.println("encodeForXMLAttributeNull");
         Encoder instance = ESAPI.encoder();
         assertEquals(null, instance.encodeForXMLAttribute(null));
     }
-    
+
     public void testEncodeForXMLAttributeSpace() {
+        System.out.println("encodeForXMLAttributeSpace");
         Encoder instance = ESAPI.encoder();
         assertEquals(" ", instance.encodeForXMLAttribute(" "));
     }
-    
+
     public void testEncodeForXMLAttributeScript() {
+        System.out.println("encodeForXMLAttributeScript");
         Encoder instance = ESAPI.encoder();
         assertEquals("&#x3c;script&#x3e;", instance.encodeForXMLAttribute("<script>"));
     }
-    
+
     public void testEncodeForXMLAttributeImmune() {
+        System.out.println("encodeFormXMLAttributeImmune");
         Encoder instance = ESAPI.encoder();
         assertEquals(",.-_", instance.encodeForXMLAttribute(",.-_"));
     }
-    
+
     public void testEncodeForXMLAttributeSymbol() {
+        System.out.println("encodeFormXMLAttributeSymbol");
         Encoder instance = ESAPI.encoder();
         assertEquals(" &#x21;&#x40;&#x24;&#x25;&#x28;&#x29;&#x3d;&#x2b;&#x7b;&#x7d;&#x5b;&#x5d;", instance.encodeForXMLAttribute(" !@$%()=+{}[]"));
     }
-    
+
     public void testEncodeForXMLAttributePound() {
+        System.out.println("encodeFormXMLAttributePound");
         Encoder instance = ESAPI.encoder();
         assertEquals("&#xa3;", instance.encodeForXMLAttribute("\u00A3"));
     }
-    
+
     /**
-	 * Test of encodeForURL method, of class org.owasp.esapi.Encoder.
+     * Test of encodeForURL method, of class org.owasp.esapi.Encoder.
      *
      * @throws Exception
      */
@@ -617,9 +663,9 @@ public class EncoderTest extends TestCase {
         assertEquals(null, instance.encodeForURL(null));
         assertEquals("%3Cscript%3E", instance.encodeForURL("<script>"));
     }
-    
+
     /**
-	 * Test of decodeFromURL method, of class org.owasp.esapi.Encoder.
+     * Test of decodeFromURL method, of class org.owasp.esapi.Encoder.
      *
      * @throws Exception
      */
@@ -627,29 +673,29 @@ public class EncoderTest extends TestCase {
         System.out.println("decodeFromURL");
         Encoder instance = ESAPI.encoder();
         try {
-        	assertEquals(null, instance.decodeFromURL(null));
+            assertEquals(null, instance.decodeFromURL(null));
             assertEquals("<script>", instance.decodeFromURL("%3Cscript%3E"));
             assertEquals("     ", instance.decodeFromURL("+++++") );
         } catch ( Exception e ) {
             fail();
         }
         try {
-        	instance.decodeFromURL( "%3xridiculous" );
-        	fail();
+            instance.decodeFromURL( "%3xridiculous" );
+            fail();
         } catch( Exception e ) {
-        	// expected
+            // expected
         }
     }
-    
+
     /**
-	 * Test of encodeForBase64 method, of class org.owasp.esapi.Encoder.
-	 */
+     * Test of encodeForBase64 method, of class org.owasp.esapi.Encoder.
+     */
     public void testEncodeForBase64() {
         System.out.println("encodeForBase64");
         Encoder instance = ESAPI.encoder();
-        
+
         try {
-        	assertEquals(null, instance.encodeForBase64(null, false));
+            assertEquals(null, instance.encodeForBase64(null, false));
             assertEquals(null, instance.encodeForBase64(null, true));
             assertEquals(null, instance.decodeFromBase64(null));
             for ( int i=0; i < 100; i++ ) {
@@ -662,10 +708,10 @@ public class EncoderTest extends TestCase {
             fail();
         }
     }
-    
+
     /**
-	 * Test of decodeFromBase64 method, of class org.owasp.esapi.Encoder.
-	 */
+     * Test of decodeFromBase64 method, of class org.owasp.esapi.Encoder.
+     */
     public void testDecodeFromBase64() {
         System.out.println("decodeFromBase64");
         Encoder instance = ESAPI.encoder();
@@ -677,25 +723,25 @@ public class EncoderTest extends TestCase {
                 assertTrue( Arrays.equals( r, decoded ) );
             } catch ( IOException e ) {
                 fail();
-	        }
+            }
         }
         for ( int i=0; i < 100; i++ ) {
             try {
                 byte[] r = ESAPI.randomizer().getRandomString( 20, EncoderConstants.CHAR_SPECIALS ).getBytes(PREFERRED_ENCODING);
                 String encoded = ESAPI.randomizer().getRandomString(1, EncoderConstants.CHAR_ALPHANUMERICS) + instance.encodeForBase64( r, ESAPI.randomizer().getRandomBoolean() );
-	            byte[] decoded = instance.decodeFromBase64( encoded );
-	            assertFalse( Arrays.equals(r, decoded) );
+                byte[] decoded = instance.decodeFromBase64( encoded );
+                assertFalse( Arrays.equals(r, decoded) );
             } catch( UnsupportedEncodingException ex) {
-            	fail();
+                fail();
             } catch ( IOException e ) {
-            	// expected
+                // expected
             }
         }
     }
-    
+
     /**
-	 * Test of WindowsCodec
-	 */
+     * Test of WindowsCodec
+     */
     public void testWindowsCodec() {
         System.out.println("WindowsCodec");
         Encoder instance = ESAPI.encoder();
@@ -703,33 +749,33 @@ public class EncoderTest extends TestCase {
         Codec<Character> win = new WindowsCodec();
         char[] immune = new char[0];
         assertEquals(null, instance.encodeForOS(win, null));
-        
+
         PushbackString npbs = new PushbackString("n");
         assertEquals(null, win.decodeCharacter(npbs));
 
         PushbackString epbs = new PushbackString("");
         assertEquals(null, win.decodeCharacter(epbs));
-        
+
         Character c = Character.valueOf('<');
         PushbackString cpbs = new PushbackString(win.encodeCharacter(immune, c));
         Character decoded = win.decodeCharacter(cpbs);
         assertEquals(c, decoded);
-        
+
         String orig = "c:\\jeff";
         String enc = win.encode(EncoderConstants.CHAR_ALPHANUMERICS, orig);
         assertEquals(orig, win.decode(enc));
         assertEquals(orig, win.decode(orig));
-        
-     // TODO: Check that these are acceptable for Windows
-        assertEquals("c^:^\\jeff", instance.encodeForOS(win, "c:\\jeff"));		
+
+        // TODO: Check that these are acceptable for Windows
+        assertEquals("c^:^\\jeff", instance.encodeForOS(win, "c:\\jeff"));
         assertEquals("c^:^\\jeff", win.encode(immune, "c:\\jeff"));
         assertEquals("dir^ ^&^ foo", instance.encodeForOS(win, "dir & foo"));
         assertEquals("dir^ ^&^ foo", win.encode(immune, "dir & foo"));
     }
 
     /**
-	 * Test of UnixCodec
-	 */
+     * Test of UnixCodec
+     */
     public void testUnixCodec() {
         System.out.println("UnixCodec");
         Encoder instance = ESAPI.encoder();
@@ -737,7 +783,7 @@ public class EncoderTest extends TestCase {
         Codec<Character> unix = new UnixCodec();
         char[] immune = new char[0];
         assertEquals(null, instance.encodeForOS(unix, null));
-        
+
         PushbackString npbs = new PushbackString("n");
         assertEquals(null, unix.decodeCharacter(npbs));
 
@@ -745,7 +791,7 @@ public class EncoderTest extends TestCase {
         PushbackString cpbs = new PushbackString(unix.encodeCharacter(immune, c));
         Character decoded = unix.decodeCharacter(cpbs);
         assertEquals(c, decoded);
-        
+
         PushbackString epbs = new PushbackString("");
         assertEquals(null, unix.decodeCharacter(epbs));
 
@@ -753,8 +799,8 @@ public class EncoderTest extends TestCase {
         String enc = unix.encode(immune, orig);
         assertEquals(orig, unix.decode(enc));
         assertEquals(orig, unix.decode(orig));
-        
-     // TODO: Check that these are acceptable for Unix hosts
+
+        // TODO: Check that these are acceptable for Unix hosts
         assertEquals("c\\:\\\\jeff", instance.encodeForOS(unix, "c:\\jeff"));
         assertEquals("c\\:\\\\jeff", unix.encode(immune, "c:\\jeff"));
         assertEquals("dir\\ \\&\\ foo", instance.encodeForOS(unix, "dir & foo"));
@@ -765,143 +811,147 @@ public class EncoderTest extends TestCase {
         assertEquals("\\/etc\\/hosts", instance.encodeForOS(unix, "/etc/hosts"));
         assertEquals("\\/etc\\/hosts\\;\\ ls\\ -l", instance.encodeForOS(unix, "/etc/hosts; ls -l"));
     }
-    
+
     public void testCanonicalizePerformance() throws Exception {
         System.out.println("Canonicalization Performance");
-    	Encoder encoder = ESAPI.encoder();
-    	int iterations = 100;
-    	String normal = "The quick brown fox jumped over the lazy dog";
-    	
-    	long start = System.currentTimeMillis();
-    	String temp = null;		// Trade in 1/2 doz warnings in Eclipse for one (never read)
+        Encoder encoder = ESAPI.encoder();
+        int iterations = 100;
+        String normal = "The quick brown fox jumped over the lazy dog";
+
+        long start = System.currentTimeMillis();
+        String temp = null;        // Trade in 1/2 doz warnings in Eclipse for one (never read)
         for ( int i=0; i< iterations; i++ ) {
-        	temp = normal;
+            temp = normal;
         }
-    	long stop = System.currentTimeMillis();
+        long stop = System.currentTimeMillis();
         System.out.println( "Normal: " + (stop-start) );
-        
-    	start = System.currentTimeMillis();
+
+        start = System.currentTimeMillis();
         for ( int i=0; i< iterations; i++ ) {
-        	temp = encoder.canonicalize( normal, false );
+            temp = encoder.canonicalize( normal, false );
         }
-    	stop = System.currentTimeMillis();
+        stop = System.currentTimeMillis();
         System.out.println( "Normal Loose: " + (stop-start) );
-        
-    	start = System.currentTimeMillis();
+
+        start = System.currentTimeMillis();
         for ( int i=0; i< iterations; i++ ) {
-        	temp = encoder.canonicalize( normal, true );
+            temp = encoder.canonicalize( normal, true );
         }
-    	stop = System.currentTimeMillis();
+        stop = System.currentTimeMillis();
         System.out.println( "Normal Strict: " + (stop-start) );
 
-    	String attack = "%2&#x35;2%3525&#x32;\\u0036lt;\r\n\r\n%&#x%%%3333\\u0033;&%23101;";
-    	
-    	start = System.currentTimeMillis();
+        String attack = "%2&#x35;2%3525&#x32;\\u0036lt;\r\n\r\n%&#x%%%3333\\u0033;&%23101;";
+
+        start = System.currentTimeMillis();
         for ( int i=0; i< iterations; i++ ) {
-        	temp = attack;
+            temp = attack;
         }
-    	stop = System.currentTimeMillis();
+        stop = System.currentTimeMillis();
         System.out.println( "Attack: " + (stop-start) );
-        
-    	start = System.currentTimeMillis();
+
+        start = System.currentTimeMillis();
         for ( int i=0; i< iterations; i++ ) {
-        	temp = encoder.canonicalize( attack, false );
+            temp = encoder.canonicalize( attack, false );
         }
-    	stop = System.currentTimeMillis();
+        stop = System.currentTimeMillis();
         System.out.println( "Attack Loose: " + (stop-start) );
-        
-    	start = System.currentTimeMillis();
+
+        start = System.currentTimeMillis();
         for ( int i=0; i< iterations; i++ ) {
-        	try {
-        		temp = encoder.canonicalize( attack, true );
-        	} catch( IntrusionException e ) { 
-        		// expected
-        	}
+            try {
+                temp = encoder.canonicalize( attack, true );
+            } catch( IntrusionException e ) {
+                // expected
+            }
         }
-    	stop = System.currentTimeMillis();
+        stop = System.currentTimeMillis();
         System.out.println( "Attack Strict: " + (stop-start) );
     }
-    
+
 
     public void testConcurrency() {
         System.out.println("Encoder Concurrency");
-		for (int i = 0; i < 10; i++) {
-			new Thread( new EncoderConcurrencyMock( i )).start();
-		}
-	}
+        for (int i = 0; i < 10; i++) {
+            new Thread( new EncoderConcurrencyMock( i )).start();
+        }
+    }
 
     /**
      *  A simple class that calls the Encoder to test thread safety
      */
     public class EncoderConcurrencyMock implements Runnable {
-    	public int num = 0;
-    	public EncoderConcurrencyMock( int num ) {
-    		this.num = num;
-    	}
-	    public void run() {
-			while( true ) {
-				String nonce = ESAPI.randomizer().getRandomString( 20, EncoderConstants.CHAR_SPECIALS );
-				String result = javaScriptEncode( nonce );
-				// randomize the threads
-				try {
-					Thread.sleep( ESAPI.randomizer().getRandomInteger( 100, 500 ) );
-				} catch (InterruptedException e) {
-					// just continue
-				}
-				assertTrue( result.equals ( javaScriptEncode( nonce ) ) );
-			}
-		}
-		
-	    public String javaScriptEncode(String str) {
-			Encoder encoder = DefaultEncoder.getInstance();
-			return encoder.encodeForJavaScript(str);
-		}
-    }
-    
+        public int num = 0;
+        public EncoderConcurrencyMock( int num ) {
+            this.num = num;
+        }
+        public void run() {
+            while( true ) {
+                String nonce = ESAPI.randomizer().getRandomString( 20, EncoderConstants.CHAR_SPECIALS );
+                String result = javaScriptEncode( nonce );
+                // randomize the threads
+                try {
+                    Thread.sleep( ESAPI.randomizer().getRandomInteger( 100, 500 ) );
+                } catch (InterruptedException e) {
+                    // just continue
+                }
+                assertTrue( result.equals ( javaScriptEncode( nonce ) ) );
+            }
+        }
+
+        public String javaScriptEncode(String str) {
+            Encoder encoder = DefaultEncoder.getInstance();
+            return encoder.encodeForJavaScript(str);
+        }
+    }
+
     public void testGetCanonicalizedUri() throws Exception {
-    	Encoder e = ESAPI.encoder();
-    	
-    	String expectedUri = "http://palpatine@foo bar.com/path_to/resource?foo=bar#frag";
-    	//Please note that section 3.2.1 of RFC-3986 explicitly states not to encode
-    	//password information as in http://palpatine:password@foo.com, and this will
-    	//not appear in the userinfo field.  
-    	String input = "http://palpatine@foo%20bar.com/path_to/resource?foo=bar#frag";
-    	URI uri = new URI(input);
-    	System.out.println(uri.toString());
-    	assertEquals(expectedUri, e.getCanonicalizedURI(uri));
-    	
-    }
-    
+        System.out.println("getCanonicalizedUri");
+        Encoder e = ESAPI.encoder();
+
+        String expectedUri = "http://palpatine@foo bar.com/path_to/resource?foo=bar#frag";
+        //Please note that section 3.2.1 of RFC-3986 explicitly states not to encode
+        //password information as in http://palpatine:password@foo.com, and this will
+        //not appear in the userinfo field.
+        String input = "http://palpatine@foo%20bar.com/path_to/resource?foo=bar#frag";
+        URI uri = new URI(input);
+        System.out.println(uri.toString());
+        assertEquals(expectedUri, e.getCanonicalizedURI(uri));
+
+    }
+
     public void testGetCanonicalizedUriPiazza() throws Exception {
-    	Encoder e = ESAPI.encoder();
-    	
-    	String expectedUri = "http://127.0.0.1:3000/campaigns?goal=all&section=active&sort-by=-id&status=Draft,Launched";
-    	//Please note that section 3.2.1 of RFC-3986 explicitly states not to encode
-    	//password information as in http://palpatine:password@foo.com, and this will
-    	//not appear in the userinfo field.  
-    	String input = "http://127.0.0.1:3000/campaigns?goal=all&section=active&sort-by=-id&status=Draft%2CLaunched";
-    	URI uri = new URI(input);
-    	System.out.println(uri.toString());
-    	assertEquals(expectedUri, e.getCanonicalizedURI(uri));
-    	
-    }
-    	
+        System.out.println("getCanonicalizedUriPiazza");
+        Encoder e = ESAPI.encoder();
+
+        String expectedUri = "http://127.0.0.1:3000/campaigns?goal=all&section=active&sort-by=-id&status=Draft,Launched";
+        //Please note that section 3.2.1 of RFC-3986 explicitly states not to encode
+        //password information as in http://palpatine:password@foo.com, and this will
+        //not appear in the userinfo field.
+        String input = "http://127.0.0.1:3000/campaigns?goal=all&section=active&sort-by=-id&status=Draft%2CLaunched";
+        URI uri = new URI(input);
+        System.out.println(uri.toString());
+        assertEquals(expectedUri, e.getCanonicalizedURI(uri));
+
+    }
+
     public void testGetCanonicalizedUriWithMailto() throws Exception {
-    	Encoder e = ESAPI.encoder();
-    	
-    	String expectedUri = "http://palpatine@foo bar.com/path_to/resource?foo=bar#frag";
-    	//Please note that section 3.2.1 of RFC-3986 explicitly states not to encode
-    	//password information as in http://palpatine:password@foo.com, and this will
-    	//not appear in the userinfo field.  
-    	String input = "http://palpatine@foo%20bar.com/path_to/resource?foo=bar#frag";
-    	URI uri = new URI(input);
-    	System.out.println(uri.toString());
-    	assertEquals(expectedUri, e.getCanonicalizedURI(uri));
-    }
-    
+        System.out.println("getCanonicalizedUriWithMailto");
+        Encoder e = ESAPI.encoder();
+
+        String expectedUri = "http://palpatine@foo bar.com/path_to/resource?foo=bar#frag";
+        //Please note that section 3.2.1 of RFC-3986 explicitly states not to encode
+        //password information as in http://palpatine:password@foo.com, and this will
+        //not appear in the userinfo field.
+        String input = "http://palpatine@foo%20bar.com/path_to/resource?foo=bar#frag";
+        URI uri = new URI(input);
+        System.out.println(uri.toString());
+        assertEquals(expectedUri, e.getCanonicalizedURI(uri));
+    }
+
     public void testHtmlEncodeStrSurrogatePair()
     {
-    	Encoder enc = ESAPI.encoder();
+        System.out.println("htmlEncodeStrSurrogatePair");
+        Encoder enc = ESAPI.encoder();
         String inStr = new String (new int[]{0x2f804}, 0, 1);
         assertEquals(false, Character.isBmpCodePoint(inStr.codePointAt(0)));
         assertEquals(true, Character.isBmpCodePoint(new String(new int[] {0x0a}, 0, 1).codePointAt(0)));
@@ -911,25 +961,28 @@ public class EncoderTest extends TestCase {
         result = enc.encodeForHTML(inStr);
         assertEquals(expected, result);
     }
-    
+
     public void testHtmlDecodeHexEntititesSurrogatePair()
     {
+        System.out.println("htmlDecodeHexEntitiesSurrogatePair");
         HTMLEntityCodec htmlCodec = new HTMLEntityCodec();
         String expected = new String (new int[]{0x2f804}, 0, 1);
         assertEquals( expected, htmlCodec.decode("&#194564;") );
         assertEquals( expected, htmlCodec.decode("&#x2f804;") );
     }
-    
+
     public void testUnicodeCanonicalize() {
+        System.out.println("UnicodeCanonicalize");
         Encoder e = ESAPI.encoder();
         String input = "测试";
         String expected = "测试";
         String output = e.canonicalize(input);
         assertEquals(expected, output);
     }
-    
+
     public void testUnicodeCanonicalizePercentEncoding() {
-        //TODO:  We need to find a way to specify the encoding type for percent encoding.  
+        System.out.println("UnicodeCanonicalizePercentEncoding");
+        //TODO:  We need to find a way to specify the encoding type for percent encoding.
         //I believe by default we're doing Latin-1 and we really should be doing UTF-8
         Encoder e = ESAPI.encoder();
         String input = "%E6%B5%8B%E8%AF%95";
@@ -937,5 +990,401 @@ public class EncoderTest extends TestCase {
         String output = e.canonicalize(input);
         assertNotSame(expected, output);
     }
-}
 
+    // Test for GitHub Issue 686.
+    public void testGetDefaultCanonicalizationCodecs() {
+        System.out.println("getDefaultCanonicalizationCodecs");
+
+        // This test input has mixed encoding. It is encoded using %-encoding (e.g.,
+        // the %20 representing spaces) and the '\\o' representing backslash
+        // encoding. This particular backslash encoding (the "e\\tc") should
+        // match *both* JavaScriptCodec and the UnixCodec.
+        String testInput = "echo%20\"Hello%20$(id)\";%20echo \"Today is: \\$(date)\" && cat \\.\\.\\///..///..///..//../e\\tc///passwd";
+
+            // SecurityConfiguration before we change it later to tweak the Encoder.DefaultCodecList property
+        SecurityConfiguration scOrig = ESAPI.securityConfiguration();
+
+        // We only use the 3 standard (default) Codecs here:
+        //      HTMLEntityCodec, PercentCodec, and JavaScriptCodec.
+        // Since testInput only has one of these encodings (the PercentCodec),
+        // it will not fire off an IntrustionDetectionException here.
+        Encoder ecOrig = new DefaultEncoder( scOrig.getDefaultCanonicalizationCodecs() );
+        String canonOrig = null;
+        boolean caughtExpected = false;
+        try {
+            ecOrig.canonicalize( testInput );
+        } catch( IntrusionException iex) {
+            caughtExpected = true;
+        }
+        assertTrue( caughtExpected );   // Verify it threw an IntrusionException
+
+        // Now set up a case where (via the Encoder.DefaultCodecList property)
+        // where "UnixCodec" is added on to the standard list of 3 normal codecs
+        // used. Since we also have encoding using '\' encoding that should be
+        // recognized by UnixCodec, we should now get an
+        // IntrusionException as we have mixed and mulitple encoding
+        // both that should be recognized here.
+        List<String> myCodecs = new ArrayList<String>();
+        myCodecs.add( "HTMLEntityCodec" );
+        myCodecs.add( "PercentCodec" );
+        // myCodecs.add( "JavaScriptCodec" );   // Don't use this or we will have to parse exception message
+                                                // to see if test was successful or not.
+            // Instead of JavaScriptCodec, we will use UnixCodec to detect the backslash encoding here.
+        myCodecs.add( "UnixCodec" );
+
+            // Finally override ESAPI to use the new SecurityConfiguration
+        ESAPI.override( new Conf( ESAPI.securityConfiguration(), myCodecs ) );
+
+        SecurityConfiguration scAltered = ESAPI.securityConfiguration();
+        List<String> origCodecs = scOrig.getDefaultCanonicalizationCodecs();
+        List<String> alteredCodecs = scAltered.getDefaultCanonicalizationCodecs();
+
+            // First, let's confirm we've actually overridden the SecurityConfiguration.
+        assertNotEquals( origCodecs, alteredCodecs );
+
+            // Now do the canonicalization w/ the new list of codecs
+        caughtExpected = true;
+        try {
+            String canonAltered = ESAPI.encoder().canonicalize( testInput );
+        } catch( IntrusionException iex ) {
+            caughtExpected = true;
+        }
+
+        assertTrue( caughtExpected );   // Verify it threw an IntrusionException
+    }
+
+    /**
+     * Test of encodeForJSON method, of class org.owasp.esapi.Encoder.
+     */
+    public void testEncodeForJSON_EmptyStrings() {
+        System.out.println("testEncodeForJSON_EmptyStrings");
+        Encoder instance = ESAPI.encoder();
+
+        // Empty strings
+        assertEquals( null, instance.encodeForJSON(null) );
+        assertEquals( "", instance.encodeForJSON("") );
+        assertEquals( " ", instance.encodeForJSON(" ") );
+    }
+
+    /**
+     * Test of encodeForJSON method, of class org.owasp.esapi.Encoder.
+     */
+    public void testEncodeForJSON_7BitClean() {
+        System.out.println("testEncodeForJSON_7BitClean");
+        Encoder instance = ESAPI.encoder();
+
+        // Walk a message without escaped characters
+        String message = "Now is the time for all good men to come to the aide of their country.";
+        for ( int i = 1; i < message.length(); ++i ) {
+            final String substring = message.substring(0, i);
+            assertEquals( substring, instance.encodeForJSON(substring) );
+        }
+    }
+
+    /**
+     * Test of encodeForJSON method, of class org.owasp.esapi.Encoder.
+     */
+    public void testEncodeForJSON_2CharEscapeSequences() {
+        System.out.println("testEncodeForJSON_2CharEscapeSequences");
+        Encoder instance = ESAPI.encoder();
+
+        // Two-character sequence escape representations of some
+        // popular characters
+        assertEquals( "\\b", instance.encodeForJSON("\b") );
+        assertEquals( "\\f", instance.encodeForJSON("\f") );
+        assertEquals( "\\r", instance.encodeForJSON("\r") );
+        assertEquals( "\\n", instance.encodeForJSON("\n") );
+        assertEquals( "\\t", instance.encodeForJSON("\t") );
+        assertEquals( "\\\"", instance.encodeForJSON("\"") );
+        assertEquals( "\\/",  instance.encodeForJSON("/" ) );
+        assertEquals( "\\\\", instance.encodeForJSON("\\") );
+    }
+
+    /**
+     * Test of encodeForJSON method, of class org.owasp.esapi.Encoder.
+     */
+    public void testEncodeForJSON_ControlCharacters() {
+        System.out.println("testEncodeForJSON_ControlCharacters");
+        Encoder instance = ESAPI.encoder();
+
+        // All Unicode characters may be placed within the quotation marks,
+        // except for the characters that MUST be escaped: quotation mark,
+        // reverse solidus, and the control characters (U+0000 through U+001F).
+        for ( int i = 0; i <= 0x1f; ++i ) {
+            final char ch = (char)i;
+            if( ch == '\b' || ch == '\f' || ch == '\r' || ch == '\n' || ch == '\t' ) {
+                continue;
+            }
+
+            final String str1 = String.format( "\\u%04x", i );
+            final String str2 = Character.toString( ch );
+            assertEquals( str1, instance.encodeForJSON(str2) );
+        }
+    }
+
+    /**
+     * Test of encodeForJSON method, of class org.owasp.esapi.Encoder.
+     */
+    public void testEncodeForJSON_PrintableChars() {
+        System.out.println("testEncodeForJSON_PrintableChars");
+        Encoder instance = ESAPI.encoder();
+
+        // And the remainder of printable characters
+        for ( int i = 32; i <= 126; ++i ) {
+            final char ch = (char)i;
+            if( ch == '/' || ch == '\\' || ch == '\"' ) {
+                continue;
+            }
+
+            final String str = Character.toString( ch );
+            assertEquals( str, instance.encodeForJSON(str) );
+        }
+    }
+
+    /**
+     * Test of decodeFromJSON method, of class org.owasp.esapi.Encoder.
+     */
+    public void testDecodeFromJSON_EmptyStrings() {
+        System.out.println("testDecodeFromJSON_EmptyStrings");
+        Encoder instance = ESAPI.encoder();
+
+        // Empty strings
+        assertEquals( null, instance.decodeFromJSON(null) );
+        assertEquals( "", instance.decodeFromJSON("") );
+        assertEquals( " ", instance.decodeFromJSON(" ") );
+    }
+
+    /**
+     * Test of decodeFromJSON method, of class org.owasp.esapi.Encoder.
+     */
+    public void testDecodeFromJSON_7BitClean() {
+        System.out.println("testDecodeFromJSON_7BitClean");
+        Encoder instance = ESAPI.encoder();
+
+        // Walk a message without escaped characters
+        String message = "Now is the time for all good men to come to the aide of their country.";
+        for ( int i = 1; i < message.length(); ++i ) {
+            final String substring = message.substring(0, i);
+            assertEquals( substring, instance.decodeFromJSON(substring) );
+        }
+    }
+
+    /**
+     * Test of decodeFromJSON method, of class org.owasp.esapi.Encoder.
+     */
+    public void testDecodeFromJSON_2CharEscapeSequences() {
+        System.out.println("testDecodeFromJSON_2CharEscapeSequences");
+        Encoder instance = ESAPI.encoder();
+
+        // Two-character sequence escape representations of some
+        // popular characters
+        assertEquals( "\b", instance.decodeFromJSON("\\b") );
+        assertEquals( "\f", instance.decodeFromJSON("\\f") );
+        assertEquals( "\r", instance.decodeFromJSON("\\r") );
+        assertEquals( "\n", instance.decodeFromJSON("\\n") );
+        assertEquals( "\t", instance.decodeFromJSON("\\t") );
+        assertEquals( "\"", instance.decodeFromJSON("\\\"") );
+        assertEquals( "/",  instance.decodeFromJSON("\\/" ) );
+        assertEquals( "\\", instance.decodeFromJSON("\\\\") );
+    }
+
+    /**
+     * Test of decodeFromJSON method, of class org.owasp.esapi.Encoder.
+     */
+    public void testDecodeFromJSON_ControlCharacters() {
+        System.out.println("testDecodeFromJSON_ControlCharacters");
+        Encoder instance = ESAPI.encoder();
+
+        // All Unicode characters may be placed within the quotation marks,
+        // except for the characters that MUST be escaped: quotation mark,
+        // reverse solidus, and the control characters (U+0000 through U+001F).
+        for ( int i = 0; i <= 0x1f; ++i ) {
+            final String str = String.format( "\\u%04x", i );
+            final Character ch = (char)i;
+
+            assertEquals( Character.toString(ch), instance.decodeFromJSON(str) );
+        }
+    }
+
+    /**
+     * Test of decodeFromJSON method, of class org.owasp.esapi.Encoder.
+     */
+    public void testDecodeFromJSON_PrintableChars() {
+        System.out.println("testDecodeFromJSON_PrintableChars");
+        Encoder instance = ESAPI.encoder();
+
+        // And the remainder of printable characters
+        for ( int i = 32; i <= 126; ++i ) {
+            final String str = String.format( "\\u%04x", i );
+            final Character ch = (char)i;
+
+            assertEquals( Character.toString(ch), instance.decodeFromJSON(str) );
+        }
+    }
+
+    /**
+     * Test of decodeFromJSON method, of class org.owasp.esapi.Encoder.
+     */
+    public void testDecodeFromJSON_Slashes() {
+        System.out.println("testDecodeFromJSON_Slashes");
+        Encoder instance = ESAPI.encoder();
+
+        // And a couple extra for good measure...
+        assertEquals( "\\", instance.decodeFromJSON("\\u005c") );
+        assertEquals( "\\", instance.decodeFromJSON("\\u005C") );
+        assertEquals( "\\\\", instance.decodeFromJSON("\\u005c\\u005c") );
+        assertEquals( "\\\\", instance.decodeFromJSON("\\u005C\\u005C") );
+    }
+
+    /**
+     * Test of decodeFromJSON method, of class org.owasp.esapi.Encoder.
+     */
+    public void testDecodeFromJSON_Malformed() {
+        System.out.println("testDecodeFromJSON_Malformed");
+        Encoder instance = ESAPI.encoder();
+
+        // Malformed. No '\a' or \c' popular characters
+        boolean exceptionThrown = false;
+        try {
+            exceptionThrown = false;
+            String unused = instance.decodeFromJSON("\\a");
+        }
+        catch (IllegalArgumentException e) {
+            exceptionThrown = true;
+        }
+        assertTrue( exceptionThrown );
+
+        // Malformed. No '\a' or \c' popular characters
+        try {
+            exceptionThrown = false;
+            String unused = instance.decodeFromJSON("\\c");
+        }
+        catch (IllegalArgumentException e) {
+            exceptionThrown = true;
+        }
+        assertTrue( exceptionThrown );
+
+        // Malformed. Must have 4 hex digits
+        try {
+            exceptionThrown = false;
+            String unused = instance.decodeFromJSON("\\u");
+        }
+        catch (IllegalArgumentException e) {
+            exceptionThrown = true;
+        }
+        assertTrue( exceptionThrown );
+
+        // Malformed. Must have 4 hex digits
+        try {
+            exceptionThrown = false;
+            String unused = instance.decodeFromJSON("\\u0");
+        }
+        catch (IllegalArgumentException e) {
+            exceptionThrown = true;
+        }
+        assertTrue( exceptionThrown );
+
+        // Malformed. Must have 4 hex digits
+        try {
+            exceptionThrown = false;
+            String unused = instance.decodeFromJSON("\\u00");
+        }
+        catch (IllegalArgumentException e) {
+            exceptionThrown = true;
+        }
+        assertTrue( exceptionThrown );
+
+        // Malformed. Must have 4 hex digits
+        try {
+            exceptionThrown = false;
+            String unused = instance.decodeFromJSON("\\u005");
+        }
+        catch (IllegalArgumentException e) {
+            exceptionThrown = true;
+        }
+        assertTrue( exceptionThrown );
+
+        // Malformed. Must have 4 hex digits
+        try {
+            exceptionThrown = false;
+            String unused = instance.decodeFromJSON("\\u0nnnABCDEFGHIJKLMNOPQRSTUVWXYZ");
+        }
+        catch (IllegalArgumentException e) {
+            exceptionThrown = true;
+        }
+        assertTrue( exceptionThrown );
+
+        // Malformed. Must have 4 hex digits
+        try {
+            exceptionThrown = false;
+            String unused = instance.decodeFromJSON("\\u00nnABCDEFGHIJKLMNOPQRSTUVWXYZ");
+        }
+        catch (IllegalArgumentException e) {
+            exceptionThrown = true;
+        }
+        assertTrue( exceptionThrown );
+
+        // Malformed. Must have 4 hex digits
+        try {
+            exceptionThrown = false;
+            String unused = instance.decodeFromJSON("\\u005nABCDEFGHIJKLMNOPQRSTUVWXYZ");
+        }
+        catch (IllegalArgumentException e) {
+            exceptionThrown = true;
+        }
+        assertTrue( exceptionThrown );
+
+        // Malformed. The '\U' must be lowercase
+        try {
+            exceptionThrown = false;
+            String unused = instance.decodeFromJSON("\\U005C");
+        }
+        catch (IllegalArgumentException e) {
+            exceptionThrown = true;
+        }
+        assertTrue( exceptionThrown );
+    }
+
+    /**
+     * Test of encodeForJSON and decodeFromJSON methods, of class org.owasp.esapi.Encoder.
+     * https://github.com/ESAPI/esapi-java-legacy/pull/722#discussion_r922860329
+     */
+    public void testRoundtripWithJSON_SupplementaryUnicode () {
+        System.out.println("testRoundtripWithJSON_SupplementaryUnicode");
+        Encoder instance = ESAPI.encoder();
+
+        // U+1F602 is "\uD83D\uDE02" in Java
+        // https://www.fileformat.info/info/unicode/char/1f602/index.htm
+        final String FACE_WITH_TEARS_OF_JOY = "\uD83D\uDE02";
+        assertEquals( FACE_WITH_TEARS_OF_JOY, instance.decodeFromJSON(instance.encodeForJSON(FACE_WITH_TEARS_OF_JOY)) );
+    }
+
+    /**
+     * Test of encodeForJSON and decodeFromJSON methods, of class org.owasp.esapi.Encoder.
+     */
+    public void testRoundtripWithJSON_Random6CharEscapes () {
+        System.out.println("testRoundtripWithJSON_Random6CharEscapes");
+        Encoder instance = ESAPI.encoder();
+
+        // Walk a message without escaped characters
+        final String str1 = "Now is the time for all good men to come to the aide of their country.";
+
+        StringBuilder sb = new StringBuilder();
+        Randomizer prng = ESAPI.randomizer();
+
+        for ( int i = 0; i < str1.length(); ++i ) {
+            // Perform 6-character escaping on a character with probability 1/4
+            final boolean encode = prng.getRandomBoolean() & prng.getRandomBoolean();
+            if ( encode ) {
+                sb.append( String.format("\\u%04x", (int)str1.charAt(i)) );
+            }
+            else {
+                sb.append( str1.charAt(i) );
+            }
+        }
+
+        final String str2 = sb.toString();
+        assertEquals( str1, instance.decodeFromJSON(str2) );
+    }
+
+}
diff --git a/src/test/java/org/owasp/esapi/reference/ExecutorTest.java b/src/test/java/org/owasp/esapi/reference/ExecutorTest.java
index d301fce..922ac2d 100644
--- a/src/test/java/org/owasp/esapi/reference/ExecutorTest.java
+++ b/src/test/java/org/owasp/esapi/reference/ExecutorTest.java
@@ -1,15 +1,15 @@
 /**
  * OWASP Enterprise Security API (ESAPI)
- * 
+ *
  * This file is part of the Open Web Application Security Project (OWASP)
  * Enterprise Security API (ESAPI) project. For details, please see
  * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
  *
  * Copyright (c) 2007 - The OWASP Foundation
- * 
+ *
  * The ESAPI is published by OWASP under the BSD license. You should read and accept the
  * LICENSE before you use, modify, and/or redistribute this software.
- * 
+ *
  * @author Jeff Williams <a href="http://www.aspectsecurity.com">Aspect Security</a>
  * @created 2007
  */
@@ -37,47 +37,45 @@ import junit.framework.TestSuite;
 
 /**
  * The Class ExecutorTest.
- * 
+ *
  * @author Jeff Williams (jeff.williams@aspectsecurity.com)
  */
 public class ExecutorTest extends TestCase {
 
-	private SecurityConfiguration origConfig;
-
-	private static class Conf extends SecurityConfigurationWrapper
-	{
-		private final List allowedExes;
-		private final File workingDir;
-
-		Conf(SecurityConfiguration orig, List allowedExes, File workingDir)
-		{
-			super(orig);
-			this.allowedExes = allowedExes;
-			this.workingDir = workingDir;
-		}
-
-		@Override
-		public List getAllowedExecutables()
-		{
-			return allowedExes;
-		}
-
-		@Override
-		public File getWorkingDirectory()
-		{
-			return workingDir;
-		}
-	}
-
-	/**
-	 * Instantiates a new executor test.
-	 * 
-	 * @param testName
-	 *            the test name
-	 */
-	public ExecutorTest(String testName) {
-		super(testName);
-	}
+    private static class Conf extends SecurityConfigurationWrapper
+    {
+        private final List allowedExes;
+        private final File workingDir;
+
+        Conf(SecurityConfiguration orig, List allowedExes, File workingDir)
+        {
+            super(orig);
+            this.allowedExes = allowedExes;
+            this.workingDir = workingDir;
+        }
+
+        @Override
+        public List getAllowedExecutables()
+        {
+            return allowedExes;
+        }
+
+        @Override
+        public File getWorkingDirectory()
+        {
+            return workingDir;
+        }
+    }
+
+    /**
+     * Instantiates a new executor test.
+     *
+     * @param testName
+     *            the test name
+     */
+    public ExecutorTest(String testName) {
+        super(testName);
+    }
 
     @Override
     protected void tearDown() throws Exception {
@@ -85,242 +83,242 @@ public class ExecutorTest extends TestCase {
     }
 
     /**
-	 * Suite.
-	 * 
-	 * @return the test
-	 */
-	public static Test suite() {
-		TestSuite suite = new TestSuite(ExecutorTest.class);
-		return suite;
-	}
-	
-	private void resetSingletonField() throws Exception {
-		//Wipe the singleton field here so we can force recreation.
-		Field singletonField = DefaultExecutor.class.getDeclaredField("singletonInstance");
-		singletonField.setAccessible(true);
-		//Object ref is ignored since field is static.
-		singletonField.set(new Object(), null);
-	}
-
-	public void testPlatformResoveWindows() throws Exception {
-		String origName = System.getProperty("os.name");
-
-		try {
-			//Wipe the singleton field here so we can force recreation.
-			resetSingletonField();
-
-			System.setProperty("os.name", "a name that includes the literal 'Windows'");
-			Executor ex = DefaultExecutor.getInstance();
-
-
-			Field codecField = DefaultExecutor.class.getDeclaredField("codec");
-			codecField.setAccessible(true);
-
-			Object instCodec = codecField.get(ex);
-
-			assertTrue(instCodec instanceof WindowsCodec);
-		} finally {
-			System.setProperty("os.name", origName);
-			resetSingletonField();
-		}
-	}
-
-	public void testPlatformResolveNx() throws Exception{
-		String origName = System.getProperty("os.name");
-
-		try {
-			//Wipe the singleton field here so we can force recreation.
-			resetSingletonField();
-
-			//Unmatched Platform is anything but the literal string "Windows" - In part or in whole.
-			System.setProperty("os.name", "unmatchedPlatform");
-			Executor ex = DefaultExecutor.getInstance();
-
-
-			Field codecField = DefaultExecutor.class.getDeclaredField("codec");
-			codecField.setAccessible(true);
-
-			Object instCodec = codecField.get(ex);
-
-			assertTrue(instCodec instanceof UnixCodec);
-		} finally {
-			System.setProperty("os.name", origName);
-			resetSingletonField();
-		}
-	}
-
-
-	/**
-	 * Test of executeOSCommand method, of class org.owasp.esapi.Executor
-	 * 
-	 * @throws Exception
-	 *             the exception
-	 */
-	public void testExecuteWindowsSystemCommand() throws Exception {
-		System.out.println("executeWindowsSystemCommand");
-
-		if ( System.getProperty("os.name").indexOf("Windows") == -1 ) {
-			System.out.println("testExecuteWindowsSystemCommand - on non-Windows platform, exiting");
-			return;	// Not windows, not going to execute this path
-		}
-		File tmpDir = new File(System.getProperty("java.io.tmpdir")).getCanonicalFile();
-		File sysRoot = new File(System.getenv("SystemRoot")).getCanonicalFile();
-		File sys32 = new File(sysRoot,"system32").getCanonicalFile();
-		File cmd = new File(sys32,"cmd.exe").getCanonicalFile();
-		ESAPI.override(
-			new Conf(
-				ESAPI.securityConfiguration(),
-				Collections.singletonList(cmd.getPath()),
-				tmpDir
-			)
-		);
-
-		Codec codec = new WindowsCodec();
-		System.out.println("executeSystemCommand");
-		Executor instance = ESAPI.executor();
-		List params = new ArrayList();
-		try {
-			params.add("/C");
-			params.add("dir");
-			ExecuteResult result = instance.executeSystemCommand(cmd, new ArrayList(params) );
-			System.out.println( "RESULT: " + result );
-			assertTrue(result.getOutput().length() > 0);
-		} catch (Exception e) {
-			e.printStackTrace();
-			fail();
-		}
-		try {
-			File exec2 = new File( cmd.getPath() + ";inject.exe" );
-			ExecuteResult result = instance.executeSystemCommand(exec2, new ArrayList(params) );
-			System.out.println( "RESULT: " + result );
-			fail();
-		} catch (Exception e) {
-			// expected
-		}
-		try {
-			File exec2 = new File( cmd.getPath() + "\\..\\cmd.exe" );
-			ExecuteResult result = instance.executeSystemCommand(exec2, new ArrayList(params) );
-			System.out.println( "RESULT: " + result );
-			fail();
-		} catch (Exception e) {
-			// expected
-		}
-		try {
-			File workdir = new File( "c:\\ridiculous" );
-			ExecuteResult result = instance.executeSystemCommand(cmd, new ArrayList(params), workdir, codec, false, false );
-			System.out.println( "RESULT: " + result );
-			fail();
-		} catch (Exception e) {
-			// expected
-		}
-		try {
-			params.add("&dir");
-			ExecuteResult result = instance.executeSystemCommand(cmd, new ArrayList(params) );
-			System.out.println( "RESULT: " + result );
-		} catch (Exception e) {
-			fail();
-		}
-
-		try {
-			params.set( params.size()-1, "c:\\autoexec.bat" );
-			ExecuteResult result = instance.executeSystemCommand(cmd, new ArrayList(params) );
-			System.out.println( "RESULT: " + result );
-		} catch (Exception e) {
-			fail();
-		}
-
-		try {
-			params.set( params.size()-1, "c:\\autoexec.bat c:\\config.sys" );
-			ExecuteResult result = instance.executeSystemCommand(cmd, new ArrayList(params) );
-			System.out.println( "RESULT: " + result );
-		} catch (Exception e) {
-			fail();
-		}
-	}
-
-	/**
-	 * Test of executeOSCommand method, of class org.owasp.esapi.Executor
-	 * 
-	 * @throws Exception
-	 *             the exception
-	 */
-	public void testExecuteUnixSystemCommand() throws Exception {
-		System.out.println("executeUnixSystemCommand");
-
-		if ( System.getProperty("os.name").indexOf("Windows") != -1 ) {
-			System.out.println("executeUnixSystemCommand - on Windows platform, exiting");
-			return;
-		}
-
-		// FIXME: need more test cases to use this codec
-		Codec codec = new UnixCodec();
-
-		// make sure we have what /bin/sh is pointing at in the allowed exes for the test
-		// and a usable working dir
-		File binSh = new File("/bin/sh").getCanonicalFile();
-		ESAPI.override(
-			new Conf(
-				ESAPI.securityConfiguration(),
-				Collections.singletonList(binSh.getPath()),
-				new File("/tmp")
-			)
-		);
-
-		Executor instance = ESAPI.executor();
-		File executable = binSh;
-		List params = new ArrayList();
-		try {
-			params.add("-c");
-			params.add("ls");
-			params.add("/");
-			ExecuteResult result = instance.executeSystemCommand(executable, new ArrayList(params) );
-			System.out.println( "RESULT: " + result );
-			assertTrue(result.getOutput().length() > 0);
-		} catch (Exception e) {
-			fail(e.getMessage());
-		}
-		try {
-			File exec2 = new File( executable.getPath() + ";./inject" );
-			ExecuteResult result = instance.executeSystemCommand(exec2, new ArrayList(params) );
-			System.out.println( "RESULT: " + result );
-			fail();
-		} catch (Exception e) {
-			// expected
-		}
-		try {
-			File exec2 = new File( executable.getPath() + "/../bin/sh" );
-			ExecuteResult result = instance.executeSystemCommand(exec2, new ArrayList(params) );
-			System.out.println( "RESULT: " + result );
-			fail();
-		} catch (Exception e) {
-			// expected
-		}
-		try {
-			params.add(";ls");
-			ExecuteResult result = instance.executeSystemCommand(executable, new ArrayList(params) );
-			System.out.println( "RESULT: " + result );
-		} catch (Exception e) {
-			fail();
-		}
-
-		try {
-			File cwd = new File(".");
-			File script = File.createTempFile("ESAPI-ExecutorTest", "sh", cwd);
-			script.deleteOnExit();
-			FileWriter output = new FileWriter(script);
-			try {
-				output.write("i=0\nwhile [ $i -lt 8192 ]\ndo\necho stdout data\necho stderr data >&2\ni=$((i+1))\ndone\n");
-			} finally {
-				output.close();
-			}
-			List deadlockParams = new ArrayList();
-			deadlockParams.add(script.getName());
-			ExecuteResult result = instance.executeSystemCommand(executable, deadlockParams, cwd, codec, true, false);
-			System.out.println( "RESULT: " + result.getExitValue() );
-			assertEquals(0, result.getExitValue());
-		} catch (Exception e) {
-			fail();
-		}
-	}
+     * Suite.
+     *
+     * @return the test
+     */
+    public static Test suite() {
+        TestSuite suite = new TestSuite(ExecutorTest.class);
+        return suite;
+    }
+
+    private void resetSingletonField() throws Exception {
+        //Wipe the singleton field here so we can force recreation.
+        Field singletonField = DefaultExecutor.class.getDeclaredField("singletonInstance");
+        singletonField.setAccessible(true);
+        //Object ref is ignored since field is static.
+        singletonField.set(new Object(), null);
+    }
+
+    public void testPlatformResoveWindows() throws Exception {
+        String origName = System.getProperty("os.name");
+
+        try {
+            //Wipe the singleton field here so we can force recreation.
+            resetSingletonField();
+
+            System.setProperty("os.name", "a name that includes the literal 'Windows'");
+            Executor ex = DefaultExecutor.getInstance();
+
+
+            Field codecField = DefaultExecutor.class.getDeclaredField("codec");
+            codecField.setAccessible(true);
+
+            Object instCodec = codecField.get(ex);
+
+            assertTrue(instCodec instanceof WindowsCodec);
+        } finally {
+            System.setProperty("os.name", origName);
+            resetSingletonField();
+        }
+    }
+
+    public void testPlatformResolveNx() throws Exception{
+        String origName = System.getProperty("os.name");
+
+        try {
+            //Wipe the singleton field here so we can force recreation.
+            resetSingletonField();
+
+            //Unmatched Platform is anything but the literal string "Windows" - In part or in whole.
+            System.setProperty("os.name", "unmatchedPlatform");
+            Executor ex = DefaultExecutor.getInstance();
+
+
+            Field codecField = DefaultExecutor.class.getDeclaredField("codec");
+            codecField.setAccessible(true);
+
+            Object instCodec = codecField.get(ex);
+
+            assertTrue(instCodec instanceof UnixCodec);
+        } finally {
+            System.setProperty("os.name", origName);
+            resetSingletonField();
+        }
+    }
+
+
+    /**
+     * Test of executeOSCommand method, of class org.owasp.esapi.Executor
+     *
+     * @throws Exception
+     *             the exception
+     */
+    public void testExecuteWindowsSystemCommand() throws Exception {
+        System.out.println("executeWindowsSystemCommand");
+
+        if ( System.getProperty("os.name").indexOf("Windows") == -1 ) {
+            System.out.println("testExecuteWindowsSystemCommand - on non-Windows platform, exiting");
+            return;    // Not windows, not going to execute this path
+        }
+        File tmpDir = new File(System.getProperty("java.io.tmpdir")).getCanonicalFile();
+        File sysRoot = new File(System.getenv("SystemRoot")).getCanonicalFile();
+        File sys32 = new File(sysRoot,"system32").getCanonicalFile();
+        File cmd = new File(sys32,"cmd.exe").getCanonicalFile();
+        ESAPI.override(
+            new Conf(
+                ESAPI.securityConfiguration(),
+                Collections.singletonList(cmd.getPath()),
+                tmpDir
+            )
+        );
+
+        Codec codec = new WindowsCodec();
+        System.out.println("executeSystemCommand");
+        Executor instance = ESAPI.executor();
+        List params = new ArrayList();
+        try {
+            params.add("/C");
+            params.add("dir");
+            ExecuteResult result = instance.executeSystemCommand(cmd, new ArrayList(params) );
+            System.out.println( "RESULT: " + result );
+            assertTrue(result.getOutput().length() > 0);
+        } catch (Exception e) {
+            e.printStackTrace();
+            fail();
+        }
+        try {
+            File exec2 = new File( cmd.getPath() + ";inject.exe" );
+            ExecuteResult result = instance.executeSystemCommand(exec2, new ArrayList(params) );
+            System.out.println( "RESULT: " + result );
+            fail();
+        } catch (Exception e) {
+            // expected
+        }
+        try {
+            File exec2 = new File( cmd.getPath() + "\\..\\cmd.exe" );
+            ExecuteResult result = instance.executeSystemCommand(exec2, new ArrayList(params) );
+            System.out.println( "RESULT: " + result );
+            fail();
+        } catch (Exception e) {
+            // expected
+        }
+        try {
+            File workdir = new File( "c:\\ridiculous" );
+            ExecuteResult result = instance.executeSystemCommand(cmd, new ArrayList(params), workdir, codec, false, false );
+            System.out.println( "RESULT: " + result );
+            fail();
+        } catch (Exception e) {
+            // expected
+        }
+        try {
+            params.add("&dir");
+            ExecuteResult result = instance.executeSystemCommand(cmd, new ArrayList(params) );
+            System.out.println( "RESULT: " + result );
+        } catch (Exception e) {
+            fail();
+        }
+
+        try {
+            params.set( params.size()-1, "c:\\autoexec.bat" );
+            ExecuteResult result = instance.executeSystemCommand(cmd, new ArrayList(params) );
+            System.out.println( "RESULT: " + result );
+        } catch (Exception e) {
+            fail();
+        }
+
+        try {
+            params.set( params.size()-1, "c:\\autoexec.bat c:\\config.sys" );
+            ExecuteResult result = instance.executeSystemCommand(cmd, new ArrayList(params) );
+            System.out.println( "RESULT: " + result );
+        } catch (Exception e) {
+            fail();
+        }
+    }
+
+    /**
+     * Test of executeOSCommand method, of class org.owasp.esapi.Executor
+     *
+     * @throws Exception
+     *             the exception
+     */
+    public void testExecuteUnixSystemCommand() throws Exception {
+        System.out.println("executeUnixSystemCommand");
+
+        if ( System.getProperty("os.name").indexOf("Windows") != -1 ) {
+            System.out.println("executeUnixSystemCommand - on Windows platform, exiting");
+            return;
+        }
+
+        // FIXME: need more test cases to use this codec
+        Codec codec = new UnixCodec();
+
+        // make sure we have what /bin/sh is pointing at in the allowed exes for the test
+        // and a usable working dir
+        File binSh = new File("/bin/sh").getCanonicalFile();
+        ESAPI.override(
+            new Conf(
+                ESAPI.securityConfiguration(),
+                Collections.singletonList(binSh.getPath()),
+                new File("/tmp")
+            )
+        );
+
+        Executor instance = ESAPI.executor();
+        File executable = binSh;
+        List params = new ArrayList();
+        try {
+            params.add("-c");
+            params.add("ls");
+            params.add("/");
+            ExecuteResult result = instance.executeSystemCommand(executable, new ArrayList(params) );
+            System.out.println( "RESULT: " + result );
+            assertTrue(result.getOutput().length() > 0);
+        } catch (Exception e) {
+            fail(e.getMessage());
+        }
+        try {
+            File exec2 = new File( executable.getPath() + ";./inject" );
+            ExecuteResult result = instance.executeSystemCommand(exec2, new ArrayList(params) );
+            System.out.println( "RESULT: " + result );
+            fail();
+        } catch (Exception e) {
+            // expected
+        }
+        try {
+            File exec2 = new File( executable.getPath() + "/../bin/sh" );
+            ExecuteResult result = instance.executeSystemCommand(exec2, new ArrayList(params) );
+            System.out.println( "RESULT: " + result );
+            fail();
+        } catch (Exception e) {
+            // expected
+        }
+        try {
+            params.add(";ls");
+            ExecuteResult result = instance.executeSystemCommand(executable, new ArrayList(params) );
+            System.out.println( "RESULT: " + result );
+        } catch (Exception e) {
+            fail();
+        }
+
+        try {
+            File cwd = new File(".");
+            File script = File.createTempFile("ESAPI-ExecutorTest", "sh", cwd);
+            script.deleteOnExit();
+            FileWriter output = new FileWriter(script);
+            try {
+                output.write("i=0\nwhile [ $i -lt 8192 ]\ndo\necho stdout data\necho stderr data >&2\ni=$((i+1))\ndone\n");
+            } finally {
+                output.close();
+            }
+            List deadlockParams = new ArrayList();
+            deadlockParams.add(script.getName());
+            ExecuteResult result = instance.executeSystemCommand(executable, deadlockParams, cwd, codec, true, false);
+            System.out.println( "RESULT: " + result.getExitValue() );
+            assertEquals(0, result.getExitValue());
+        } catch (Exception e) {
+            fail();
+        }
+    }
 
 }
diff --git a/src/test/java/org/owasp/esapi/reference/ExtensiveEncoderURITest.java b/src/test/java/org/owasp/esapi/reference/ExtensiveEncoderURITest.java
index 18d88c7..38e6103 100644
--- a/src/test/java/org/owasp/esapi/reference/ExtensiveEncoderURITest.java
+++ b/src/test/java/org/owasp/esapi/reference/ExtensiveEncoderURITest.java
@@ -21,39 +21,39 @@ import org.owasp.esapi.Validator;
 
 @RunWith(Parameterized.class)
 public class ExtensiveEncoderURITest {
-	static List<String> inputs = new ArrayList<>();
-	Validator v = ESAPI.validator();
-	String uri;
-	boolean expected;
-	
-	public ExtensiveEncoderURITest(String uri){
-		String[] values = uri.split(","); 
-		this.uri = values[0];
-		this.expected = Boolean.parseBoolean(values[1]);
-	}
-	
-	@Parameters
-	public static Collection<String> getMyUris() throws Exception{
-		URL url = ExtensiveEncoderURITest.class.getResource("/urisForTest.txt");
-
-		try( BufferedReader br = new BufferedReader(new InputStreamReader(url.openStream(), StandardCharsets.UTF_8)) ) {
-			inputs = readAllLines(br);
-		}
-		return inputs;
-	}
-
-	private static List<String> readAllLines(BufferedReader br) throws IOException {
-		List<String> lines = new ArrayList<>();
-		String line;
-		while ((line = br.readLine()) != null) {
-			lines.add(line);
-		}
-		return lines;
-	}
-
-	@Test
-	public void testUrlsFromFile() {
-		assertEquals(this.expected, v.isValidURI("URL", uri, false));
-	}
+    static List<String> inputs = new ArrayList<>();
+    Validator v = ESAPI.validator();
+    String uri;
+    boolean expected;
+
+    public ExtensiveEncoderURITest(String uri){
+        String[] values = uri.split(",");
+        this.uri = values[0];
+        this.expected = Boolean.parseBoolean(values[1]);
+    }
+
+    @Parameters
+    public static Collection<String> getMyUris() throws Exception{
+        URL url = ExtensiveEncoderURITest.class.getResource("/urisForTest.txt");
+
+        try( BufferedReader br = new BufferedReader(new InputStreamReader(url.openStream(), StandardCharsets.UTF_8)) ) {
+            inputs = readAllLines(br);
+        }
+        return inputs;
+    }
+
+    private static List<String> readAllLines(BufferedReader br) throws IOException {
+        List<String> lines = new ArrayList<>();
+        String line;
+        while ((line = br.readLine()) != null) {
+            lines.add(line);
+        }
+        return lines;
+    }
+
+    @Test
+    public void testUrlsFromFile() {
+        assertEquals(this.expected, v.isValidURI("URL", uri, false));
+    }
 
 }
diff --git a/src/test/java/org/owasp/esapi/reference/HTTPUtilitiesTest.java b/src/test/java/org/owasp/esapi/reference/HTTPUtilitiesTest.java
index aac1686..80a7010 100644
--- a/src/test/java/org/owasp/esapi/reference/HTTPUtilitiesTest.java
+++ b/src/test/java/org/owasp/esapi/reference/HTTPUtilitiesTest.java
@@ -1,15 +1,15 @@
 /**
  * OWASP Enterprise Security API (ESAPI)
- * 
+ *
  * This file is part of the Open Web Application Security Project (OWASP)
  * Enterprise Security API (ESAPI) project. For details, please see
  * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
  *
  * Copyright (c) 2007 - The OWASP Foundation
- * 
+ *
  * The ESAPI is published by OWASP under the BSD license. You should read and accept the
  * LICENSE before you use, modify, and/or redistribute this software.
- * 
+ *
  * @author Jeff Williams <a href="http://www.aspectsecurity.com">Aspect Security</a>
  * @created 2007
  */
@@ -56,299 +56,299 @@ import org.junit.Rule;
 import org.junit.rules.ExpectedException;
 /**
  * The Class HTTPUtilitiesTest.
- * 
+ *
  * @author Jeff Williams (jeff.williams@aspectsecurity.com)
  */
 public class HTTPUtilitiesTest extends TestCase
 {
-	private static final Class<HTTPUtilitiesTest> CLASS = HTTPUtilitiesTest.class;
-	private static final String CLASS_NAME = CLASS.getName();
-
-	/**
-	 * Suite.
-	 * 
-	 * @return the test
-	 */
-	public static Test suite() {
-		return new TestSuite(HTTPUtilitiesTest.class);
-	}
-
-	/**
-	 * Instantiates a new HTTP utilities test.
-	 * 
-	 * @param testName the test name
-	 */
-	public HTTPUtilitiesTest(String testName) {
-		super(testName);
-	}
-
-	/**
-	 * {@inheritDoc}
-	 * @throws Exception
-	 */
-	protected void setUp() throws Exception {
-		// none
-	}
-
-	/**
-	 * {@inheritDoc}
-	 * @throws Exception
-	 */
-	protected void tearDown() throws Exception {
-		// none
-	}
-
-	public void testCSRFToken() throws Exception {
-		System.out.println( "CSRFToken");
-		String username = ESAPI.randomizer().getRandomString(8, EncoderConstants.CHAR_ALPHANUMERICS);
-		User user = ESAPI.authenticator().createUser(username, "addCSRFToken", "addCSRFToken");
-		ESAPI.authenticator().setCurrentUser( user );
-		String token = ESAPI.httpUtilities().getCSRFToken();
-		assertEquals( 8, token.length() );
-		MockHttpServletRequest request = new MockHttpServletRequest();
-		try {
-			ESAPI.httpUtilities().verifyCSRFToken(request);
-			fail();
-		} catch( Exception e ) {
-			// expected
-		}
-		request.addParameter( DefaultHTTPUtilities.CSRF_TOKEN_NAME, token );
-		ESAPI.httpUtilities().verifyCSRFToken(request);
-	}
-
-	/**
-	 * Test of addCSRFToken method, of class org.owasp.esapi.HTTPUtilities.
-	 * @throws AuthenticationException 
-	 */
-	public void testAddCSRFToken() throws AuthenticationException {
-		Authenticator instance = ESAPI.authenticator();
-		String username = ESAPI.randomizer().getRandomString(8, EncoderConstants.CHAR_ALPHANUMERICS);
-		User user = instance.createUser(username, "addCSRFToken", "addCSRFToken");
-		instance.setCurrentUser( user );
-
-		System.out.println("addCSRFToken");
-		String csrf1=ESAPI.httpUtilities().addCSRFToken("/test1");
-		System.out.println( "CSRF1:" + csrf1);
-		assertTrue(csrf1.indexOf("?") > -1);
-
-		String csrf2=ESAPI.httpUtilities().addCSRFToken("/test1?one=two");
-		System.out.println( "CSRF1:" + csrf1);
-		assertTrue(csrf2.indexOf("&") > -1);
-	}
-
-
-	/**
-	 * Test of assertSecureRequest method, of class org.owasp.esapi.HTTPUtilities.
-	 */
-	public void testAssertSecureRequest() {
-		System.out.println("assertSecureRequest");
-		MockHttpServletRequest request = new MockHttpServletRequest();
-		try {
-			request.setRequestURL( "http://example.com");
-			ESAPI.httpUtilities().assertSecureRequest( request );
-			fail();
-		} catch( Exception e ) {
-			// pass
-		}
-		try {
-			request.setRequestURL( "ftp://example.com");
-			ESAPI.httpUtilities().assertSecureRequest( request );
-			fail();
-		} catch( Exception e ) {
-			// pass
-		}
-		try {
-			request.setRequestURL( "");
-			ESAPI.httpUtilities().assertSecureRequest( request );
-			fail();
-		} catch( Exception e ) {
-			// pass
-		}
-		try {
-			request.setRequestURL( null );
-			ESAPI.httpUtilities().assertSecureRequest( request );
-			fail();
-		} catch( Exception e ) {
-			// pass
-		}
-		try {
-			request.setRequestURL( "https://example.com");
-			ESAPI.httpUtilities().assertSecureRequest( request );
-			// pass
-		} catch( Exception e ) {
-			fail();
-		}
-	}
-
-
-	/**
-	 * Test of sendRedirect method, of class org.owasp.esapi.HTTPUtilities.
-	 * 
-	 * @throws EnterpriseSecurityException
-	 */
-	public void testChangeSessionIdentifier() throws EnterpriseSecurityException {
-		System.out.println("changeSessionIdentifier");
-		MockHttpServletRequest request = new MockHttpServletRequest();
-		MockHttpServletResponse response = new MockHttpServletResponse();
-		MockHttpSession session = (MockHttpSession) request.getSession();
-		ESAPI.httpUtilities().setCurrentHTTP(request, response);
-		session.setAttribute("one", "one");
-		session.setAttribute("two", "two");
-		session.setAttribute("three", "three");
-		String id1 = session.getId();
-		session = (MockHttpSession) ESAPI.httpUtilities().changeSessionIdentifier( request );
-		String id2 = session.getId();
-		assertTrue(!id1.equals(id2));
-		assertEquals("one", (String) session.getAttribute("one"));
-	}
-
-	/**
-	 * Test of formatHttpRequestForLog method, of class org.owasp.esapi.HTTPUtilities.
-	 * @throws IOException 
-	 */
-	public void testGetFileUploads() throws Exception {
-		File home = null;
-
-		try
-		{
-			home = FileTestUtils.createTmpDirectory(CLASS_NAME);
-			String content = "--ridiculous\r\nContent-Disposition: form-data; name=\"upload\"; filename=\"testupload.txt\"\r\nContent-Type: application/octet-stream\r\n\r\nThis is a test of the multipart broadcast system.\r\nThis is only a test.\r\nStop.\r\n\r\n--ridiculous\r\nContent-Disposition: form-data; name=\"submit\"\r\n\r\nSubmit Query\r\n--ridiculous--\r\nEpilogue";
-
-			MockHttpServletResponse response = new MockHttpServletResponse();    
-			MockHttpServletRequest request1 = new MockHttpServletRequest("/test", content.getBytes(response.getCharacterEncoding()));
-			ESAPI.httpUtilities().setCurrentHTTP(request1, response);
-			try {
-				ESAPI.httpUtilities().getFileUploads(request1, home);
-				fail();
-			} catch( ValidationException e ) {
-				// expected
-			}
-
-			MockHttpServletRequest request2 = new MockHttpServletRequest("/test", content.getBytes(response.getCharacterEncoding()));
-			request2.setContentType( "multipart/form-data; boundary=ridiculous");
-			ESAPI.httpUtilities().setCurrentHTTP(request2, response);
-			List<File> response2 = new ArrayList<>();
-			try {
-				response2 = ESAPI.httpUtilities().getFileUploads(request2, home);
-				assertTrue( response2.size() > 0 );
-			} finally {
-				response2.forEach(file -> file.delete());
-			}
-
-			MockHttpServletRequest request4 = new MockHttpServletRequest("/test", content.getBytes(response.getCharacterEncoding()));
-			request4.setContentType( "multipart/form-data; boundary=ridiculous");
-			ESAPI.httpUtilities().setCurrentHTTP(request4, response);
-			System.err.println("UPLOAD DIRECTORY: " + ESAPI.securityConfiguration().getUploadDirectory());
-			List<File> response4 = new ArrayList<>();
-			try {
-			    response4 = ESAPI.httpUtilities().getFileUploads(request4, home);
-			    assertTrue( response4.size() > 0 );
-			} finally {
-			    response4.forEach(file -> file.delete());
-			}
-
-			MockHttpServletRequest request3 = new MockHttpServletRequest("/test", content.replaceAll("txt", "ridiculous").getBytes(response.getCharacterEncoding()));
-			request3.setContentType( "multipart/form-data; boundary=ridiculous");
-			ESAPI.httpUtilities().setCurrentHTTP(request3, response);
-			try {
-				ESAPI.httpUtilities().getFileUploads(request3, home);
-				fail();
-			} catch (ValidationException e) {
-				// expected
-			}
-		}
-		finally
-		{
-			FileTestUtils.deleteRecursively(home);
-		}
-
-	}
-
-
-
-	/**
-	 * Test of killAllCookies method, of class org.owasp.esapi.HTTPUtilities.
-	 */
-	public void testKillAllCookies() {
-		System.out.println("killAllCookies");
-		MockHttpServletRequest request = new MockHttpServletRequest();
-		MockHttpServletResponse response = new MockHttpServletResponse();
-		assertTrue(response.getCookies().isEmpty());
-		ArrayList<Cookie> list = new ArrayList<Cookie>();
-		list.add(new Cookie("test1", "1"));
-		list.add(new Cookie("test2", "2"));
-		list.add(new Cookie("test3", "3"));
-		request.setCookies(list);
-		ESAPI.httpUtilities().killAllCookies(request, response);
-		assertTrue(response.getCookies().size() == 3);
-	}
-
-	/**
-	 * Test of killCookie method, of class org.owasp.esapi.HTTPUtilities.
-	 */
-	public void testKillCookie() {
-		System.out.println("killCookie");
-		MockHttpServletRequest request = new MockHttpServletRequest();
-		MockHttpServletResponse response = new MockHttpServletResponse();
-		ESAPI.httpUtilities().setCurrentHTTP(request, response);
-		assertTrue(response.getCookies().isEmpty());
-		ArrayList<Cookie> list = new ArrayList<Cookie>();
-		list.add(new Cookie("test1", "1"));
-		list.add(new Cookie("test2", "2"));
-		list.add(new Cookie("test3", "3"));
-		request.setCookies(list);
-		ESAPI.httpUtilities().killCookie( request, response, "test1" );
-		assertTrue(response.getCookies().size() == 1);
-	}
-
-	/**
-	 * Test of sendRedirect method, of class org.owasp.esapi.HTTPUtilities.
-	 * 
-	 * @throws ValidationException the validation exception
-	 * @throws IOException Signals that an I/O exception has occurred.
-	 */
-	public void testSendSafeRedirect() throws Exception {
-		System.out.println("sendSafeRedirect");
-		MockHttpServletResponse response = new MockHttpServletResponse();
-		try {
-			ESAPI.httpUtilities().sendRedirect(response, "/test1/abcdefg");
-			ESAPI.httpUtilities().sendRedirect(response,"/test2/1234567");
-		} catch (AccessControlException e) {
-			fail();
-		}
-		try {
-			ESAPI.httpUtilities().sendRedirect(response,"http://www.aspectsecurity.com");
-			fail();
-		} catch (AccessControlException e) {
-			// expected
-		}
-		try {
-			ESAPI.httpUtilities().sendRedirect(response,"/ridiculous");
-			fail();
-		} catch (AccessControlException e) {
-			// expected
-		}
-	}
+    private static final Class<HTTPUtilitiesTest> CLASS = HTTPUtilitiesTest.class;
+    private static final String CLASS_NAME = CLASS.getName();
+
+    /**
+     * Suite.
+     *
+     * @return the test
+     */
+    public static Test suite() {
+        return new TestSuite(HTTPUtilitiesTest.class);
+    }
+
+    /**
+     * Instantiates a new HTTP utilities test.
+     *
+     * @param testName the test name
+     */
+    public HTTPUtilitiesTest(String testName) {
+        super(testName);
+    }
+
+    /**
+     * {@inheritDoc}
+     * @throws Exception
+     */
+    protected void setUp() throws Exception {
+        // none
+    }
+
+    /**
+     * {@inheritDoc}
+     * @throws Exception
+     */
+    protected void tearDown() throws Exception {
+        // none
+    }
+
+    public void testCSRFToken() throws Exception {
+        System.out.println( "CSRFToken");
+        String username = ESAPI.randomizer().getRandomString(8, EncoderConstants.CHAR_ALPHANUMERICS);
+        User user = ESAPI.authenticator().createUser(username, "addCSRFToken", "addCSRFToken");
+        ESAPI.authenticator().setCurrentUser( user );
+        String token = ESAPI.httpUtilities().getCSRFToken();
+        assertEquals( 8, token.length() );
+        MockHttpServletRequest request = new MockHttpServletRequest();
+        try {
+            ESAPI.httpUtilities().verifyCSRFToken(request);
+            fail();
+        } catch( Exception e ) {
+            // expected
+        }
+        request.addParameter( DefaultHTTPUtilities.CSRF_TOKEN_NAME, token );
+        ESAPI.httpUtilities().verifyCSRFToken(request);
+    }
+
+    /**
+     * Test of addCSRFToken method, of class org.owasp.esapi.HTTPUtilities.
+     * @throws AuthenticationException
+     */
+    public void testAddCSRFToken() throws AuthenticationException {
+        Authenticator instance = ESAPI.authenticator();
+        String username = ESAPI.randomizer().getRandomString(8, EncoderConstants.CHAR_ALPHANUMERICS);
+        User user = instance.createUser(username, "addCSRFToken", "addCSRFToken");
+        instance.setCurrentUser( user );
+
+        System.out.println("addCSRFToken");
+        String csrf1=ESAPI.httpUtilities().addCSRFToken("/test1");
+        System.out.println( "CSRF1:" + csrf1);
+        assertTrue(csrf1.indexOf("?") > -1);
+
+        String csrf2=ESAPI.httpUtilities().addCSRFToken("/test1?one=two");
+        System.out.println( "CSRF1:" + csrf1);
+        assertTrue(csrf2.indexOf("&") > -1);
+    }
+
+
+    /**
+     * Test of assertSecureRequest method, of class org.owasp.esapi.HTTPUtilities.
+     */
+    public void testAssertSecureRequest() {
+        System.out.println("assertSecureRequest");
+        MockHttpServletRequest request = new MockHttpServletRequest();
+        try {
+            request.setRequestURL( "http://example.com");
+            ESAPI.httpUtilities().assertSecureRequest( request );
+            fail();
+        } catch( Exception e ) {
+            // pass
+        }
+        try {
+            request.setRequestURL( "ftp://example.com");
+            ESAPI.httpUtilities().assertSecureRequest( request );
+            fail();
+        } catch( Exception e ) {
+            // pass
+        }
+        try {
+            request.setRequestURL( "");
+            ESAPI.httpUtilities().assertSecureRequest( request );
+            fail();
+        } catch( Exception e ) {
+            // pass
+        }
+        try {
+            request.setRequestURL( null );
+            ESAPI.httpUtilities().assertSecureRequest( request );
+            fail();
+        } catch( Exception e ) {
+            // pass
+        }
+        try {
+            request.setRequestURL( "https://example.com");
+            ESAPI.httpUtilities().assertSecureRequest( request );
+            // pass
+        } catch( Exception e ) {
+            fail();
+        }
+    }
+
+
+    /**
+     * Test of sendRedirect method, of class org.owasp.esapi.HTTPUtilities.
+     *
+     * @throws EnterpriseSecurityException
+     */
+    public void testChangeSessionIdentifier() throws EnterpriseSecurityException {
+        System.out.println("changeSessionIdentifier");
+        MockHttpServletRequest request = new MockHttpServletRequest();
+        MockHttpServletResponse response = new MockHttpServletResponse();
+        MockHttpSession session = (MockHttpSession) request.getSession();
+        ESAPI.httpUtilities().setCurrentHTTP(request, response);
+        session.setAttribute("one", "one");
+        session.setAttribute("two", "two");
+        session.setAttribute("three", "three");
+        String id1 = session.getId();
+        session = (MockHttpSession) ESAPI.httpUtilities().changeSessionIdentifier( request );
+        String id2 = session.getId();
+        assertTrue(!id1.equals(id2));
+        assertEquals("one", (String) session.getAttribute("one"));
+    }
+
+    /**
+     * Test of formatHttpRequestForLog method, of class org.owasp.esapi.HTTPUtilities.
+     * @throws IOException
+     */
+    public void testGetFileUploads() throws Exception {
+        File home = null;
+
+        try
+        {
+            home = FileTestUtils.createTmpDirectory(CLASS_NAME);
+            String content = "--ridiculous\r\nContent-Disposition: form-data; name=\"upload\"; filename=\"testupload.txt\"\r\nContent-Type: application/octet-stream\r\n\r\nThis is a test of the multipart broadcast system.\r\nThis is only a test.\r\nStop.\r\n\r\n--ridiculous\r\nContent-Disposition: form-data; name=\"submit\"\r\n\r\nSubmit Query\r\n--ridiculous--\r\nEpilogue";
+
+            MockHttpServletResponse response = new MockHttpServletResponse();
+            MockHttpServletRequest request1 = new MockHttpServletRequest("/test", content.getBytes(response.getCharacterEncoding()));
+            ESAPI.httpUtilities().setCurrentHTTP(request1, response);
+            try {
+                ESAPI.httpUtilities().getFileUploads(request1, home);
+                fail();
+            } catch( ValidationException e ) {
+                // expected
+            }
+
+            MockHttpServletRequest request2 = new MockHttpServletRequest("/test", content.getBytes(response.getCharacterEncoding()));
+            request2.setContentType( "multipart/form-data; boundary=ridiculous");
+            ESAPI.httpUtilities().setCurrentHTTP(request2, response);
+            List<File> response2 = new ArrayList<>();
+            try {
+                response2 = ESAPI.httpUtilities().getFileUploads(request2, home);
+                assertTrue( response2.size() > 0 );
+            } finally {
+                response2.forEach(file -> file.delete());
+            }
+
+            MockHttpServletRequest request4 = new MockHttpServletRequest("/test", content.getBytes(response.getCharacterEncoding()));
+            request4.setContentType( "multipart/form-data; boundary=ridiculous");
+            ESAPI.httpUtilities().setCurrentHTTP(request4, response);
+            System.err.println("UPLOAD DIRECTORY: " + ESAPI.securityConfiguration().getUploadDirectory());
+            List<File> response4 = new ArrayList<>();
+            try {
+                response4 = ESAPI.httpUtilities().getFileUploads(request4, home);
+                assertTrue( response4.size() > 0 );
+            } finally {
+                response4.forEach(file -> file.delete());
+            }
+
+            MockHttpServletRequest request3 = new MockHttpServletRequest("/test", content.replaceAll("txt", "ridiculous").getBytes(response.getCharacterEncoding()));
+            request3.setContentType( "multipart/form-data; boundary=ridiculous");
+            ESAPI.httpUtilities().setCurrentHTTP(request3, response);
+            try {
+                ESAPI.httpUtilities().getFileUploads(request3, home);
+                fail();
+            } catch (ValidationException e) {
+                // expected
+            }
+        }
+        finally
+        {
+            FileTestUtils.deleteRecursively(home);
+        }
+
+    }
+
+
+
+    /**
+     * Test of killAllCookies method, of class org.owasp.esapi.HTTPUtilities.
+     */
+    public void testKillAllCookies() {
+        System.out.println("killAllCookies");
+        MockHttpServletRequest request = new MockHttpServletRequest();
+        MockHttpServletResponse response = new MockHttpServletResponse();
+        assertTrue(response.getCookies().isEmpty());
+        ArrayList<Cookie> list = new ArrayList<Cookie>();
+        list.add(new Cookie("test1", "1"));
+        list.add(new Cookie("test2", "2"));
+        list.add(new Cookie("test3", "3"));
+        request.setCookies(list);
+        ESAPI.httpUtilities().killAllCookies(request, response);
+        assertTrue(response.getCookies().size() == 3);
+    }
+
+    /**
+     * Test of killCookie method, of class org.owasp.esapi.HTTPUtilities.
+     */
+    public void testKillCookie() {
+        System.out.println("killCookie");
+        MockHttpServletRequest request = new MockHttpServletRequest();
+        MockHttpServletResponse response = new MockHttpServletResponse();
+        ESAPI.httpUtilities().setCurrentHTTP(request, response);
+        assertTrue(response.getCookies().isEmpty());
+        ArrayList<Cookie> list = new ArrayList<Cookie>();
+        list.add(new Cookie("test1", "1"));
+        list.add(new Cookie("test2", "2"));
+        list.add(new Cookie("test3", "3"));
+        request.setCookies(list);
+        ESAPI.httpUtilities().killCookie( request, response, "test1" );
+        assertTrue(response.getCookies().size() == 1);
+    }
+
+    /**
+     * Test of sendRedirect method, of class org.owasp.esapi.HTTPUtilities.
+     *
+     * @throws ValidationException the validation exception
+     * @throws IOException Signals that an I/O exception has occurred.
+     */
+    public void testSendSafeRedirect() throws Exception {
+        System.out.println("sendSafeRedirect");
+        MockHttpServletResponse response = new MockHttpServletResponse();
+        try {
+            ESAPI.httpUtilities().sendRedirect(response, "/test1/abcdefg");
+            ESAPI.httpUtilities().sendRedirect(response,"/test2/1234567");
+        } catch (AccessControlException e) {
+            fail();
+        }
+        try {
+            ESAPI.httpUtilities().sendRedirect(response,"http://www.aspectsecurity.com");
+            fail();
+        } catch (AccessControlException e) {
+            // expected
+        }
+        try {
+            ESAPI.httpUtilities().sendRedirect(response,"/ridiculous");
+            fail();
+        } catch (AccessControlException e) {
+            // expected
+        }
+    }
 
         @Rule
         public ExpectedException thrown = ExpectedException.none();
-        
-	/**
-	 * Test of setCookie method, of class org.owasp.esapi.HTTPUtilities.
-	 */
-	public void testSetCookie() {
-		System.out.println("setCookie");
-		HTTPUtilities instance = ESAPI.httpUtilities(); 
-		MockHttpServletResponse response = new MockHttpServletResponse();
-		assertTrue(response.getHeaderNames().isEmpty());
-
-		instance.addCookie( response, new Cookie( "test1", "test1" ) );
-		assertTrue(response.getHeaderNames().size() == 1);
-
-		instance.addCookie( response, new Cookie( "test2", "test2" ) );
-		assertTrue(response.getHeaderNames().size() == 2);
-
-		// test illegal name - this case is now handled by the servlet API
+
+    /**
+     * Test of setCookie method, of class org.owasp.esapi.HTTPUtilities.
+     */
+    public void testSetCookie() {
+        System.out.println("setCookie");
+        HTTPUtilities instance = ESAPI.httpUtilities();
+        MockHttpServletResponse response = new MockHttpServletResponse();
+        assertTrue(response.getHeaderNames().isEmpty());
+
+        instance.addCookie( response, new Cookie( "test1", "test1" ) );
+        assertTrue(response.getHeaderNames().size() == 1);
+
+        instance.addCookie( response, new Cookie( "test2", "test2" ) );
+        assertTrue(response.getHeaderNames().size() == 2);
+
+        // test illegal name - this case is now handled by the servlet API
                 try {
                     instance.addCookie( response, new Cookie( "tes<t3", "test3" ) );
                     fail("Expected IllegalArgumentException");
@@ -356,226 +356,226 @@ public class HTTPUtilitiesTest extends TestCase
                     assertThat(iae.getMessage(), is("Cookie name \"tes<t3\" is a reserved token"));
                 }
 
-		// test illegal value
-		instance.addCookie( response, new Cookie( "test3", "tes<t3" ) );
-		assertTrue(response.getHeaderNames().size() == 2);
-	}
-	
-	/**
-	 * Test of setCookie method, of class org.owasp.esapi.HTTPUtilities.
-	 * Validation failures should prevent cookies being added.  
-	 */
-	public void testSetCookieExceedingMaxValueAndName() {
-		HTTPUtilities instance = ESAPI.httpUtilities(); 
-		MockHttpServletResponse response = new MockHttpServletResponse();
-		assertTrue(response.getHeaderNames().isEmpty());
-		//request.addParameter(TestUtils.generateStringOfLength(32), "pass");
-		instance.addCookie( response, new Cookie( TestUtils.generateStringOfLength(32), "pass" ) );
-		assertTrue(response.getHeaderNames().size() == 1);
-
-		instance.addCookie( response, new Cookie( "pass", TestUtils.generateStringOfLength(32) ) );
-		assertTrue(response.getHeaderNames().size() == 2);
-		instance.addCookie( response, new Cookie( TestUtils.generateStringOfLength(5000), "fail" ) );
-		assertTrue(response.getHeaderNames().size() == 2);
-		instance.addCookie( response, new Cookie( "fail", TestUtils.generateStringOfLength(5001) ) );
-		assertTrue(response.getHeaderNames().size() == 2);
-	}
-
-
-	/**
-	 *
-	 * @throws java.lang.Exception
-	 */
-	public void testGetStateFromEncryptedCookie() throws Exception {
-		System.out.println("getStateFromEncryptedCookie");
-		MockHttpServletRequest request = new MockHttpServletRequest();
-		MockHttpServletResponse response = new MockHttpServletResponse();
-
-		// test null cookie array
-		Map<String, String> empty = ESAPI.httpUtilities().decryptStateFromCookie(request);
-		assertTrue( empty.isEmpty() );
-
-		HashMap<String, String> map = new HashMap<String, String>();
-		map.put( "one", "aspect" );
-		map.put( "two", "ridiculous" );
-		map.put( "test_hard", "&(@#*!^|;,." );
-		try {
-			ESAPI.httpUtilities().encryptStateInCookie(response, map);
-			String value = response.getHeader( "Set-Cookie" );
-			String encrypted = value.substring(value.indexOf("=")+1, value.indexOf(";"));
-			request.setCookie( DefaultHTTPUtilities.ESAPI_STATE, encrypted );
-			Map<String, String> state = ESAPI.httpUtilities().decryptStateFromCookie(request);
-			Iterator<?> i = map.entrySet().iterator();
-			while ( i.hasNext() ) {
-				Map.Entry<?, ?> entry = (Map.Entry<?, ?>)i.next();
-				String origname = (String)entry.getKey();
-				String origvalue = (String)entry.getValue();
-				if( !state.get( origname ).equals( origvalue ) ) {
-					fail();
-				}
-			}
-		} catch( EncryptionException e ) {
-			fail();
-		}
-	}
-
-	/**
-	 *
-	 */
-	public void testSaveStateInEncryptedCookie() {
-		System.out.println("saveStateInEncryptedCookie");
-		MockHttpServletRequest request = new MockHttpServletRequest();
-		MockHttpServletResponse response = new MockHttpServletResponse();
-		ESAPI.httpUtilities().setCurrentHTTP(request, response);
-		HashMap<String, String> map = new HashMap<String, String>();
-		map.put( "one", "aspect" );
-		map.put( "two", "ridiculous" );
-		map.put( "test_hard", "&(@#*!^|;,." );
-		try {
-			ESAPI.httpUtilities().encryptStateInCookie(response,map);
-			String value = response.getHeader( "Set-Cookie" );
-			String encrypted = value.substring(value.indexOf("=")+1, value.indexOf(";"));
-			byte[] serializedCiphertext = Hex.decode(encrypted);
-	        CipherText restoredCipherText =
-	            CipherText.fromPortableSerializedBytes(serializedCiphertext);
-	        ESAPI.encryptor().decrypt(restoredCipherText);
-		} catch( EncryptionException e ) {
-			fail();
-		}
-	}
-
-
-	/**
-	 *
-	 */
-	public void testSaveTooLongStateInEncryptedCookieException() {
-		System.out.println("saveTooLongStateInEncryptedCookie");
-
-		MockHttpServletRequest request = new MockHttpServletRequest();
-		MockHttpServletResponse response = new MockHttpServletResponse();
-		ESAPI.httpUtilities().setCurrentHTTP(request, response);
-
-		String foo = ESAPI.randomizer().getRandomString(4096, EncoderConstants.CHAR_ALPHANUMERICS);
-
-		HashMap<String, String> map = new HashMap<String, String>();
-		map.put("long", foo);
-		try {
-			ESAPI.httpUtilities().encryptStateInCookie(response, map);
-			fail("Should have thrown an exception");
-		}
-		catch (EncryptionException expected) {
-			//expected
-		}    	
-	}
-
-	/**
-	 * Test set no cache headers.
-	 */
-	public void testSetNoCacheHeaders() {
-		System.out.println("setNoCacheHeaders");
-		MockHttpServletRequest request = new MockHttpServletRequest();
-		MockHttpServletResponse response = new MockHttpServletResponse();
-		ESAPI.httpUtilities().setCurrentHTTP(request, response);
-		assertTrue(response.getHeaderNames().isEmpty());
-		response.addHeader("test1", "1");
-		response.addHeader("test2", "2");
-		response.addHeader("test3", "3");
-		assertFalse(response.getHeaderNames().isEmpty());
-		ESAPI.httpUtilities().setNoCacheHeaders( response );
-		assertTrue(response.containsHeader("Cache-Control"));
-		assertTrue(response.containsHeader("Expires"));
-	}
-
-	/**
-	 *
-	 * @throws org.owasp.esapi.errors.AuthenticationException
-	 */
-	@SuppressWarnings("deprecation")
-	public void testDeprecatedSetRememberToken() throws AuthenticationException {
-		System.out.println("setRememberToken");
-		Authenticator instance = ESAPI.authenticator();
-		String accountName=ESAPI.randomizer().getRandomString(8, EncoderConstants.CHAR_ALPHANUMERICS);
-		String password = instance.generateStrongPassword();
-		User user = instance.createUser(accountName, password, password);
-		user.enable();
-		MockHttpServletRequest request = new MockHttpServletRequest();
-		request.addParameter("username", accountName);
-		request.addParameter("password", password);
-		MockHttpServletResponse response = new MockHttpServletResponse();
-		ESAPI.httpUtilities().setCurrentHTTP(request, response);
-		instance.login( request, response);
-
-		int maxAge = ( 60 * 60 * 24 * 14 );
-		ESAPI.httpUtilities().setRememberToken( request, response, password, maxAge, "domain", "/" );
-		// Can't test this because we're using safeSetCookie, which sets a header, not a real cookie!
-		// String value = response.getCookie( Authenticator.REMEMBER_TOKEN_COOKIE_NAME ).getValue();
-		// assertEquals( user.getRememberToken(), value );
-	}
-	
-	/**
-	 *
-	 * @throws org.owasp.esapi.errors.AuthenticationException
-	 */
-	public void testSetRememberToken() throws Exception {
-		//System.out.println("setRememberToken");
-		Authenticator instance = ESAPI.authenticator();
-		String accountName=ESAPI.randomizer().getRandomString(8, EncoderConstants.CHAR_ALPHANUMERICS);
-		String password = instance.generateStrongPassword();
-		User user = instance.createUser(accountName, password, password);
-		user.enable();
-		MockHttpServletRequest request = new MockHttpServletRequest();
-		request.addParameter("username", accountName);
-		request.addParameter("password", password);
-		HttpServletResponse response = new MockHttpServletResponse();
-		ESAPI.httpUtilities().setCurrentHTTP(request, response);
-		instance.login( request, response);
-
-		int maxAge = ( 60 * 60 * 24 * 14 );
-
-		ESAPI.httpUtilities().setRememberToken( request, response, maxAge, "domain", "/" );
-		
-		Field field = response.getClass().getDeclaredField("cookies");
-		field.setAccessible(true);
-		@SuppressWarnings("unchecked")
-		List<Cookie> cookies = (List<Cookie>) field.get(response);
-		Cookie cookie = null;
-		for(Cookie c: cookies){
-			if(c.getName().equals(HTTPUtilities.REMEMBER_TOKEN_COOKIE_NAME)){
-				cookie = c; 
-				break;
-			}
-		}
-		assertEquals(HTTPUtilities.REMEMBER_TOKEN_COOKIE_NAME, cookie.getName());
-	}
-
-	public void testGetSessionAttribute() throws Exception {
-		HttpServletRequest request = new MockHttpServletRequest();
-		HttpSession session = request.getSession();
-		session.setAttribute("testAttribute", 43f);
-
-		try {
-			// Deleting the unused assignment of the results to test1 causes the expected ClassCastException to not occur. So don't delete it!
-			@SuppressWarnings("unused")
-			Integer test1 = ESAPI.httpUtilities().getSessionAttribute( session, "testAttribute" );
-			fail();
-		} catch ( ClassCastException cce ) {}
-
-		Float test2 = ESAPI.httpUtilities().getSessionAttribute( session, "testAttribute" );
-		assertEquals( test2, 43f );
-	}
-
-	public void testGetRequestAttribute() throws Exception {
-		HttpServletRequest request = new MockHttpServletRequest();
-		request.setAttribute( "testAttribute", 43f );
-		try {
-			// Deleting the unused assignment of the results to test1 causes the expected ClassCastException to not occur. So don't delete it!
-			@SuppressWarnings("unused")
-			Integer test1 = ESAPI.httpUtilities().getRequestAttribute( request, "testAttribute" );
-			fail();
-		} catch ( ClassCastException cce ) {}
-
-		Float test2 = ESAPI.httpUtilities().getRequestAttribute( request, "testAttribute" );
-		assertEquals( test2, 43f );
-	}
+        // test illegal value
+        instance.addCookie( response, new Cookie( "test3", "tes<t3" ) );
+        assertTrue(response.getHeaderNames().size() == 2);
+    }
+
+    /**
+     * Test of setCookie method, of class org.owasp.esapi.HTTPUtilities.
+     * Validation failures should prevent cookies being added.
+     */
+    public void testSetCookieExceedingMaxValueAndName() {
+        HTTPUtilities instance = ESAPI.httpUtilities();
+        MockHttpServletResponse response = new MockHttpServletResponse();
+        assertTrue(response.getHeaderNames().isEmpty());
+        //request.addParameter(TestUtils.generateStringOfLength(32), "pass");
+        instance.addCookie( response, new Cookie( TestUtils.generateStringOfLength(32), "pass" ) );
+        assertTrue(response.getHeaderNames().size() == 1);
+
+        instance.addCookie( response, new Cookie( "pass", TestUtils.generateStringOfLength(32) ) );
+        assertTrue(response.getHeaderNames().size() == 2);
+        instance.addCookie( response, new Cookie( TestUtils.generateStringOfLength(5000), "fail" ) );
+        assertTrue(response.getHeaderNames().size() == 2);
+        instance.addCookie( response, new Cookie( "fail", TestUtils.generateStringOfLength(5001) ) );
+        assertTrue(response.getHeaderNames().size() == 2);
+    }
+
+
+    /**
+     *
+     * @throws java.lang.Exception
+     */
+    public void testGetStateFromEncryptedCookie() throws Exception {
+        System.out.println("getStateFromEncryptedCookie");
+        MockHttpServletRequest request = new MockHttpServletRequest();
+        MockHttpServletResponse response = new MockHttpServletResponse();
+
+        // test null cookie array
+        Map<String, String> empty = ESAPI.httpUtilities().decryptStateFromCookie(request);
+        assertTrue( empty.isEmpty() );
+
+        HashMap<String, String> map = new HashMap<String, String>();
+        map.put( "one", "aspect" );
+        map.put( "two", "ridiculous" );
+        map.put( "test_hard", "&(@#*!^|;,." );
+        try {
+            ESAPI.httpUtilities().encryptStateInCookie(response, map);
+            String value = response.getHeader( "Set-Cookie" );
+            String encrypted = value.substring(value.indexOf("=")+1, value.indexOf(";"));
+            request.setCookie( DefaultHTTPUtilities.ESAPI_STATE, encrypted );
+            Map<String, String> state = ESAPI.httpUtilities().decryptStateFromCookie(request);
+            Iterator<?> i = map.entrySet().iterator();
+            while ( i.hasNext() ) {
+                Map.Entry<?, ?> entry = (Map.Entry<?, ?>)i.next();
+                String origname = (String)entry.getKey();
+                String origvalue = (String)entry.getValue();
+                if( !state.get( origname ).equals( origvalue ) ) {
+                    fail();
+                }
+            }
+        } catch( EncryptionException e ) {
+            fail();
+        }
+    }
+
+    /**
+     *
+     */
+    public void testSaveStateInEncryptedCookie() {
+        System.out.println("saveStateInEncryptedCookie");
+        MockHttpServletRequest request = new MockHttpServletRequest();
+        MockHttpServletResponse response = new MockHttpServletResponse();
+        ESAPI.httpUtilities().setCurrentHTTP(request, response);
+        HashMap<String, String> map = new HashMap<String, String>();
+        map.put( "one", "aspect" );
+        map.put( "two", "ridiculous" );
+        map.put( "test_hard", "&(@#*!^|;,." );
+        try {
+            ESAPI.httpUtilities().encryptStateInCookie(response,map);
+            String value = response.getHeader( "Set-Cookie" );
+            String encrypted = value.substring(value.indexOf("=")+1, value.indexOf(";"));
+            byte[] serializedCiphertext = Hex.decode(encrypted);
+            CipherText restoredCipherText =
+                CipherText.fromPortableSerializedBytes(serializedCiphertext);
+            ESAPI.encryptor().decrypt(restoredCipherText);
+        } catch( EncryptionException e ) {
+            fail();
+        }
+    }
+
+
+    /**
+     *
+     */
+    public void testSaveTooLongStateInEncryptedCookieException() {
+        System.out.println("saveTooLongStateInEncryptedCookie");
+
+        MockHttpServletRequest request = new MockHttpServletRequest();
+        MockHttpServletResponse response = new MockHttpServletResponse();
+        ESAPI.httpUtilities().setCurrentHTTP(request, response);
+
+        String foo = ESAPI.randomizer().getRandomString(4096, EncoderConstants.CHAR_ALPHANUMERICS);
+
+        HashMap<String, String> map = new HashMap<String, String>();
+        map.put("long", foo);
+        try {
+            ESAPI.httpUtilities().encryptStateInCookie(response, map);
+            fail("Should have thrown an exception");
+        }
+        catch (EncryptionException expected) {
+            //expected
+        }
+    }
+
+    /**
+     * Test set no cache headers.
+     */
+    public void testSetNoCacheHeaders() {
+        System.out.println("setNoCacheHeaders");
+        MockHttpServletRequest request = new MockHttpServletRequest();
+        MockHttpServletResponse response = new MockHttpServletResponse();
+        ESAPI.httpUtilities().setCurrentHTTP(request, response);
+        assertTrue(response.getHeaderNames().isEmpty());
+        response.addHeader("test1", "1");
+        response.addHeader("test2", "2");
+        response.addHeader("test3", "3");
+        assertFalse(response.getHeaderNames().isEmpty());
+        ESAPI.httpUtilities().setNoCacheHeaders( response );
+        assertTrue(response.containsHeader("Cache-Control"));
+        assertTrue(response.containsHeader("Expires"));
+    }
+
+    /**
+     *
+     * @throws org.owasp.esapi.errors.AuthenticationException
+     */
+    @SuppressWarnings("deprecation")
+    public void testDeprecatedSetRememberToken() throws AuthenticationException {
+        System.out.println("setRememberToken");
+        Authenticator instance = ESAPI.authenticator();
+        String accountName=ESAPI.randomizer().getRandomString(8, EncoderConstants.CHAR_ALPHANUMERICS);
+        String password = instance.generateStrongPassword();
+        User user = instance.createUser(accountName, password, password);
+        user.enable();
+        MockHttpServletRequest request = new MockHttpServletRequest();
+        request.addParameter("username", accountName);
+        request.addParameter("password", password);
+        MockHttpServletResponse response = new MockHttpServletResponse();
+        ESAPI.httpUtilities().setCurrentHTTP(request, response);
+        instance.login( request, response);
+
+        int maxAge = ( 60 * 60 * 24 * 14 );
+        ESAPI.httpUtilities().setRememberToken( request, response, password, maxAge, "domain", "/" );
+        // Can't test this because we're using safeSetCookie, which sets a header, not a real cookie!
+        // String value = response.getCookie( Authenticator.REMEMBER_TOKEN_COOKIE_NAME ).getValue();
+        // assertEquals( user.getRememberToken(), value );
+    }
+
+    /**
+     *
+     * @throws org.owasp.esapi.errors.AuthenticationException
+     */
+    public void testSetRememberToken() throws Exception {
+        //System.out.println("setRememberToken");
+        Authenticator instance = ESAPI.authenticator();
+        String accountName=ESAPI.randomizer().getRandomString(8, EncoderConstants.CHAR_ALPHANUMERICS);
+        String password = instance.generateStrongPassword();
+        User user = instance.createUser(accountName, password, password);
+        user.enable();
+        MockHttpServletRequest request = new MockHttpServletRequest();
+        request.addParameter("username", accountName);
+        request.addParameter("password", password);
+        HttpServletResponse response = new MockHttpServletResponse();
+        ESAPI.httpUtilities().setCurrentHTTP(request, response);
+        instance.login( request, response);
+
+        int maxAge = ( 60 * 60 * 24 * 14 );
+
+        ESAPI.httpUtilities().setRememberToken( request, response, maxAge, "domain", "/" );
+
+        Field field = response.getClass().getDeclaredField("cookies");
+        field.setAccessible(true);
+        @SuppressWarnings("unchecked")
+        List<Cookie> cookies = (List<Cookie>) field.get(response);
+        Cookie cookie = null;
+        for(Cookie c: cookies){
+            if(c.getName().equals(HTTPUtilities.REMEMBER_TOKEN_COOKIE_NAME)){
+                cookie = c;
+                break;
+            }
+        }
+        assertEquals(HTTPUtilities.REMEMBER_TOKEN_COOKIE_NAME, cookie.getName());
+    }
+
+    public void testGetSessionAttribute() throws Exception {
+        HttpServletRequest request = new MockHttpServletRequest();
+        HttpSession session = request.getSession();
+        session.setAttribute("testAttribute", 43f);
+
+        try {
+            // Deleting the unused assignment of the results to test1 causes the expected ClassCastException to not occur. So don't delete it!
+            @SuppressWarnings("unused")
+            Integer test1 = ESAPI.httpUtilities().getSessionAttribute( session, "testAttribute" );
+            fail();
+        } catch ( ClassCastException cce ) {}
+
+        Float test2 = ESAPI.httpUtilities().getSessionAttribute( session, "testAttribute" );
+        assertEquals( test2, 43f );
+    }
+
+    public void testGetRequestAttribute() throws Exception {
+        HttpServletRequest request = new MockHttpServletRequest();
+        request.setAttribute( "testAttribute", 43f );
+        try {
+            // Deleting the unused assignment of the results to test1 causes the expected ClassCastException to not occur. So don't delete it!
+            @SuppressWarnings("unused")
+            Integer test1 = ESAPI.httpUtilities().getRequestAttribute( request, "testAttribute" );
+            fail();
+        } catch ( ClassCastException cce ) {}
+
+        Float test2 = ESAPI.httpUtilities().getRequestAttribute( request, "testAttribute" );
+        assertEquals( test2, 43f );
+    }
 }
 
diff --git a/src/test/java/org/owasp/esapi/reference/IntegerAccessReferenceMapTest.java b/src/test/java/org/owasp/esapi/reference/IntegerAccessReferenceMapTest.java
index dacd2e2..0367ce0 100644
--- a/src/test/java/org/owasp/esapi/reference/IntegerAccessReferenceMapTest.java
+++ b/src/test/java/org/owasp/esapi/reference/IntegerAccessReferenceMapTest.java
@@ -1,15 +1,15 @@
 /**
  * OWASP Enterprise Security API (ESAPI)
- * 
+ *
  * This file is part of the Open Web Application Security Project (OWASP)
  * Enterprise Security API (ESAPI) project. For details, please see
  * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
  *
  * Copyright (c) 2007 - The OWASP Foundation
- * 
+ *
  * The ESAPI is published by OWASP under the BSD license. You should read and accept the
  * LICENSE before you use, modify, and/or redistribute this software.
- * 
+ *
  * @author Jeff Williams <a href="http://www.aspectsecurity.com">Aspect Security</a>
  * @created 2007
  */
@@ -33,17 +33,17 @@ import org.owasp.esapi.errors.EncryptionException;
 
 /**
  * The Class AccessReferenceMapTest.
- * 
+ *
  * @author Jeff Williams (jeff.williams@aspectsecurity.com)
  */
 public class IntegerAccessReferenceMapTest extends TestCase {
-    
+
     /**
-	 * Instantiates a new access reference map test.
-	 * 
-	 * @param testName
-	 *            the test name
-	 */
+     * Instantiates a new access reference map test.
+     *
+     * @param testName
+     *            the test name
+     */
     public IntegerAccessReferenceMapTest(String testName) {
         super(testName);
     }
@@ -53,7 +53,7 @@ public class IntegerAccessReferenceMapTest extends TestCase {
      * @throws Exception
      */
     protected void setUp() throws Exception {
-    	// none
+        // none
     }
 
     /**
@@ -61,139 +61,139 @@ public class IntegerAccessReferenceMapTest extends TestCase {
      * @throws Exception
      */
     protected void tearDown() throws Exception {
-    	// none
+        // none
     }
 
     /**
-	 * Suite.
-	 * 
-	 * @return the test
-	 */
+     * Suite.
+     *
+     * @return the test
+     */
     public static Test suite() {
         TestSuite suite = new TestSuite(IntegerAccessReferenceMapTest.class);
         return suite;
     }
 
-    
+
     /**
-	 * Test of update method, of class org.owasp.esapi.AccessReferenceMap.
-	 * 
-	 * @throws AuthenticationException
+     * Test of update method, of class org.owasp.esapi.AccessReferenceMap.
+     *
+     * @throws AuthenticationException
      *             the authentication exception
      * @throws EncryptionException
-	 */
+     */
     public void testUpdate() throws AuthenticationException, EncryptionException {
         System.out.println("update");
-    	IntegerAccessReferenceMap arm = new IntegerAccessReferenceMap();
-    	Authenticator auth = ESAPI.authenticator();
-    	
-    	String pass = auth.generateStrongPassword();
-    	User u = auth.createUser( "armUpdate", pass, pass );
-    	
-    	// test to make sure update returns something
-		arm.update(auth.getUserNames());
-		String indirect = arm.getIndirectReference( u.getAccountName() );
-		if ( indirect == null ) fail();
-		
-		// test to make sure update removes items that are no longer in the list
-		auth.removeUser( u.getAccountName() );
-		arm.update(auth.getUserNames());
-		indirect = arm.getIndirectReference( u.getAccountName() );
-		if ( indirect != null ) fail();
-		
-		// test to make sure old indirect reference is maintained after an update
-		arm.update(auth.getUserNames());
-		String newIndirect = arm.getIndirectReference( u.getAccountName() );
-		assertEquals(indirect, newIndirect);
+        IntegerAccessReferenceMap arm = new IntegerAccessReferenceMap();
+        Authenticator auth = ESAPI.authenticator();
+
+        String pass = auth.generateStrongPassword();
+        User u = auth.createUser( "armUpdate", pass, pass );
+
+        // test to make sure update returns something
+        arm.update(auth.getUserNames());
+        String indirect = arm.getIndirectReference( u.getAccountName() );
+        if ( indirect == null ) fail();
+
+        // test to make sure update removes items that are no longer in the list
+        auth.removeUser( u.getAccountName() );
+        arm.update(auth.getUserNames());
+        indirect = arm.getIndirectReference( u.getAccountName() );
+        if ( indirect != null ) fail();
+
+        // test to make sure old indirect reference is maintained after an update
+        arm.update(auth.getUserNames());
+        String newIndirect = arm.getIndirectReference( u.getAccountName() );
+        assertEquals(indirect, newIndirect);
     }
-    
-    
+
+
     /**
-	 * Test of iterator method, of class org.owasp.esapi.AccessReferenceMap.
-	 */
+     * Test of iterator method, of class org.owasp.esapi.AccessReferenceMap.
+     */
     public void testIterator() {
         System.out.println("iterator");
-    	IntegerAccessReferenceMap arm = new IntegerAccessReferenceMap();
+        IntegerAccessReferenceMap arm = new IntegerAccessReferenceMap();
         Authenticator auth = ESAPI.authenticator();
-        
-		arm.update(auth.getUserNames());
-
-		Iterator i = arm.iterator();
-		while ( i.hasNext() ) {
-			String userName = (String)i.next();
-			User u = auth.getUser( userName );
-			if ( u == null ) fail();
-		}
+
+        arm.update(auth.getUserNames());
+
+        Iterator i = arm.iterator();
+        while ( i.hasNext() ) {
+            String userName = (String)i.next();
+            User u = auth.getUser( userName );
+            if ( u == null ) fail();
+        }
     }
-    
+
     /**
-	 * Test of getIndirectReference method, of class
-	 * org.owasp.esapi.AccessReferenceMap.
-	 */
+     * Test of getIndirectReference method, of class
+     * org.owasp.esapi.AccessReferenceMap.
+     */
     public void testGetIndirectReference() {
         System.out.println("getIndirectReference");
-        
+
         String directReference = "234";
         Set list = new HashSet();
         list.add( "123" );
         list.add( directReference );
         list.add( "345" );
         IntegerAccessReferenceMap instance = new IntegerAccessReferenceMap( list );
-        
+
         String expResult = directReference;
         String result = instance.getIndirectReference(directReference);
-        assertNotSame(expResult, result);        
+        assertNotSame(expResult, result);
     }
 
     /**
-	 * Test of getDirectReference method, of class
-	 * org.owasp.esapi.AccessReferenceMap.
-	 * 
-	 * @throws AccessControlException
-	 *             the access control exception
-	 */
+     * Test of getDirectReference method, of class
+     * org.owasp.esapi.AccessReferenceMap.
+     *
+     * @throws AccessControlException
+     *             the access control exception
+     */
     public void testGetDirectReference() throws AccessControlException {
         System.out.println("getDirectReference");
-        
+
         String directReference = "234";
         Set list = new HashSet();
         list.add( "123" );
         list.add( directReference );
         list.add( "345" );
         IntegerAccessReferenceMap instance = new IntegerAccessReferenceMap( list );
-        
+
         String ind = instance.getIndirectReference(directReference);
         String dir = (String)instance.getDirectReference(ind);
         assertEquals(directReference, dir);
         try {
-        	instance.getDirectReference("invalid");
-        	fail();
+            instance.getDirectReference("invalid");
+            fail();
         } catch( AccessControlException e ) {
-        	// success
+            // success
         }
     }
-    
+
     /**
      *
      * @throws org.owasp.esapi.errors.AccessControlException
      */
     public void testAddDirectReference() throws AccessControlException {
         System.out.println("addDirectReference");
-        
+
         String directReference = "234";
         Set list = new HashSet();
         list.add( "123" );
         list.add( directReference );
         list.add( "345" );
         IntegerAccessReferenceMap instance = new IntegerAccessReferenceMap( list );
-        
+
         String newDirect = instance.addDirectReference("newDirect");
         assertNotNull( newDirect );
         String ind = instance.addDirectReference(directReference);
         String dir = (String)instance.getDirectReference(ind);
         assertEquals(directReference, dir);
-    	String newInd = instance.addDirectReference(directReference);
-    	assertEquals(ind, newInd);
+        String newInd = instance.addDirectReference(directReference);
+        assertEquals(ind, newInd);
     }
 
     /**
@@ -202,22 +202,22 @@ public class IntegerAccessReferenceMapTest extends TestCase {
      */
     public void testRemoveDirectReference() throws AccessControlException {
         System.out.println("removeDirectReference");
-        
+
         String directReference = "234";
         Set list = new HashSet();
         list.add( "123" );
         list.add( directReference );
         list.add( "345" );
         IntegerAccessReferenceMap instance = new IntegerAccessReferenceMap( list );
-        
+
         String indirect = instance.getIndirectReference(directReference);
         assertNotNull(indirect);
         String deleted = instance.removeDirectReference(directReference);
         assertEquals(indirect,deleted);
-    	deleted = instance.removeDirectReference("ridiculous");
-    	assertNull(deleted);
+        deleted = instance.removeDirectReference("ridiculous");
+        assertNull(deleted);
     }
-    
-    
-    
+
+
+
 }
diff --git a/src/test/java/org/owasp/esapi/reference/IntrusionDetectorTest.java b/src/test/java/org/owasp/esapi/reference/IntrusionDetectorTest.java
index 5ea853b..46cb932 100644
--- a/src/test/java/org/owasp/esapi/reference/IntrusionDetectorTest.java
+++ b/src/test/java/org/owasp/esapi/reference/IntrusionDetectorTest.java
@@ -1,15 +1,15 @@
 /**
  * OWASP Enterprise Security API (ESAPI)
- * 
+ *
  * This file is part of the Open Web Application Security Project (OWASP)
  * Enterprise Security API (ESAPI) project. For details, please see
  * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
  *
  * Copyright (c) 2007 - The OWASP Foundation
- * 
+ *
  * The ESAPI is published by OWASP under the BSD license. You should read and accept the
  * LICENSE before you use, modify, and/or redistribute this software.
- * 
+ *
  * @author Jeff Williams <a href="http://www.aspectsecurity.com">Aspect Security</a>
  * @created 2007
  */
@@ -32,101 +32,101 @@ import org.owasp.esapi.http.MockHttpServletResponse;
 
 /**
  * The Class IntrusionDetectorTest.
- * 
+ *
  * @author Jeff Williams (jeff.williams@aspectsecurity.com)
  */
 public class IntrusionDetectorTest extends TestCase {
 
-	/**
-	 * Instantiates a new intrusion detector test.
-	 * 
-	 * @param testName
-	 *            the test name
-	 */
-	public IntrusionDetectorTest(String testName) {
-		super(testName);
-	}
+    /**
+     * Instantiates a new intrusion detector test.
+     *
+     * @param testName
+     *            the test name
+     */
+    public IntrusionDetectorTest(String testName) {
+        super(testName);
+    }
 
-	/**
+    /**
      * {@inheritDoc}
      *
      * @throws Exception
      */
-	protected void setUp() throws Exception {
-		// none
-	}
+    protected void setUp() throws Exception {
+        // none
+    }
 
-	/**
+    /**
      * {@inheritDoc}
      *
      * @throws Exception
      */
-	protected void tearDown() throws Exception {
-		// none
-	}
+    protected void tearDown() throws Exception {
+        // none
+    }
 
-	/**
-	 * Suite.
-	 * 
-	 * @return the test
-	 */
-	public static Test suite() {
-		TestSuite suite = new TestSuite(IntrusionDetectorTest.class);
+    /**
+     * Suite.
+     *
+     * @return the test
+     */
+    public static Test suite() {
+        TestSuite suite = new TestSuite(IntrusionDetectorTest.class);
 
-		return suite;
-	}
+        return suite;
+    }
 
-	/**
-	 * Test of addException method, of class org.owasp.esapi.IntrusionDetector.
-	 * 
-	 * @throws AuthenticationException
-	 *             the authentication exception
-	 */
-	public void testAddException() throws AuthenticationException {
-		System.out.println("addException");
-		ESAPI.intrusionDetector().addException( new RuntimeException("message") );
-		ESAPI.intrusionDetector().addException( new ValidationException("user message", "log message") );
-		ESAPI.intrusionDetector().addException( new IntrusionException("user message", "log message") );
-		String username = ESAPI.randomizer().getRandomString(8, EncoderConstants.CHAR_ALPHANUMERICS);
+    /**
+     * Test of addException method, of class org.owasp.esapi.IntrusionDetector.
+     *
+     * @throws AuthenticationException
+     *             the authentication exception
+     */
+    public void testAddException() throws AuthenticationException {
+        System.out.println("addException");
+        ESAPI.intrusionDetector().addException( new RuntimeException("message") );
+        ESAPI.intrusionDetector().addException( new ValidationException("user message", "log message") );
+        ESAPI.intrusionDetector().addException( new IntrusionException("user message", "log message") );
+        String username = ESAPI.randomizer().getRandomString(8, EncoderConstants.CHAR_ALPHANUMERICS);
         Authenticator auth = ESAPI.authenticator();
-		User user = auth.createUser(username, "addException", "addException");
-		user.enable();
-	    MockHttpServletRequest request = new MockHttpServletRequest();
-		MockHttpServletResponse response = new MockHttpServletResponse();
-		ESAPI.httpUtilities().setCurrentHTTP(request, response);
-		user.loginWithPassword("addException");
-		
-		// Now generate some exceptions to disable account
-		for ( int i = 0; i < ESAPI.securityConfiguration().getQuota(IntegrityException.class.getName()).count; i++ ) {
+        User user = auth.createUser(username, "addException", "addException");
+        user.enable();
+        MockHttpServletRequest request = new MockHttpServletRequest();
+        MockHttpServletResponse response = new MockHttpServletResponse();
+        ESAPI.httpUtilities().setCurrentHTTP(request, response);
+        user.loginWithPassword("addException");
+
+        // Now generate some exceptions to disable account
+        for ( int i = 0; i < ESAPI.securityConfiguration().getQuota(IntegrityException.class.getName()).count; i++ ) {
             // EnterpriseSecurityExceptions are added to IntrusionDetector automatically
             new IntegrityException( "IntegrityException " + i, "IntegrityException " + i );
-		}
+        }
         assertFalse( user.isLoggedIn() );
-	}
+    }
+
 
-    
     /**
      * Test of addEvent method, of class org.owasp.esapi.IntrusionDetector.
-     * 
+     *
      * @throws AuthenticationException
      *             the authentication exception
      */
     public void testAddEvent() throws AuthenticationException {
         System.out.println("addEvent");
-		String username = ESAPI.randomizer().getRandomString(8, EncoderConstants.CHAR_ALPHANUMERICS);
+        String username = ESAPI.randomizer().getRandomString(8, EncoderConstants.CHAR_ALPHANUMERICS);
         Authenticator auth = ESAPI.authenticator();
-		User user = auth.createUser(username, "addEvent", "addEvent");
-		user.enable();
-	    MockHttpServletRequest request = new MockHttpServletRequest();
-		MockHttpServletResponse response = new MockHttpServletResponse();
-		ESAPI.httpUtilities().setCurrentHTTP(request, response);
-		user.loginWithPassword("addEvent");
-        
+        User user = auth.createUser(username, "addEvent", "addEvent");
+        user.enable();
+        MockHttpServletRequest request = new MockHttpServletRequest();
+        MockHttpServletResponse response = new MockHttpServletResponse();
+        ESAPI.httpUtilities().setCurrentHTTP(request, response);
+        user.loginWithPassword("addEvent");
+
         // Now generate some events to disable user account
         for ( int i = 0; i < ESAPI.securityConfiguration().getQuota("event.test").count; i++ ) {
             ESAPI.intrusionDetector().addEvent("test", "test message");
         }
         assertFalse( user.isEnabled() );
     }
-    
+
 }
diff --git a/src/test/java/org/owasp/esapi/reference/RandomizerTest.java b/src/test/java/org/owasp/esapi/reference/RandomizerTest.java
index 32dc9bd..e01101c 100644
--- a/src/test/java/org/owasp/esapi/reference/RandomizerTest.java
+++ b/src/test/java/org/owasp/esapi/reference/RandomizerTest.java
@@ -1,15 +1,15 @@
 /**
  * OWASP Enterprise Security API (ESAPI)
- * 
+ *
  * This file is part of the Open Web Application Security Project (OWASP)
  * Enterprise Security API (ESAPI) project. For details, please see
  * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
  *
  * Copyright (c) 2007 - The OWASP Foundation
- * 
+ *
  * The ESAPI is published by OWASP under the BSD license. You should read and accept the
  * LICENSE before you use, modify, and/or redistribute this software.
- * 
+ *
  * @author Jeff Williams <a href="http://www.aspectsecurity.com">Aspect Security</a>
  * @created 2007
  */
@@ -31,17 +31,17 @@ import org.owasp.esapi.errors.EncryptionException;
 
 /**
  * The Class RandomizerTest.
- * 
+ *
  * @author Jeff Williams (jeff.williams@aspectsecurity.com)
  */
 public class RandomizerTest extends TestCase {
-    
+
     /**
-	 * Instantiates a new randomizer test.
-	 * 
-	 * @param testName
-	 *            the test name
-	 */
+     * Instantiates a new randomizer test.
+     *
+     * @param testName
+     *            the test name
+     */
     public RandomizerTest(String testName) {
         super(testName);
     }
@@ -51,7 +51,7 @@ public class RandomizerTest extends TestCase {
      * @throws Exception
      */
     protected void setUp() throws Exception {
-    	// none
+        // none
     }
 
     /**
@@ -59,22 +59,22 @@ public class RandomizerTest extends TestCase {
      * @throws Exception
      */
     protected void tearDown() throws Exception {
-    	// none
+        // none
     }
 
     /**
-	 * Suite.
-	 * 
-	 * @return the test
-	 */
+     * Suite.
+     *
+     * @return the test
+     */
     public static Test suite() {
-        TestSuite suite = new TestSuite(RandomizerTest.class);        
+        TestSuite suite = new TestSuite(RandomizerTest.class);
         return suite;
     }
 
     /**
-	 * Test of getRandomString method, of class org.owasp.esapi.Randomizer.
-	 */
+     * Test of getRandomString method, of class org.owasp.esapi.Randomizer.
+     */
     public void testGetRandomString() {
         System.out.println("getRandomString");
         int length = 20;
@@ -84,37 +84,37 @@ public class RandomizerTest extends TestCase {
         for ( int i = 0; i < 1000; i++ ) {
             String result = instance.getRandomString(length, EncoderConstants.CHAR_ALPHANUMERICS );
             for ( int j=0;j<result.length();j++ ) {
-            	char c = result.charAt(j);
-            	counts[c]++;
+                char c = result.charAt(j);
+                counts[c]++;
             }
             assertEquals(length, result.length());
         }
-        
+
         // Simple check to see if the overall character counts are within 10% of each other
         int min=Integer.MAX_VALUE;
         int max=0;
         for ( int i = 0; i < 128; i++ ) {
-        	if ( counts[i] > max ) { max = counts[i]; } 
-        	if ( counts[i] > 0 && counts[i] < min ) { min = counts[i]; }
-        	if ( max - min > trials/10 ) {
-        		System.err.println("*** WARNING: RandomizerTest.testGetRandomString(): " +
+            if ( counts[i] > max ) { max = counts[i]; }
+            if ( counts[i] > 0 && counts[i] < min ) { min = counts[i]; }
+            if ( max - min > trials/10 ) {
+                System.err.println("*** WARNING: RandomizerTest.testGetRandomString(): " +
                         "Randomness counts are off. This may be simply from " +
                         "statistical variance or it could signify a flaw in " +
                         "Randomizer.getRandomString(). Repeat this test " +
                         "multiple times and if you get repeated warnings " +
                         "you should assume the latter and investigate further.");
-        	}
+            }
         }
     }
 
     /**
-	 * Test of getRandomInteger method, of class org.owasp.esapi.Randomizer.
-	 */
+     * Test of getRandomInteger method, of class org.owasp.esapi.Randomizer.
+     */
     public void testGetRandomInteger() {
-        System.out.println("getRandomInteger");        
+        System.out.println("getRandomInteger");
         int min = -20;
         int max = 100;
-        Randomizer instance = ESAPI.randomizer();        
+        Randomizer instance = ESAPI.randomizer();
         int minResult = ( max - min ) / 2;
         int maxResult = ( max - min ) / 2;
         for ( int i = 0; i < 100; i++ ) {
@@ -126,8 +126,8 @@ public class RandomizerTest extends TestCase {
     }
 
     /**
-	 * Test of getRandomReal method, of class org.owasp.esapi.Randomizer.
-	 */
+     * Test of getRandomReal method, of class org.owasp.esapi.Randomizer.
+     */
     public void testGetRandomReal() {
         System.out.println("getRandomReal");
         float min = -20.5234F;
@@ -142,8 +142,8 @@ public class RandomizerTest extends TestCase {
         }
         assertEquals(true, (minResult >= min && maxResult < max));
     }
-    
-    
+
+
     /**
      * Test of getRandomGUID method, of class org.owasp.esapi.Randomizer.
      * @throws EncryptionException
@@ -159,24 +159,24 @@ public class RandomizerTest extends TestCase {
         }
     }
 
-    
+
     /**
      * Run this class to generate a file named "tokens.txt" with 20,000 random 20 character ALPHANUMERIC tokens.
      * Use Burp Pro sequencer to load this file and run a series of randomness tests.
-     * 
+     *
      * NOTE: be careful not to include any CRLF characters (10 or 13 ASCII) because they'll create new tokens
      * Check to be sure your analysis tool loads exactly 20,000 tokens of 20 characters each.
      */
-    
-	public static void main(String[] args) throws IOException {
-		FileWriter fw = new FileWriter("tokens.txt");
-		for (int i = 0; i < 20000; i++) {
-			String token = ESAPI.randomizer().getRandomString(20, EncoderConstants.CHAR_ALPHANUMERICS);
-			fw.write(token + "\n");
-		}
-		fw.close();
-	}
-
-
-     
+
+    public static void main(String[] args) throws IOException {
+        FileWriter fw = new FileWriter("tokens.txt");
+        for (int i = 0; i < 20000; i++) {
+            String token = ESAPI.randomizer().getRandomString(20, EncoderConstants.CHAR_ALPHANUMERICS);
+            fw.write(token + "\n");
+        }
+        fw.close();
+    }
+
+
+
 }
diff --git a/src/test/java/org/owasp/esapi/reference/SafeFileTest.java b/src/test/java/org/owasp/esapi/reference/SafeFileTest.java
index 923b75e..63fc424 100644
--- a/src/test/java/org/owasp/esapi/reference/SafeFileTest.java
+++ b/src/test/java/org/owasp/esapi/reference/SafeFileTest.java
@@ -1,15 +1,15 @@
 /**
  * OWASP Enterprise Security API (ESAPI)
- * 
+ *
  * This file is part of the Open Web Application Security Project (OWASP)
  * Enterprise Security API (ESAPI) project. For details, please see
  * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
  *
  * Copyright (c) 2007 - The OWASP Foundation
- * 
+ *
  * The ESAPI is published by OWASP under the BSD license. You should read and accept the
  * LICENSE before you use, modify, and/or redistribute this software.
- * 
+ *
  * @author Jeff Williams <a href="http://www.aspectsecurity.com">Aspect Security</a>
  * @created 2007
  */
@@ -33,256 +33,256 @@ import junit.framework.TestSuite;
  */
 public class SafeFileTest extends TestCase
 {
-	private static final Class CLASS = SafeFileTest.class;
-	private static final String CLASS_NAME = CLASS.getName();
-	/** Name of the file in the temporary directory */
-	private static final String TEST_FILE_NAME = "test.file";
-	private static final Set GOOD_FILE_CHARS = CollectionsUtil.strToUnmodifiableSet("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-" /* + "." */);
-	private static final Set BAD_FILE_CHARS = CollectionsUtil.strToUnmodifiableSet("\u0000" + /*(File.separatorChar == '/' ? '\\' : '/') +*/ "*|<>?:" /*+ "~!@#$%^&(){}[],`;"*/);
+    private static final Class CLASS = SafeFileTest.class;
+    private static final String CLASS_NAME = CLASS.getName();
+    /** Name of the file in the temporary directory */
+    private static final String TEST_FILE_NAME = "test.file";
+    private static final Set GOOD_FILE_CHARS = CollectionsUtil.strToUnmodifiableSet("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-" /* + "." */);
+    private static final Set BAD_FILE_CHARS = CollectionsUtil.strToUnmodifiableSet("\u0000" + /*(File.separatorChar == '/' ? '\\' : '/') +*/ "*|<>?:" /*+ "~!@#$%^&(){}[],`;"*/);
+
+    private File testDir = null;
+    private File testFile = null;
+
+    String pathWithNullByte = "/temp/file.txt" + (char)0;
+
+    /**
+     * {@inheritDoc}
+     */
+    protected void setUp() throws Exception
+    {
+        // create a file to test with
+        testDir = FileTestUtils.createTmpDirectory(CLASS_NAME).getCanonicalFile();
+        testFile = new File(testDir, TEST_FILE_NAME);
+        testFile.createNewFile();
+        testFile = testFile.getCanonicalFile();
+    }
 
-	private File testDir = null;
-	private File testFile = null;
+    /**
+     * {@inheritDoc}
+     */
+    protected void tearDown() throws Exception
+    {
+        FileTestUtils.deleteRecursively(testDir);
+    }
 
-	String pathWithNullByte = "/temp/file.txt" + (char)0;
+    public static Test suite() {
+        TestSuite suite = new TestSuite(SafeFileTest.class);
+        return suite;
+    }
 
-	/**
-	 * {@inheritDoc}
-	 */
-	protected void setUp() throws Exception
-	{
-		// create a file to test with
-		testDir = FileTestUtils.createTmpDirectory(CLASS_NAME).getCanonicalFile();
-		testFile = new File(testDir, TEST_FILE_NAME);
-		testFile.createNewFile();
-		testFile = testFile.getCanonicalFile();
-	}
+    public void testEscapeCharactersInFilename() {
+        System.out.println("testEscapeCharactersInFilenameInjection");
+        File tf = testFile;
+        if ( tf.exists() ) {
+            System.out.println( "File is there: " + tf );
+        }
 
-	/**
-	 * {@inheritDoc}
-	 */
-	protected void tearDown() throws Exception
-	{
-		FileTestUtils.deleteRecursively(testDir);
-	}
+        try {
+            File sf = new SafeFile(testDir, "test^.file" );
+        } catch (ValidationException e) {
+            assertEquals("Invalid directory", e.getMessage());
+        }
 
-	public static Test suite() {
-		TestSuite suite = new TestSuite(SafeFileTest.class);
-		return suite;
-	}
+    }
 
-	public void testEscapeCharactersInFilename() {
-		System.out.println("testEscapeCharactersInFilenameInjection");
-		File tf = testFile;
-		if ( tf.exists() ) {
-			System.out.println( "File is there: " + tf );
-		}
+    public void testEscapeCharacterInDirectoryInjection() {
+        System.out.println("testEscapeCharacterInDirectoryInjection");
+        try {
+            File sf = new SafeFile(testDir, "test\\^.^.\\file");
+        } catch (ValidationException e) {
+            assertEquals("Invalid directory", e.getMessage());
+        }
+    }
 
-		try {
-			File sf = new SafeFile(testDir, "test^.file" );
-		} catch (ValidationException e) {
-			assertEquals("Invalid directory", e.getMessage());
-		}
-	    
-	}
+    public void testJavaFileInjectionGood() throws ValidationException
+    {
+        for(Iterator i=GOOD_FILE_CHARS.iterator();i.hasNext();)
+        {
+            String ch = i.next().toString();    // avoids generic issues in 1.4&1.5
+            File sf = new SafeFile(testDir, TEST_FILE_NAME + ch);
+            assertFalse("File \"" + TEST_FILE_NAME + ch + "\" should not exist ((int)ch=" + (int)ch.charAt(0) + ").", sf.exists());
+            sf = new SafeFile(testDir, TEST_FILE_NAME + ch + "test");
+            assertFalse("File \"" + TEST_FILE_NAME + ch + "\" should not exist ((int)ch=" + (int)ch.charAt(0) + ").", sf.exists());
+        }
+    }
 
-	public void testEscapeCharacterInDirectoryInjection() {
-		System.out.println("testEscapeCharacterInDirectoryInjection");
-		try {
-			File sf = new SafeFile(testDir, "test\\^.^.\\file");
-		} catch (ValidationException e) {
-			assertEquals("Invalid directory", e.getMessage());
-		}
-	}
+    public void testJavaFileInjectionBad()
+    {
+        for(Iterator i=BAD_FILE_CHARS.iterator();i.hasNext();)
+        {
+            String ch = i.next().toString();    // avoids generic issues in 1.4&1.5
+            try
+            {
+                File sf = new SafeFile(testDir, TEST_FILE_NAME + ch);
+                fail("Able to create SafeFile \"" + TEST_FILE_NAME + ch + "\" ((int)ch=" + (int)ch.charAt(0) + ").");
+            }
+            catch(ValidationException expected)
+            {
+            }
+            try
+            {
+                File sf = new SafeFile(testDir, TEST_FILE_NAME + ch  + "test");
+                fail("Able to create SafeFile \"" + TEST_FILE_NAME + ch + "\" ((int)ch=" + (int)ch.charAt(0) + ").");
+            }
+            catch(ValidationException expected)
+            {
+            }
+        }
+    }
 
-	public void testJavaFileInjectionGood() throws ValidationException
-	{
-		for(Iterator i=GOOD_FILE_CHARS.iterator();i.hasNext();)
-		{
-			String ch = i.next().toString();	// avoids generic issues in 1.4&1.5
-			File sf = new SafeFile(testDir, TEST_FILE_NAME + ch);
-			assertFalse("File \"" + TEST_FILE_NAME + ch + "\" should not exist ((int)ch=" + (int)ch.charAt(0) + ").", sf.exists());
-			sf = new SafeFile(testDir, TEST_FILE_NAME + ch + "test");
-			assertFalse("File \"" + TEST_FILE_NAME + ch + "\" should not exist ((int)ch=" + (int)ch.charAt(0) + ").", sf.exists());
-		}		
-	}
+    public void testMultipleJavaFileInjectionGood() throws ValidationException
+    {
+        for(Iterator i=GOOD_FILE_CHARS.iterator();i.hasNext();)
+        {
+            String ch = i.next().toString();    // avoids generic issues in 1.4&1.5
+            ch = ch + ch + ch;
+            File sf = new SafeFile(testDir, TEST_FILE_NAME + ch);
+            assertFalse("File \"" + TEST_FILE_NAME + ch + "\" should not exist ((int)ch=" + (int)ch.charAt(0) + ").", sf.exists());
+            sf = new SafeFile(testDir, TEST_FILE_NAME + ch + "test");
+            assertFalse("File \"" + TEST_FILE_NAME + ch + "\" should not exist ((int)ch=" + (int)ch.charAt(0) + ").", sf.exists());
+        }
+    }
 
-	public void testJavaFileInjectionBad()
-	{
-		for(Iterator i=BAD_FILE_CHARS.iterator();i.hasNext();)
-		{
-			String ch = i.next().toString();	// avoids generic issues in 1.4&1.5
-			try
-			{
-				File sf = new SafeFile(testDir, TEST_FILE_NAME + ch);
-				fail("Able to create SafeFile \"" + TEST_FILE_NAME + ch + "\" ((int)ch=" + (int)ch.charAt(0) + ").");
-			}
-			catch(ValidationException expected)
-			{
-			}
-			try
-			{
-				File sf = new SafeFile(testDir, TEST_FILE_NAME + ch  + "test");
-				fail("Able to create SafeFile \"" + TEST_FILE_NAME + ch + "\" ((int)ch=" + (int)ch.charAt(0) + ").");
-			}
-			catch(ValidationException expected)
-			{
-			}
-		}		
-	}
+    public void testMultipleJavaFileInjectionBad()
+    {
+        for(Iterator i=BAD_FILE_CHARS.iterator();i.hasNext();)
+        {
+            String ch = i.next().toString();    // avoids generic issues in 1.4&1.5
+            ch = ch + ch + ch;
+            try
+            {
+                File sf = new SafeFile(testDir, TEST_FILE_NAME + ch);
+                fail("Able to create SafeFile \"" + TEST_FILE_NAME + ch + "\" ((int)ch=" + (int)ch.charAt(0) + ").");
+            }
+            catch(ValidationException expected)
+            {
+            }
+            try
+            {
+                File sf = new SafeFile(testDir, TEST_FILE_NAME + ch  + "test");
+                fail("Able to create SafeFile \"" + TEST_FILE_NAME + ch + "\" ((int)ch=" + (int)ch.charAt(0) + ").");
+            }
+            catch(ValidationException expected)
+            {
+            }
+        }
+    }
 
-	public void testMultipleJavaFileInjectionGood() throws ValidationException
-	{
-		for(Iterator i=GOOD_FILE_CHARS.iterator();i.hasNext();)
-		{
-			String ch = i.next().toString();	// avoids generic issues in 1.4&1.5
-			ch = ch + ch + ch;
-			File sf = new SafeFile(testDir, TEST_FILE_NAME + ch);
-			assertFalse("File \"" + TEST_FILE_NAME + ch + "\" should not exist ((int)ch=" + (int)ch.charAt(0) + ").", sf.exists());
-			sf = new SafeFile(testDir, TEST_FILE_NAME + ch + "test");
-			assertFalse("File \"" + TEST_FILE_NAME + ch + "\" should not exist ((int)ch=" + (int)ch.charAt(0) + ").", sf.exists());
-		}		
-	}
+    public void testAlternateDataStream() {
+        try
+        {
+            File sf = new SafeFile(testDir, TEST_FILE_NAME + ":secret.txt");
+            fail("Able to construct SafeFile for alternate data stream: " + sf.getPath());
+        }
+        catch(ValidationException expected)
+        {
+        }
+    }
 
-	public void testMultipleJavaFileInjectionBad()
-	{
-		for(Iterator i=BAD_FILE_CHARS.iterator();i.hasNext();)
-		{
-			String ch = i.next().toString();	// avoids generic issues in 1.4&1.5
-			ch = ch + ch + ch;
-			try
-			{
-				File sf = new SafeFile(testDir, TEST_FILE_NAME + ch);
-				fail("Able to create SafeFile \"" + TEST_FILE_NAME + ch + "\" ((int)ch=" + (int)ch.charAt(0) + ").");
-			}
-			catch(ValidationException expected)
-			{
-			}
-			try
-			{
-				File sf = new SafeFile(testDir, TEST_FILE_NAME + ch  + "test");
-				fail("Able to create SafeFile \"" + TEST_FILE_NAME + ch + "\" ((int)ch=" + (int)ch.charAt(0) + ").");
-			}
-			catch(ValidationException expected)
-			{
-			}
-		}		
-	}
+    static public String toHex(final byte b) {
+        final char hexDigit[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
+        final char[] array = { hexDigit[(b >> 4) & 0x0f], hexDigit[b & 0x0f] };
+        return new String(array);
+    }
 
-	public void testAlternateDataStream() {
-		try
-		{
-			File sf = new SafeFile(testDir, TEST_FILE_NAME + ":secret.txt");
-			fail("Able to construct SafeFile for alternate data stream: " + sf.getPath());
-		}
-		catch(ValidationException expected)
-		{
-		}
-	}
+    public void testCreatePath() throws Exception
+    {
+        SafeFile sf = new SafeFile(testFile.getPath());
+        assertTrue(sf.exists());
+    }
 
-	static public String toHex(final byte b) {
-		final char hexDigit[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
-		final char[] array = { hexDigit[(b >> 4) & 0x0f], hexDigit[b & 0x0f] };
-		return new String(array);
-	}	
+    public void testCreateParentPathName() throws Exception
+    {
+        SafeFile sf = new SafeFile(testDir, testFile.getName());
+        assertTrue(sf.exists());
+    }
 
-	public void testCreatePath() throws Exception
-	{
-		SafeFile sf = new SafeFile(testFile.getPath());
-		assertTrue(sf.exists());
-	}
+    public void testCreateParentFileName() throws Exception
+    {
+        SafeFile sf = new SafeFile(testFile.getParentFile(), testFile.getName());
+        assertTrue(sf.exists());
+    }
 
-	public void testCreateParentPathName() throws Exception
-	{
-		SafeFile sf = new SafeFile(testDir, testFile.getName());
-		assertTrue(sf.exists());
-	}
+    public void testCreateURI() throws Exception
+    {
+        SafeFile sf = new SafeFile(testFile.toURI());
+        assertTrue(sf.exists());
+    }
 
-	public void testCreateParentFileName() throws Exception
-	{
-		SafeFile sf = new SafeFile(testFile.getParentFile(), testFile.getName());
-		assertTrue(sf.exists());
-	}
+    public void testCreateFileNamePercentNull()
+    {
+        try
+        {
+            SafeFile sf = new SafeFile(testDir + File.separator + "file%00.txt");
+            fail("no exception thrown for file name with percent encoded null");
+        }
+        catch(ValidationException expected)
+        {
+        }
+    }
 
-	public void testCreateURI() throws Exception
-	{
-		SafeFile sf = new SafeFile(testFile.toURI());
-		assertTrue(sf.exists());
-	}
+    public void testCreateFileNameQuestion()
+    {
+        try
+        {
+            SafeFile sf = new SafeFile(testFile.getParent() + File.separator + "file?.txt");
+            fail("no exception thrown for file name with question mark in it");
+        }
+        catch(ValidationException e)
+        {
+            // expected
+        }
+    }
 
-	public void testCreateFileNamePercentNull()
-	{
-		try
-		{
-			SafeFile sf = new SafeFile(testDir + File.separator + "file%00.txt");
-			fail("no exception thrown for file name with percent encoded null");
-		}
-		catch(ValidationException expected)
-		{
-		}
-	}
+    public void testCreateFileNameNull()
+    {
+        try
+        {
+            SafeFile sf = new SafeFile(testFile.getParent() + File.separator + "file" + ((char)0) + ".txt");
+            fail("no exception thrown for file name with null in it");
+        }
+        catch(ValidationException e)
+        {
+            // expected
+        }
+    }
 
-	public void testCreateFileNameQuestion()
-	{
-		try
-		{
-			SafeFile sf = new SafeFile(testFile.getParent() + File.separator + "file?.txt");
-			fail("no exception thrown for file name with question mark in it");
-		}
-		catch(ValidationException e)
-		{
-			// expected
-		}
-	}
+    public void testCreateFileHighByte()
+    {
+        try
+        {
+            SafeFile sf = new SafeFile(testFile.getParent() + File.separator + "file" + ((char)160) + ".txt");
+            fail("no exception thrown for file name with high byte in it");
+        }
+        catch(ValidationException e)
+        {
+            // expected
+        }
+    }
 
-	public void testCreateFileNameNull()
-	{
-		try
-		{
-			SafeFile sf = new SafeFile(testFile.getParent() + File.separator + "file" + ((char)0) + ".txt");
-			fail("no exception thrown for file name with null in it");
-		}
-		catch(ValidationException e)
-		{
-			// expected
-		}
-	}
+    public void testCreateParentPercentNull()
+    {
+        try
+        {
+            SafeFile sf = new SafeFile(testFile.getParent() + File.separator + "file%00.txt");
+            fail("no exception thrown for file name with percent encoded null");
+        }
+        catch(ValidationException e)
+        {
+            // expected
+        }
+    }
 
-	public void testCreateFileHighByte()
-	{
-		try
-		{
-			SafeFile sf = new SafeFile(testFile.getParent() + File.separator + "file" + ((char)160) + ".txt");
-			fail("no exception thrown for file name with high byte in it");
-		}
-		catch(ValidationException e)
-		{
-			// expected
-		}
-	}
+    public final void testSafeFileShouldAcceptEmptyPath() throws ValidationException
+    {
+        String filename = "hello.txt";
+        //API dictates that NPE should be thrown.
+        try{
+            SafeFile file = new SafeFile(filename);
+        }catch(NullPointerException npe){
+            assertNotNull(npe);
+        }
 
-	public void testCreateParentPercentNull()
-	{
-		try
-		{
-			SafeFile sf = new SafeFile(testFile.getParent() + File.separator + "file%00.txt");
-			fail("no exception thrown for file name with percent encoded null");
-		}
-		catch(ValidationException e)
-		{
-			// expected
-		}
-	}
-	
-	public final void testSafeFileShouldAcceptEmptyPath() throws ValidationException
-	{
-		String filename = "hello.txt";
-		//API dictates that NPE should be thrown.
-		try{
-			SafeFile file = new SafeFile(filename);
-		}catch(NullPointerException npe){
-			assertNotNull(npe);
-		}
-		
 
-	}
+    }
 }
diff --git a/src/test/java/org/owasp/esapi/reference/TestDebug.java b/src/test/java/org/owasp/esapi/reference/TestDebug.java
index 1d37deb..c0c6d58 100644
--- a/src/test/java/org/owasp/esapi/reference/TestDebug.java
+++ b/src/test/java/org/owasp/esapi/reference/TestDebug.java
@@ -8,15 +8,15 @@ import junit.framework.TestCase;
  * @author August Detlefsen (augustd at codemagi dot com)
  *         <a href="http://www.codemagi.com">CodeMagi, Inc.</a>
  * @since October 15, 2010
- * @see org.owasp.esapi.logging.log4j.Log4JLoggerTest
+ * @see org.owasp.esapi.logging.java.JavaLoggerTest
  */
 public class TestDebug extends TestCase {
 
-	/** 
-	 * Dummy method so that JUnit won't complain
-	 */
-	public void testLogging() {
+    /**
+     * Dummy method so that JUnit won't complain
+     */
+    public void testLogging() {
 
-	}
+    }
 
 }
diff --git a/src/test/java/org/owasp/esapi/reference/TestError.java b/src/test/java/org/owasp/esapi/reference/TestError.java
index ab59e79..17e889f 100644
--- a/src/test/java/org/owasp/esapi/reference/TestError.java
+++ b/src/test/java/org/owasp/esapi/reference/TestError.java
@@ -8,15 +8,15 @@ import junit.framework.TestCase;
  * @author August Detlefsen (augustd at codemagi dot com)
  *         <a href="http://www.codemagi.com">CodeMagi, Inc.</a>
  * @since October 15, 2010
- * @see org.owasp.esapi.logging.log4j.Log4JLoggerTest
+ * @see org.owasp.esapi.logging.java.JavaLoggerTest
  */
 public class TestError extends TestCase {
 
-	/**
-	 * Dummy method so that JUnit won't complain
-	 */
-	public void testLogging() {
+    /**
+     * Dummy method so that JUnit won't complain
+     */
+    public void testLogging() {
 
-	}
+    }
 
 }
diff --git a/src/test/java/org/owasp/esapi/reference/TestFatal.java b/src/test/java/org/owasp/esapi/reference/TestFatal.java
index 49ff15a..a8176a2 100644
--- a/src/test/java/org/owasp/esapi/reference/TestFatal.java
+++ b/src/test/java/org/owasp/esapi/reference/TestFatal.java
@@ -8,15 +8,15 @@ import junit.framework.TestCase;
  * @author August Detlefsen (augustd at codemagi dot com)
  *         <a href="http://www.codemagi.com">CodeMagi, Inc.</a>
  * @since October 15, 2010
- * @see org.owasp.esapi.logging.log4j.Log4JLoggerTest
+ * @see org.owasp.esapi.logging.java.JavaLoggerTest
  */
 public class TestFatal extends TestCase {
 
-	/**
-	 * Dummy method so that JUnit won't complain
-	 */
-	public void testLogging() {
+    /**
+     * Dummy method so that JUnit won't complain
+     */
+    public void testLogging() {
 
-	}
+    }
 
 }
diff --git a/src/test/java/org/owasp/esapi/reference/TestInfo.java b/src/test/java/org/owasp/esapi/reference/TestInfo.java
index 8977e51..f404ecb 100644
--- a/src/test/java/org/owasp/esapi/reference/TestInfo.java
+++ b/src/test/java/org/owasp/esapi/reference/TestInfo.java
@@ -8,15 +8,15 @@ import junit.framework.TestCase;
  * @author August Detlefsen (augustd at codemagi dot com)
  *         <a href="http://www.codemagi.com">CodeMagi, Inc.</a>
  * @since October 15, 2010
- * @see org.owasp.esapi.logging.log4j.Log4JLoggerTest
+ * @see org.owasp.esapi.logging.java.JavaLoggerTest
  */
 public class TestInfo extends TestCase {
 
-	/**
-	 * Dummy method so that JUnit won't complain
-	 */
-	public void testLogging() {
+    /**
+     * Dummy method so that JUnit won't complain
+     */
+    public void testLogging() {
 
-	}
+    }
 
 }
diff --git a/src/test/java/org/owasp/esapi/reference/TestTrace.java b/src/test/java/org/owasp/esapi/reference/TestTrace.java
index 8e3df1e..3e7b841 100644
--- a/src/test/java/org/owasp/esapi/reference/TestTrace.java
+++ b/src/test/java/org/owasp/esapi/reference/TestTrace.java
@@ -8,15 +8,15 @@ import junit.framework.TestCase;
  * @author August Detlefsen (augustd at codemagi dot com)
  *         <a href="http://www.codemagi.com">CodeMagi, Inc.</a>
  * @since October 15, 2010
- * @see org.owasp.esapi.logging.log4j.Log4JLoggerTest
+ * @see org.owasp.esapi.logging.java.JavaLoggerTest
  */
 public class TestTrace extends TestCase {
 
-	/**
-	 * Dummy method so that JUnit won't complain
-	 */
-	public void testLogging() {
+    /**
+     * Dummy method so that JUnit won't complain
+     */
+    public void testLogging() {
 
-	}
+    }
 
 }
diff --git a/src/test/java/org/owasp/esapi/reference/TestUnspecified.java b/src/test/java/org/owasp/esapi/reference/TestUnspecified.java
index 8f0979d..c8c9c26 100644
--- a/src/test/java/org/owasp/esapi/reference/TestUnspecified.java
+++ b/src/test/java/org/owasp/esapi/reference/TestUnspecified.java
@@ -8,15 +8,15 @@ import junit.framework.TestCase;
  * @author August Detlefsen (augustd at codemagi dot com)
  *         <a href="http://www.codemagi.com">CodeMagi, Inc.</a>
  * @since October 15, 2010
- * @see org.owasp.esapi.logging.log4j.Log4JLoggerTest
+ * @see org.owasp.esapi.logging.java.JavaLoggerTest
  */
 public class TestUnspecified extends TestCase {
 
-	/**
-	 * Dummy method so that JUnit won't complain
-	 */
-	public void testLogging() {
+    /**
+     * Dummy method so that JUnit won't complain
+     */
+    public void testLogging() {
 
-	}
+    }
 
 }
diff --git a/src/test/java/org/owasp/esapi/reference/TestWarning.java b/src/test/java/org/owasp/esapi/reference/TestWarning.java
index 5536460..0d80c1c 100644
--- a/src/test/java/org/owasp/esapi/reference/TestWarning.java
+++ b/src/test/java/org/owasp/esapi/reference/TestWarning.java
@@ -8,15 +8,15 @@ import junit.framework.TestCase;
  * @author August Detlefsen (augustd at codemagi dot com)
  *         <a href="http://www.codemagi.com">CodeMagi, Inc.</a>
  * @since October 15, 2010
- * @see org.owasp.esapi.logging.log4j.Log4JLoggerTest
+ * @see org.owasp.esapi.logging.java.JavaLoggerTest
  */
 public class TestWarning extends TestCase {
 
-	/**
-	 * Dummy method so that JUnit won't complain
-	 */
-	public void testLogging() {
+    /**
+     * Dummy method so that JUnit won't complain
+     */
+    public void testLogging() {
 
-	}
+    }
 
 }
diff --git a/src/test/java/org/owasp/esapi/reference/UnitTestSecurityConfiguration.java b/src/test/java/org/owasp/esapi/reference/UnitTestSecurityConfiguration.java
index cc0f2ef..b44bd53 100644
--- a/src/test/java/org/owasp/esapi/reference/UnitTestSecurityConfiguration.java
+++ b/src/test/java/org/owasp/esapi/reference/UnitTestSecurityConfiguration.java
@@ -6,47 +6,47 @@ public class UnitTestSecurityConfiguration extends DefaultSecurityConfiguration
     }
 
     public void setApplicationName(String v) {
-    	getESAPIProperties().setProperty(APPLICATION_NAME, v);
+        getESAPIProperties().setProperty(APPLICATION_NAME, v);
     }
 
     public void setLogImplementation(String v) {
-    	getESAPIProperties().setProperty(LOG_IMPLEMENTATION, v);
+        getESAPIProperties().setProperty(LOG_IMPLEMENTATION, v);
     }
 
     public void setAuthenticationImplementation(String v) {
-    	getESAPIProperties().setProperty(AUTHENTICATION_IMPLEMENTATION, v);
+        getESAPIProperties().setProperty(AUTHENTICATION_IMPLEMENTATION, v);
     }
 
     public void setEncoderImplementation(String v) {
-    	getESAPIProperties().setProperty(ENCODER_IMPLEMENTATION, v);
+        getESAPIProperties().setProperty(ENCODER_IMPLEMENTATION, v);
     }
 
     public void setAccessControlImplementation(String v) {
-    	getESAPIProperties().setProperty(ACCESS_CONTROL_IMPLEMENTATION, v);
+        getESAPIProperties().setProperty(ACCESS_CONTROL_IMPLEMENTATION, v);
     }
 
     public void setEncryptionImplementation(String v) {
-    	getESAPIProperties().setProperty(ENCRYPTION_IMPLEMENTATION, v);
+        getESAPIProperties().setProperty(ENCRYPTION_IMPLEMENTATION, v);
     }
 
     public void setIntrusionDetectionImplementation(String v) {
-    	getESAPIProperties().setProperty(INTRUSION_DETECTION_IMPLEMENTATION, v);
+        getESAPIProperties().setProperty(INTRUSION_DETECTION_IMPLEMENTATION, v);
     }
 
     public void setRandomizerImplementation(String v) {
-    	getESAPIProperties().setProperty(RANDOMIZER_IMPLEMENTATION, v);
+        getESAPIProperties().setProperty(RANDOMIZER_IMPLEMENTATION, v);
     }
 
     public void setExecutorImplementation(String v) {
-    	getESAPIProperties().setProperty(EXECUTOR_IMPLEMENTATION, v);
+        getESAPIProperties().setProperty(EXECUTOR_IMPLEMENTATION, v);
     }
 
     public void setHTTPUtilitiesImplementation(String v) {
-    	getESAPIProperties().setProperty(HTTP_UTILITIES_IMPLEMENTATION, v);
+        getESAPIProperties().setProperty(HTTP_UTILITIES_IMPLEMENTATION, v);
     }
 
     public void setValidationImplementation(String v) {
-    	getESAPIProperties().setProperty(VALIDATOR_IMPLEMENTATION, v);
+        getESAPIProperties().setProperty(VALIDATOR_IMPLEMENTATION, v);
     }
 
 }
diff --git a/src/test/java/org/owasp/esapi/reference/UserTest.java b/src/test/java/org/owasp/esapi/reference/UserTest.java
index e091526..2a95a41 100644
--- a/src/test/java/org/owasp/esapi/reference/UserTest.java
+++ b/src/test/java/org/owasp/esapi/reference/UserTest.java
@@ -1,15 +1,15 @@
 /**
  * OWASP Enterprise Security API (ESAPI)
- * 
+ *
  * This file is part of the Open Web Application Security Project (OWASP)
  * Enterprise Security API (ESAPI) project. For details, please see
  * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
  *
  * Copyright (c) 2007 - The OWASP Foundation
- * 
+ *
  * The ESAPI is published by OWASP under the BSD license. You should read and accept the
  * LICENSE before you use, modify, and/or redistribute this software.
- * 
+ *
  * @author Jeff Williams <a href="http://www.aspectsecurity.com">Aspect Security</a>
  * @created 2007
  */
@@ -38,330 +38,330 @@ import org.owasp.esapi.http.MockHttpSession;
 
 /**
  * The Class UserTest.
- * 
+ *
  * @author Jeff Williams (jeff.williams@aspectsecurity.com)
  */
 public class UserTest extends TestCase {
 
-	/**
-	 * Suite.
-	 * 
-	 * @return the test
-	 */
-	public static Test suite() {
-		TestSuite suite = new TestSuite(UserTest.class);
-		return suite;
-	}
-	
-	/**
-	 * Instantiates a new user test.
-	 * 
-	 * @param testName
-	 *            the test name
-	 */
-	public UserTest(String testName) {
-		super(testName);
-	}
-
-	/**
-	 * Creates the test user.
-	 * 
-	 * @param password
-	 *            the password
-	 * 
-	 * @return the user
-	 * 
-	 * @throws AuthenticationException
-	 *             the authentication exception
-	 */
-	private DefaultUser createTestUser(String password) throws AuthenticationException {
-		String username = ESAPI.randomizer().getRandomString(8, EncoderConstants.CHAR_ALPHANUMERICS);
-		Exception e = new Exception();
-		System.out.println("Creating user " + username + " for " + e.getStackTrace()[1].getMethodName());
-		DefaultUser user = (DefaultUser) ESAPI.authenticator().createUser(username, password, password);
-		return user;
-	}
-
-	/**
+    /**
+     * Suite.
+     *
+     * @return the test
+     */
+    public static Test suite() {
+        TestSuite suite = new TestSuite(UserTest.class);
+        return suite;
+    }
+
+    /**
+     * Instantiates a new user test.
+     *
+     * @param testName
+     *            the test name
+     */
+    public UserTest(String testName) {
+        super(testName);
+    }
+
+    /**
+     * Creates the test user.
+     *
+     * @param password
+     *            the password
+     *
+     * @return the user
+     *
+     * @throws AuthenticationException
+     *             the authentication exception
+     */
+    private DefaultUser createTestUser(String password) throws AuthenticationException {
+        String username = ESAPI.randomizer().getRandomString(8, EncoderConstants.CHAR_ALPHANUMERICS);
+        Exception e = new Exception();
+        System.out.println("Creating user " + username + " for " + e.getStackTrace()[1].getMethodName());
+        DefaultUser user = (DefaultUser) ESAPI.authenticator().createUser(username, password, password);
+        return user;
+    }
+
+    /**
      * {@inheritDoc}
      *
      * @throws Exception
      */
-	protected void setUp() throws Exception {
-		// none
-	}
+    protected void setUp() throws Exception {
+        // none
+    }
 
-	/**
+    /**
      * {@inheritDoc}
      *
      * @throws Exception
      */
-	protected void tearDown() throws Exception {
-		// none
-	}
-
-	/**
-	 * Test of testAddRole method, of class org.owasp.esapi.User.
-	 * 
-	 * @exception Exception
-	 * 				any Exception thrown by testing addRole()
-	 */
-	public void testAddRole() throws Exception {
-		System.out.println("addRole");
-		Authenticator instance = ESAPI.authenticator();
-		String accountName = ESAPI.randomizer().getRandomString(8, EncoderConstants.CHAR_ALPHANUMERICS);
-		String password = ESAPI.authenticator().generateStrongPassword();
-		String role = ESAPI.randomizer().getRandomString(8, EncoderConstants.CHAR_LOWERS);
-		User user = instance.createUser(accountName, password, password);
-		user.addRole(role);
-		assertTrue(user.isInRole(role));
-		assertFalse(user.isInRole("ridiculous"));
-	}
-
-	/**
-	 * Test of addRoles method, of class org.owasp.esapi.User.
-	 * 
-	 * @throws AuthenticationException
-	 *             the authentication exception
-	 */
-	public void testAddRoles() throws AuthenticationException {
-		System.out.println("addRoles");
-		Authenticator instance = ESAPI.authenticator();
-		String oldPassword = instance.generateStrongPassword();
-		DefaultUser user = createTestUser(oldPassword);
-		Set set = new HashSet();
-		set.add("rolea");
-		set.add("roleb");
-		user.addRoles(set);
-		assertTrue(user.isInRole("rolea"));
-		assertTrue(user.isInRole("roleb"));
-		assertFalse(user.isInRole("ridiculous"));
-	}
-
-	/**
-	 * Test of changePassword method, of class org.owasp.esapi.User.
-	 * 
-	 * @throws Exception
-	 *             the exception
-	 */
-	public void testChangePassword() throws Exception {
-		System.out.println("changePassword");
-		Authenticator instance = ESAPI.authenticator();
-		String oldPassword = "Password12!@";
-		DefaultUser user = createTestUser(oldPassword);
-		System.out.println("Hash of " + oldPassword + " = " + ((FileBasedAuthenticator)instance).getHashedPassword(user));
-		String password1 = "SomethingElse34#$";
-		user.changePassword(oldPassword, password1, password1);
-		System.out.println("Hash of " + password1 + " = " + ((FileBasedAuthenticator)instance).getHashedPassword(user));
-		assertTrue(user.verifyPassword(password1));
-		String password2 = "YetAnother56%^";
-		user.changePassword(password1, password2, password2);
-		System.out.println("Hash of " + password2 + " = " + ((FileBasedAuthenticator)instance).getHashedPassword(user));
-		try {
-			user.changePassword(password2, password1, password1);
-			fail("Shouldn't be able to reuse a password");
-		} catch( AuthenticationException e ) {
-			// expected
-		}
-		try {
-			// Test for GitHub issue 288; note that GitHub issue 287
-			// needed fixed first, because that's what made the password
-			// history work!
-			user.changePassword(password2, oldPassword, oldPassword);
-			fail("Shouldn't be able to reuse original (initial) password.");
-		} catch( AuthenticationException e ) {
-			// expected
-		}
-		assertTrue(user.verifyPassword(password2));
-		assertFalse(user.verifyPassword("badpass"));
-	}
-
-	/**
-	 * Test of disable method, of class org.owasp.esapi.User.
-	 * 
-	 * @throws AuthenticationException
-	 *             the authentication exception
-	 */
-	public void testDisable() throws AuthenticationException {
-		System.out.println("disable");
-		Authenticator instance = ESAPI.authenticator();
-		String oldPassword = instance.generateStrongPassword();
-		DefaultUser user = createTestUser(oldPassword);
-		user.enable();
-		assertTrue(user.isEnabled());
-		user.disable();
-		assertFalse(user.isEnabled());
-	}
-
-	/**
-	 * Test of enable method, of class org.owasp.esapi.User.
-	 * 
-	 * @throws AuthenticationException
-	 *             the authentication exception
-	 */
-	public void testEnable() throws AuthenticationException {
-		System.out.println("enable");
-		Authenticator instance = ESAPI.authenticator();
-		String oldPassword = instance.generateStrongPassword();
-		DefaultUser user = createTestUser(oldPassword);
-		user.enable();
-		assertTrue(user.isEnabled());
-		user.disable();
-		assertFalse(user.isEnabled());
-	}
-
-	/**
-	 * Test of failedLoginCount lockout, of class org.owasp.esapi.User.
-	 * 
-	 * @throws AuthenticationException
-	 *             the authentication exception
-	 * @throws EncryptionException
-	 *             any EncryptionExceptions thrown by testing failedLoginLockout()
-	 */
-	public void testFailedLoginLockout() throws AuthenticationException, EncryptionException {
-		System.out.println("failedLoginLockout");
-		DefaultUser user = createTestUser("failedLoginLockout");
-		user.enable();
-		MockHttpServletRequest request = new MockHttpServletRequest();
-		MockHttpServletResponse response = new MockHttpServletResponse();
-		ESAPI.httpUtilities().setCurrentHTTP(request, response);
-        
-		user.loginWithPassword("failedLoginLockout");
-		
-		try {
-    		user.loginWithPassword("ridiculous");
-		} catch( AuthenticationException e ) { 
-    		// expected
-    	}
- 		System.out.println("FAILED: " + user.getFailedLoginCount());
-		assertFalse(user.isLocked());
-
-		try {
-    		user.loginWithPassword("ridiculous");
-		} catch( AuthenticationException e ) { 
-    		// expected
-    	}
-		System.out.println("FAILED: " + user.getFailedLoginCount());
-		assertFalse(user.isLocked());
-
-		try {
-    		user.loginWithPassword("ridiculous");
-		} catch( AuthenticationException e ) { 
-    		// expected
-    	}
-		System.out.println("FAILED: " + user.getFailedLoginCount());
-		assertTrue(user.isLocked());
-	}
-
-	/**
-	 * Test of getAccountName method, of class org.owasp.esapi.User.
-	 * 
-	 * @throws AuthenticationException
-	 *             the authentication exception
-	 */
-	public void testGetAccountName() throws AuthenticationException {
-		System.out.println("getAccountName");
-		DefaultUser user = createTestUser("getAccountName");
-		String accountName = ESAPI.randomizer().getRandomString(7, EncoderConstants.CHAR_ALPHANUMERICS);
-		user.setAccountName(accountName);
-		assertEquals(accountName.toLowerCase(), user.getAccountName());
-		assertFalse("ridiculous".equals(user.getAccountName()));
-	}
-
-	/**
-	 * Test get last failed login time.
-	 * 
-	 * @throws Exception
-	 *             the exception
-	 */
-	public void testGetLastFailedLoginTime() throws Exception {
-		System.out.println("getLastLoginTime");
-		Authenticator instance = ESAPI.authenticator();
-		String oldPassword = instance.generateStrongPassword();
-		DefaultUser user = createTestUser(oldPassword);
-		try {
-    		user.loginWithPassword("ridiculous");
-		} catch( AuthenticationException e ) { 
-    		// expected
-    	}
-		Date llt1 = user.getLastFailedLoginTime();
-		Thread.sleep(100); // need a short delay to separate attempts
-		try {
-    		user.loginWithPassword("ridiculous");
-		} catch( AuthenticationException e ) { 
-    		// expected
-    	}
-		Date llt2 = user.getLastFailedLoginTime();
-		assertTrue(llt1.before(llt2));
-	}
-
-	/**
-	 * Test get last login time.
-	 * 
-	 * @throws Exception
-	 *             the exception
-	 */
-	public void testGetLastLoginTime() throws Exception {
-		System.out.println("getLastLoginTime");
-		Authenticator instance = ESAPI.authenticator();
-		String oldPassword = instance.generateStrongPassword();
-		DefaultUser user = createTestUser(oldPassword);
-		user.verifyPassword(oldPassword);
-		Date llt1 = user.getLastLoginTime();
-		Thread.sleep(10); // need a short delay to separate attempts
-		user.verifyPassword(oldPassword);
-		Date llt2 = user.getLastLoginTime();
-		assertTrue(llt1.before(llt2));
-	}
-
-	/**
-	 * Test getLastPasswordChangeTime method, of class org.owasp.esapi.User.
-	 * 
-	 * @throws Exception
-	 *             the exception
-	 */
-	public void testGetLastPasswordChangeTime() throws Exception {
-		System.out.println("getLastPasswordChangeTime");
-		DefaultUser user = createTestUser("getLastPasswordChangeTime");
-		Date t1 = user.getLastPasswordChangeTime();
-		Thread.sleep(10); // need a short delay to separate attempts
-		String newPassword = ESAPI.authenticator().generateStrongPassword(user, "getLastPasswordChangeTime");
-		user.changePassword("getLastPasswordChangeTime", newPassword, newPassword);
-		Date t2 = user.getLastPasswordChangeTime();
-		assertTrue(t2.after(t1));
-	}
-
-	/**
-	 * Test of getRoles method, of class org.owasp.esapi.User.
+    protected void tearDown() throws Exception {
+        // none
+    }
+
+    /**
+     * Test of testAddRole method, of class org.owasp.esapi.User.
+     *
+     * @exception Exception
+     *                 any Exception thrown by testing addRole()
+     */
+    public void testAddRole() throws Exception {
+        System.out.println("addRole");
+        Authenticator instance = ESAPI.authenticator();
+        String accountName = ESAPI.randomizer().getRandomString(8, EncoderConstants.CHAR_ALPHANUMERICS);
+        String password = ESAPI.authenticator().generateStrongPassword();
+        String role = ESAPI.randomizer().getRandomString(8, EncoderConstants.CHAR_LOWERS);
+        User user = instance.createUser(accountName, password, password);
+        user.addRole(role);
+        assertTrue(user.isInRole(role));
+        assertFalse(user.isInRole("ridiculous"));
+    }
+
+    /**
+     * Test of addRoles method, of class org.owasp.esapi.User.
+     *
+     * @throws AuthenticationException
+     *             the authentication exception
+     */
+    public void testAddRoles() throws AuthenticationException {
+        System.out.println("addRoles");
+        Authenticator instance = ESAPI.authenticator();
+        String oldPassword = instance.generateStrongPassword();
+        DefaultUser user = createTestUser(oldPassword);
+        Set set = new HashSet();
+        set.add("rolea");
+        set.add("roleb");
+        user.addRoles(set);
+        assertTrue(user.isInRole("rolea"));
+        assertTrue(user.isInRole("roleb"));
+        assertFalse(user.isInRole("ridiculous"));
+    }
+
+    /**
+     * Test of changePassword method, of class org.owasp.esapi.User.
+     *
+     * @throws Exception
+     *             the exception
+     */
+    public void testChangePassword() throws Exception {
+        System.out.println("changePassword");
+        Authenticator instance = ESAPI.authenticator();
+        String oldPassword = "Password12!@";
+        DefaultUser user = createTestUser(oldPassword);
+        System.out.println("Hash of " + oldPassword + " = " + ((FileBasedAuthenticator)instance).getHashedPassword(user));
+        String password1 = "SomethingElse34#$";
+        user.changePassword(oldPassword, password1, password1);
+        System.out.println("Hash of " + password1 + " = " + ((FileBasedAuthenticator)instance).getHashedPassword(user));
+        assertTrue(user.verifyPassword(password1));
+        String password2 = "YetAnother56%^";
+        user.changePassword(password1, password2, password2);
+        System.out.println("Hash of " + password2 + " = " + ((FileBasedAuthenticator)instance).getHashedPassword(user));
+        try {
+            user.changePassword(password2, password1, password1);
+            fail("Shouldn't be able to reuse a password");
+        } catch( AuthenticationException e ) {
+            // expected
+        }
+        try {
+            // Test for GitHub issue 288; note that GitHub issue 287
+            // needed fixed first, because that's what made the password
+            // history work!
+            user.changePassword(password2, oldPassword, oldPassword);
+            fail("Shouldn't be able to reuse original (initial) password.");
+        } catch( AuthenticationException e ) {
+            // expected
+        }
+        assertTrue(user.verifyPassword(password2));
+        assertFalse(user.verifyPassword("badpass"));
+    }
+
+    /**
+     * Test of disable method, of class org.owasp.esapi.User.
+     *
+     * @throws AuthenticationException
+     *             the authentication exception
+     */
+    public void testDisable() throws AuthenticationException {
+        System.out.println("disable");
+        Authenticator instance = ESAPI.authenticator();
+        String oldPassword = instance.generateStrongPassword();
+        DefaultUser user = createTestUser(oldPassword);
+        user.enable();
+        assertTrue(user.isEnabled());
+        user.disable();
+        assertFalse(user.isEnabled());
+    }
+
+    /**
+     * Test of enable method, of class org.owasp.esapi.User.
+     *
+     * @throws AuthenticationException
+     *             the authentication exception
+     */
+    public void testEnable() throws AuthenticationException {
+        System.out.println("enable");
+        Authenticator instance = ESAPI.authenticator();
+        String oldPassword = instance.generateStrongPassword();
+        DefaultUser user = createTestUser(oldPassword);
+        user.enable();
+        assertTrue(user.isEnabled());
+        user.disable();
+        assertFalse(user.isEnabled());
+    }
+
+    /**
+     * Test of failedLoginCount lockout, of class org.owasp.esapi.User.
+     *
+     * @throws AuthenticationException
+     *             the authentication exception
+     * @throws EncryptionException
+     *             any EncryptionExceptions thrown by testing failedLoginLockout()
+     */
+    public void testFailedLoginLockout() throws AuthenticationException, EncryptionException {
+        System.out.println("failedLoginLockout");
+        DefaultUser user = createTestUser("failedLoginLockout");
+        user.enable();
+        MockHttpServletRequest request = new MockHttpServletRequest();
+        MockHttpServletResponse response = new MockHttpServletResponse();
+        ESAPI.httpUtilities().setCurrentHTTP(request, response);
+
+        user.loginWithPassword("failedLoginLockout");
+
+        try {
+            user.loginWithPassword("ridiculous");
+        } catch( AuthenticationException e ) {
+            // expected
+        }
+         System.out.println("FAILED: " + user.getFailedLoginCount());
+        assertFalse(user.isLocked());
+
+        try {
+            user.loginWithPassword("ridiculous");
+        } catch( AuthenticationException e ) {
+            // expected
+        }
+        System.out.println("FAILED: " + user.getFailedLoginCount());
+        assertFalse(user.isLocked());
+
+        try {
+            user.loginWithPassword("ridiculous");
+        } catch( AuthenticationException e ) {
+            // expected
+        }
+        System.out.println("FAILED: " + user.getFailedLoginCount());
+        assertTrue(user.isLocked());
+    }
+
+    /**
+     * Test of getAccountName method, of class org.owasp.esapi.User.
+     *
+     * @throws AuthenticationException
+     *             the authentication exception
+     */
+    public void testGetAccountName() throws AuthenticationException {
+        System.out.println("getAccountName");
+        DefaultUser user = createTestUser("getAccountName");
+        String accountName = ESAPI.randomizer().getRandomString(7, EncoderConstants.CHAR_ALPHANUMERICS);
+        user.setAccountName(accountName);
+        assertEquals(accountName.toLowerCase(), user.getAccountName());
+        assertFalse("ridiculous".equals(user.getAccountName()));
+    }
+
+    /**
+     * Test get last failed login time.
+     *
+     * @throws Exception
+     *             the exception
+     */
+    public void testGetLastFailedLoginTime() throws Exception {
+        System.out.println("getLastLoginTime");
+        Authenticator instance = ESAPI.authenticator();
+        String oldPassword = instance.generateStrongPassword();
+        DefaultUser user = createTestUser(oldPassword);
+        try {
+            user.loginWithPassword("ridiculous");
+        } catch( AuthenticationException e ) {
+            // expected
+        }
+        Date llt1 = user.getLastFailedLoginTime();
+        Thread.sleep(100); // need a short delay to separate attempts
+        try {
+            user.loginWithPassword("ridiculous");
+        } catch( AuthenticationException e ) {
+            // expected
+        }
+        Date llt2 = user.getLastFailedLoginTime();
+        assertTrue(llt1.before(llt2));
+    }
+
+    /**
+     * Test get last login time.
+     *
+     * @throws Exception
+     *             the exception
+     */
+    public void testGetLastLoginTime() throws Exception {
+        System.out.println("getLastLoginTime");
+        Authenticator instance = ESAPI.authenticator();
+        String oldPassword = instance.generateStrongPassword();
+        DefaultUser user = createTestUser(oldPassword);
+        user.verifyPassword(oldPassword);
+        Date llt1 = user.getLastLoginTime();
+        Thread.sleep(10); // need a short delay to separate attempts
+        user.verifyPassword(oldPassword);
+        Date llt2 = user.getLastLoginTime();
+        assertTrue(llt1.before(llt2));
+    }
+
+    /**
+     * Test getLastPasswordChangeTime method, of class org.owasp.esapi.User.
+     *
+     * @throws Exception
+     *             the exception
+     */
+    public void testGetLastPasswordChangeTime() throws Exception {
+        System.out.println("getLastPasswordChangeTime");
+        DefaultUser user = createTestUser("getLastPasswordChangeTime");
+        Date t1 = user.getLastPasswordChangeTime();
+        Thread.sleep(10); // need a short delay to separate attempts
+        String newPassword = ESAPI.authenticator().generateStrongPassword(user, "getLastPasswordChangeTime");
+        user.changePassword("getLastPasswordChangeTime", newPassword, newPassword);
+        Date t2 = user.getLastPasswordChangeTime();
+        assertTrue(t2.after(t1));
+    }
+
+    /**
+     * Test of getRoles method, of class org.owasp.esapi.User.
      *
      * @throws Exception
      */
-	public void testGetRoles() throws Exception {
-		System.out.println("getRoles");
-		Authenticator instance = ESAPI.authenticator();
-		String accountName = ESAPI.randomizer().getRandomString(8, EncoderConstants.CHAR_ALPHANUMERICS);
-		String password = ESAPI.authenticator().generateStrongPassword();
-		String role = ESAPI.randomizer().getRandomString(8, EncoderConstants.CHAR_LOWERS);
-		User user = instance.createUser(accountName, password, password);
-		user.addRole(role);
-		Set roles = user.getRoles();
-		assertTrue(roles.size() > 0);
-	}
-
-	/**
-	 * Test of getScreenName method, of class org.owasp.esapi.User.
-	 * 
-	 * @throws AuthenticationException
-	 *             the authentication exception
-	 */
-	public void testGetScreenName() throws AuthenticationException {
-		System.out.println("getScreenName");
-		DefaultUser user = createTestUser("getScreenName");
-		String screenName = ESAPI.randomizer().getRandomString(7, EncoderConstants.CHAR_ALPHANUMERICS);
-		user.setScreenName(screenName);
-		assertEquals(screenName, user.getScreenName());
-		assertFalse("ridiculous".equals(user.getScreenName()));
-	}
+    public void testGetRoles() throws Exception {
+        System.out.println("getRoles");
+        Authenticator instance = ESAPI.authenticator();
+        String accountName = ESAPI.randomizer().getRandomString(8, EncoderConstants.CHAR_ALPHANUMERICS);
+        String password = ESAPI.authenticator().generateStrongPassword();
+        String role = ESAPI.randomizer().getRandomString(8, EncoderConstants.CHAR_LOWERS);
+        User user = instance.createUser(accountName, password, password);
+        user.addRole(role);
+        Set roles = user.getRoles();
+        assertTrue(roles.size() > 0);
+    }
+
+    /**
+     * Test of getScreenName method, of class org.owasp.esapi.User.
+     *
+     * @throws AuthenticationException
+     *             the authentication exception
+     */
+    public void testGetScreenName() throws AuthenticationException {
+        System.out.println("getScreenName");
+        DefaultUser user = createTestUser("getScreenName");
+        String screenName = ESAPI.randomizer().getRandomString(7, EncoderConstants.CHAR_ALPHANUMERICS);
+        user.setScreenName(screenName);
+        assertEquals(screenName, user.getScreenName());
+        assertFalse("ridiculous".equals(user.getScreenName()));
+    }
 
     /**
      *
@@ -386,363 +386,363 @@ public class UserTest extends TestCase {
             System.out.println( ">>>" + s.getId() );
         }
         assertTrue(sessions.size() == 3);
-	}
-	
-	
+    }
+
+
     /**
      *
      */
     public void testAddSession() {
-	    // TODO
-	}
-	
+        // TODO
+    }
+
     /**
      *
      */
     public void testRemoveSession() {
-	    // TODO
-	}
-	
-	/**
-	 * Test of incrementFailedLoginCount method, of class org.owasp.esapi.User.
-	 * 
-	 * @throws AuthenticationException
-	 *             the authentication exception
-	 */
-	public void testIncrementFailedLoginCount() throws AuthenticationException {
-		System.out.println("incrementFailedLoginCount");
-		DefaultUser user = createTestUser("incrementFailedLoginCount");
-		user.enable();
-		assertEquals(0, user.getFailedLoginCount());
-		MockHttpServletRequest request = new MockHttpServletRequest();
-		MockHttpServletResponse response = new MockHttpServletResponse();
-		ESAPI.httpUtilities().setCurrentHTTP(request, response);
-		try {
-			user.loginWithPassword("ridiculous");
-		} catch (AuthenticationException e) {
-			// expected
-		}
-		assertEquals(1, user.getFailedLoginCount());
-		try {
-			user.loginWithPassword("ridiculous");
-		} catch (AuthenticationException e) {
-			// expected
-		}
-		assertEquals(2, user.getFailedLoginCount());
-		try {
-			user.loginWithPassword("ridiculous");
-		} catch (AuthenticationException e) {
-			// expected
-		}
-		assertEquals(3, user.getFailedLoginCount());
-		try {
-			user.loginWithPassword("ridiculous");
-		} catch (AuthenticationException e) {
-			// expected
-		}
-		assertTrue(user.isLocked());
-	}
-
-	/**
-	 * Test of isEnabled method, of class org.owasp.esapi.User.
-	 * 
-	 * @throws AuthenticationException
-	 *             the authentication exception
-	 */
-	public void testIsEnabled() throws AuthenticationException {
-		System.out.println("isEnabled");
-		DefaultUser user = createTestUser("isEnabled");
-		user.disable();
-		assertFalse(user.isEnabled());
-		user.enable();
-		assertTrue(user.isEnabled());
-	}
-
-    
-    
-	/**
-	 * Test of isInRole method, of class org.owasp.esapi.User.
-	 * 
-	 * @throws AuthenticationException
-	 *             the authentication exception
-	 */
-	public void testIsInRole() throws AuthenticationException {
-		System.out.println("isInRole");
-		DefaultUser user = createTestUser("isInRole");
-		String role = "TestRole";
-		assertFalse(user.isInRole(role));
-		user.addRole(role);
-		assertTrue(user.isInRole(role));
-		assertFalse(user.isInRole("Ridiculous"));
-	}
-
-	/**
-	 * Test of isLocked method, of class org.owasp.esapi.User.
-	 * 
-	 * @throws AuthenticationException
-	 *             the authentication exception
-	 */
-	public void testIsLocked() throws AuthenticationException {
-		System.out.println("isLocked");
-		DefaultUser user = createTestUser("isLocked");
-		user.lock();
-		assertTrue(user.isLocked());
-		user.unlock();
-		assertFalse(user.isLocked());
-	}
-
-	/**
-	 * Test of isSessionAbsoluteTimeout method, of class
-	 * org.owasp.esapi.IntrusionDetector.
-	 * 
-	 * @throws AuthenticationException
-	 *             the authentication exception
-	 */
-	public void testIsSessionAbsoluteTimeout() throws AuthenticationException {
-		System.out.println("isSessionAbsoluteTimeout");
-		Authenticator instance = ESAPI.authenticator();
-		String oldPassword = instance.generateStrongPassword();
-		DefaultUser user = createTestUser(oldPassword);
-		long now = System.currentTimeMillis();
-		// setup request and response
-		MockHttpServletRequest request = new MockHttpServletRequest();
-		MockHttpServletResponse response = new MockHttpServletResponse();
-		ESAPI.httpUtilities().setCurrentHTTP(request, response);
-		MockHttpSession session = (MockHttpSession)request.getSession();
-				
-		// set session creation -3 hours (default is 2 hour timeout)		
-		session.setCreationTime( now - (1000 * 60 * 60 * 3) );
-		assertTrue(user.isSessionAbsoluteTimeout());
-		
-		// set session creation -1 hour (default is 2 hour timeout)
-		session.setCreationTime( now - (1000 * 60 * 60 * 1) );
-		assertFalse(user.isSessionAbsoluteTimeout());
-	}
-
-	/**
-	 * Test of isSessionTimeout method, of class
-	 * org.owasp.esapi.IntrusionDetector.
-	 * 
-	 * @throws AuthenticationException
-	 *             the authentication exception
-	 */
-	public void testIsSessionTimeout() throws AuthenticationException {
-		System.out.println("isSessionTimeout");
-		Authenticator instance = ESAPI.authenticator();
-		String oldPassword = instance.generateStrongPassword();
-		DefaultUser user = createTestUser(oldPassword);
-		long now = System.currentTimeMillis();
-		// setup request and response
-		MockHttpServletRequest request = new MockHttpServletRequest();
-		MockHttpServletResponse response = new MockHttpServletResponse();
-		ESAPI.httpUtilities().setCurrentHTTP(request, response);
-		MockHttpSession session = (MockHttpSession)request.getSession();
-		
-		// set creation -30 mins (default is 20 min timeout)
-		session.setAccessedTime( now - 1000 * 60 * 30 );
-		assertTrue(user.isSessionTimeout());
-		
-		// set creation -1 hour (default is 20 min timeout)
-		session.setAccessedTime( now - 1000 * 60 * 10 );
-		assertFalse(user.isSessionTimeout());
-	}
-
-	/**
-	 * Test of lockAccount method, of class org.owasp.esapi.User.
-	 * 
-	 * @throws AuthenticationException
-	 *             the authentication exception
-	 */
-	public void testLock() throws AuthenticationException {
-		System.out.println("lock");
-		Authenticator instance = ESAPI.authenticator();
-		String oldPassword = instance.generateStrongPassword();
-		DefaultUser user = createTestUser(oldPassword);
-		user.lock();
-		assertTrue(user.isLocked());
-		user.unlock();
-		assertFalse(user.isLocked());
-	}
-
-	/**
-	 * Test of loginWithPassword method, of class org.owasp.esapi.User.
-	 * 
-	 * @throws AuthenticationException
-	 *             the authentication exception
-	 */
-	public void testLoginWithPassword() throws AuthenticationException {
-		System.out.println("loginWithPassword");
-		MockHttpServletRequest request = new MockHttpServletRequest();
-		MockHttpSession session = (MockHttpSession) request.getSession();
-		assertFalse(session.getInvalidated());
-		DefaultUser user = createTestUser("loginWithPassword");
-		user.enable();
-		user.loginWithPassword("loginWithPassword");
-		assertTrue(user.isLoggedIn());
-		user.logout();
-		assertFalse(user.isLoggedIn());
-		assertFalse(user.isLocked());
-		try {
-			user.loginWithPassword("ridiculous");
-		} catch (AuthenticationException e) {
-			// expected
-		}
-		assertFalse(user.isLoggedIn());
-		try {
-			user.loginWithPassword("ridiculous");
-		} catch (AuthenticationException e) {
-			// expected
-		}
-		try {
-			user.loginWithPassword("ridiculous");
-		} catch (AuthenticationException e) {
-			// expected
-		}
-		assertTrue(user.isLocked());
-		user.unlock();
-		assertTrue(user.getFailedLoginCount() == 0 );
-	}
-
-
-	/**
-	 * Test of logout method, of class org.owasp.esapi.User.
-	 * 
-	 * @throws AuthenticationException
-	 *             the authentication exception
-	 */
-	public void testLogout() throws AuthenticationException {
-		System.out.println("logout");
-		MockHttpServletRequest request = new MockHttpServletRequest();
-		MockHttpServletResponse response = new MockHttpServletResponse();
-		MockHttpSession session = (MockHttpSession) request.getSession();
-		assertFalse(session.getInvalidated());
-		Authenticator instance = ESAPI.authenticator();
-		ESAPI.httpUtilities().setCurrentHTTP(request, response);
-		String oldPassword = instance.generateStrongPassword();
-		DefaultUser user = createTestUser(oldPassword);
-		user.enable();
-		System.out.println(user.getLastLoginTime());
-		user.loginWithPassword(oldPassword);
-		assertTrue(user.isLoggedIn());
-		// get new session after user logs in
-		session = (MockHttpSession) request.getSession();
-		assertFalse(session.getInvalidated());
-		user.logout();
-		assertFalse(user.isLoggedIn());
-		assertTrue(session.getInvalidated());
-	}
-
-	/**
-	 * Test of testRemoveRole method, of class org.owasp.esapi.User.
-	 * 
-	 * @throws AuthenticationException
-	 *             the authentication exception
-	 */
-	public void testRemoveRole() throws AuthenticationException {
-		System.out.println("removeRole");
-		String role = ESAPI.randomizer().getRandomString(8, EncoderConstants.CHAR_LOWERS);
-		DefaultUser user = createTestUser("removeRole");
-		user.addRole(role);
-		assertTrue(user.isInRole(role));
-		user.removeRole(role);
-		assertFalse(user.isInRole(role));
-	}
-
-	/**
-	 * Test of testResetCSRFToken method, of class org.owasp.esapi.User.
-	 * 
-	 * @throws AuthenticationException
-	 *             the authentication exception
-	 */
-	public void testResetCSRFToken() throws AuthenticationException {
-		System.out.println("resetCSRFToken");
-		DefaultUser user = createTestUser("resetCSRFToken");
+        // TODO
+    }
+
+    /**
+     * Test of incrementFailedLoginCount method, of class org.owasp.esapi.User.
+     *
+     * @throws AuthenticationException
+     *             the authentication exception
+     */
+    public void testIncrementFailedLoginCount() throws AuthenticationException {
+        System.out.println("incrementFailedLoginCount");
+        DefaultUser user = createTestUser("incrementFailedLoginCount");
+        user.enable();
+        assertEquals(0, user.getFailedLoginCount());
+        MockHttpServletRequest request = new MockHttpServletRequest();
+        MockHttpServletResponse response = new MockHttpServletResponse();
+        ESAPI.httpUtilities().setCurrentHTTP(request, response);
+        try {
+            user.loginWithPassword("ridiculous");
+        } catch (AuthenticationException e) {
+            // expected
+        }
+        assertEquals(1, user.getFailedLoginCount());
+        try {
+            user.loginWithPassword("ridiculous");
+        } catch (AuthenticationException e) {
+            // expected
+        }
+        assertEquals(2, user.getFailedLoginCount());
+        try {
+            user.loginWithPassword("ridiculous");
+        } catch (AuthenticationException e) {
+            // expected
+        }
+        assertEquals(3, user.getFailedLoginCount());
+        try {
+            user.loginWithPassword("ridiculous");
+        } catch (AuthenticationException e) {
+            // expected
+        }
+        assertTrue(user.isLocked());
+    }
+
+    /**
+     * Test of isEnabled method, of class org.owasp.esapi.User.
+     *
+     * @throws AuthenticationException
+     *             the authentication exception
+     */
+    public void testIsEnabled() throws AuthenticationException {
+        System.out.println("isEnabled");
+        DefaultUser user = createTestUser("isEnabled");
+        user.disable();
+        assertFalse(user.isEnabled());
+        user.enable();
+        assertTrue(user.isEnabled());
+    }
+
+
+
+    /**
+     * Test of isInRole method, of class org.owasp.esapi.User.
+     *
+     * @throws AuthenticationException
+     *             the authentication exception
+     */
+    public void testIsInRole() throws AuthenticationException {
+        System.out.println("isInRole");
+        DefaultUser user = createTestUser("isInRole");
+        String role = "TestRole";
+        assertFalse(user.isInRole(role));
+        user.addRole(role);
+        assertTrue(user.isInRole(role));
+        assertFalse(user.isInRole("Ridiculous"));
+    }
+
+    /**
+     * Test of isLocked method, of class org.owasp.esapi.User.
+     *
+     * @throws AuthenticationException
+     *             the authentication exception
+     */
+    public void testIsLocked() throws AuthenticationException {
+        System.out.println("isLocked");
+        DefaultUser user = createTestUser("isLocked");
+        user.lock();
+        assertTrue(user.isLocked());
+        user.unlock();
+        assertFalse(user.isLocked());
+    }
+
+    /**
+     * Test of isSessionAbsoluteTimeout method, of class
+     * org.owasp.esapi.IntrusionDetector.
+     *
+     * @throws AuthenticationException
+     *             the authentication exception
+     */
+    public void testIsSessionAbsoluteTimeout() throws AuthenticationException {
+        System.out.println("isSessionAbsoluteTimeout");
+        Authenticator instance = ESAPI.authenticator();
+        String oldPassword = instance.generateStrongPassword();
+        DefaultUser user = createTestUser(oldPassword);
+        long now = System.currentTimeMillis();
+        // setup request and response
+        MockHttpServletRequest request = new MockHttpServletRequest();
+        MockHttpServletResponse response = new MockHttpServletResponse();
+        ESAPI.httpUtilities().setCurrentHTTP(request, response);
+        MockHttpSession session = (MockHttpSession)request.getSession();
+
+        // set session creation -3 hours (default is 2 hour timeout)
+        session.setCreationTime( now - (1000 * 60 * 60 * 3) );
+        assertTrue(user.isSessionAbsoluteTimeout());
+
+        // set session creation -1 hour (default is 2 hour timeout)
+        session.setCreationTime( now - (1000 * 60 * 60 * 1) );
+        assertFalse(user.isSessionAbsoluteTimeout());
+    }
+
+    /**
+     * Test of isSessionTimeout method, of class
+     * org.owasp.esapi.IntrusionDetector.
+     *
+     * @throws AuthenticationException
+     *             the authentication exception
+     */
+    public void testIsSessionTimeout() throws AuthenticationException {
+        System.out.println("isSessionTimeout");
+        Authenticator instance = ESAPI.authenticator();
+        String oldPassword = instance.generateStrongPassword();
+        DefaultUser user = createTestUser(oldPassword);
+        long now = System.currentTimeMillis();
+        // setup request and response
+        MockHttpServletRequest request = new MockHttpServletRequest();
+        MockHttpServletResponse response = new MockHttpServletResponse();
+        ESAPI.httpUtilities().setCurrentHTTP(request, response);
+        MockHttpSession session = (MockHttpSession)request.getSession();
+
+        // set creation -30 mins (default is 20 min timeout)
+        session.setAccessedTime( now - 1000 * 60 * 30 );
+        assertTrue(user.isSessionTimeout());
+
+        // set creation -1 hour (default is 20 min timeout)
+        session.setAccessedTime( now - 1000 * 60 * 10 );
+        assertFalse(user.isSessionTimeout());
+    }
+
+    /**
+     * Test of lockAccount method, of class org.owasp.esapi.User.
+     *
+     * @throws AuthenticationException
+     *             the authentication exception
+     */
+    public void testLock() throws AuthenticationException {
+        System.out.println("lock");
+        Authenticator instance = ESAPI.authenticator();
+        String oldPassword = instance.generateStrongPassword();
+        DefaultUser user = createTestUser(oldPassword);
+        user.lock();
+        assertTrue(user.isLocked());
+        user.unlock();
+        assertFalse(user.isLocked());
+    }
+
+    /**
+     * Test of loginWithPassword method, of class org.owasp.esapi.User.
+     *
+     * @throws AuthenticationException
+     *             the authentication exception
+     */
+    public void testLoginWithPassword() throws AuthenticationException {
+        System.out.println("loginWithPassword");
+        MockHttpServletRequest request = new MockHttpServletRequest();
+        MockHttpSession session = (MockHttpSession) request.getSession();
+        assertFalse(session.getInvalidated());
+        DefaultUser user = createTestUser("loginWithPassword");
+        user.enable();
+        user.loginWithPassword("loginWithPassword");
+        assertTrue(user.isLoggedIn());
+        user.logout();
+        assertFalse(user.isLoggedIn());
+        assertFalse(user.isLocked());
+        try {
+            user.loginWithPassword("ridiculous");
+        } catch (AuthenticationException e) {
+            // expected
+        }
+        assertFalse(user.isLoggedIn());
+        try {
+            user.loginWithPassword("ridiculous");
+        } catch (AuthenticationException e) {
+            // expected
+        }
+        try {
+            user.loginWithPassword("ridiculous");
+        } catch (AuthenticationException e) {
+            // expected
+        }
+        assertTrue(user.isLocked());
+        user.unlock();
+        assertTrue(user.getFailedLoginCount() == 0 );
+    }
+
+
+    /**
+     * Test of logout method, of class org.owasp.esapi.User.
+     *
+     * @throws AuthenticationException
+     *             the authentication exception
+     */
+    public void testLogout() throws AuthenticationException {
+        System.out.println("logout");
+        MockHttpServletRequest request = new MockHttpServletRequest();
+        MockHttpServletResponse response = new MockHttpServletResponse();
+        MockHttpSession session = (MockHttpSession) request.getSession();
+        assertFalse(session.getInvalidated());
+        Authenticator instance = ESAPI.authenticator();
+        ESAPI.httpUtilities().setCurrentHTTP(request, response);
+        String oldPassword = instance.generateStrongPassword();
+        DefaultUser user = createTestUser(oldPassword);
+        user.enable();
+        System.out.println(user.getLastLoginTime());
+        user.loginWithPassword(oldPassword);
+        assertTrue(user.isLoggedIn());
+        // get new session after user logs in
+        session = (MockHttpSession) request.getSession();
+        assertFalse(session.getInvalidated());
+        user.logout();
+        assertFalse(user.isLoggedIn());
+        assertTrue(session.getInvalidated());
+    }
+
+    /**
+     * Test of testRemoveRole method, of class org.owasp.esapi.User.
+     *
+     * @throws AuthenticationException
+     *             the authentication exception
+     */
+    public void testRemoveRole() throws AuthenticationException {
+        System.out.println("removeRole");
+        String role = ESAPI.randomizer().getRandomString(8, EncoderConstants.CHAR_LOWERS);
+        DefaultUser user = createTestUser("removeRole");
+        user.addRole(role);
+        assertTrue(user.isInRole(role));
+        user.removeRole(role);
+        assertFalse(user.isInRole(role));
+    }
+
+    /**
+     * Test of testResetCSRFToken method, of class org.owasp.esapi.User.
+     *
+     * @throws AuthenticationException
+     *             the authentication exception
+     */
+    public void testResetCSRFToken() throws AuthenticationException {
+        System.out.println("resetCSRFToken");
+        DefaultUser user = createTestUser("resetCSRFToken");
         String token1 = user.resetCSRFToken();
         String token2 = user.resetCSRFToken();
         assertFalse( token1.equals( token2 ) );
-	}
-	
-	/**
-	 * Test of setAccountName method, of class org.owasp.esapi.User.
+    }
+
+    /**
+     * Test of setAccountName method, of class org.owasp.esapi.User.
      *
      * @throws AuthenticationException
      */
-	public void testSetAccountName() throws AuthenticationException {
-		System.out.println("setAccountName");
-		DefaultUser user = createTestUser("setAccountName");
-		String accountName = ESAPI.randomizer().getRandomString(7, EncoderConstants.CHAR_ALPHANUMERICS);
-		user.setAccountName(accountName);
-		assertEquals(accountName.toLowerCase(), user.getAccountName());
-		assertFalse("ridiculous".equals(user.getAccountName()));
-	}
+    public void testSetAccountName() throws AuthenticationException {
+        System.out.println("setAccountName");
+        DefaultUser user = createTestUser("setAccountName");
+        String accountName = ESAPI.randomizer().getRandomString(7, EncoderConstants.CHAR_ALPHANUMERICS);
+        user.setAccountName(accountName);
+        assertEquals(accountName.toLowerCase(), user.getAccountName());
+        assertFalse("ridiculous".equals(user.getAccountName()));
+    }
 
-	/**
-	 * Test of setExpirationTime method, of class org.owasp.esapi.User.
+    /**
+     * Test of setExpirationTime method, of class org.owasp.esapi.User.
      *
      * @throws Exception
      */
-	public void testSetExpirationTime() throws Exception {
-		Date longAgo = new Date(0);
-		Date now = new Date();
-		assertTrue("new Date(0) returned " + longAgo + " which is considered before new Date() " + now + ". Please report this output to the email list or as a issue", longAgo.before(now));
-		String password=ESAPI.randomizer().getRandomString(8, EncoderConstants.CHAR_ALPHANUMERICS);
-		DefaultUser user = createTestUser(password);
-		user.setExpirationTime(longAgo);
-		assertTrue( user.isExpired() );
-	}
-
-	
-	/**
-	 * Test of setRoles method, of class org.owasp.esapi.User.
-	 * 
-	 * @throws AuthenticationException
-	 *             the authentication exception
-	 */
-	public void testSetRoles() throws AuthenticationException {
-		System.out.println("setRoles");
-		DefaultUser user = createTestUser("setRoles");
-		user.addRole("user");
-		assertTrue(user.isInRole("user"));
-		Set set = new HashSet();
-		set.add("rolea");
-		set.add("roleb");
-		user.setRoles(set);
-		assertFalse(user.isInRole("user"));
-		assertTrue(user.isInRole("rolea"));
-		assertTrue(user.isInRole("roleb"));
-		assertFalse(user.isInRole("ridiculous"));
-	}
-
-	/**
-	 * Test of setScreenName method, of class org.owasp.esapi.User.
-	 * 
-	 * @throws AuthenticationException
-	 *             the authentication exception
-	 */
-	public void testSetScreenName() throws AuthenticationException {
-		System.out.println("setScreenName");
-		DefaultUser user = createTestUser("setScreenName");
-		String screenName = ESAPI.randomizer().getRandomString(7, EncoderConstants.CHAR_ALPHANUMERICS);
-		user.setScreenName(screenName);
-		assertEquals(screenName, user.getScreenName());
-		assertFalse("ridiculous".equals(user.getScreenName()));
-	}
-
-	/**
-	 * Test of unlockAccount method, of class org.owasp.esapi.User.
-	 * 
-	 * @throws AuthenticationException
-	 *             the authentication exception
-	 */
-	public void testUnlock() throws AuthenticationException {
-		System.out.println("unlockAccount");
-		Authenticator instance = ESAPI.authenticator();
-		String oldPassword = instance.generateStrongPassword();
-		DefaultUser user = createTestUser(oldPassword);
-		user.lock();
-		assertTrue(user.isLocked());
-		user.unlock();
-		assertFalse(user.isLocked());
-	}
+    public void testSetExpirationTime() throws Exception {
+        Date longAgo = new Date(0);
+        Date now = new Date();
+        assertTrue("new Date(0) returned " + longAgo + " which is considered before new Date() " + now + ". Please report this output to the email list or as a issue", longAgo.before(now));
+        String password=ESAPI.randomizer().getRandomString(8, EncoderConstants.CHAR_ALPHANUMERICS);
+        DefaultUser user = createTestUser(password);
+        user.setExpirationTime(longAgo);
+        assertTrue( user.isExpired() );
+    }
+
+
+    /**
+     * Test of setRoles method, of class org.owasp.esapi.User.
+     *
+     * @throws AuthenticationException
+     *             the authentication exception
+     */
+    public void testSetRoles() throws AuthenticationException {
+        System.out.println("setRoles");
+        DefaultUser user = createTestUser("setRoles");
+        user.addRole("user");
+        assertTrue(user.isInRole("user"));
+        Set set = new HashSet();
+        set.add("rolea");
+        set.add("roleb");
+        user.setRoles(set);
+        assertFalse(user.isInRole("user"));
+        assertTrue(user.isInRole("rolea"));
+        assertTrue(user.isInRole("roleb"));
+        assertFalse(user.isInRole("ridiculous"));
+    }
+
+    /**
+     * Test of setScreenName method, of class org.owasp.esapi.User.
+     *
+     * @throws AuthenticationException
+     *             the authentication exception
+     */
+    public void testSetScreenName() throws AuthenticationException {
+        System.out.println("setScreenName");
+        DefaultUser user = createTestUser("setScreenName");
+        String screenName = ESAPI.randomizer().getRandomString(7, EncoderConstants.CHAR_ALPHANUMERICS);
+        user.setScreenName(screenName);
+        assertEquals(screenName, user.getScreenName());
+        assertFalse("ridiculous".equals(user.getScreenName()));
+    }
+
+    /**
+     * Test of unlockAccount method, of class org.owasp.esapi.User.
+     *
+     * @throws AuthenticationException
+     *             the authentication exception
+     */
+    public void testUnlock() throws AuthenticationException {
+        System.out.println("unlockAccount");
+        Authenticator instance = ESAPI.authenticator();
+        String oldPassword = instance.generateStrongPassword();
+        DefaultUser user = createTestUser(oldPassword);
+        user.lock();
+        assertTrue(user.isLocked());
+        user.unlock();
+        assertFalse(user.isLocked());
+    }
 
 }
diff --git a/src/test/java/org/owasp/esapi/reference/ValidatorTest.java b/src/test/java/org/owasp/esapi/reference/ValidatorTest.java
index 1e5cfc7..7a530e4 100644
--- a/src/test/java/org/owasp/esapi/reference/ValidatorTest.java
+++ b/src/test/java/org/owasp/esapi/reference/ValidatorTest.java
@@ -61,7 +61,7 @@ import org.owasp.esapi.util.TestUtils;
  * @author Jeff Williams (jeff.williams@aspectsecurity.com)
  */
 public class ValidatorTest {
-	
+
     private static final String PREFERRED_ENCODING = "UTF-8";
 
     @Rule
@@ -77,17 +77,17 @@ public class ValidatorTest {
 
     @Test
     public void testAssertValidFileUpload() {
-        // TODO -		assertValidFileUpload(String, String, String, byte[], int, boolean, ValidationErrorList)
+        // TODO -        assertValidFileUpload(String, String, String, byte[], int, boolean, ValidationErrorList)
     }
 
     @Test
     public void testGetPrintable1() {
-        // TODO -		getValidPrintable(String, char[], int, boolean, ValidationErrorList)
+        // TODO -        getValidPrintable(String, char[], int, boolean, ValidationErrorList)
     }
 
     @Test
     public void testGetPrintable2() {
-        //	 TODO -	getValidPrintable(String, String, int, boolean, ValidationErrorList)
+        //     TODO -    getValidPrintable(String, String, int, boolean, ValidationErrorList)
     }
 
     @Test
@@ -376,7 +376,7 @@ public class ValidatorTest {
             // Unix specific paths should pass
             assertTrue(instance.isValidDirectoryPath("test6", "/", parent, false, errors));         // Root directory
             assertEquals(5, errors.size());
-        	// Note, we used to say that about '/bin', but Ubuntu 20.x
+            // Note, we used to say that about '/bin', but Ubuntu 20.x
             // changed '/bin' to a sym link to 'usr/bin'. We can't use '/etc'
             // because under MacOS, that is a sym link to 'private/etc'.
             assertTrue(instance.isValidDirectoryPath("test7", "/dev", parent, false, errors));      // Always exist directory
@@ -392,7 +392,7 @@ public class ValidatorTest {
         }
     }
 
-    // GitHub issue # xxxx - GHSL-2022-008
+    // GHSL-2022-008 - CVE-2022-23457 - Patched in commit a0d67b7
     @Test
     public void testIsValidDirectoryPathGHSL_POC() throws IOException {
         // Note this uses different 'parent' and 'input' directories that generally don't already
@@ -401,10 +401,10 @@ public class ValidatorTest {
 
         Validator instance = ESAPI.validator();
         ValidationErrorList errors = new ValidationErrorList();
-        
+
         String invalidPath = tempFolder.newFolder("esapi-test2").getAbsolutePath();
         File parent = tempFolder.newFolder("sibling-of-esapi-test2");
-        String validPath = tempFolder.newFolder("sibling-of-esapi-test2", "child").getAbsolutePath();
+        String validPath = tempFolder.newFolder("sibling-of-esapi-test2", "child").getCanonicalPath();
 
         // Before the fix, this incorrectly would return 'true' even though
         // 'esapi-test2' directory clearly was not within the 'esapi-test'
@@ -424,9 +424,9 @@ public class ValidatorTest {
     @Test
     public void testIsValidDouble() {
         // isValidDouble(String, String, double, double, boolean)
-    	Validator instance = ESAPI.validator();
-    	ValidationErrorList errors = new ValidationErrorList();
-    	//testing negative range
+        Validator instance = ESAPI.validator();
+        ValidationErrorList errors = new ValidationErrorList();
+        //testing negative range
         assertFalse(instance.isValidDouble("test1", "-4", 1, 10, false, errors));
         assertEquals(1, errors.size());
         assertTrue(instance.isValidDouble("test2", "-4", -10, 10, false, errors));
@@ -575,7 +575,7 @@ public class ValidatorTest {
         System.err.println(instance.isValidInput("test", "jeff\\WILLIAMS", "HTTPParameterValue", 100, false));;
         assertFalse(instance.isValidInput("test", "jeff^WILLIAMS", "HTTPParameterValue", 100, false));
         assertFalse(instance.isValidInput("test", "jeff\\WILLIAMS", "HTTPParameterValue", 100, false));
-        
+
         assertTrue(instance.isValidInput("test", null, "Email", 100, true));
         assertFalse(instance.isValidInput("test", null, "Email", 100, false));
 
@@ -889,7 +889,7 @@ public class ValidatorTest {
 
     @Test
     public void testIsValidRedirectLocation() {
-        // TODO -		isValidRedirectLocation(String, String, boolean)
+        // TODO -        isValidRedirectLocation(String, String, boolean)
     }
 
     //      Test split out and moved to HTMLValidationRuleLogsTest.java & HTMLValidationRuleThrowsTest.java
@@ -1008,14 +1008,14 @@ public class ValidatorTest {
             assertTrue(safeRequest.getParameter("p" + i).equals(request.getParameter("p" + i)));
         }
         for (int i = 1; i <= 2; i++) {
-        	boolean testResult = false;
-        	try {
-        		testResult = safeRequest.getParameter("f" + i).equals(request.getParameter("f" + i));
-        	} catch (NullPointerException npe) {
-        		//the test is this block SHOULD fail. a NPE is an acceptable failure state
-        		testResult = false; //redundant, just being descriptive here
-        	}
-        	assertFalse(testResult);
+            boolean testResult = false;
+            try {
+                testResult = safeRequest.getParameter("f" + i).equals(request.getParameter("f" + i));
+            } catch (NullPointerException npe) {
+                //the test is this block SHOULD fail. a NPE is an acceptable failure state
+                testResult = false; //redundant, just being descriptive here
+            }
+            assertFalse(testResult);
         }
         assertNull(safeRequest.getParameter("e1"));
 
@@ -1057,13 +1057,13 @@ public class ValidatorTest {
         assertFalse(safeRequest.getHeader("f2").equals(request.getHeader("f2")));
         assertNull(safeRequest.getHeader("p3"));
     }
-    
+
     @Test
     public void testHeaderLengthChecks(){
-    	Validator v = ESAPI.validator();
-    	SecurityConfiguration sc = ESAPI.securityConfiguration();
-    	assertFalse(v.isValidInput("addHeader", TestUtils.generateStringOfLength(257), "HTTPHeaderName", sc.getIntProp("HttpUtilities.MaxHeaderNameSize"), false));
-    	assertFalse(v.isValidInput("addHeader", TestUtils.generateStringOfLength(4097), "HTTPHeaderValue", sc.getIntProp("HttpUtilities.MaxHeaderValueSize"), false));
+        Validator v = ESAPI.validator();
+        SecurityConfiguration sc = ESAPI.securityConfiguration();
+        assertFalse(v.isValidInput("addHeader", TestUtils.generateStringOfLength(257), "HTTPHeaderName", sc.getIntProp("HttpUtilities.MaxHeaderNameSize"), false));
+        assertFalse(v.isValidInput("addHeader", TestUtils.generateStringOfLength(4097), "HTTPHeaderValue", sc.getIntProp("HttpUtilities.MaxHeaderValueSize"), false));
     }
 
     @Test
@@ -1118,44 +1118,44 @@ public class ValidatorTest {
         // Fail-case - URL Splitting
         assertFalse(ESAPI.validator().isValidInput("HTTPContextPath", "/\\nGET http://evil.com", "HTTPContextPath", 512, true));
     }
-    
+
     @Test
     public void testGmailEmailAddress(){
-    	Validator v = ESAPI.validator();
-    	assertTrue(v.isValidInput("Gmail", "Darth+Sidious@gmail.com", "Gmail", 512, false));
-    	assertTrue(v.isValidInput("Gmail", "Darth.Sidious@gmail.com", "Gmail", 512, false));
+        Validator v = ESAPI.validator();
+        assertTrue(v.isValidInput("Gmail", "Darth+Sidious@gmail.com", "Gmail", 512, false));
+        assertTrue(v.isValidInput("Gmail", "Darth.Sidious@gmail.com", "Gmail", 512, false));
     }
-    
+
     @Test
     public void testGetValidUri(){
-    	Validator v = ESAPI.validator();
-    	assertFalse(v.isValidURI("test", "http://core-jenkins.scansafe.cisco.com/佐贺诺伦-^ńörén.jpg", false));
+        Validator v = ESAPI.validator();
+        assertFalse(v.isValidURI("test", "http://core-jenkins.scansafe.cisco.com/佐贺诺伦-^ńörén.jpg", false));
     }
-    
+
     @Test
     public void testGetValidUriNullInput(){
-    	Validator v = ESAPI.validator();
-    	boolean isValid = v.isValidURI("test", null, true);
-    	assertTrue(isValid);
+        Validator v = ESAPI.validator();
+        boolean isValid = v.isValidURI("test", null, true);
+        assertTrue(isValid);
     }
-    
+
     @Test
     public void testRegex(){
-    	Validator v = ESAPI.validator();
-    	boolean isValid = v.isValidInput("RegexString", "%2d%2d%3e%3c%2f%73%43%72%49%70%54%3e%3c%73%43%72%49%70%54%3e%61%6c%65%72%74%28%31%36%35%38%38%29%3c%2f%73%43%72%49%70%54%3e", "RegexString", 30000, true);
-    	assertFalse(isValid);
+        Validator v = ESAPI.validator();
+        boolean isValid = v.isValidInput("RegexString", "%2d%2d%3e%3c%2f%73%43%72%49%70%54%3e%3c%73%43%72%49%70%54%3e%61%6c%65%72%74%28%31%36%35%38%38%29%3c%2f%73%43%72%49%70%54%3e", "RegexString", 30000, true);
+        assertFalse(isValid);
     }
-    
+
     @Test(expected = ValidationException.class)
     public void testRegexWithGetValid() throws IntrusionException, ValidationException {
-    	Validator v = ESAPI.validator();
-    	String foo = v.getValidInput("RegexString", "%2d%2d%3e%3c%2f%73%43%72%49%70%54%3e%3c%73%43%72%49%70%54%3e%61%6c%65%72%74%28%31%36%35%38%38%29%3c%2f%73%43%72%49%70%54%3e", "RegexString", 30000, true);
+        Validator v = ESAPI.validator();
+        String foo = v.getValidInput("RegexString", "%2d%2d%3e%3c%2f%73%43%72%49%70%54%3e%3c%73%43%72%49%70%54%3e%61%6c%65%72%74%28%31%36%35%38%38%29%3c%2f%73%43%72%49%70%54%3e", "RegexString", 30000, true);
     }
-    
+
     @Test
     public void testavaloqLooseSafeString(){
-    	Validator v = ESAPI.validator();
-    	boolean isValid = v.isValidInput("RegexString", "&quot;test&quot;", "avaloqLooseSafeString", 2147483647, true, true);
-    	assertFalse(isValid);
+        Validator v = ESAPI.validator();
+        boolean isValid = v.isValidInput("RegexString", "&quot;test&quot;", "avaloqLooseSafeString", 2147483647, true, true);
+        assertFalse(isValid);
     }
 }
diff --git a/src/test/java/org/owasp/esapi/reference/accesscontrol/AccessControllerTest.java b/src/test/java/org/owasp/esapi/reference/accesscontrol/AccessControllerTest.java
index 7e5c8b7..9c4864c 100644
--- a/src/test/java/org/owasp/esapi/reference/accesscontrol/AccessControllerTest.java
+++ b/src/test/java/org/owasp/esapi/reference/accesscontrol/AccessControllerTest.java
@@ -19,110 +19,110 @@ import org.owasp.esapi.reference.accesscontrol.ExperimentalAccessController;
  *
  */
 public class AccessControllerTest {
-	
-	protected AccessController accessController;
-		
-	@Before
-	public void setup() {
-		Map accessControlRules = new HashMap(3);
-		accessControlRules.put("AlwaysTrue", new AlwaysTrueACR());
-		accessControlRules.put("AlwaysFalse", new AlwaysFalseACR());		
-		accessControlRules.put("EchoRuntimeParameter", new EchoRuntimeParameterACR());
-		accessController = new ExperimentalAccessController(accessControlRules);
-	}
-	
-	@Test 
-	public void isAuthorized() {
-		assertEquals("Rule Not Found: null", accessController.isAuthorized(null, null), false);
-		assertEquals("Rule Not Found: Invalid Key", accessController.isAuthorized("A key that does not map to a rule", null), false);		
-
-		assertEquals("AlwaysTrue", accessController.isAuthorized("AlwaysTrue", null), true);
-		assertEquals("AlwaysFalse", accessController.isAuthorized("AlwaysFalse", null), false);
-		
-		assertEquals("EchoRuntimeParameter: True", accessController.isAuthorized("EchoRuntimeParameter", Boolean.TRUE), true );
-		assertEquals("EchoRuntimeParameter: False", accessController.isAuthorized("EchoRuntimeParameter", Boolean.FALSE), false);
-		assertEquals("EchoRuntimeParameter: ClassCastException", accessController.isAuthorized("EchoRuntimeParameter", "This is not a boolean"), false);
-		assertEquals("EchoRuntimeParameter: null Runtime Parameter", accessController.isAuthorized("EchoRuntimeParameter", null), false);
-	}
-	
-	@Test (expected = AccessControlException.class)	 
-	public void enforceAuthorizationRuleNotFoundNullKey() throws Exception {		
-		accessController.assertAuthorized(null, null);
-	}
-	@Test (expected = AccessControlException.class)	 
-	public void enforceAuthorizationRuleAKeyThatDoesNotMapToARule() throws Exception {		
-		accessController.assertAuthorized("A key that does not map to a rule", null);
-	}
-	
-	
-	@Test  
-	//Should not throw an exception
-	public void enforceAuthorizationAlwaysTrue() throws Exception {		
-		accessController.assertAuthorized("AlwaysTrue", null);
-	}
-	
-	@Test (expected = AccessControlException.class)	 
-	public void enforceAuthorizationAlwaysFalse() throws Exception {		
-		accessController.assertAuthorized("AlwaysFalse", null);
-	}
-	
-	/**
-	 * Ensure that isAuthorized does nothing if enforceAuthorization 
-	 * is called and isAuthorized returns true
-	 */
-	@Test 
-	//Should not throw an exception
-	public void enforceAuthorizationEchoRuntimeParameterTrue() throws Exception {
-		accessController.assertAuthorized("EchoRuntimeParameter", Boolean.TRUE);
-	}
-	
-	/**
-	 * Ensure that isAuthorized translates into an exception if enforceAuthorization 
-	 * is called and isAuthorized returns false
-	 */
-	@Test (expected = AccessControlException.class)	 
-	public void enforceAuthorizationEchoRuntimeParameterFalse() throws Exception {		
-		accessController.assertAuthorized("EchoRuntimeParameter", Boolean.FALSE);
-	}
-	
-	@Test (expected = AccessControlException.class)	 
-	public void enforceAuthorizationEchoRuntimeParameterClassCastException() throws Exception {	
-		accessController.assertAuthorized("EchoRuntimeParameter", "This is not a boolean");
-	}
-	
-	@Test (expected = AccessControlException.class)	 
-	public void enforceAuthorizationEchoRuntimeParameterNullRuntimeParameter() throws Exception {		
-		accessController.assertAuthorized("EchoRuntimeParameter", null);
-	}
-	
-	@org.junit.Test
-	public void delegatingACR() throws Exception {
-		DelegatingACR delegatingACR = new DelegatingACR();
-		DynaBeanACRParameter policyParameter = new DynaBeanACRParameter();
-
-		delegatingACR = new DelegatingACR();
-		policyParameter = new DynaBeanACRParameter();
-		policyParameter.set("delegateClass", "java.lang.Object");
-		policyParameter.set("delegateMethod", "equals");
-		policyParameter.set("parameterClasses", new String[] {"java.lang.Object"});
-		delegatingACR.setPolicyParameters(policyParameter);
-		org.junit.Assert.assertFalse(delegatingACR.isAuthorized(new Object[] {new Object()}));
-		org.junit.Assert.assertFalse(delegatingACR.isAuthorized(new Object[] {delegatingACR}));
-
-		
-		policyParameter.set("delegateClass", "org.owasp.esapi.reference.accesscontrol.AlwaysTrueACR");
-		policyParameter.set("delegateMethod", "isAuthorized");
-		policyParameter.set("parameterClasses", new String[] {"java.lang.Object"});
-		delegatingACR.setPolicyParameters(policyParameter);
-		org.junit.Assert.assertTrue(delegatingACR.isAuthorized(new Object[] {null}));
-		
-		delegatingACR = new DelegatingACR();
-		policyParameter = new DynaBeanACRParameter();
-		policyParameter.set("delegateClass", "org.owasp.esapi.reference.accesscontrol.AlwaysFalseACR");
-		policyParameter.set("delegateMethod", "isAuthorized");
-		policyParameter.set("parameterClasses", new String[] {"java.lang.Object"});
-		delegatingACR.setPolicyParameters(policyParameter);
-		org.junit.Assert.assertFalse(delegatingACR.isAuthorized(new Object[] {null}));
-	}
-	
+
+    protected AccessController accessController;
+
+    @Before
+    public void setup() {
+        Map accessControlRules = new HashMap(3);
+        accessControlRules.put("AlwaysTrue", new AlwaysTrueACR());
+        accessControlRules.put("AlwaysFalse", new AlwaysFalseACR());
+        accessControlRules.put("EchoRuntimeParameter", new EchoRuntimeParameterACR());
+        accessController = new ExperimentalAccessController(accessControlRules);
+    }
+
+    @Test
+    public void isAuthorized() {
+        assertEquals("Rule Not Found: null", accessController.isAuthorized(null, null), false);
+        assertEquals("Rule Not Found: Invalid Key", accessController.isAuthorized("A key that does not map to a rule", null), false);
+
+        assertEquals("AlwaysTrue", accessController.isAuthorized("AlwaysTrue", null), true);
+        assertEquals("AlwaysFalse", accessController.isAuthorized("AlwaysFalse", null), false);
+
+        assertEquals("EchoRuntimeParameter: True", accessController.isAuthorized("EchoRuntimeParameter", Boolean.TRUE), true );
+        assertEquals("EchoRuntimeParameter: False", accessController.isAuthorized("EchoRuntimeParameter", Boolean.FALSE), false);
+        assertEquals("EchoRuntimeParameter: ClassCastException", accessController.isAuthorized("EchoRuntimeParameter", "This is not a boolean"), false);
+        assertEquals("EchoRuntimeParameter: null Runtime Parameter", accessController.isAuthorized("EchoRuntimeParameter", null), false);
+    }
+
+    @Test (expected = AccessControlException.class)
+    public void enforceAuthorizationRuleNotFoundNullKey() throws Exception {
+        accessController.assertAuthorized(null, null);
+    }
+    @Test (expected = AccessControlException.class)
+    public void enforceAuthorizationRuleAKeyThatDoesNotMapToARule() throws Exception {
+        accessController.assertAuthorized("A key that does not map to a rule", null);
+    }
+
+
+    @Test
+    //Should not throw an exception
+    public void enforceAuthorizationAlwaysTrue() throws Exception {
+        accessController.assertAuthorized("AlwaysTrue", null);
+    }
+
+    @Test (expected = AccessControlException.class)
+    public void enforceAuthorizationAlwaysFalse() throws Exception {
+        accessController.assertAuthorized("AlwaysFalse", null);
+    }
+
+    /**
+     * Ensure that isAuthorized does nothing if enforceAuthorization
+     * is called and isAuthorized returns true
+     */
+    @Test
+    //Should not throw an exception
+    public void enforceAuthorizationEchoRuntimeParameterTrue() throws Exception {
+        accessController.assertAuthorized("EchoRuntimeParameter", Boolean.TRUE);
+    }
+
+    /**
+     * Ensure that isAuthorized translates into an exception if enforceAuthorization
+     * is called and isAuthorized returns false
+     */
+    @Test (expected = AccessControlException.class)
+    public void enforceAuthorizationEchoRuntimeParameterFalse() throws Exception {
+        accessController.assertAuthorized("EchoRuntimeParameter", Boolean.FALSE);
+    }
+
+    @Test (expected = AccessControlException.class)
+    public void enforceAuthorizationEchoRuntimeParameterClassCastException() throws Exception {
+        accessController.assertAuthorized("EchoRuntimeParameter", "This is not a boolean");
+    }
+
+    @Test (expected = AccessControlException.class)
+    public void enforceAuthorizationEchoRuntimeParameterNullRuntimeParameter() throws Exception {
+        accessController.assertAuthorized("EchoRuntimeParameter", null);
+    }
+
+    @org.junit.Test
+    public void delegatingACR() throws Exception {
+        DelegatingACR delegatingACR = new DelegatingACR();
+        DynaBeanACRParameter policyParameter = new DynaBeanACRParameter();
+
+        delegatingACR = new DelegatingACR();
+        policyParameter = new DynaBeanACRParameter();
+        policyParameter.set("delegateClass", "java.lang.Object");
+        policyParameter.set("delegateMethod", "equals");
+        policyParameter.set("parameterClasses", new String[] {"java.lang.Object"});
+        delegatingACR.setPolicyParameters(policyParameter);
+        org.junit.Assert.assertFalse(delegatingACR.isAuthorized(new Object[] {new Object()}));
+        org.junit.Assert.assertFalse(delegatingACR.isAuthorized(new Object[] {delegatingACR}));
+
+
+        policyParameter.set("delegateClass", "org.owasp.esapi.reference.accesscontrol.AlwaysTrueACR");
+        policyParameter.set("delegateMethod", "isAuthorized");
+        policyParameter.set("parameterClasses", new String[] {"java.lang.Object"});
+        delegatingACR.setPolicyParameters(policyParameter);
+        org.junit.Assert.assertTrue(delegatingACR.isAuthorized(new Object[] {null}));
+
+        delegatingACR = new DelegatingACR();
+        policyParameter = new DynaBeanACRParameter();
+        policyParameter.set("delegateClass", "org.owasp.esapi.reference.accesscontrol.AlwaysFalseACR");
+        policyParameter.set("delegateMethod", "isAuthorized");
+        policyParameter.set("parameterClasses", new String[] {"java.lang.Object"});
+        delegatingACR.setPolicyParameters(policyParameter);
+        org.junit.Assert.assertFalse(delegatingACR.isAuthorized(new Object[] {null}));
+    }
+
 }
diff --git a/src/test/java/org/owasp/esapi/reference/accesscontrol/policyloader/ACRPolicyFileLoaderTest.java b/src/test/java/org/owasp/esapi/reference/accesscontrol/policyloader/ACRPolicyFileLoaderTest.java
index 851364b..a8d4394 100644
--- a/src/test/java/org/owasp/esapi/reference/accesscontrol/policyloader/ACRPolicyFileLoaderTest.java
+++ b/src/test/java/org/owasp/esapi/reference/accesscontrol/policyloader/ACRPolicyFileLoaderTest.java
@@ -16,55 +16,55 @@ import org.owasp.esapi.errors.AccessControlException;
  */
 public class ACRPolicyFileLoaderTest {
 
-	protected AccessController accessController;
+    protected AccessController accessController;
 
-	@Before
-	public void setUp() throws Exception {
-		accessController = ESAPI.accessController();
-	}
+    @Before
+    public void setUp() throws Exception {
+        accessController = ESAPI.accessController();
+    }
 
-	@Test
-	public void testSetup() throws AccessControlException {
-		/**
-		 * This tests the policy file
-		 */
-		ACRPolicyFileLoader policyDescriptor = new ACRPolicyFileLoader();
-		PolicyDTO policyDTO = policyDescriptor.load();
-		Map accessControlRules = policyDTO.getAccessControlRules();
-		assertTrue("Some AccessControlRules are loaded", !accessControlRules
-				.isEmpty());
-		assertTrue("Access Control Map Contains AlwaysTrue", accessControlRules
-				.containsKey("AlwaysTrue"));
-		assertTrue("Access Control Map Contains AlwaysFalse",
-				accessControlRules.containsKey("AlwaysFalse"));
-		assertTrue("Access Control Map Contains EchoRuntimeParameter",
-				accessControlRules.containsKey("EchoRuntimeParameter"));
-		assertTrue("Access Control Map Contains EchoPolicyParameter",
-				accessControlRules.containsKey("EchoPolicyParameter"));
-	}
+    @Test
+    public void testSetup() throws AccessControlException {
+        /**
+         * This tests the policy file
+         */
+        ACRPolicyFileLoader policyDescriptor = new ACRPolicyFileLoader();
+        PolicyDTO policyDTO = policyDescriptor.load();
+        Map accessControlRules = policyDTO.getAccessControlRules();
+        assertTrue("Some AccessControlRules are loaded", !accessControlRules
+                .isEmpty());
+        assertTrue("Access Control Map Contains AlwaysTrue", accessControlRules
+                .containsKey("AlwaysTrue"));
+        assertTrue("Access Control Map Contains AlwaysFalse",
+                accessControlRules.containsKey("AlwaysFalse"));
+        assertTrue("Access Control Map Contains EchoRuntimeParameter",
+                accessControlRules.containsKey("EchoRuntimeParameter"));
+        assertTrue("Access Control Map Contains EchoPolicyParameter",
+                accessControlRules.containsKey("EchoPolicyParameter"));
+    }
 
-	@Test
-	public void isAuthorizedEchoPolicyParameter() {
-		assertEquals("EchoPolicyParameter", accessController
-				.isAuthorized("EchoPolicyParameter", null), true);
-		assertEquals("EchoRuntimeParameterClassCastException", accessController
-				.isAuthorized("EchoRuntimeParameterClassCastException", null),
-				false);
-		// Policy parameter value null, empty or missing. (TODO add more fail
-		// state tests
-		// assertEquals("EchoRuntimeParameterValueNull",
-		// accessController.isAuthorized("EchoRuntimeParameterValueNull", null),
-		// false);
-		// assertEquals("EchoRuntimeParameterValueEmpty",
-		// accessController.isAuthorized("EchoRuntimeParameterValueEmpty",
-		// null), false);
-		// assertEquals("EchoRuntimeParameterValueMissing",
-		// accessController.isAuthorized("EchoRuntimeParameterValueMissing",
-		// null), false);
-	}
-	
-	@Test(expected = AccessControlException.class)
-	public void enforceAuthorizationRuleNotFoundNullKey() throws AccessControlException {
-		accessController.assertAuthorized(null, null);
-	}
+    @Test
+    public void isAuthorizedEchoPolicyParameter() {
+        assertEquals("EchoPolicyParameter", accessController
+                .isAuthorized("EchoPolicyParameter", null), true);
+        assertEquals("EchoRuntimeParameterClassCastException", accessController
+                .isAuthorized("EchoRuntimeParameterClassCastException", null),
+                false);
+        // Policy parameter value null, empty or missing. (TODO add more fail
+        // state tests
+        // assertEquals("EchoRuntimeParameterValueNull",
+        // accessController.isAuthorized("EchoRuntimeParameterValueNull", null),
+        // false);
+        // assertEquals("EchoRuntimeParameterValueEmpty",
+        // accessController.isAuthorized("EchoRuntimeParameterValueEmpty",
+        // null), false);
+        // assertEquals("EchoRuntimeParameterValueMissing",
+        // accessController.isAuthorized("EchoRuntimeParameterValueMissing",
+        // null), false);
+    }
+
+    @Test(expected = AccessControlException.class)
+    public void enforceAuthorizationRuleNotFoundNullKey() throws AccessControlException {
+        accessController.assertAuthorized(null, null);
+    }
 }
diff --git a/src/test/java/org/owasp/esapi/reference/crypto/CryptoPolicy.java b/src/test/java/org/owasp/esapi/reference/crypto/CryptoPolicy.java
index fe3a8e9..f679f4c 100644
--- a/src/test/java/org/owasp/esapi/reference/crypto/CryptoPolicy.java
+++ b/src/test/java/org/owasp/esapi/reference/crypto/CryptoPolicy.java
@@ -61,14 +61,14 @@ public class CryptoPolicy {
             byte[] raw = skey.getEncoded();
             SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
             Cipher cipher = Cipher.getInstance("AES/ECB/NoPadding");
-            
+
                 // This usually will throw InvalidKeyException unless the
                 // unlimited jurisdiction policy files are installed. However,
                 // it can succeed even if it's not a provider chooses to use
                 // an exemption mechanism such as key escrow, key recovery, or
                 // key weakening for this cipher instead.
             cipher.init(Cipher.ENCRYPT_MODE, skeySpec);
-            
+
                 // Try the encryption on dummy string to make sure it works.
                 // Not using padding so # bytes must be multiple of AES cipher
                 // block size which is 16 bytes. Also, OK not to use UTF-8 here.
@@ -83,7 +83,7 @@ public class CryptoPolicy {
             }
         } catch( InvalidKeyException ikex ) {
             System.out.println("CryptoPolicy: 256 bits is " +
-            		"invalid key size ==> unlimited strength crypto NOT installed!");
+                    "invalid key size ==> unlimited strength crypto NOT installed!");
             return false;
         } catch( Exception ex ) {
             System.out.println("Caught unexpected exception: " + ex);
diff --git a/src/test/java/org/owasp/esapi/reference/crypto/EncryptedPropertiesTest.java b/src/test/java/org/owasp/esapi/reference/crypto/EncryptedPropertiesTest.java
index bd35261..0f7882b 100644
--- a/src/test/java/org/owasp/esapi/reference/crypto/EncryptedPropertiesTest.java
+++ b/src/test/java/org/owasp/esapi/reference/crypto/EncryptedPropertiesTest.java
@@ -1,15 +1,15 @@
 /**
  * OWASP Enterprise Security API (ESAPI)
- * 
+ *
  * This file is part of the Open Web Application Security Project (OWASP)
  * Enterprise Security API (ESAPI) project. For details, please see
  * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
  *
  * Copyright (c) 2007 - The OWASP Foundation
- * 
+ *
  * The ESAPI is published by OWASP under the BSD license. You should read and accept the
  * LICENSE before you use, modify, and/or redistribute this software.
- * 
+ *
  * @author Jeff Williams <a href="http://www.aspectsecurity.com">Aspect Security</a>
  * @created 2007
  */
@@ -31,82 +31,82 @@ import org.owasp.esapi.reference.crypto.DefaultEncryptedProperties;
 
 /**
  * The Class EncryptedPropertiesTest.
- * 
+ *
  * @author Jeff Williams (jeff.williams@aspectsecurity.com)
  */
 public class EncryptedPropertiesTest extends TestCase {
 
-	/**
-	 * Instantiates a new encrypted properties test.
-	 * 
-	 * @param testName
-	 *            the test name
-	 */
-	public EncryptedPropertiesTest(String testName) {
-		super(testName);
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	protected void setUp() throws Exception {
-		// none
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	protected void tearDown() throws Exception {
-		// none
-	}
-
-	/**
-	 * Suite.
-	 * 
-	 * @return the test
-	 */
-	public static Test suite() {
-		TestSuite suite = new TestSuite(EncryptedPropertiesTest.class);
-
-		return suite;
-	}
-
-	/**
-	 * Test of getProperty method, of class org.owasp.esapi.EncryptedProperties.
-	 * 
-	 * @throws EncryptionException
-	 *             the encryption exception
-	 */
-	public void testGetProperty() throws EncryptionException {
-		System.out.println("getProperty");
-		DefaultEncryptedProperties instance = new DefaultEncryptedProperties();
-		String name = "name";
-		String value = "value";
-		instance.setProperty(name, value);
-		String result = instance.getProperty(name);
-		assertEquals(value, result);
-		assertNull(instance.getProperty("ridiculous"));
-	}
-
-	/**
-	 * Test of setProperty method, of class org.owasp.esapi.EncryptedProperties.
-	 * 
-	 * @throws EncryptionException
-	 *             the encryption exception
-	 */
-	public void testSetProperty() throws EncryptionException {
-		System.out.println("setProperty");
-		DefaultEncryptedProperties instance = new DefaultEncryptedProperties();
-		String name = "name";
-		String value = "value";
-		instance.setProperty(name, value);
-		String result = instance.getProperty(name);
-		assertEquals(value, result);
-		
+    /**
+     * Instantiates a new encrypted properties test.
+     *
+     * @param testName
+     *            the test name
+     */
+    public EncryptedPropertiesTest(String testName) {
+        super(testName);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    protected void setUp() throws Exception {
+        // none
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    protected void tearDown() throws Exception {
+        // none
+    }
+
+    /**
+     * Suite.
+     *
+     * @return the test
+     */
+    public static Test suite() {
+        TestSuite suite = new TestSuite(EncryptedPropertiesTest.class);
+
+        return suite;
+    }
+
+    /**
+     * Test of getProperty method, of class org.owasp.esapi.EncryptedProperties.
+     *
+     * @throws EncryptionException
+     *             the encryption exception
+     */
+    public void testGetProperty() throws EncryptionException {
+        System.out.println("getProperty");
+        DefaultEncryptedProperties instance = new DefaultEncryptedProperties();
+        String name = "name";
+        String value = "value";
+        instance.setProperty(name, value);
+        String result = instance.getProperty(name);
+        assertEquals(value, result);
+        assertNull(instance.getProperty("ridiculous"));
+    }
+
+    /**
+     * Test of setProperty method, of class org.owasp.esapi.EncryptedProperties.
+     *
+     * @throws EncryptionException
+     *             the encryption exception
+     */
+    public void testSetProperty() throws EncryptionException {
+        System.out.println("setProperty");
+        DefaultEncryptedProperties instance = new DefaultEncryptedProperties();
+        String name = "name";
+        String value = "value";
+        instance.setProperty(name, value);
+        String result = instance.getProperty(name);
+        assertEquals(value, result);
+
         instance.setProperty(name, "");
         result = instance.getProperty(name);
         assertEquals(result, "");
-        
+
         try {
             instance.setProperty(null, value);
             fail("testSetProperty(): Null property name did not result in expected exception.");
@@ -119,114 +119,114 @@ public class EncryptedPropertiesTest extends TestCase {
         } catch( Exception e ) {
             assertTrue( e instanceof EncryptionException );
         }
-		try {
-			instance.setProperty(null, null);			
-			fail("testSetProperty(): Null property name and valud did not result in expected exception.");
-		} catch( Exception e ) {
-		    assertTrue( e instanceof EncryptionException );
-		}
-	}
-
-	/**
-	 * Test the behavior when the requested key does not exist.
-	 */
-	public void testNonExistantKeyValue() throws Exception
-	{
-		DefaultEncryptedProperties instance = new DefaultEncryptedProperties();
-		assertNull(instance.getProperty("not.there"));
-	}
-
-	/**
-	 * Test of keySet method, of class org.owasp.esapi.EncryptedProperties.
-	 */
-	public void testKeySet() throws Exception
-	{
-		boolean sawTwo = false;
-		boolean sawOne = false;
-
-		System.out.println("keySet");
-		DefaultEncryptedProperties instance = new DefaultEncryptedProperties();
-		instance.setProperty("one", "two");
-		instance.setProperty("two", "three");
-		Iterator i = instance.keySet().iterator();
-		while(i.hasNext())
-		{
-			String key = (String)i.next();
-
-			assertNotNull("key returned from keySet() iterator was null", key);
-			if(key.equals("one"))
-				if(sawOne)
-					fail("Key one seen more than once.");
-				else
-					sawOne = true;
-			else if(key.equals("two"))
-				if(sawTwo)
-					fail("Key two seen more than once.");
-				else
-					sawTwo = true;
-			else
-				fail("Unset key " + key + " returned from keySet().iterator()");
-		}
-		assertTrue("Key one was never seen", sawOne);
-		assertTrue("Key two was never seen", sawTwo);
-	}
-
-	/**
-	 * Test storing and loading of encrypted properties.
-	 */
-	public void testStoreLoad() throws Exception
-	{
-		DefaultEncryptedProperties toLoad = new DefaultEncryptedProperties();
-		ByteArrayOutputStream baos = new ByteArrayOutputStream();
-		ByteArrayInputStream bais;
-		boolean sawOne = false;
-		boolean sawTwo = false;
-		boolean sawSeuss = false;
-
-	    DefaultEncryptedProperties toStore = new DefaultEncryptedProperties();
-		toStore.setProperty("one", "two");
-		toStore.setProperty("two", "three");
-		toStore.setProperty("seuss.schneier", "one fish, twofish, red fish, blowfish");
-		toStore.store(baos, "testStore");
-
-		bais = new ByteArrayInputStream(baos.toByteArray());
-		toLoad.load(bais);
-
-		for(Iterator i=toLoad.keySet().iterator();i.hasNext();)
-		{
-			String key = (String)i.next();
-
-			assertNotNull("key returned from keySet() iterator was null", key);
-			if(key.equals("one"))
-				if(sawOne)
-					fail("Key one seen more than once.");
-				else
-				{
-					sawOne = true;
-					assertEquals("Key one's value was not two", "two", toLoad.getProperty("one"));
-				}
-			else if(key.equals("two"))
-				if(sawTwo)
-					fail("Key two seen more than once.");
-				else
-				{
-					sawTwo = true;
-					assertEquals("Key two's value was not three", "three", toLoad.getProperty("two"));
-				}
-	         else if(key.equals("seuss.schneier"))
-	                if(sawSeuss)
-	                    fail("Key seuss.schneier seen more than once.");
-	                else
-	                {
-	                    sawSeuss = true;
-	                    assertEquals("Key seuss.schneier's value was not expected value",
-	                                 "one fish, twofish, red fish, blowfish",
-	                                 toStore.getProperty("seuss.schneier"));
-	                }
-			else
-				fail("Unset key " + key + " returned from keySet().iterator()");
-		}
-		assertTrue("Key one was never seen", sawOne);
-		assertTrue("Key two was never seen", sawTwo);
-	}
+        try {
+            instance.setProperty(null, null);
+            fail("testSetProperty(): Null property name and valud did not result in expected exception.");
+        } catch( Exception e ) {
+            assertTrue( e instanceof EncryptionException );
+        }
+    }
+
+    /**
+     * Test the behavior when the requested key does not exist.
+     */
+    public void testNonExistantKeyValue() throws Exception
+    {
+        DefaultEncryptedProperties instance = new DefaultEncryptedProperties();
+        assertNull(instance.getProperty("not.there"));
+    }
+
+    /**
+     * Test of keySet method, of class org.owasp.esapi.EncryptedProperties.
+     */
+    public void testKeySet() throws Exception
+    {
+        boolean sawTwo = false;
+        boolean sawOne = false;
+
+        System.out.println("keySet");
+        DefaultEncryptedProperties instance = new DefaultEncryptedProperties();
+        instance.setProperty("one", "two");
+        instance.setProperty("two", "three");
+        Iterator i = instance.keySet().iterator();
+        while(i.hasNext())
+        {
+            String key = (String)i.next();
+
+            assertNotNull("key returned from keySet() iterator was null", key);
+            if(key.equals("one"))
+                if(sawOne)
+                    fail("Key one seen more than once.");
+                else
+                    sawOne = true;
+            else if(key.equals("two"))
+                if(sawTwo)
+                    fail("Key two seen more than once.");
+                else
+                    sawTwo = true;
+            else
+                fail("Unset key " + key + " returned from keySet().iterator()");
+        }
+        assertTrue("Key one was never seen", sawOne);
+        assertTrue("Key two was never seen", sawTwo);
+    }
+
+    /**
+     * Test storing and loading of encrypted properties.
+     */
+    public void testStoreLoad() throws Exception
+    {
+        DefaultEncryptedProperties toLoad = new DefaultEncryptedProperties();
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        ByteArrayInputStream bais;
+        boolean sawOne = false;
+        boolean sawTwo = false;
+        boolean sawSeuss = false;
+
+        DefaultEncryptedProperties toStore = new DefaultEncryptedProperties();
+        toStore.setProperty("one", "two");
+        toStore.setProperty("two", "three");
+        toStore.setProperty("seuss.schneier", "one fish, twofish, red fish, blowfish");
+        toStore.store(baos, "testStore");
+
+        bais = new ByteArrayInputStream(baos.toByteArray());
+        toLoad.load(bais);
+
+        for(Iterator i=toLoad.keySet().iterator();i.hasNext();)
+        {
+            String key = (String)i.next();
+
+            assertNotNull("key returned from keySet() iterator was null", key);
+            if(key.equals("one"))
+                if(sawOne)
+                    fail("Key one seen more than once.");
+                else
+                {
+                    sawOne = true;
+                    assertEquals("Key one's value was not two", "two", toLoad.getProperty("one"));
+                }
+            else if(key.equals("two"))
+                if(sawTwo)
+                    fail("Key two seen more than once.");
+                else
+                {
+                    sawTwo = true;
+                    assertEquals("Key two's value was not three", "three", toLoad.getProperty("two"));
+                }
+             else if(key.equals("seuss.schneier"))
+                    if(sawSeuss)
+                        fail("Key seuss.schneier seen more than once.");
+                    else
+                    {
+                        sawSeuss = true;
+                        assertEquals("Key seuss.schneier's value was not expected value",
+                                     "one fish, twofish, red fish, blowfish",
+                                     toStore.getProperty("seuss.schneier"));
+                    }
+            else
+                fail("Unset key " + key + " returned from keySet().iterator()");
+        }
+        assertTrue("Key one was never seen", sawOne);
+        assertTrue("Key two was never seen", sawTwo);
+    }
 }
diff --git a/src/test/java/org/owasp/esapi/reference/crypto/EncryptedPropertiesUtilsTest.java b/src/test/java/org/owasp/esapi/reference/crypto/EncryptedPropertiesUtilsTest.java
index e222af0..124e289 100644
--- a/src/test/java/org/owasp/esapi/reference/crypto/EncryptedPropertiesUtilsTest.java
+++ b/src/test/java/org/owasp/esapi/reference/crypto/EncryptedPropertiesUtilsTest.java
@@ -1,15 +1,15 @@
 /**
  * OWASP Enterprise Security API (ESAPI)
- * 
+ *
  * This file is part of the Open Web Application Security Project (OWASP)
  * Enterprise Security API (ESAPI) project. For details, please see
  * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
  *
  * Copyright (c) 2007 - The OWASP Foundation
- * 
+ *
  * The ESAPI is published by OWASP under the BSD license. You should read and accept the
  * LICENSE before you use, modify, and/or redistribute this software.
- * 
+ *
  * @author Jeff Williams <a href="http://www.aspectsecurity.com">Aspect Security</a>
  * @created 2007
  */
@@ -31,146 +31,146 @@ import org.junit.rules.TestName;
 
 /**
  * The Class EncryptedPropertiesTest.
- * 
+ *
  * @author August Detlefsen (augustd at codemagi dot com)
  *         <a href="http://www.codemagi.com">CodeMagi, Inc.</a>
  * @since October 8, 2010
  */
 public class EncryptedPropertiesUtilsTest {
 
-	private static final String KEY1	= "quick";
-	private static final String VALUE1	= "brown fox";
-	private static final String KEY2	= "jumps";
-	private static final String VALUE2	= "lazy dog";
-	private static final String KEY3	= "joe bob";
-	private static final String VALUE3	= "jim bob";
-	private static final String KEY4	= "sally sue";
-	private static final String VALUE4	= "betty mae";
-
-	
-	/** Rule to acquire the running test's information at runtime.*/
-	@Rule
-	public TestName testName = new TestName();
-
-	/** File management component for IO targets during test executions.*/
-	@Rule
-	public TemporaryFolder tempFolder = new TemporaryFolder();
-	
-	/** Counter used to track the number of files created for a single test to assist with creating unique file references.*/
-	private int fileIndex = 0;
-	
-	/**
-	 * Creates a new properties file reference for the active test which will be cleaned up upon test completion.
-	 * @return File New unique file reference for the active test.
-	 * @throws IOException If a new file could not be generated.
-	 */
-	private final File getTempPropertiesFile() throws IOException {
-	    return tempFolder.newFile(String.format("%s_%2d.properties", testName.getMethodName(), fileIndex++));
-	}
-	/**
-	 * Test of creating and storing a new EncryptedProperties from scratch,
-	 * as if calling:
-	 * <code>
-	 *     EncryptedPropertiesUtils --out encrypted.properties
-	 * </code>
-	 *
-	 * @throws Exception Any exception that occurs
-	 */
-	@Test public void testCreateNew() throws Exception {
-	    File encryptedFile = getTempPropertiesFile();
-	    
-		//create a new properties with no input
-		Properties props = EncryptedPropertiesUtils.loadProperties(null, null);
-		
-		//add some properties
-		Object prop1 = EncryptedPropertiesUtils.addProperty(props, KEY1, VALUE1);
-		assertNull("Expected null but returned: " + prop1, prop1);
-
-		Object prop2 = EncryptedPropertiesUtils.addProperty(props, KEY2, VALUE2);
-		assertNull("Expected null but returned: " + prop2, prop2);
-
-		//store the file 
-		EncryptedPropertiesUtils.storeProperties(encryptedFile.getAbsolutePath(), props, "Encrypted Properties File generated by EncryptedPropertiesUtilsTest");
-
-		//try reading in the resulting file
-		ReferenceEncryptedProperties loadedProps = new ReferenceEncryptedProperties();
-		loadedProps.load(new FileReader(encryptedFile.getAbsolutePath()));
-		
-		assertEquals(VALUE1, loadedProps.getProperty(KEY1));
-		assertEquals(VALUE2, loadedProps.getProperty(KEY2));
-	}
-
-	/**
-	 * Test of loading a plaintext file and storing it as an encrypted properties file,
-	 * as if calling:
-	 * <code>
-	 *     EncryptedPropertiesUtils --in plaintext.properties --out encrypted.properties --in-encrypted false
-	 * </code>
-	 *
-	 * @throws Exception Any exception that occurs
-	 */
-	@Test public void testLoadPlaintextAndEncrypt() throws Exception {
-	    File encryptedFile = getTempPropertiesFile();
-	    File plainTextFile = getTempPropertiesFile();
-	    
-	  //write an initial plaintext properties file
+    private static final String KEY1    = "quick";
+    private static final String VALUE1    = "brown fox";
+    private static final String KEY2    = "jumps";
+    private static final String VALUE2    = "lazy dog";
+    private static final String KEY3    = "joe bob";
+    private static final String VALUE3    = "jim bob";
+    private static final String KEY4    = "sally sue";
+    private static final String VALUE4    = "betty mae";
+
+
+    /** Rule to acquire the running test's information at runtime.*/
+    @Rule
+    public TestName testName = new TestName();
+
+    /** File management component for IO targets during test executions.*/
+    @Rule
+    public TemporaryFolder tempFolder = new TemporaryFolder();
+
+    /** Counter used to track the number of files created for a single test to assist with creating unique file references.*/
+    private int fileIndex = 0;
+
+    /**
+     * Creates a new properties file reference for the active test which will be cleaned up upon test completion.
+     * @return File New unique file reference for the active test.
+     * @throws IOException If a new file could not be generated.
+     */
+    private final File getTempPropertiesFile() throws IOException {
+        return tempFolder.newFile(String.format("%s_%2d.properties", testName.getMethodName(), fileIndex++));
+    }
+    /**
+     * Test of creating and storing a new EncryptedProperties from scratch,
+     * as if calling:
+     * <code>
+     *     EncryptedPropertiesUtils --out encrypted.properties
+     * </code>
+     *
+     * @throws Exception Any exception that occurs
+     */
+    @Test public void testCreateNew() throws Exception {
+        File encryptedFile = getTempPropertiesFile();
+
+        //create a new properties with no input
+        Properties props = EncryptedPropertiesUtils.loadProperties(null, null);
+
+        //add some properties
+        Object prop1 = EncryptedPropertiesUtils.addProperty(props, KEY1, VALUE1);
+        assertNull("Expected null but returned: " + prop1, prop1);
+
+        Object prop2 = EncryptedPropertiesUtils.addProperty(props, KEY2, VALUE2);
+        assertNull("Expected null but returned: " + prop2, prop2);
+
+        //store the file
+        EncryptedPropertiesUtils.storeProperties(encryptedFile.getAbsolutePath(), props, "Encrypted Properties File generated by EncryptedPropertiesUtilsTest");
+
+        //try reading in the resulting file
+        ReferenceEncryptedProperties loadedProps = new ReferenceEncryptedProperties();
+        loadedProps.load(new FileReader(encryptedFile.getAbsolutePath()));
+
+        assertEquals(VALUE1, loadedProps.getProperty(KEY1));
+        assertEquals(VALUE2, loadedProps.getProperty(KEY2));
+    }
+
+    /**
+     * Test of loading a plaintext file and storing it as an encrypted properties file,
+     * as if calling:
+     * <code>
+     *     EncryptedPropertiesUtils --in plaintext.properties --out encrypted.properties --in-encrypted false
+     * </code>
+     *
+     * @throws Exception Any exception that occurs
+     */
+    @Test public void testLoadPlaintextAndEncrypt() throws Exception {
+        File encryptedFile = getTempPropertiesFile();
+        File plainTextFile = getTempPropertiesFile();
+
+      //write an initial plaintext properties file
         Properties props = new Properties();
         props.setProperty(KEY3, VALUE3);
         props.setProperty(KEY4, VALUE4);
 
         props.store(new FileOutputStream(plainTextFile.getAbsolutePath()), "Plaintext test file created by EncryptedPropertiesUtilsTest");
-	    
-		//load the plaintext properties file
-		props = EncryptedPropertiesUtils.loadProperties(plainTextFile.getAbsolutePath(), false);
-
-		//test some properties using getProperty
-		assertEquals(VALUE3, props.getProperty(KEY3));
-		assertEquals(VALUE4, props.getProperty(KEY4));
-
-		//store the file
-		EncryptedPropertiesUtils.storeProperties(encryptedFile.getAbsolutePath(), props, "Encrypted Properties File generated by EncryptedPropertiesUtilsTest");
-
-		//try reading in the resulting file
-		ReferenceEncryptedProperties loadedProps = new ReferenceEncryptedProperties();
-		loadedProps.load(new FileReader(encryptedFile.getAbsolutePath()));
-
-		assertEquals(VALUE3, loadedProps.getProperty(KEY3));
-		assertEquals(VALUE4, loadedProps.getProperty(KEY4));
-	}
-
-	/**
-	 * Test of loading an encrypted file, adding new properties and storing it as an encrypted properties file,
-	 * as if calling:
-	 * <code>
-	 *     EncryptedPropertiesUtils --in encrypted.properties --out encrypted.2.properties
-	 * </code>
-	 *
-	 * @throws Exception Any exception that occurs
-	 */
-	@Test public void testLoadEncryptedAndAdd() throws Exception {
-	    File encryptedFile = getTempPropertiesFile();
-	    File encryptedFile2 = getTempPropertiesFile();
-		//load the plaintext properties file
-		Properties props = EncryptedPropertiesUtils.loadProperties(encryptedFile.getAbsolutePath(), true);
-
-		//add some new properties
-		EncryptedPropertiesUtils.addProperty(props, KEY1, VALUE1);
-		EncryptedPropertiesUtils.addProperty(props, KEY2, VALUE2);
-
-		//test the newly added properties
-		assertEquals(VALUE1, props.getProperty(KEY1));
-		assertEquals(VALUE2, props.getProperty(KEY2));
-
-		//store the file
-		EncryptedPropertiesUtils.storeProperties(encryptedFile2.getAbsolutePath(), props, "Encrypted Properties File generated by EncryptedPropertiesUtilsTest");
-
-		//try reading in the resulting file
-		ReferenceEncryptedProperties loadedProps = new ReferenceEncryptedProperties();
-		loadedProps.load(new FileReader(encryptedFile2.getAbsolutePath()));
-
-		//test the values read in
-		assertEquals(VALUE1, loadedProps.getProperty(KEY1));
-		assertEquals(VALUE2, loadedProps.getProperty(KEY2));
-	}
+
+        //load the plaintext properties file
+        props = EncryptedPropertiesUtils.loadProperties(plainTextFile.getAbsolutePath(), false);
+
+        //test some properties using getProperty
+        assertEquals(VALUE3, props.getProperty(KEY3));
+        assertEquals(VALUE4, props.getProperty(KEY4));
+
+        //store the file
+        EncryptedPropertiesUtils.storeProperties(encryptedFile.getAbsolutePath(), props, "Encrypted Properties File generated by EncryptedPropertiesUtilsTest");
+
+        //try reading in the resulting file
+        ReferenceEncryptedProperties loadedProps = new ReferenceEncryptedProperties();
+        loadedProps.load(new FileReader(encryptedFile.getAbsolutePath()));
+
+        assertEquals(VALUE3, loadedProps.getProperty(KEY3));
+        assertEquals(VALUE4, loadedProps.getProperty(KEY4));
+    }
+
+    /**
+     * Test of loading an encrypted file, adding new properties and storing it as an encrypted properties file,
+     * as if calling:
+     * <code>
+     *     EncryptedPropertiesUtils --in encrypted.properties --out encrypted.2.properties
+     * </code>
+     *
+     * @throws Exception Any exception that occurs
+     */
+    @Test public void testLoadEncryptedAndAdd() throws Exception {
+        File encryptedFile = getTempPropertiesFile();
+        File encryptedFile2 = getTempPropertiesFile();
+        //load the plaintext properties file
+        Properties props = EncryptedPropertiesUtils.loadProperties(encryptedFile.getAbsolutePath(), true);
+
+        //add some new properties
+        EncryptedPropertiesUtils.addProperty(props, KEY1, VALUE1);
+        EncryptedPropertiesUtils.addProperty(props, KEY2, VALUE2);
+
+        //test the newly added properties
+        assertEquals(VALUE1, props.getProperty(KEY1));
+        assertEquals(VALUE2, props.getProperty(KEY2));
+
+        //store the file
+        EncryptedPropertiesUtils.storeProperties(encryptedFile2.getAbsolutePath(), props, "Encrypted Properties File generated by EncryptedPropertiesUtilsTest");
+
+        //try reading in the resulting file
+        ReferenceEncryptedProperties loadedProps = new ReferenceEncryptedProperties();
+        loadedProps.load(new FileReader(encryptedFile2.getAbsolutePath()));
+
+        //test the values read in
+        assertEquals(VALUE1, loadedProps.getProperty(KEY1));
+        assertEquals(VALUE2, loadedProps.getProperty(KEY2));
+    }
 
 }
diff --git a/src/test/java/org/owasp/esapi/reference/crypto/EncryptorTest.java b/src/test/java/org/owasp/esapi/reference/crypto/EncryptorTest.java
index 62eb47f..08819d1 100644
--- a/src/test/java/org/owasp/esapi/reference/crypto/EncryptorTest.java
+++ b/src/test/java/org/owasp/esapi/reference/crypto/EncryptorTest.java
@@ -1,15 +1,15 @@
 /**
  * OWASP Enterprise Security API (ESAPI)
- * 
+ *
  * This file is part of the Open Web Application Security Project (OWASP)
  * Enterprise Security API (ESAPI) project. For details, please see
  * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
  *
  * Copyright (c) 2007 - The OWASP Foundation
- * 
+ *
  * The ESAPI is published by OWASP under the BSD license. You should read and accept the
  * LICENSE before you use, modify, and/or redistribute this software.
- * 
+ *
  * @author Jeff Williams <a href="http://www.aspectsecurity.com">Aspect Security</a>
  * @created 2007
  */
@@ -36,7 +36,7 @@ import org.owasp.esapi.reference.crypto.JavaEncryptor;
 
 /**
  * The Class EncryptorTest.
- * 
+ *
  * @author Jeff Williams (jeff.williams@aspectsecurity.com)
  * @author kevin.w.wall@gmail.com
  */
@@ -54,13 +54,13 @@ public class EncryptorTest extends TestCase {
                                 " be skipped.");
         }
     }
-    
+
     /**
-	 * Instantiates a new encryptor test.
-	 * 
-	 * @param testName
-	 *            the test name
-	 */
+     * Instantiates a new encryptor test.
+     *
+     * @param testName
+     *            the test name
+     */
     public EncryptorTest(String testName) {
         super(testName);
     }
@@ -70,10 +70,10 @@ public class EncryptorTest extends TestCase {
      * @throws Exception
      */
     @SuppressWarnings("deprecation")
-	protected void setUp() throws Exception {
+    protected void setUp() throws Exception {
         // This is only mechanism to change this for now. Will do this with
         // a soon to be CryptoControls class or equivalent mechanism in a
-    	// future release.
+        // future release.
         ESAPI.securityConfiguration().setCipherTransformation("AES/CBC/PKCS5Padding");
     }
 
@@ -82,23 +82,23 @@ public class EncryptorTest extends TestCase {
      * @throws Exception
      */
     protected void tearDown() throws Exception {
-    	// none
+        // none
     }
 
     /**
      * Run all the test cases in this suite.
      * This is to allow running from {@code org.owasp.esapi.AllTests}.
-     * 
-	 * @return the test
-	 */
+     *
+     * @return the test
+     */
     public static Test suite() {
         TestSuite suite = new TestSuite(EncryptorTest.class);
-        
+
         return suite;
     }
 
     /**
-	 * Test of hash method, of class org.owasp.esapi.Encryptor.
+     * Test of hash method, of class org.owasp.esapi.Encryptor.
      *
      * @throws EncryptionException
      */
@@ -114,12 +114,12 @@ public class EncryptorTest extends TestCase {
     }
 
     /**
-	 * Test of new encrypt / decrypt method for Strings whose length is
-	 * not a multiple of the cipher block size (16 bytes for AES).
-	 * 
-	 * @throws EncryptionException
-	 *             the encryption exception
-	 */
+     * Test of new encrypt / decrypt method for Strings whose length is
+     * not a multiple of the cipher block size (16 bytes for AES).
+     *
+     * @throws EncryptionException
+     *             the encryption exception
+     */
     public void testEncryptDecrypt1() throws EncryptionException {
         System.out.println("testEncryptDecrypt2()");
         Encryptor instance = ESAPI.encryptor();
@@ -130,14 +130,14 @@ public class EncryptorTest extends TestCase {
             assertTrue( pt.toString().equals(plaintext) );
         }
         catch( EncryptionException e ) {
-        	fail("testEncryptDecrypt2(): Caught exception: " + e);
+            fail("testEncryptDecrypt2(): Caught exception: " + e);
         }
     }
 
     /**
-	 * Test of new encrypt / decrypt method for Strings whose length is
-	 * same as cipher block size (16 bytes for AES).
-	 */
+     * Test of new encrypt / decrypt method for Strings whose length is
+     * same as cipher block size (16 bytes for AES).
+     */
     public void testEncryptDecrypt2() {
         System.out.println("testEncryptDecrypt2()");
         Encryptor instance = ESAPI.encryptor();
@@ -148,7 +148,7 @@ public class EncryptorTest extends TestCase {
             assertTrue( pt.toString().equals(plaintext) );
         }
         catch( EncryptionException e ) {
-        	fail("testEncryptDecrypt2(): Caught exception: " + e);
+            fail("testEncryptDecrypt2(): Caught exception: " + e);
         }
     }
 
@@ -168,7 +168,7 @@ public class EncryptorTest extends TestCase {
             fail("testEncryptEmptyStrings() -- Caught exception: " + e);
         }
     }
-    
+
     /**
      * Test encryption method for null.
      */
@@ -176,7 +176,7 @@ public class EncryptorTest extends TestCase {
         System.out.println("testEncryptNull()");
         Encryptor instance = ESAPI.encryptor();
         try {
-			CipherText ct = instance.encrypt( null );  // Should throw NPE or AssertionError
+            CipherText ct = instance.encrypt( null );  // Should throw NPE or AssertionError
             fail("New encrypt(PlainText) method did not throw. Result was: " + ct.toString());
         } catch(Throwable t) {
             // It should be one of these, depending on whether or not assertions are enabled.
@@ -191,40 +191,40 @@ public class EncryptorTest extends TestCase {
         System.out.println("testDecryptNull()");
         Encryptor instance = ESAPI.encryptor();
         try {
-			PlainText pt = instance.decrypt( null );  // Should throw IllegalArgumentException or AssertionError
+            PlainText pt = instance.decrypt( null );  // Should throw IllegalArgumentException or AssertionError
             fail("New decrypt(PlainText) method did not throw. Result was: " + pt.toString());
         } catch(Throwable t) {
             // It should be one of these, depending on whether or not assertions are enabled.
             assertTrue( t instanceof IllegalArgumentException || t instanceof AssertionError);
         }
     }
-    
+
     /**
      * Test of new encrypt / decrypt methods added in ESAPI 2.0.
      */
     public void testNewEncryptDecrypt() {
-    	System.out.println("testNewEncryptDecrypt()");
-    	try {
-    	    // Let's try it with a 2-key version of 3DES. This should work for all
-    	    // installations, whereas the 3-key Triple DES will only work for those
-    	    // who have the Unlimited Strength Jurisdiction Policy files installed.
-			runNewEncryptDecryptTestCase("DESede/CBC/PKCS5Padding", 112, "1234567890".getBytes("UTF-8"));
-			runNewEncryptDecryptTestCase("DESede/CBC/NoPadding", 112, "12345678".getBytes("UTF-8"));
-			
-	        runNewEncryptDecryptTestCase("AES/CBC/PKCS5Padding", 128, "Encrypt the world!".getBytes("UTF-8"));
-	        
-	        // These tests are only valid (and run) if one has the JCE Unlimited
-	        // Strength Jurisdiction Policy files installed for this Java VM.
-	            // 256-bit AES
+        System.out.println("testNewEncryptDecrypt()");
+        try {
+            // Let's try it with a 2-key version of 3DES. This should work for all
+            // installations, whereas the 3-key Triple DES will only work for those
+            // who have the Unlimited Strength Jurisdiction Policy files installed.
+            runNewEncryptDecryptTestCase("DESede/CBC/PKCS5Padding", 112, "1234567890".getBytes("UTF-8"));
+            runNewEncryptDecryptTestCase("DESede/CBC/NoPadding", 112, "12345678".getBytes("UTF-8"));
+
+            runNewEncryptDecryptTestCase("AES/CBC/PKCS5Padding", 128, "Encrypt the world!".getBytes("UTF-8"));
+
+            // These tests are only valid (and run) if one has the JCE Unlimited
+            // Strength Jurisdiction Policy files installed for this Java VM.
+                // 256-bit AES
             runNewEncryptDecryptTestCase("AES/ECB/NoPadding", 256, "test1234test1234".getBytes("UTF-8"));
                 // 168-bit (aka, 3-key) Triple DES
             runNewEncryptDecryptTestCase("DESede/CBC/PKCS5Padding", 168, "Groucho's secret word".getBytes("UTF-8"));
-		} catch (UnsupportedEncodingException e) {
-			fail("OK, who stole UTF-8 encoding from the Java rt.jar ???");
-		}
-    	
+        } catch (UnsupportedEncodingException e) {
+            fail("OK, who stole UTF-8 encoding from the Java rt.jar ???");
+        }
+
     }
-    
+
     /** Special encryption case!!! Test encryption with DES, which has a key less than the
      * min key size specified as Encryptor.EncryptionKeyLength in the file
      * src/test/resources/esapi/ESAPI.properties.
@@ -268,37 +268,37 @@ public class EncryptorTest extends TestCase {
 
     /**
      * Helper method to test new encryption / decryption.
-     * @param cipherXform	Cipher transformation
-     * @param keySize	Size of key, in bits.
+     * @param cipherXform    Cipher transformation
+     * @param keySize    Size of key, in bits.
      * @param plaintextBytes Byte array of plaintext.
      * @return The base64-encoded IV+ciphertext (or just ciphertext if no IV) or
      *         null if {@code keysize} is greater than 128 bits and unlimited
      *         strength crypto is not available for this Java VM.
      */
     private String runNewEncryptDecryptTestCase(String cipherXform, int keySize, byte[] plaintextBytes) {
-    	// System.err.println("New encrypt / decrypt: " + cipherXform + "; requested key size: " + keySize + " bits.");
-    	
-    	if ( keySize > 128 && !unlimitedStrengthJurisdictionPolicyInstalled ) {
-    	    System.err.println("Skipping test for cipher transformation " +
-    	                       cipherXform + " with key size of " + keySize +
-    	                       " bits because this requires JCE Unlimited Strength" +
-    	                       " Jurisdiction Policy files to be installed and they" +
-    	                       " are not.");
-    	    return null;
-    	}
-
-    	try {
-    		// Generate an appropriate random secret key
-			SecretKey skey = CryptoHelper.generateSecretKey(cipherXform, keySize);	
-			assertTrue( skey.getAlgorithm().equals(cipherXform.split("/")[0]) );
-			String cipherAlg = cipherXform.split("/")[0];
+        // System.err.println("New encrypt / decrypt: " + cipherXform + "; requested key size: " + keySize + " bits.");
+
+        if ( keySize > 128 && !unlimitedStrengthJurisdictionPolicyInstalled ) {
+            System.err.println("Skipping test for cipher transformation " +
+                               cipherXform + " with key size of " + keySize +
+                               " bits because this requires JCE Unlimited Strength" +
+                               " Jurisdiction Policy files to be installed and they" +
+                               " are not.");
+            return null;
+        }
+
+        try {
+            // Generate an appropriate random secret key
+            SecretKey skey = CryptoHelper.generateSecretKey(cipherXform, keySize);
+            assertTrue( skey.getAlgorithm().equals(cipherXform.split("/")[0]) );
+            String cipherAlg = cipherXform.split("/")[0];
 
             // System.err.println("Key size of generated encoded key: " + skey.getEncoded().length * 8 + " bits.");
-			
-			// Adjust key size for DES and DESede specific oddities.
-			// NOTE: Key size that encrypt() method is using is 192 bits!!!
-    		//        which is 3 times 64 bits, but DES key size is only 56 bits.
-    		// See 'IMPORTANT NOTE', in JavaEncryptor, near line 376. It's a "feature"!!!
+
+            // Adjust key size for DES and DESede specific oddities.
+            // NOTE: Key size that encrypt() method is using is 192 bits!!!
+            //        which is 3 times 64 bits, but DES key size is only 56 bits.
+            // See 'IMPORTANT NOTE', in JavaEncryptor, near line 376. It's a "feature"!!!
 /////   This section is causing problems. BC for instance sometimes creates a
 /////   192 bit key and then subsequently creates a 128-bit key for 2-key
 /////   3DES so adjusing this is futile. THis is a holdover when we were
@@ -310,126 +310,126 @@ public class EncryptorTest extends TestCase {
 /////   official 2.2.0.0 release.
 /////
 /*
-			if ( cipherAlg.equals( "DESede" ) ) {
+            if ( cipherAlg.equals( "DESede" ) ) {
                 System.err.println("Adjusting requested key size of " + keySize + " bits to 192 bits for DESede");
-				keySize = 192;
-			} else if ( cipherAlg.equals( "DES" ) ) {
+                keySize = 192;
+            } else if ( cipherAlg.equals( "DES" ) ) {
                 System.err.println("Adjusting requested key size of " + keySize + " bits to 64 bits for DES");
-				keySize = 64;
-			} // Else... use specified keySize.
+                keySize = 64;
+            } // Else... use specified keySize.
  */
 
             assertTrue(cipherXform + ": encoded key size of " + skey.getEncoded().length + " shorter than requested key size of: " + (keySize / 8),
-            		skey.getEncoded().length >= (keySize / 8) );
+                    skey.getEncoded().length >= (keySize / 8) );
 
-			// Change to a possibly different cipher. This is kludgey at best. Am thinking about an
-			// alternate way to do this using a new 'CryptoControls' class. Maybe not until release 2.1.
-			// Change the cipher transform from whatever it currently is to the specified cipherXform.
-	    	@SuppressWarnings("deprecation")
-			String oldCipherXform = ESAPI.securityConfiguration().setCipherTransformation(cipherXform);
+            // Change to a possibly different cipher. This is kludgey at best. Am thinking about an
+            // alternate way to do this using a new 'CryptoControls' class. Maybe not until release 2.1.
+            // Change the cipher transform from whatever it currently is to the specified cipherXform.
+            @SuppressWarnings("deprecation")
+            String oldCipherXform = ESAPI.securityConfiguration().setCipherTransformation(cipherXform);
 /*
-	    	if ( ! cipherXform.equals(oldCipherXform) ) {
-	    		System.err.println("Cipher xform changed from \"" + oldCipherXform + "\" to \"" + cipherXform + "\"");
-	    	}
+            if ( ! cipherXform.equals(oldCipherXform) ) {
+                System.err.println("Cipher xform changed from \"" + oldCipherXform + "\" to \"" + cipherXform + "\"");
+            }
  */
-	    	
-	    	// Get an Encryptor instance with the specified, possibly new, cipher transformation.
-	    	Encryptor instance = ESAPI.encryptor();
-	    	PlainText plaintext = new PlainText(plaintextBytes);
-	    	PlainText origPlainText = new PlainText( plaintext.toString() ); // Make _copy_ of original for comparison.
-	    	
-	    	// Do the encryption with the new encrypt() method and get back the CipherText.
-	    	CipherText ciphertext = instance.encrypt(skey, plaintext);	// The new encrypt() method.
-	    	System.err.println("DEBUG: Encrypt(): CipherText object is -- " + ciphertext);
-	    	assertNotNull( ciphertext );
-//	    	System.err.println("DEBUG: After encryption: base64-encoded IV+ciphertext: " + ciphertext.getEncodedIVCipherText());
-//	    	System.err.println("\t\tOr... " + ESAPI.encoder().decodeFromBase64(ciphertext.getEncodedIVCipherText()) );
-//	    	System.err.println("DEBUG: After encryption: base64-encoded raw ciphertext: " + ciphertext.getBase64EncodedRawCipherText());
-//	    	System.err.println("\t\tOr... " + ESAPI.encoder().decodeFromBase64(ciphertext.getBase64EncodedRawCipherText()) );
-
-	    	// If we are supposed to have overwritten the plaintext, check this to see
-	    	// if origPlainText was indeed overwritten.
-	    	@SuppressWarnings("deprecation")
-			boolean overwritePlaintext = ESAPI.securityConfiguration().overwritePlainText();
-			if ( overwritePlaintext ) {
-				assertTrue( isPlaintextOverwritten(plaintext) );
-			}
-	    	
-	    	// Take the resulting ciphertext and decrypt w/ new decryption method.
-	    	PlainText decryptedPlaintext  = instance.decrypt(skey, ciphertext);		// The new decrypt() method.
-	    	
-	    	// Make sure we got back the same thing we started with.
-	    	System.out.println("\tOriginal plaintext: " + origPlainText);
-	    	System.out.println("\tResult after decryption: " + decryptedPlaintext);
-			assertEquals( "Failed to decrypt properly.", origPlainText.toString(), decryptedPlaintext.toString() );
-	    	
-	    	// Restore the previous cipher transformation. For now, this is only way to do this.
-	    	@SuppressWarnings("deprecation")
-			String previousCipherXform = ESAPI.securityConfiguration().setCipherTransformation(null);
-	    	assertEquals( previousCipherXform,  cipherXform  );
-	    	@SuppressWarnings("deprecation")
-	    	String defaultCipherXform = ESAPI.securityConfiguration().getCipherTransformation();
-	    	assertEquals( defaultCipherXform, oldCipherXform );
-	    	
-	    	return ciphertext.getEncodedIVCipherText();
-		} catch (Exception e) {
-			// OK if not counted toward code coverage.
-			System.out.println("testNewEncryptDecrypt(): Caught unexpected exception: " + e.getClass().getName());
-			e.printStackTrace(System.out);
-			fail("Caught unexpected exception; msg was: " + e);
-		}
-		return null;
+
+            // Get an Encryptor instance with the specified, possibly new, cipher transformation.
+            Encryptor instance = ESAPI.encryptor();
+            PlainText plaintext = new PlainText(plaintextBytes);
+            PlainText origPlainText = new PlainText( plaintext.toString() ); // Make _copy_ of original for comparison.
+
+            // Do the encryption with the new encrypt() method and get back the CipherText.
+            CipherText ciphertext = instance.encrypt(skey, plaintext);    // The new encrypt() method.
+            System.err.println("DEBUG: Encrypt(): CipherText object is -- " + ciphertext);
+            assertNotNull( ciphertext );
+//            System.err.println("DEBUG: After encryption: base64-encoded IV+ciphertext: " + ciphertext.getEncodedIVCipherText());
+//            System.err.println("\t\tOr... " + ESAPI.encoder().decodeFromBase64(ciphertext.getEncodedIVCipherText()) );
+//            System.err.println("DEBUG: After encryption: base64-encoded raw ciphertext: " + ciphertext.getBase64EncodedRawCipherText());
+//            System.err.println("\t\tOr... " + ESAPI.encoder().decodeFromBase64(ciphertext.getBase64EncodedRawCipherText()) );
+
+            // If we are supposed to have overwritten the plaintext, check this to see
+            // if origPlainText was indeed overwritten.
+            @SuppressWarnings("deprecation")
+            boolean overwritePlaintext = ESAPI.securityConfiguration().overwritePlainText();
+            if ( overwritePlaintext ) {
+                assertTrue( isPlaintextOverwritten(plaintext) );
+            }
+
+            // Take the resulting ciphertext and decrypt w/ new decryption method.
+            PlainText decryptedPlaintext  = instance.decrypt(skey, ciphertext);        // The new decrypt() method.
+
+            // Make sure we got back the same thing we started with.
+            System.out.println("\tOriginal plaintext: " + origPlainText);
+            System.out.println("\tResult after decryption: " + decryptedPlaintext);
+            assertEquals( "Failed to decrypt properly.", origPlainText.toString(), decryptedPlaintext.toString() );
+
+            // Restore the previous cipher transformation. For now, this is only way to do this.
+            @SuppressWarnings("deprecation")
+            String previousCipherXform = ESAPI.securityConfiguration().setCipherTransformation(null);
+            assertEquals( previousCipherXform,  cipherXform  );
+            @SuppressWarnings("deprecation")
+            String defaultCipherXform = ESAPI.securityConfiguration().getCipherTransformation();
+            assertEquals( defaultCipherXform, oldCipherXform );
+
+            return ciphertext.getEncodedIVCipherText();
+        } catch (Exception e) {
+            // OK if not counted toward code coverage.
+            System.out.println("testNewEncryptDecrypt(): Caught unexpected exception: " + e.getClass().getName());
+            e.printStackTrace(System.out);
+            fail("Caught unexpected exception; msg was: " + e);
+        }
+        return null;
     }
-    
+
     private static boolean isPlaintextOverwritten(PlainText plaintext) {
-    	// Note: An assumption here that the original plaintext did not consist
-    	// entirely of all '*' characters.
-    	byte[] ptBytes = plaintext.asBytes();
-    	
-    	for ( int i = 0; i < ptBytes.length; i++ ) {
-    		if ( ptBytes[i] != '*' ) {
-    			return false;
-    		}
-    	}
-    	return true;
+        // Note: An assumption here that the original plaintext did not consist
+        // entirely of all '*' characters.
+        byte[] ptBytes = plaintext.asBytes();
+
+        for ( int i = 0; i < ptBytes.length; i++ ) {
+            if ( ptBytes[i] != '*' ) {
+                return false;
+            }
+        }
+        return true;
     }
-    
+
     // TODO - Because none of the encryption / decryption tests persists
-    //		  encrypted data across runs, that means everything is run
-    //		  under same JVM at same time thus always with the same
-    //		  _native_ byte encoding.
+    //          encrypted data across runs, that means everything is run
+    //          under same JVM at same time thus always with the same
+    //          _native_ byte encoding.
     //
-    //		  Need test(s) such that data is persisted across JVM runs
-    //		  so we can test a run on (say) a Windows Intel box can decrypt
-    //		  encrypted data produced by the reference Encryptor on
-    //		  (say) a Solaris SPARC box. I.e., test that the change to
-    //		  JavaEncryptor to use UTF-8 encoding throughout works as
-    //		  desired.
+    //          Need test(s) such that data is persisted across JVM runs
+    //          so we can test a run on (say) a Windows Intel box can decrypt
+    //          encrypted data produced by the reference Encryptor on
+    //          (say) a Solaris SPARC box. I.e., test that the change to
+    //          JavaEncryptor to use UTF-8 encoding throughout works as
+    //          desired.
     //
-    //		  Files saved across tests need to be added to SVN (under
-    //		  resources or where) and they should be named so we know
-    //		  where and how they were created. E.g., WinOS-AES-ECB.dat,
-    //		  Sparc-Solaris-AEC-CBC-PKCS5Padding.dat, etc., but they should be
-    //		  able to be decrypted from any platform. May wish to place that
-    //		  under a separate JUnit test.
+    //          Files saved across tests need to be added to SVN (under
+    //          resources or where) and they should be named so we know
+    //          where and how they were created. E.g., WinOS-AES-ECB.dat,
+    //          Sparc-Solaris-AEC-CBC-PKCS5Padding.dat, etc., but they should be
+    //          able to be decrypted from any platform. May wish to place that
+    //          under a separate JUnit test.
     //
     // TODO - Need to test rainy day paths of new encrypt / decrypt so can
-    //		  verify that exception handling working OK, etc. Maybe also in
-    //		  a separate JUnit test, since everything here seems to be sunny
-    //		  day path. (Note: Some of this no in new test case,
-    //		  org.owasp.esapi.crypto.ESAPICryptoMACByPassTest.)
+    //          verify that exception handling working OK, etc. Maybe also in
+    //          a separate JUnit test, since everything here seems to be sunny
+    //          day path. (Note: Some of this no in new test case,
+    //          org.owasp.esapi.crypto.ESAPICryptoMACByPassTest.)
     //
-    //				-kevin wall
-    
+    //                -kevin wall
+
 
     /**
-	 * Test of sign method, of class org.owasp.esapi.Encryptor.
-	 * 
-	 * @throws EncryptionException
-	 *             the encryption exception
-	 */
+     * Test of sign method, of class org.owasp.esapi.Encryptor.
+     *
+     * @throws EncryptionException
+     *             the encryption exception
+     */
     public void testSign() throws EncryptionException {
-        System.out.println("testSign()");        
+        System.out.println("testSign()");
         Encryptor instance = ESAPI.encryptor();
         String plaintext = ESAPI.randomizer().getRandomString( 32, EncoderConstants.CHAR_ALPHANUMERICS );
         String signature = instance.sign(plaintext);
@@ -439,11 +439,11 @@ public class EncryptorTest extends TestCase {
     }
 
     /**
-	 * Test of verifySignature method, of class org.owasp.esapi.Encryptor.
-	 * 
-	 * @throws EncryptionException
-	 *             the encryption exception
-	 */
+     * Test of verifySignature method, of class org.owasp.esapi.Encryptor.
+     *
+     * @throws EncryptionException
+     *             the encryption exception
+     */
     public void testVerifySignature() throws EncryptionException {
         System.out.println("testVerifySignature()");
         Encryptor instance = ESAPI.encryptor();
@@ -451,20 +451,20 @@ public class EncryptorTest extends TestCase {
         String signature = instance.sign(plaintext);
         assertTrue( instance.verifySignature( signature, plaintext ) );
     }
-    
- 
+
+
     /**
-	 * Test of seal method, of class org.owasp.esapi.Encryptor.
-	 * 
+     * Test of seal method, of class org.owasp.esapi.Encryptor.
+     *
      * @throws IntegrityException
-	 */
+     */
     public void testSeal() throws IntegrityException {
         System.out.println("testSeal()");
-        Encryptor instance = ESAPI.encryptor(); 
+        Encryptor instance = ESAPI.encryptor();
         String plaintext = ESAPI.randomizer().getRandomString( 32, EncoderConstants.CHAR_ALPHANUMERICS );
         String seal = instance.seal( plaintext, instance.getTimeStamp() + 1000*60 );
         instance.verifySeal( seal );
-        
+
         int progressMark = 1;
         boolean caughtExpectedEx = false;
         try {
@@ -484,7 +484,7 @@ public class EncryptorTest extends TestCase {
             fail("Failed null string test; did not get expected IllegalArgumentException: " + e);
         }
         assertTrue(caughtExpectedEx);
-        
+
         try {
             seal = instance.seal("test", 0);
             progressMark++;
@@ -504,21 +504,21 @@ public class EncryptorTest extends TestCase {
     }
 
     /**
-	 * Test of verifySeal method, of class org.owasp.esapi.Encryptor.
-	 * 
+     * Test of verifySeal method, of class org.owasp.esapi.Encryptor.
+     *
      * @throws EnterpriseSecurityException
-	 */
+     */
     public void testVerifySeal() throws EnterpriseSecurityException {
         final int NSEC = 5;
         System.out.println("testVerifySeal()");
-        Encryptor instance = ESAPI.encryptor(); 
+        Encryptor instance = ESAPI.encryptor();
         String plaintext = "ridiculous:with:delimiters";    // Should now work w/ : (issue #28)
         String seal = instance.seal( plaintext, instance.getRelativeTimeStamp( 1000 * NSEC ) );
         try {
-        	assertNotNull("Encryptor.seal() returned null", seal );
-        	assertTrue("Failed to verify seal", instance.verifySeal( seal ) );
+            assertNotNull("Encryptor.seal() returned null", seal );
+            assertTrue("Failed to verify seal", instance.verifySeal( seal ) );
         } catch ( Exception e ) {
-        	fail();
+            fail();
         }
         int progressMark = 1;
         try {
@@ -534,10 +534,10 @@ public class EncryptorTest extends TestCase {
             //
             // All these should return false and log a warning with an Exception stack
             // trace caused by an EncryptionException indicating "Invalid seal".
-        	assertFalse( instance.verifySeal( plaintext ) );
-        	progressMark++;      	
+            assertFalse( instance.verifySeal( plaintext ) );
+            progressMark++;
             assertFalse( instance.verifySeal( instance.encrypt( new PlainText(plaintext) ).getBase64EncodedRawCipherText() ) );
-            progressMark++;            
+            progressMark++;
             assertFalse( instance.verifySeal( instance.encrypt( new PlainText(100 + ":" + plaintext) ).getBase64EncodedRawCipherText() ) );
             progressMark++;
             assertFalse( instance.verifySeal( instance.encrypt( new PlainText(Long.MAX_VALUE + ":" + plaintext) ).getBase64EncodedRawCipherText() ) );
@@ -549,12 +549,12 @@ public class EncryptorTest extends TestCase {
             assertFalse( instance.verifySeal( instance.encrypt( new PlainText(Long.MAX_VALUE + ":random:" + plaintext + ":"+ instance.sign( Long.MAX_VALUE + ":random:" + plaintext) ) ).getBase64EncodedRawCipherText() ) );
             progressMark++;
         } catch ( Exception e ) {
-        	// fail("Failed invalid seal test # " + progressMark + " to verify seal.");
+            // fail("Failed invalid seal test # " + progressMark + " to verify seal.");
             System.err.println("Failed seal verification at step # " + progressMark);
             System.err.println("Exception was: " + e);
             e.printStackTrace(System.err);
         }
-        
+
         try {
             Thread.sleep(1000 * (NSEC + 1) );
                 // Seal now past expiration date.
@@ -563,22 +563,22 @@ public class EncryptorTest extends TestCase {
             fail("Failed expired seal test. Seal should be expired.");
         }
     }
-        
+
 
     @SuppressWarnings("deprecation")
     public void testEncryptionSerialization() throws EncryptionException {
         String secretMsg = "Secret Message";
         ESAPI.securityConfiguration().setCipherTransformation("AES/CBC/PKCS5Padding");
         CipherText ct = ESAPI.encryptor().encrypt(new PlainText(secretMsg));
-        
+
         byte[] serializedCipherText = ct.asPortableSerializedByteArray();
-        
+
         PlainText plainText = ESAPI.encryptor().decrypt(
                                 CipherText.fromPortableSerializedBytes(serializedCipherText) );
-        
+
         assertTrue( secretMsg.equals( plainText.toString() ) );
     }
-    
+
     /**
      * Test of main method, of class org.owasp.esapi.Encryptor. Must be done by
      * visual inspection for now. (Needs improvement.)
@@ -587,13 +587,13 @@ public class EncryptorTest extends TestCase {
     public void testMain() throws Exception {
         System.out.println("testMain(): Encryptor Main with '-print' argument.");
         String[] args = {};
-        JavaEncryptor.main( args );        
+        JavaEncryptor.main( args );
             // TODO:
             // It probably would be a better if System.out were changed to be
             // a file or a byte stream so that the output could be slurped up
             // and checked against (at least some of) the expected output.
             // Left as an exercise to some future, ambitious ESAPI developer. ;-)
         String[] args1 = {"-print"};
-        JavaEncryptor.main( args1 );        
-    }    
+        JavaEncryptor.main( args1 );
+    }
 }
diff --git a/src/test/java/org/owasp/esapi/reference/crypto/ReferenceEncryptedPropertiesTest.java b/src/test/java/org/owasp/esapi/reference/crypto/ReferenceEncryptedPropertiesTest.java
index 9236dd7..eaa2507 100644
--- a/src/test/java/org/owasp/esapi/reference/crypto/ReferenceEncryptedPropertiesTest.java
+++ b/src/test/java/org/owasp/esapi/reference/crypto/ReferenceEncryptedPropertiesTest.java
@@ -1,15 +1,15 @@
 /**
  * OWASP Enterprise Security API (ESAPI)
- * 
+ *
  * This file is part of the Open Web Application Security Project (OWASP)
  * Enterprise Security API (ESAPI) project. For details, please see
  * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
  *
  * Copyright (c) 2007 - The OWASP Foundation
- * 
+ *
  * The ESAPI is published by OWASP under the BSD license. You should read and accept the
  * LICENSE before you use, modify, and/or redistribute this software.
- * 
+ *
  * @author Jeff Williams <a href="http://www.aspectsecurity.com">Aspect Security</a>
  * @created 2007
  */
@@ -31,7 +31,7 @@ import org.owasp.esapi.errors.EncryptionRuntimeException;
 
 /**
  * The Class EncryptedPropertiesTest.
- * 
+ *
  * @author August Detlefsen (augustd at codemagi dot com)
  *         <a href="http://www.codemagi.com">CodeMagi, Inc.</a>
  * @since October 8, 2010
@@ -40,43 +40,43 @@ public class ReferenceEncryptedPropertiesTest {
 
     @Rule
     public TemporaryFolder tempFolder = new TemporaryFolder();
-	
-	/**
-	 * Test of getProperty method, of class org.owasp.esapi.EncryptedProperties.
-	 * 
-	 * @throws EncryptionException
-	 *             the encryption exception
-	 */
-	@Test public void testGetProperty() throws EncryptionException {
-		System.out.println("getProperty");
-		ReferenceEncryptedProperties instance = new ReferenceEncryptedProperties();
-		String name = "name";
-		String value = "value";
-		instance.setProperty(name, value);
-		String result = instance.getProperty(name);
-		assertEquals(value, result);
-		assertNull(instance.getProperty("ridiculous"));
-	}
-
-	/**
-	 * Test of setProperty method, of class org.owasp.esapi.EncryptedProperties.
-	 * 
-	 * @throws EncryptionException
-	 *             the encryption exception
-	 */
-	@Test public void testSetProperty() throws EncryptionException {
-		System.out.println("setProperty");
-		ReferenceEncryptedProperties instance = new ReferenceEncryptedProperties();
-		String name = "name";
-		String value = "value";
-		instance.setProperty(name, value);
-		String result = instance.getProperty(name);
-		assertEquals(value, result);
-		
+
+    /**
+     * Test of getProperty method, of class org.owasp.esapi.EncryptedProperties.
+     *
+     * @throws EncryptionException
+     *             the encryption exception
+     */
+    @Test public void testGetProperty() throws EncryptionException {
+        System.out.println("getProperty");
+        ReferenceEncryptedProperties instance = new ReferenceEncryptedProperties();
+        String name = "name";
+        String value = "value";
+        instance.setProperty(name, value);
+        String result = instance.getProperty(name);
+        assertEquals(value, result);
+        assertNull(instance.getProperty("ridiculous"));
+    }
+
+    /**
+     * Test of setProperty method, of class org.owasp.esapi.EncryptedProperties.
+     *
+     * @throws EncryptionException
+     *             the encryption exception
+     */
+    @Test public void testSetProperty() throws EncryptionException {
+        System.out.println("setProperty");
+        ReferenceEncryptedProperties instance = new ReferenceEncryptedProperties();
+        String name = "name";
+        String value = "value";
+        instance.setProperty(name, value);
+        String result = instance.getProperty(name);
+        assertEquals(value, result);
+
         instance.setProperty(name, "");
         result = instance.getProperty(name);
         assertEquals(result, "");
-        
+
         try {
             instance.setProperty(null, value);
             fail("testSetProperty(): Null property name did not result in expected exception.");
@@ -89,218 +89,218 @@ public class ReferenceEncryptedPropertiesTest {
         } catch( Exception e ) {
             assertTrue( e instanceof EncryptionRuntimeException );
         }
-		try {
-			instance.setProperty(null, null);			
-			fail("testSetProperty(): Null property name and valud did not result in expected exception.");
-		} catch( Exception e ) {
-		    assertTrue( e instanceof EncryptionRuntimeException );
-		}
-	}
-
-	/**
-	 * Test the behavior when the requested key does not exist.
-	 */
-	@Test public void testNonExistantKeyValue() throws Exception
-	{
-		ReferenceEncryptedProperties instance = new ReferenceEncryptedProperties();
-		assertNull(instance.getProperty("not.there"));
-	}
-
-	/**
-	 * Test of keySet method, of class org.owasp.esapi.EncryptedProperties.
-	 */
-	@Test public void testKeySet() throws Exception
-	{
-		boolean sawTwo = false;
-		boolean sawOne = false;
-
-		System.out.println("keySet");
-		ReferenceEncryptedProperties instance = new ReferenceEncryptedProperties();
-		instance.setProperty("one", "two");
-		instance.setProperty("two", "three");
-		Iterator i = instance.keySet().iterator();
-		while(i.hasNext())
-		{
-			String key = (String)i.next();
-
-			assertNotNull("key returned from keySet() iterator was null", key);
-			if(key.equals("one"))
-				if(sawOne)
-					fail("Key one seen more than once.");
-				else
-					sawOne = true;
-			else if(key.equals("two"))
-				if(sawTwo)
-					fail("Key two seen more than once.");
-				else
-					sawTwo = true;
-			else
-				fail("Unset key " + key + " returned from keySet().iterator()");
-		}
-		assertTrue("Key one was never seen", sawOne);
-		assertTrue("Key two was never seen", sawTwo);
-	}
-
-	/**
-	 * Test storing and loading of encrypted properties.
-	 */
-	@Test public void testStoreLoad() throws Exception
-	{
-		ReferenceEncryptedProperties toLoad = new ReferenceEncryptedProperties();
-		ByteArrayOutputStream baos = new ByteArrayOutputStream();
-		ByteArrayInputStream bais;
-		boolean sawOne = false;
-		boolean sawTwo = false;
-		boolean sawSeuss = false;
-
-	    ReferenceEncryptedProperties toStore = new ReferenceEncryptedProperties();
-		toStore.setProperty("one", "two");
-		toStore.setProperty("two", "three");
-		toStore.setProperty("seuss.schneier", "one fish, twofish, red fish, blowfish");
-		toStore.store(baos, "testStore");
-
-		bais = new ByteArrayInputStream(baos.toByteArray());
-		toLoad.load(bais);
-
-		for(Iterator i=toLoad.keySet().iterator();i.hasNext();)
-		{
-			String key = (String)i.next();
-
-			assertNotNull("key returned from keySet() iterator was null", key);
-			if(key.equals("one"))
-				if(sawOne)
-					fail("Key one seen more than once.");
-				else
-				{
-					sawOne = true;
-					assertEquals("Key one's value was not two", "two", toLoad.getProperty("one"));
-				}
-			else if(key.equals("two"))
-				if(sawTwo)
-					fail("Key two seen more than once.");
-				else
-				{
-					sawTwo = true;
-					assertEquals("Key two's value was not three", "three", toLoad.getProperty("two"));
-				}
-	         else if(key.equals("seuss.schneier"))
-	                if(sawSeuss)
-	                    fail("Key seuss.schneier seen more than once.");
-	                else
-	                {
-	                    sawSeuss = true;
-	                    assertEquals("Key seuss.schneier's value was not expected value",
-	                                 "one fish, twofish, red fish, blowfish",
-	                                 toStore.getProperty("seuss.schneier"));
-	                }
-			else
-				fail("Unset key " + key + " returned from keySet().iterator()");
-		}
-		assertTrue("Key one was never seen", sawOne);
-		assertTrue("Key two was never seen", sawTwo);
-	}
-
-	/**
-	 * Test storing and loading of encrypted properties.
-	 */
-	@Test public void testStoreLoadWithReader() throws Exception
-	{
+        try {
+            instance.setProperty(null, null);
+            fail("testSetProperty(): Null property name and valud did not result in expected exception.");
+        } catch( Exception e ) {
+            assertTrue( e instanceof EncryptionRuntimeException );
+        }
+    }
+
+    /**
+     * Test the behavior when the requested key does not exist.
+     */
+    @Test public void testNonExistantKeyValue() throws Exception
+    {
+        ReferenceEncryptedProperties instance = new ReferenceEncryptedProperties();
+        assertNull(instance.getProperty("not.there"));
+    }
+
+    /**
+     * Test of keySet method, of class org.owasp.esapi.EncryptedProperties.
+     */
+    @Test public void testKeySet() throws Exception
+    {
+        boolean sawTwo = false;
+        boolean sawOne = false;
+
+        System.out.println("keySet");
+        ReferenceEncryptedProperties instance = new ReferenceEncryptedProperties();
+        instance.setProperty("one", "two");
+        instance.setProperty("two", "three");
+        Iterator i = instance.keySet().iterator();
+        while(i.hasNext())
+        {
+            String key = (String)i.next();
+
+            assertNotNull("key returned from keySet() iterator was null", key);
+            if(key.equals("one"))
+                if(sawOne)
+                    fail("Key one seen more than once.");
+                else
+                    sawOne = true;
+            else if(key.equals("two"))
+                if(sawTwo)
+                    fail("Key two seen more than once.");
+                else
+                    sawTwo = true;
+            else
+                fail("Unset key " + key + " returned from keySet().iterator()");
+        }
+        assertTrue("Key one was never seen", sawOne);
+        assertTrue("Key two was never seen", sawTwo);
+    }
+
+    /**
+     * Test storing and loading of encrypted properties.
+     */
+    @Test public void testStoreLoad() throws Exception
+    {
+        ReferenceEncryptedProperties toLoad = new ReferenceEncryptedProperties();
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        ByteArrayInputStream bais;
+        boolean sawOne = false;
+        boolean sawTwo = false;
+        boolean sawSeuss = false;
+
+        ReferenceEncryptedProperties toStore = new ReferenceEncryptedProperties();
+        toStore.setProperty("one", "two");
+        toStore.setProperty("two", "three");
+        toStore.setProperty("seuss.schneier", "one fish, twofish, red fish, blowfish");
+        toStore.store(baos, "testStore");
+
+        bais = new ByteArrayInputStream(baos.toByteArray());
+        toLoad.load(bais);
+
+        for(Iterator i=toLoad.keySet().iterator();i.hasNext();)
+        {
+            String key = (String)i.next();
+
+            assertNotNull("key returned from keySet() iterator was null", key);
+            if(key.equals("one"))
+                if(sawOne)
+                    fail("Key one seen more than once.");
+                else
+                {
+                    sawOne = true;
+                    assertEquals("Key one's value was not two", "two", toLoad.getProperty("one"));
+                }
+            else if(key.equals("two"))
+                if(sawTwo)
+                    fail("Key two seen more than once.");
+                else
+                {
+                    sawTwo = true;
+                    assertEquals("Key two's value was not three", "three", toLoad.getProperty("two"));
+                }
+             else if(key.equals("seuss.schneier"))
+                    if(sawSeuss)
+                        fail("Key seuss.schneier seen more than once.");
+                    else
+                    {
+                        sawSeuss = true;
+                        assertEquals("Key seuss.schneier's value was not expected value",
+                                     "one fish, twofish, red fish, blowfish",
+                                     toStore.getProperty("seuss.schneier"));
+                    }
+            else
+                fail("Unset key " + key + " returned from keySet().iterator()");
+        }
+        assertTrue("Key one was never seen", sawOne);
+        assertTrue("Key two was never seen", sawTwo);
+    }
+
+    /**
+     * Test storing and loading of encrypted properties.
+     */
+    @Test public void testStoreLoadWithReader() throws Exception
+    {
 /*
-		//create an EncryptedProperties to store
-		ReferenceEncryptedProperties toStore = new ReferenceEncryptedProperties();
-		toStore.setProperty("one", "two");
-		toStore.setProperty("two", "three");
-		toStore.setProperty("seuss.schneier", "one fish, twofish, red fish, blowfish");
-
-		//store properties to a Writer
-		CharArrayWriter writer = new CharArrayWriter();
-		//toStore.store(writer, "testStore");
-
-		//read it back in from a Reader
-		Reader reader = new CharArrayReader(writer.toCharArray());
-
-		ReferenceEncryptedProperties toLoad = new ReferenceEncryptedProperties();
-		toLoad.load(reader);
-
-		//test the resulting loaded properties
-		boolean sawOne = false;
-		boolean sawTwo = false;
-		boolean sawSeuss = false;
-
-		for(Iterator i=toLoad.keySet().iterator();i.hasNext();)
-		{
-			String key = (String)i.next();
-
-			assertNotNull("key returned from keySet() iterator was null", key);
-			if(key.equals("one"))
-				if(sawOne)
-					fail("Key one seen more than once.");
-				else
-				{
-					sawOne = true;
-					assertEquals("Key one's value was not two", "two", toLoad.getProperty("one"));
-				}
-			else if(key.equals("two"))
-				if(sawTwo)
-					fail("Key two seen more than once.");
-				else
-				{
-					sawTwo = true;
-					assertEquals("Key two's value was not three", "three", toLoad.getProperty("two"));
-				}
-	         else if(key.equals("seuss.schneier"))
-	                if(sawSeuss)
-	                    fail("Key seuss.schneier seen more than once.");
-	                else
-	                {
-	                    sawSeuss = true;
-	                    assertEquals("Key seuss.schneier's value was not expected value",
-	                                 "one fish, twofish, red fish, blowfish",
-	                                 toStore.getProperty("seuss.schneier"));
-	                }
-			else
-				fail("Unset key " + key + " returned from keySet().iterator()");
-		}
-		assertTrue("Key one was never seen", sawOne);
-		assertTrue("Key two was never seen", sawTwo);
+        //create an EncryptedProperties to store
+        ReferenceEncryptedProperties toStore = new ReferenceEncryptedProperties();
+        toStore.setProperty("one", "two");
+        toStore.setProperty("two", "three");
+        toStore.setProperty("seuss.schneier", "one fish, twofish, red fish, blowfish");
+
+        //store properties to a Writer
+        CharArrayWriter writer = new CharArrayWriter();
+        //toStore.store(writer, "testStore");
+
+        //read it back in from a Reader
+        Reader reader = new CharArrayReader(writer.toCharArray());
+
+        ReferenceEncryptedProperties toLoad = new ReferenceEncryptedProperties();
+        toLoad.load(reader);
+
+        //test the resulting loaded properties
+        boolean sawOne = false;
+        boolean sawTwo = false;
+        boolean sawSeuss = false;
+
+        for(Iterator i=toLoad.keySet().iterator();i.hasNext();)
+        {
+            String key = (String)i.next();
+
+            assertNotNull("key returned from keySet() iterator was null", key);
+            if(key.equals("one"))
+                if(sawOne)
+                    fail("Key one seen more than once.");
+                else
+                {
+                    sawOne = true;
+                    assertEquals("Key one's value was not two", "two", toLoad.getProperty("one"));
+                }
+            else if(key.equals("two"))
+                if(sawTwo)
+                    fail("Key two seen more than once.");
+                else
+                {
+                    sawTwo = true;
+                    assertEquals("Key two's value was not three", "three", toLoad.getProperty("two"));
+                }
+             else if(key.equals("seuss.schneier"))
+                    if(sawSeuss)
+                        fail("Key seuss.schneier seen more than once.");
+                    else
+                    {
+                        sawSeuss = true;
+                        assertEquals("Key seuss.schneier's value was not expected value",
+                                     "one fish, twofish, red fish, blowfish",
+                                     toStore.getProperty("seuss.schneier"));
+                    }
+            else
+                fail("Unset key " + key + " returned from keySet().iterator()");
+        }
+        assertTrue("Key one was never seen", sawOne);
+        assertTrue("Key two was never seen", sawTwo);
 */
-	}
+    }
 
-	/**
-	 * Test overridden put method.
-	 */
-	@Test public void testPut() throws Exception
-	{
-		ReferenceEncryptedProperties props = new ReferenceEncryptedProperties();
+    /**
+     * Test overridden put method.
+     */
+    @Test public void testPut() throws Exception
+    {
+        ReferenceEncryptedProperties props = new ReferenceEncryptedProperties();
 
-		String name = "name";
-		String value = "value";
+        String name = "name";
+        String value = "value";
 
-		props.put(name, value);  //should work and store encrypted
-		String result = props.getProperty(name);
-		assertEquals(value, result);
+        props.put(name, value);  //should work and store encrypted
+        String result = props.getProperty(name);
+        assertEquals(value, result);
 
-		Integer five = new Integer(5);
+        Integer five = new Integer(5);
 
-		try {
-			props.put("Integer", five); //should fail and throw IllegalArgumentException
-			fail("testPut(): Non-String property value did not result in expected exception.");
-		} catch( Exception e ) {
+        try {
+            props.put("Integer", five); //should fail and throw IllegalArgumentException
+            fail("testPut(): Non-String property value did not result in expected exception.");
+        } catch( Exception e ) {
             assertTrue( e instanceof IllegalArgumentException );
         }
-		try {
-			props.put(five, "Integer"); //should fail and throw IllegalArgumentException
-			fail("testPut(): Non-String property key did not result in expected exception.");
-		} catch( Exception e ) {
+        try {
+            props.put(five, "Integer"); //should fail and throw IllegalArgumentException
+            fail("testPut(): Non-String property key did not result in expected exception.");
+        } catch( Exception e ) {
             assertTrue( e instanceof IllegalArgumentException );
         }
-		try {
-			props.put(five, five); //should fail and throw IllegalArgumentException
-			fail("testPut(): Non-String property key and value did not result in expected exception.");
-		} catch( Exception e ) {
+        try {
+            props.put(five, five); //should fail and throw IllegalArgumentException
+            fail("testPut(): Non-String property key and value did not result in expected exception.");
+        } catch( Exception e ) {
             assertTrue( e instanceof IllegalArgumentException );
         }
-		try {
+        try {
             props.put(null, five);
             fail("testSetProperty(): Null property name and non-String value did not result in expected exception.");
         } catch( Exception e ) {
@@ -312,7 +312,7 @@ public class ReferenceEncryptedPropertiesTest {
         } catch( Exception e ) {
             assertTrue( e instanceof IllegalArgumentException );
         }
-		try {
+        try {
             props.put(null, value);
             fail("testSetProperty(): Null property name did not result in expected exception.");
         } catch( Exception e ) {
@@ -324,176 +324,176 @@ public class ReferenceEncryptedPropertiesTest {
         } catch( Exception e ) {
             assertTrue( e instanceof IllegalArgumentException );
         }
-		try {
-			props.put(null, null);
-			fail("testSetProperty(): Null property name and valud did not result in expected exception.");
-		} catch( Exception e ) {
-		    assertTrue( e instanceof IllegalArgumentException );
-		}
-	}
-
-	/**
-	 * Test that ReferenceEncryptedProperties can be properly constructed
-	 * with an instance of Properties.
-	 */
-	@Test public void testConstructWithProperties() {
-		Properties props = new Properties();
-		props.setProperty("one", "two");
-		props.setProperty("two", "three");
-		props.setProperty("seuss.schneier", "one fish, twofish, red fish, blowfish");
-
-		ReferenceEncryptedProperties eProps = new ReferenceEncryptedProperties(props);
-
-		boolean sawOne = false;
-		boolean sawTwo = false;
-		boolean sawSeuss = false;
-
-		for(Iterator i=eProps.keySet().iterator();i.hasNext();)
-		{
-			String key = (String)i.next();
-
-			assertNotNull("key returned from keySet() iterator was null", key);
-			if(key.equals("one"))
-				if(sawOne)
-					fail("Key one seen more than once.");
-				else
-				{
-					sawOne = true;
-					assertEquals("Key one's value was not two", "two", eProps.getProperty("one"));
-				}
-			else if(key.equals("two"))
-				if(sawTwo)
-					fail("Key two seen more than once.");
-				else
-				{
-					sawTwo = true;
-					assertEquals("Key two's value was not three", "three", eProps.getProperty("two"));
-				}
-	         else if(key.equals("seuss.schneier"))
-	                if(sawSeuss)
-	                    fail("Key seuss.schneier seen more than once.");
-	                else
-	                {
-	                    sawSeuss = true;
-	                    assertEquals("Key seuss.schneier's value was not expected value",
-	                                 "one fish, twofish, red fish, blowfish",
-	                                 eProps.getProperty("seuss.schneier"));
-	                }
-			else
-				fail("Unset key " + key + " returned from keySet().iterator()");
-		}
-		assertTrue("Key one was never seen", sawOne);
-		assertTrue("Key two was never seen", sawTwo);
-	}
-
-	/**
-	 * Test that ReferenceEncryptedProperties can be properly constructed
-	 * with an instance of EncryptedProperties.
-	 */
-	@Test public void testConstructWithEncryptedProperties() throws Exception {
-		ReferenceEncryptedProperties props = new ReferenceEncryptedProperties();
-		props.setProperty("one", "two");
-		props.setProperty("two", "three");
-		props.setProperty("seuss.schneier", "one fish, twofish, red fish, blowfish");
-
-		ReferenceEncryptedProperties eProps = new ReferenceEncryptedProperties(props);
-
-		boolean sawOne = false;
-		boolean sawTwo = false;
-		boolean sawSeuss = false;
-
-		for(Iterator i=eProps.keySet().iterator();i.hasNext();)
-		{
-			String key = (String)i.next();
-
-			assertNotNull("key returned from keySet() iterator was null", key);
-			if(key.equals("one"))
-				if(sawOne)
-					fail("Key one seen more than once.");
-				else
-				{
-					sawOne = true;
-					assertEquals("Key one's value was not two", "two", eProps.getProperty("one"));
-				}
-			else if(key.equals("two"))
-				if(sawTwo)
-					fail("Key two seen more than once.");
-				else
-				{
-					sawTwo = true;
-					assertEquals("Key two's value was not three", "three", eProps.getProperty("two"));
-				}
-	         else if(key.equals("seuss.schneier"))
-	                if(sawSeuss)
-	                    fail("Key seuss.schneier seen more than once.");
-	                else
-	                {
-	                    sawSeuss = true;
-	                    assertEquals("Key seuss.schneier's value was not expected value",
-	                                 "one fish, twofish, red fish, blowfish",
-	                                 eProps.getProperty("seuss.schneier"));
-	                }
-			else
-				fail("Unset key " + key + " returned from keySet().iterator()");
-		}
-		assertTrue("Key one was never seen", sawOne);
-		assertTrue("Key two was never seen", sawTwo);
-	}
-
-
-	/**
-	 * Test overridden methods from Properties and Hashtable.
-	 */
-	@Test public void testOverriddenMethods() throws Exception {
-		Properties props = new ReferenceEncryptedProperties();
-		props.setProperty("one", "two");
-		props.setProperty("two", "three");
-		props.setProperty("seuss.schneier", "one fish, twofish, red fish, blowfish");
-
-		FileOutputStream out = new FileOutputStream(tempFolder.newFile("ReferenceEncryptedProperties.test.txt"));
-		PrintStream ps = new PrintStream(out);
-		try {
-			props.list(ps);
-			fail("testOverriddenMethods(): list(PrintStream) did not result in expected Exception");
-		} catch( Exception e ) {
-		    assertTrue( e instanceof UnsupportedOperationException );
-		}
-
-		PrintWriter pw = new PrintWriter(new FileWriter(tempFolder.newFile("test.out")));
-		try {
-			props.list(pw);
-			fail("testOverriddenMethods(): list(PrintWriter) did not result in expected Exception");
-		} catch( Exception e ) {
-		    assertTrue( e instanceof UnsupportedOperationException );
-		}
-
-		try {
-			props.list(ps);
-			fail("testOverriddenMethods(): list(PrintStream) did not result in expected Exception");
-		} catch( Exception e ) {
-		    assertTrue( e instanceof UnsupportedOperationException );
-		}
-
-		try {
-			Collection c = props.values();
-			fail("testOverriddenMethods(): values() did not result in expected Exception");
-		} catch( Exception e ) {
-		    assertTrue( e instanceof UnsupportedOperationException );
-		}
-
-		try {
-			Collection c = props.entrySet();
-			fail("testOverriddenMethods(): entrySet() did not result in expected Exception");
-		} catch( Exception e ) {
-		    assertTrue( e instanceof UnsupportedOperationException );
-		}
-
-		try {
-			Enumeration e = props.elements();
-			fail("testOverriddenMethods(): elements() did not result in expected Exception");
-		} catch( Exception e ) {
-		    assertTrue( e instanceof UnsupportedOperationException );
-		}
-	}
+        try {
+            props.put(null, null);
+            fail("testSetProperty(): Null property name and valud did not result in expected exception.");
+        } catch( Exception e ) {
+            assertTrue( e instanceof IllegalArgumentException );
+        }
+    }
+
+    /**
+     * Test that ReferenceEncryptedProperties can be properly constructed
+     * with an instance of Properties.
+     */
+    @Test public void testConstructWithProperties() {
+        Properties props = new Properties();
+        props.setProperty("one", "two");
+        props.setProperty("two", "three");
+        props.setProperty("seuss.schneier", "one fish, twofish, red fish, blowfish");
+
+        ReferenceEncryptedProperties eProps = new ReferenceEncryptedProperties(props);
+
+        boolean sawOne = false;
+        boolean sawTwo = false;
+        boolean sawSeuss = false;
+
+        for(Iterator i=eProps.keySet().iterator();i.hasNext();)
+        {
+            String key = (String)i.next();
+
+            assertNotNull("key returned from keySet() iterator was null", key);
+            if(key.equals("one"))
+                if(sawOne)
+                    fail("Key one seen more than once.");
+                else
+                {
+                    sawOne = true;
+                    assertEquals("Key one's value was not two", "two", eProps.getProperty("one"));
+                }
+            else if(key.equals("two"))
+                if(sawTwo)
+                    fail("Key two seen more than once.");
+                else
+                {
+                    sawTwo = true;
+                    assertEquals("Key two's value was not three", "three", eProps.getProperty("two"));
+                }
+             else if(key.equals("seuss.schneier"))
+                    if(sawSeuss)
+                        fail("Key seuss.schneier seen more than once.");
+                    else
+                    {
+                        sawSeuss = true;
+                        assertEquals("Key seuss.schneier's value was not expected value",
+                                     "one fish, twofish, red fish, blowfish",
+                                     eProps.getProperty("seuss.schneier"));
+                    }
+            else
+                fail("Unset key " + key + " returned from keySet().iterator()");
+        }
+        assertTrue("Key one was never seen", sawOne);
+        assertTrue("Key two was never seen", sawTwo);
+    }
+
+    /**
+     * Test that ReferenceEncryptedProperties can be properly constructed
+     * with an instance of EncryptedProperties.
+     */
+    @Test public void testConstructWithEncryptedProperties() throws Exception {
+        ReferenceEncryptedProperties props = new ReferenceEncryptedProperties();
+        props.setProperty("one", "two");
+        props.setProperty("two", "three");
+        props.setProperty("seuss.schneier", "one fish, twofish, red fish, blowfish");
+
+        ReferenceEncryptedProperties eProps = new ReferenceEncryptedProperties(props);
+
+        boolean sawOne = false;
+        boolean sawTwo = false;
+        boolean sawSeuss = false;
+
+        for(Iterator i=eProps.keySet().iterator();i.hasNext();)
+        {
+            String key = (String)i.next();
+
+            assertNotNull("key returned from keySet() iterator was null", key);
+            if(key.equals("one"))
+                if(sawOne)
+                    fail("Key one seen more than once.");
+                else
+                {
+                    sawOne = true;
+                    assertEquals("Key one's value was not two", "two", eProps.getProperty("one"));
+                }
+            else if(key.equals("two"))
+                if(sawTwo)
+                    fail("Key two seen more than once.");
+                else
+                {
+                    sawTwo = true;
+                    assertEquals("Key two's value was not three", "three", eProps.getProperty("two"));
+                }
+             else if(key.equals("seuss.schneier"))
+                    if(sawSeuss)
+                        fail("Key seuss.schneier seen more than once.");
+                    else
+                    {
+                        sawSeuss = true;
+                        assertEquals("Key seuss.schneier's value was not expected value",
+                                     "one fish, twofish, red fish, blowfish",
+                                     eProps.getProperty("seuss.schneier"));
+                    }
+            else
+                fail("Unset key " + key + " returned from keySet().iterator()");
+        }
+        assertTrue("Key one was never seen", sawOne);
+        assertTrue("Key two was never seen", sawTwo);
+    }
+
+
+    /**
+     * Test overridden methods from Properties and Hashtable.
+     */
+    @Test public void testOverriddenMethods() throws Exception {
+        Properties props = new ReferenceEncryptedProperties();
+        props.setProperty("one", "two");
+        props.setProperty("two", "three");
+        props.setProperty("seuss.schneier", "one fish, twofish, red fish, blowfish");
+
+        FileOutputStream out = new FileOutputStream(tempFolder.newFile("ReferenceEncryptedProperties.test.txt"));
+        PrintStream ps = new PrintStream(out);
+        try {
+            props.list(ps);
+            fail("testOverriddenMethods(): list(PrintStream) did not result in expected Exception");
+        } catch( Exception e ) {
+            assertTrue( e instanceof UnsupportedOperationException );
+        }
+
+        PrintWriter pw = new PrintWriter(new FileWriter(tempFolder.newFile("test.out")));
+        try {
+            props.list(pw);
+            fail("testOverriddenMethods(): list(PrintWriter) did not result in expected Exception");
+        } catch( Exception e ) {
+            assertTrue( e instanceof UnsupportedOperationException );
+        }
+
+        try {
+            props.list(ps);
+            fail("testOverriddenMethods(): list(PrintStream) did not result in expected Exception");
+        } catch( Exception e ) {
+            assertTrue( e instanceof UnsupportedOperationException );
+        }
+
+        try {
+            Collection c = props.values();
+            fail("testOverriddenMethods(): values() did not result in expected Exception");
+        } catch( Exception e ) {
+            assertTrue( e instanceof UnsupportedOperationException );
+        }
+
+        try {
+            Collection c = props.entrySet();
+            fail("testOverriddenMethods(): entrySet() did not result in expected Exception");
+        } catch( Exception e ) {
+            assertTrue( e instanceof UnsupportedOperationException );
+        }
+
+        try {
+            Enumeration e = props.elements();
+            fail("testOverriddenMethods(): elements() did not result in expected Exception");
+        } catch( Exception e ) {
+            assertTrue( e instanceof UnsupportedOperationException );
+        }
+    }
 
 }
diff --git a/src/test/java/org/owasp/esapi/reference/validation/BaseValidationRuleTest.java b/src/test/java/org/owasp/esapi/reference/validation/BaseValidationRuleTest.java
index 9bf078c..36a7b1b 100644
--- a/src/test/java/org/owasp/esapi/reference/validation/BaseValidationRuleTest.java
+++ b/src/test/java/org/owasp/esapi/reference/validation/BaseValidationRuleTest.java
@@ -1,15 +1,15 @@
 /**
  * OWASP Enterprise Security API (ESAPI)
- * 
+ *
  * This file is part of the Open Web Application Security Project (OWASP)
  * Enterprise Security API (ESAPI) project. For details, please see
  * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
  *
  * Copyright (c) 2007 - The OWASP Foundation
- * 
+ *
  * The ESAPI is published by OWASP under the BSD license. You should read and accept the
  * LICENSE before you use, modify, and/or redistribute this software.
- * 
+ *
  * @author Ben Sleek <a href="http://www.spartasystems.com">Sparta Systems</a>
  * @created 2015
  */
@@ -52,7 +52,7 @@ public class BaseValidationRuleTest {
 
     private BaseValidationRule uit = mock(BaseValidationRule.class, CALLS_REAL_METHODS);
     @Test
-    public void testCtrNullTypeName() throws Exception { 
+    public void testCtrNullTypeName() throws Exception {
         String typename = null;
         BaseValidationRule rule = mock(BaseValidationRule.class, withSettings()
                 .useConstructor(typename)
@@ -72,7 +72,7 @@ public class BaseValidationRuleTest {
         assertEquals(typename, rule.getTypeName());
         assertNull(rule.getEncoder());
     }
-    
+
     @Test
     public void testCtrNullTypenameNullEncoder() {
         String typename = null;
@@ -108,7 +108,7 @@ public class BaseValidationRuleTest {
 
     @Test
     public void testSetTypeNameNull() {
-        uit.setTypeName(null); 
+        uit.setTypeName(null);
         assertNull(uit.getTypeName());
     }
 
@@ -219,11 +219,11 @@ public class BaseValidationRuleTest {
     }
 
     /* *************************
-     * TO DISCUSS 
+     * TO DISCUSS
      * FIXME
      * Tests below this block are items which are valid against the current implementation, but have side effects
      * or unclear results under certain conditions.
-     * 
+     *
      * Once Items are discussed and understood they should probably be well-commented and moved out of this area.
      */
 
@@ -236,13 +236,13 @@ public class BaseValidationRuleTest {
         /*
          * Side-effect of ValidationErrorList. If the same context is used against a BaseValidationRule multiple times resulting in exception, the ValidationErrorList impl will blow up.
          * This can be an unclear event at runtime if a single BaseValidationRule instance is shared in an application and multiple parts happen to use the same contextual string to capture failure events.
-         * 
+         *
          */
         uit.getValid(STR_VAL, STR_VAL, vel);
     }
 
     //None of the Whitelist content belongs in this class, IMO.
-    
+
     @Test
     public void testWhitelistCharArrayCleansString() {
         String myString = "AAAGaaadBBB12345*";
@@ -281,7 +281,7 @@ public class BaseValidationRuleTest {
     }
 
     @Test
-    
+
     public void testWhitelistSetExtendedCharacterSets() {
         String myString = "𡘾𦴩<𥻂";
         //(55365 56894) (55387 56617) 60 (55383 57026)
diff --git a/src/test/java/org/owasp/esapi/reference/validation/DateValidationRulePowerMockTest.java b/src/test/java/org/owasp/esapi/reference/validation/DateValidationRulePowerMockTest.java
index 071c7b3..1b7c9ed 100644
--- a/src/test/java/org/owasp/esapi/reference/validation/DateValidationRulePowerMockTest.java
+++ b/src/test/java/org/owasp/esapi/reference/validation/DateValidationRulePowerMockTest.java
@@ -23,7 +23,7 @@ import org.powermock.modules.junit4.PowerMockRunner;
 @RunWith(PowerMockRunner.class)
 @PrepareForTest({ObjFactory.class})
 public class DateValidationRulePowerMockTest {
-    
+
     @Rule
     public TestName testName = new TestName();
     private Encoder mockEncoder;
@@ -31,111 +31,111 @@ public class DateValidationRulePowerMockTest {
     private DateValidationRule uit;
     @Mock
     private SecurityConfiguration mockSecConfig;
-    
+
     @Before
     public void configureStaticContexts() throws Exception {
         PowerMockito.mockStatic(ObjFactory.class);
         PowerMockito.when(ObjFactory.class, "make", ArgumentMatchers.anyString(), ArgumentMatchers.eq("SecurityConfiguration")).thenReturn(mockSecConfig);
-        
+
         mockEncoder = Mockito.mock(Encoder.class);
         testFormat = Mockito.spy(testFormat);
     }
-    
+
     @Test
     public void testSetDateFormatLenientTrueFromCtr() {
         Mockito.when(mockSecConfig.getLenientDatesAccepted()).thenReturn(true);
-        
+
         testFormat.setLenient(false);
         Mockito.reset(testFormat);
-        
+
         uit = new DateValidationRule(testName.getMethodName(), mockEncoder, testFormat);
-        
+
         Assert.assertTrue(testFormat.isLenient());
-       
+
         Mockito.verify(mockSecConfig, Mockito.times(1)).getLenientDatesAccepted();
         Mockito.verify(testFormat, Mockito.times(1)).setLenient(true);
         Mockito.verify(testFormat, Mockito.times(0)).setLenient(false);
-        
+
         PowerMockito.verifyStatic(ObjFactory.class, VerificationModeFactory.times(1));
         ObjFactory.make(ArgumentMatchers.anyString(), ArgumentMatchers.eq("SecurityConfiguration"));
-        
+
         PowerMockito.verifyNoMoreInteractions(ObjFactory.class);
-        
-       
+
+
     }
-    
+
     @Test
     public void testSetDateFormatLenientFalseFromCtr() {
         Mockito.when(mockSecConfig.getLenientDatesAccepted()).thenReturn(false);
-        
+
         testFormat.setLenient(true);
         Mockito.reset(testFormat);
-        
+
         uit = new DateValidationRule(testName.getMethodName(), mockEncoder, testFormat);
-        
+
         Assert.assertFalse(testFormat.isLenient());
-       
+
         Mockito.verify(mockSecConfig, Mockito.times(1)).getLenientDatesAccepted();
         Mockito.verify(testFormat, Mockito.times(0)).setLenient(true);
         Mockito.verify(testFormat, Mockito.times(1)).setLenient(false);
-        
+
         PowerMockito.verifyStatic(ObjFactory.class, VerificationModeFactory.times(1));
         ObjFactory.make(ArgumentMatchers.anyString(), ArgumentMatchers.eq("SecurityConfiguration"));
-        
+
         PowerMockito.verifyNoMoreInteractions(ObjFactory.class);
     }
-    
+
     @Test
     public void testSetDateFormatLenientFalseFromSetter() {
         Mockito.when(mockSecConfig.getLenientDatesAccepted()).thenReturn(false);
-        
+
         uit = new DateValidationRule(testName.getMethodName(), mockEncoder, testFormat);
-        
+
         //Configuration is lenient=false
         testFormat.setLenient(true);
         Mockito.reset(testFormat, mockSecConfig);
         Assert.assertTrue(testFormat.isLenient());
-        
+
         Mockito.when(mockSecConfig.getLenientDatesAccepted()).thenReturn(false);
-        
+
         uit.setDateFormat(testFormat);
-        
+
         Assert.assertFalse(testFormat.isLenient());
-        
+
         Mockito.verify(mockSecConfig, Mockito.times(1)).getLenientDatesAccepted();
         Mockito.verify(testFormat, Mockito.times(0)).setLenient(true);
         Mockito.verify(testFormat, Mockito.times(1)).setLenient(false);
-        
+
         PowerMockito.verifyStatic(ObjFactory.class, VerificationModeFactory.times(2));
         ObjFactory.make(ArgumentMatchers.anyString(), ArgumentMatchers.eq("SecurityConfiguration"));
-        
+
         PowerMockito.verifyNoMoreInteractions(ObjFactory.class);
     }
-    
+
     @Test
     public void testSetDateFormatLenientTrueFromSetter() {
         Mockito.when(mockSecConfig.getLenientDatesAccepted()).thenReturn(true);
-        
+
         uit = new DateValidationRule(testName.getMethodName(), mockEncoder, testFormat);
-        
+
         //Configuration is lenient=true
         testFormat.setLenient(false);
         Mockito.reset(testFormat, mockSecConfig);
         Assert.assertFalse(testFormat.isLenient());
-        
+
         Mockito.when(mockSecConfig.getLenientDatesAccepted()).thenReturn(true);
-        
+
         uit.setDateFormat(testFormat);
-        
+
         Assert.assertTrue(testFormat.isLenient());
-        
+
         Mockito.verify(mockSecConfig, Mockito.times(1)).getLenientDatesAccepted();
         Mockito.verify(testFormat, Mockito.times(1)).setLenient(true);
         Mockito.verify(testFormat, Mockito.times(0)).setLenient(false);
-        
+
         PowerMockito.verifyStatic(ObjFactory.class, VerificationModeFactory.times(2));
         ObjFactory.make(ArgumentMatchers.anyString(), ArgumentMatchers.eq("SecurityConfiguration"));
-        
+
         PowerMockito.verifyNoMoreInteractions(ObjFactory.class);
     }
 }
diff --git a/src/test/java/org/owasp/esapi/reference/validation/DateValidationRuleTest.java b/src/test/java/org/owasp/esapi/reference/validation/DateValidationRuleTest.java
index 3e25597..57e9d02 100644
--- a/src/test/java/org/owasp/esapi/reference/validation/DateValidationRuleTest.java
+++ b/src/test/java/org/owasp/esapi/reference/validation/DateValidationRuleTest.java
@@ -23,11 +23,11 @@ import org.owasp.esapi.Encoder;
 import org.owasp.esapi.ValidationErrorList;
 import org.owasp.esapi.errors.ValidationException;
 import org.owasp.esapi.reference.DefaultSecurityConfiguration;
+import static org.owasp.esapi.PropNames.ACCEPT_LENIENT_DATES;
 import org.powermock.reflect.Whitebox;
 
-
 public class DateValidationRuleTest {
-    
+
     @Rule
     public ExpectedException exEx = ExpectedException.none();
     @Rule
@@ -36,19 +36,19 @@ public class DateValidationRuleTest {
     private Date testDate = new Date();
     private String dateString;
     private String canonDateString ;
-    
+
     private String contextStr;
     private Encoder mockEncoder;
     private DateFormat testFormat = DateFormat.getDateInstance(DateFormat.MEDIUM, Locale.US);
     private DateValidationRule uit;
-    
+
     @Before
     public void setup() {
         mockEncoder = Mockito.mock(Encoder.class);
         testFormat = Mockito.spy(testFormat);
         uit = new DateValidationRule(testName.getMethodName(), mockEncoder, testFormat);
         contextStr = testName.getMethodName();
-        
+
         dateString = testFormat.format(testDate);
         canonDateString = dateString;
     }
@@ -58,41 +58,41 @@ public class DateValidationRuleTest {
         exEx.expectMessage("DateValidationRule.setDateFormat requires a non-null DateFormat");
         new DateValidationRule("context", mockEncoder, null);
     }
-    
+
     @Test
     public void testCtrSetDateFormat() {
         DateFormat uitFormat = Whitebox.getInternalState(uit, "format");
         Assert.assertEquals(testFormat, uitFormat);
     }
-    
+
     @Test
     public void testsetDateFormatNullThrows() {
         exEx.expect(IllegalArgumentException.class);
         exEx.expectMessage("DateValidationRule.setDateFormat requires a non-null DateFormat");
         uit.setDateFormat(null);
     }
-    
+
     @Test
     public void testsetDateFormat() {
-        boolean acceptLenient = ESAPI.securityConfiguration().getBooleanProp( DefaultSecurityConfiguration.ACCEPT_LENIENT_DATES);
+        boolean acceptLenient = ESAPI.securityConfiguration().getBooleanProp( ACCEPT_LENIENT_DATES );
         DateFormat newFormat = DateFormat.getDateInstance(DateFormat.SHORT, Locale.US);
         newFormat.setLenient(!acceptLenient);
-        
+
         newFormat = Mockito.spy(newFormat);
-        
+
         uit.setDateFormat(newFormat);
         DateFormat uitFormat = Whitebox.getInternalState(uit, "format");
         Assert.assertEquals(newFormat, uitFormat);
         Mockito.verify(newFormat).setLenient(acceptLenient);
     }
-    
+
     @Test
     public void testGetValidNullInputAllowed() throws ValidationException {
         uit.setAllowNull(true);
         Date vDate = uit.getValid(contextStr, null);
         Assert.assertNull(vDate);
     }
-    
+
     @Test
     public void testGetValidNullInputNotAllowed() throws ValidationException {
         exEx.expect(ValidationException.class);
@@ -100,7 +100,7 @@ public class DateValidationRuleTest {
         uit.setAllowNull(false);
         uit.getValid(contextStr, null);
     }
-    
+
     @Test
     public void testGetValidNullInputNotAllowedEmptyString() throws ValidationException {
         exEx.expect(ValidationException.class);
@@ -108,7 +108,7 @@ public class DateValidationRuleTest {
         uit.setAllowNull(false);
         uit.getValid(contextStr, "");
     }
-    
+
     @Test
     public void testGetValidBadDateThrows() throws ValidationException, ParseException {
         exEx.expect(ValidationException.class);
@@ -120,32 +120,32 @@ public class DateValidationRuleTest {
                return item.equals(testParseEx);
             }
         });
-        
+
         Mockito.when(mockEncoder.canonicalize(dateString)).thenReturn(canonDateString);
         Mockito.doThrow(testParseEx).when(testFormat).parse(canonDateString);
-        
+
         uit.getValid(contextStr, dateString);
     }
-    
+
     @Test
     public void testGetValidHappyPath() throws ValidationException, ParseException {
         Mockito.when(mockEncoder.canonicalize(dateString)).thenReturn(canonDateString);
         Mockito.doReturn(testDate).when(testFormat).parse(canonDateString);
-        
+
         Date date = uit.getValid(contextStr, dateString);
         Assert.assertEquals(testDate, date);
     }
-    
+
     @Test
     public void testGetValidDateWithCruft() throws ValidationException, ParseException {
         String cruftyDate = canonDateString + "' union select * from another_table where user_id like '%";
         Mockito.when(mockEncoder.canonicalize(cruftyDate)).thenReturn(cruftyDate);
         Mockito.doReturn(testDate).when(testFormat).parse(cruftyDate);
-        
+
         Date date = uit.getValid(contextStr, cruftyDate);
         Assert.assertEquals(testDate, date);
     }
-    
+
 
     @Test
     public void testSanitizeNullInputAllowed() throws ValidationException {
@@ -153,48 +153,48 @@ public class DateValidationRuleTest {
         Date vDate = uit.sanitize(contextStr, null);
         Assert.assertNull(vDate);
     }
-    
+
     @Test
     public void testSanitizeNullInputNotAllowed() throws ValidationException {
         uit.setAllowNull(false);
         Date date = uit.sanitize(contextStr, null);
         Assert.assertEquals(0, date.getTime());
     }
-    
+
     @Test
     public void testSanitizeNullInputNotAllowedEmptyString() throws ValidationException {
         uit.setAllowNull(false);
         Date date = uit.sanitize(contextStr, "");
         Assert.assertEquals(0, date.getTime());
     }
-    
+
     @Test
     public void testSanitizeBadDateReturnsDefault() throws ValidationException, ParseException {
         Mockito.when(mockEncoder.canonicalize(dateString)).thenReturn(canonDateString);
         Mockito.doThrow(testParseEx).when(testFormat).parse(canonDateString);
-        
+
         Date date =  uit.sanitize(contextStr, dateString);
         Assert.assertEquals(0, date.getTime());
     }
-    
+
     @Test
     public void testSanitizeErrorListContainsError() throws ValidationException, ParseException {
         ValidationErrorList vel = new ValidationErrorList();
         Mockito.when(mockEncoder.canonicalize(dateString)).thenReturn(canonDateString);
         Mockito.doThrow(testParseEx).when(testFormat).parse(canonDateString);
-        
+
         Date date =  uit.sanitize(contextStr, dateString, vel);
         Assert.assertEquals(0, date.getTime());
         Assert.assertEquals(1, vel.size());
         ValidationException wrapper = vel.errors().get(0);
         Assert.assertEquals(testParseEx, wrapper.getCause());
     }
-    
+
     @Test
     public void testSanitizeHappyPath() throws ValidationException, ParseException {
         Mockito.when(mockEncoder.canonicalize(dateString)).thenReturn(canonDateString);
         Mockito.doReturn(testDate).when(testFormat).parse(canonDateString);
-        
+
         Date date = uit.sanitize(contextStr, dateString);
         Assert.assertEquals(testDate, date);
     }
@@ -203,11 +203,11 @@ public class DateValidationRuleTest {
         String cruftyDate = canonDateString + "' union select * from another_table where user_id like '%";
         Mockito.when(mockEncoder.canonicalize(cruftyDate)).thenReturn(cruftyDate);
         Mockito.doReturn(testDate).when(testFormat).parse(cruftyDate);
-        
+
         Date date = uit.sanitize(contextStr, cruftyDate);
         Assert.assertEquals(0, date.getTime());
     }
-    
+
     @Test
     public void testGithubIssue299() throws ParseException, ValidationException {
         Map<DateFormat, String> formatDateMap = new HashMap<>();
@@ -217,27 +217,27 @@ public class DateValidationRuleTest {
         formatDateMap.put(new SimpleDateFormat("dd/MM/yyyy"),"01/01/2012'SELECT * FROM user_table'");
         formatDateMap.put(new SimpleDateFormat("dd/yyyy/MM"),"01/2aaa/01");
         formatDateMap.put(SimpleDateFormat.getDateInstance(SimpleDateFormat.LONG, Locale.US), "September 11, 2001' union select * from another_table where user_id like '%");
-        
+
         for (Entry<DateFormat, String> pair : formatDateMap.entrySet()) {
             String cruftyDate = pair.getValue();
             Mockito.when(mockEncoder.canonicalize(cruftyDate)).thenReturn(cruftyDate);
-            
+
             DateFormat lenientFormat = Mockito.spy(pair.getKey());
             lenientFormat.setLenient(true);
             Mockito.doNothing().when(lenientFormat).setLenient(ArgumentMatchers.anyBoolean());
             Mockito.doReturn(testDate).when(lenientFormat).parse(cruftyDate);
-            
+
             DateFormat strictFormat = Mockito.spy(pair.getKey());
             strictFormat.setLenient(false);
             Mockito.doNothing().when(strictFormat).setLenient(ArgumentMatchers.anyBoolean());
             Mockito.doReturn(testDate).when(strictFormat).parse(cruftyDate);
-            
+
             uit.setDateFormat(lenientFormat);
             Date lenientValidDate = uit.getValid(contextStr, cruftyDate);
             Assert.assertEquals("calls to getValid should not change the parsed date regardless of cruft",testDate, lenientValidDate);
             Date lenientSanitizedDate = uit.sanitize(contextStr, cruftyDate);
             Assert.assertEquals("calls to sanitize should return default date if cruft exists in input string",0, lenientSanitizedDate.getTime());
-            
+
             uit.setDateFormat(strictFormat);
             Date strictValidDate = uit.getValid(contextStr, cruftyDate);
             Assert.assertEquals("calls to getValid should not change the parsed date regardless of cruft",testDate, strictValidDate);
diff --git a/src/test/java/org/owasp/esapi/reference/validation/HTMLValidationRuleAntisamyPropertyTest.java b/src/test/java/org/owasp/esapi/reference/validation/HTMLValidationRuleAntisamyPropertyTest.java
index 9355904..082bd62 100644
--- a/src/test/java/org/owasp/esapi/reference/validation/HTMLValidationRuleAntisamyPropertyTest.java
+++ b/src/test/java/org/owasp/esapi/reference/validation/HTMLValidationRuleAntisamyPropertyTest.java
@@ -15,12 +15,8 @@
  */
 package org.owasp.esapi.reference.validation;
 
-import org.junit.After;
-import org.junit.AfterClass;
-import org.junit.Before;
-import org.junit.BeforeClass;
 import org.junit.Test;
-import org.owasp.validator.html.Policy;
+import org.owasp.validator.html.PolicyException;
 
 /**
  * Isolate scope test to assert the behavior of the HTMLValidationRule
@@ -32,21 +28,9 @@ public class HTMLValidationRuleAntisamyPropertyTest {
      */
     private static final String INVALID_ANTISAMY_POLICY_FILE = "antisamy-InvalidPolicy.xml";
 
-    @AfterClass
-    public static void enableAntisamySchemaValidation() {
-        Policy.setSchemaValidation(true);
-    }
-    
-    @BeforeClass
-    public static void disableAntisamySchemaValidation() {
-        Policy.setSchemaValidation(false);
-        //System property is read once, so we're preferring the static method for testing.
-        //System.setProperty( "owasp.validator.validateschema", "false" ); 
+    @Test( expected = PolicyException.class )
+    public void checkAntisamySystemPropertyWorksAsAdvertised() throws Exception {
+        HTMLValidationRule.loadAntisamyPolicy(INVALID_ANTISAMY_POLICY_FILE);
     }
 
-	@Test
-	public void checkAntisamySystemPropertyWorksAsAdvertised() throws Exception {
-	    HTMLValidationRule.loadAntisamyPolicy(INVALID_ANTISAMY_POLICY_FILE);
-	}
-	
 }
diff --git a/src/test/java/org/owasp/esapi/reference/validation/HTMLValidationRuleClasspathTest.java b/src/test/java/org/owasp/esapi/reference/validation/HTMLValidationRuleClasspathTest.java
index 3b6fd34..0170a92 100644
--- a/src/test/java/org/owasp/esapi/reference/validation/HTMLValidationRuleClasspathTest.java
+++ b/src/test/java/org/owasp/esapi/reference/validation/HTMLValidationRuleClasspathTest.java
@@ -32,6 +32,8 @@ import org.owasp.esapi.ValidationErrorList;
 import org.owasp.esapi.Validator;
 import org.owasp.esapi.errors.ValidationException;
 import org.owasp.validator.html.PolicyException;
+import static org.owasp.esapi.PropNames.VALIDATOR_HTML_VALIDATION_ACTION;
+import static org.owasp.esapi.PropNames.VALIDATOR_HTML_VALIDATION_CONFIGURATION_FILE;
 
 /**
  * The Class HTMLValidationRuleThrowsTest.
@@ -58,23 +60,23 @@ public class HTMLValidationRuleClasspathTest {
      * actually <i>use</i> it for anything.
      */
     private static final String ANTISAMY_POLICY_FILE_NONSTANDARD_LOCATION = "antisamy-esapi-CP.xml";
- 
-	private static class ConfOverride extends SecurityConfigurationWrapper {
-	    private String desiredReturnAction = "clean";
-	    private String desiredReturnConfigurationFile = null;
-	    
-		ConfOverride(SecurityConfiguration orig, String desiredReturnAction, String desiredReturnConfigurationFile) {
-			super(orig);
+
+    private static class ConfOverride extends SecurityConfigurationWrapper {
+        private String desiredReturnAction = "clean";
+        private String desiredReturnConfigurationFile = null;
+
+        ConfOverride(SecurityConfiguration orig, String desiredReturnAction, String desiredReturnConfigurationFile) {
+            super(orig);
             this.desiredReturnAction = desiredReturnAction;
-			this.desiredReturnConfigurationFile = desiredReturnConfigurationFile;
-		}
+            this.desiredReturnConfigurationFile = desiredReturnConfigurationFile;
+        }
 
-		@Override
-		public String getStringProp(String propName) {
+        @Override
+        public String getStringProp(String propName) {
             // Would it be better making this file a static import?
-			if ( propName.equals( org.owasp.esapi.reference.DefaultSecurityConfiguration.VALIDATOR_HTML_VALIDATION_ACTION ) ) {
+            if ( propName.equals( VALIDATOR_HTML_VALIDATION_ACTION ) ) {
                 return desiredReturnAction;
-            } else if ( propName.equals( org.owasp.esapi.reference.DefaultSecurityConfiguration.VALIDATOR_HTML_VALIDATION_CONFIGURATION_FILE ) ) {
+            } else if ( propName.equals( VALIDATOR_HTML_VALIDATION_CONFIGURATION_FILE ) ) {
                 return desiredReturnConfigurationFile;
             } else {
                 return super.getStringProp( propName );
@@ -91,21 +93,21 @@ public class HTMLValidationRuleClasspathTest {
         ESAPI.override(null);
     }
 
-	@Before
+    @Before
     public void setUp() throws Exception {
-		ESAPI.override(
-			new ConfOverride( ESAPI.securityConfiguration(), "throw", ANTISAMY_POLICY_FILE_NONSTANDARD_LOCATION )
-		);
+        ESAPI.override(
+            new ConfOverride( ESAPI.securityConfiguration(), "throw", ANTISAMY_POLICY_FILE_NONSTANDARD_LOCATION )
+        );
     }
 
-	
-	@Test
+
+    @Test
     public void checkPolicyExceptionWithBadConfig() throws Exception {
         ESAPI.override(null);
         thrownEx.expect(PolicyException.class);
         HTMLValidationRule.loadAntisamyPolicy(INVALID_ANTISAMY_POLICY_FILE);
     }
-	
+
     @Test
     public void testGetValid() throws Exception {
         System.out.println("getValidCP");
diff --git a/src/test/java/org/owasp/esapi/reference/validation/HTMLValidationRuleCleanTest.java b/src/test/java/org/owasp/esapi/reference/validation/HTMLValidationRuleCleanTest.java
index b10c3d4..2795737 100644
--- a/src/test/java/org/owasp/esapi/reference/validation/HTMLValidationRuleCleanTest.java
+++ b/src/test/java/org/owasp/esapi/reference/validation/HTMLValidationRuleCleanTest.java
@@ -26,6 +26,7 @@ import org.owasp.esapi.errors.IntrusionException;
 import org.owasp.esapi.errors.ValidationException;
 import org.owasp.esapi.filters.SecurityWrapperRequest;
 import org.owasp.esapi.reference.validation.HTMLValidationRule;
+import static org.owasp.esapi.PropNames.VALIDATOR_HTML_VALIDATION_ACTION;
 
 import org.junit.Test;
 import org.junit.Before;
@@ -54,18 +55,18 @@ import static org.junit.Assert.*;
  */
 public class HTMLValidationRuleCleanTest {
 
-	private static class ConfOverride extends SecurityConfigurationWrapper {
+    private static class ConfOverride extends SecurityConfigurationWrapper {
         private String desiredReturn = "clean";
 
-		ConfOverride(SecurityConfiguration orig, String desiredReturn) {
-			super(orig);
+        ConfOverride(SecurityConfiguration orig, String desiredReturn) {
+            super(orig);
             this.desiredReturn = desiredReturn;
-		}
+        }
 
-		@Override
-		public String getStringProp(String propName) {
+        @Override
+        public String getStringProp(String propName) {
             // Would it be better making this file a static import?
-			if ( propName.equals( org.owasp.esapi.reference.DefaultSecurityConfiguration.VALIDATOR_HTML_VALIDATION_ACTION ) ) {
+            if ( propName.equals( VALIDATOR_HTML_VALIDATION_ACTION ) ) {
                 return desiredReturn;
             } else {
                 return super.getStringProp( propName );
@@ -85,11 +86,11 @@ public class HTMLValidationRuleCleanTest {
         ESAPI.override(null);
     }
 
-	@Before
+    @Before
     public void setUp() throws Exception {
-		ESAPI.override(
-			new ConfOverride( ESAPI.securityConfiguration(), "clean" )
-		);
+        ESAPI.override(
+            new ConfOverride( ESAPI.securityConfiguration(), "clean" )
+        );
 
     }
 
@@ -198,17 +199,17 @@ public class HTMLValidationRuleCleanTest {
         assertTrue(errors.size() == 0);
 
     }
-    
+
     @Test
     public void testAntiSamyRegressionCDATAWithJavascriptURL() throws Exception {
         Validator instance = ESAPI.validator();
         ValidationErrorList errors = new ValidationErrorList();
         String input = "<style/>b<![cdata[</style><a href=javascript:alert(1)>test";
-		assertTrue(instance.isValidSafeHTML("test8", input, 100, false, errors));
-		String expected = "b&lt;/style&gt;&lt;a href=javascript:alert(1)&gt;test";
-		String output = instance.getValidSafeHTML("javascript Link", input, 250, false);
-		assertEquals(expected, output);
-		assertTrue(errors.size() == 0);
+        assertTrue(instance.isValidSafeHTML("test8", input, 100, false, errors));
+        String expected = "b&lt;/style&gt;&lt;a href=javascript:alert(1)&gt;test";
+        String output = instance.getValidSafeHTML("javascript Link", input, 250, false);
+        assertEquals(expected, output);
+        assertTrue(errors.size() == 0);
     }
 
     @Test
@@ -216,11 +217,11 @@ public class HTMLValidationRuleCleanTest {
         Validator instance = ESAPI.validator();
         ValidationErrorList errors = new ValidationErrorList();
         String input = "<select<style/>W<xmp<script>alert(1)</script>";
-		assertTrue(instance.isValidSafeHTML("test9", input, 100, false, errors));
-		String expected = "W&lt;script&gt;alert(1)&lt;/script&gt;";
-		String output = instance.getValidSafeHTML("escaping style tag attack with script tag", input, 250, false);
-		assertEquals(expected, output);
-		assertTrue(errors.size() == 0);
+        assertTrue(instance.isValidSafeHTML("test9", input, 100, false, errors));
+        String expected = "W&lt;script&gt;alert(1)&lt;/script&gt;";
+        String output = instance.getValidSafeHTML("escaping style tag attack with script tag", input, 250, false);
+        assertEquals(expected, output);
+        assertTrue(errors.size() == 0);
     }
 
     @Test
@@ -228,20 +229,20 @@ public class HTMLValidationRuleCleanTest {
         Validator instance = ESAPI.validator();
         ValidationErrorList errors = new ValidationErrorList();
         String input = "<select<style/>k<input<</>input/onfocus=alert(1)>";
-		assertTrue(instance.isValidSafeHTML("test10", input, 100, false, errors));
-		String expected = "k&lt;input/onfocus=alert(1)&gt;";	// Suspicious? Doesn't agree w/ AntiSamy test.
-		String output = instance.getValidSafeHTML("escaping style tag attack with onfocus attribute", input, 250, false);
-		assertEquals(expected, output);
-		assertTrue(errors.size() == 0);
+        assertTrue(instance.isValidSafeHTML("test10", input, 100, false, errors));
+        String expected = "k&lt;input/onfocus=alert(1)&gt;";    // Suspicious? Doesn't agree w/ AntiSamy test.
+        String output = instance.getValidSafeHTML("escaping style tag attack with onfocus attribute", input, 250, false);
+        assertEquals(expected, output);
+        assertTrue(errors.size() == 0);
     }
 
     // This test was a DoS issue (CVE-2022-28366) within a transitive dependency (Neko-HtmlUnit) that AntiSamy uses.
     // It is fixed only in Neko-HtmlUnit 2.27 and later, but all those releases are only available for Java 8 and later.
-    // 
+    //
     // When the input here is called with AntiSamy.scan().getCleanHtml(), AntiSamy throws a ScanException.
     // (For details, see the AntiSamy JUnit test case "testMalformedPIScan" in
     // https://github.com/nahsra/antisamy/blob/main/src/test/java/org/owasp/validator/html/test/AntiSamyTest.java.)
-    // 
+    //
     @Test
     public void testNekoDOSWithAnHTMLComment() throws Exception {
         System.out.println("testNekoDOSWithAnHTMLComment");
@@ -249,11 +250,11 @@ public class HTMLValidationRuleCleanTest {
         Validator instance = ESAPI.validator();
         ValidationErrorList errors = new ValidationErrorList();
         String input = "<!--><?a/";
-		assertTrue(instance.isValidSafeHTML("test11", input, 100, false, errors)); // Safe bc "" gets returned!!!
+        assertTrue(instance.isValidSafeHTML("test11", input, 100, false, errors)); // Safe bc "" gets returned!!!
 
-		String expectEmpty = "";
-		String output = instance.getValidSafeHTML("escaping style tag attack", input, 250, false);
-		assertEquals(expectEmpty, output);  // Because AntiSamy's CleanResults.getCleanHTML() should throw and is caught.
-		assertTrue(errors.size() == 0);
+        String expectEmpty = "";
+        String output = instance.getValidSafeHTML("escaping style tag attack", input, 250, false);
+        assertEquals(expectEmpty, output);  // Because AntiSamy's CleanResults.getCleanHTML() should throw and is caught.
+        assertTrue(errors.size() == 0);
     }
 }
diff --git a/src/test/java/org/owasp/esapi/reference/validation/HTMLValidationRuleThrowsTest.java b/src/test/java/org/owasp/esapi/reference/validation/HTMLValidationRuleThrowsTest.java
index 7605462..8965ea2 100644
--- a/src/test/java/org/owasp/esapi/reference/validation/HTMLValidationRuleThrowsTest.java
+++ b/src/test/java/org/owasp/esapi/reference/validation/HTMLValidationRuleThrowsTest.java
@@ -23,6 +23,7 @@ import org.owasp.esapi.ValidationRule;
 import org.owasp.esapi.Validator;
 import org.owasp.esapi.errors.ValidationException;
 import org.owasp.esapi.reference.validation.HTMLValidationRule;
+import static org.owasp.esapi.PropNames.VALIDATOR_HTML_VALIDATION_ACTION;
 
 import org.junit.Test;
 import org.junit.Before;
@@ -48,18 +49,18 @@ import static org.junit.Assert.*;
  * the cleansed (sanitizied) output when certain unsafe input is encountered.
  */
 public class HTMLValidationRuleThrowsTest {
-	private static class ConfOverride extends SecurityConfigurationWrapper {
+    private static class ConfOverride extends SecurityConfigurationWrapper {
         private String desiredReturn = "clean";
 
-		ConfOverride(SecurityConfiguration orig, String desiredReturn) {
-			super(orig);
+        ConfOverride(SecurityConfiguration orig, String desiredReturn) {
+            super(orig);
             this.desiredReturn = desiredReturn;
-		}
+        }
 
-		@Override
-		public String getStringProp(String propName) {
+        @Override
+        public String getStringProp(String propName) {
             // Would it be better making this file a static import?
-			if ( propName.equals( org.owasp.esapi.reference.DefaultSecurityConfiguration.VALIDATOR_HTML_VALIDATION_ACTION ) ) {
+            if ( propName.equals( VALIDATOR_HTML_VALIDATION_ACTION ) ) {
                 return desiredReturn;
             } else {
                 return super.getStringProp( propName );
@@ -77,11 +78,11 @@ public class HTMLValidationRuleThrowsTest {
         thrownEx = ExpectedException.none();
     }
 
-	@Before
+    @Before
     public void setUp() throws Exception {
-		ESAPI.override(
-			new ConfOverride( ESAPI.securityConfiguration(), "throw" )
-		);
+        ESAPI.override(
+            new ConfOverride( ESAPI.securityConfiguration(), "throw" )
+        );
 
     }
 
diff --git a/src/test/java/org/owasp/esapi/reference/validation/StringValidationRuleTest.java b/src/test/java/org/owasp/esapi/reference/validation/StringValidationRuleTest.java
index e172e2e..4028e5f 100644
--- a/src/test/java/org/owasp/esapi/reference/validation/StringValidationRuleTest.java
+++ b/src/test/java/org/owasp/esapi/reference/validation/StringValidationRuleTest.java
@@ -11,170 +11,170 @@ import org.owasp.esapi.errors.ValidationException;
 
 public class StringValidationRuleTest {
 
-	@Test
-	public void testWhitelistPattern() throws ValidationException {
-		
-		StringValidationRule validationRule = new StringValidationRule("Alphabetic");
-		
-		Assert.assertEquals("Magnum44", validationRule.getValid("", "Magnum44"));
-		validationRule.addWhitelistPattern("^[a-zA-Z]*");
-		try {
-			validationRule.getValid("", "Magnum44");
-			Assert.fail("Expected Exception not thrown");
-		}
-		catch (ValidationException ve) {
-			Assert.assertNotNull(ve.getMessage());
-		}
-		Assert.assertEquals("MagnumPI", validationRule.getValid("", "MagnumPI"));
-		
-	}
-	
-	@Test
-	public void testWhitelistPattern_Invalid() throws ValidationException {
-		
-		StringValidationRule validationRule = new StringValidationRule("");
-		
-		//null white list patterns throw IllegalArgumentException
-		try {
-			String pattern = null;
-			validationRule.addWhitelistPattern(pattern);
-			Assert.fail("Expected Exception not thrown");
-		}
-		catch (IllegalArgumentException ie) {
-			Assert.assertNotNull(ie.getMessage());
-		}
-		
-		try {
-			java.util.regex.Pattern pattern = null;
-			validationRule.addWhitelistPattern(pattern);
-			Assert.fail("Expected Exception not thrown");
-		}
-		catch (IllegalArgumentException ie) {
-			Assert.assertNotNull(ie.getMessage());
-		}
-		
-		//invalid white list patterns throw PatternSyntaxException
-		try {
-			String pattern = "_][0}[";
-			validationRule.addWhitelistPattern(pattern);
-			Assert.fail("Expected Exception not thrown");
-		}
-		catch (IllegalArgumentException ie) {
-			Assert.assertNotNull(ie.getMessage());
-		}
-	}
-	
-	@Test
-	public void testWhitelist() {
-		StringValidationRule validationRule = new StringValidationRule("");
-		
-		char[] whitelistArray = new char[] {'a', 'b', 'c'};
-		Assert.assertEquals("abc", validationRule.whitelist("12345abcdef", whitelistArray));
-	}
-	
-	@Test
-	public void testBlacklistPattern() throws ValidationException {
-		
-		StringValidationRule validationRule = new StringValidationRule("NoAngleBrackets");
-		
-		Assert.assertEquals("beg <script> end", validationRule.getValid("", "beg <script> end"));
-		validationRule.addBlacklistPattern("^.*(<|>).*");
-		try {
-			validationRule.getValid("", "beg <script> end");
-			Assert.fail("Expected Exception not thrown");
-		}
-		catch (ValidationException ve) {
-			Assert.assertNotNull(ve.getMessage());
-		}
-		Assert.assertEquals("beg script end", validationRule.getValid("", "beg script end"));
-	}
-	
-	@Test
-	public void testBlacklistPattern_Invalid() throws ValidationException {
-		
-		StringValidationRule validationRule = new StringValidationRule("");
-		
-		//null black list patterns throw IllegalArgumentException
-		try {
-			String pattern = null;
-			validationRule.addBlacklistPattern(pattern);
-			Assert.fail("Expected Exception not thrown");
-		}
-		catch (IllegalArgumentException ie) {
-			Assert.assertNotNull(ie.getMessage());
-		}
-		
-		try {
-			java.util.regex.Pattern pattern = null;
-			validationRule.addBlacklistPattern(pattern);
-			Assert.fail("Expected Exception not thrown");
-		}
-		catch (IllegalArgumentException ie) {
-			Assert.assertNotNull(ie.getMessage());
-		}
-		
-		//invalid black list patterns throw PatternSyntaxException
-		try {
-			String pattern = "_][0}[";
-			validationRule.addBlacklistPattern(pattern);
-			Assert.fail("Expected Exception not thrown");
-		}
-		catch (IllegalArgumentException ie) {
-			Assert.assertNotNull(ie.getMessage());
-		}
-	}	
-	
-	@Test
-	public void testCheckLengths() throws ValidationException {
-		
-		StringValidationRule validationRule = new StringValidationRule("Max12_Min2");
-		validationRule.setMinimumLength(2);
-		validationRule.setMaximumLength(12);
-		
-		Assert.assertTrue(validationRule.isValid("", "12"));
-		Assert.assertTrue(validationRule.isValid("", "123456"));
-		Assert.assertTrue(validationRule.isValid("", "ABCDEFGHIJKL"));
-		
-		Assert.assertFalse(validationRule.isValid("", "1"));
-		Assert.assertFalse(validationRule.isValid("", "ABCDEFGHIJKLM"));
-		
-		ValidationErrorList errorList = new ValidationErrorList();
-		Assert.assertEquals("1234567890", validationRule.getValid("", "1234567890", errorList));
-		Assert.assertEquals(0, errorList.size());
-		Assert.assertEquals(null, validationRule.getValid("", "123456789012345", errorList));
-		Assert.assertEquals(1, errorList.size());
-	}
-	
-	@Test
-	public void testAllowNull() throws ValidationException {
-		
-		StringValidationRule validationRule = new StringValidationRule("");
-		
-		Assert.assertFalse(validationRule.isAllowNull());
-		Assert.assertFalse(validationRule.isValid("", null));
-		
-		validationRule.setAllowNull(true);
-		Assert.assertTrue(validationRule.isAllowNull());
-		Assert.assertTrue(validationRule.isValid("", null));
-	}
-	
-	@Test
-	public void testSetCanonicalize() throws ValidationException {
-	    String context = "test-scope";
-	    String inputString = "SomeInputValue";
-	    String encoderReturn = "MockReturnValue";
-	    Encoder mockEncoder = Mockito.mock(Encoder.class);
-	    Mockito.when(mockEncoder.canonicalize(inputString)).thenReturn(encoderReturn);
-	    StringValidationRule testRule = new StringValidationRule(context, mockEncoder);
-	    String valid = testRule.getValid(context, inputString);
-	    Assert.assertEquals(encoderReturn, valid);
-	    Mockito.verify(mockEncoder, Mockito.times(1)).canonicalize(inputString);
-	    Mockito.reset(mockEncoder);
-	    
-	    testRule.setCanonicalize(false);
+    @Test
+    public void testWhitelistPattern() throws ValidationException {
+
+        StringValidationRule validationRule = new StringValidationRule("Alphabetic");
+
+        Assert.assertEquals("Magnum44", validationRule.getValid("", "Magnum44"));
+        validationRule.addWhitelistPattern("^[a-zA-Z]*");
+        try {
+            validationRule.getValid("", "Magnum44");
+            Assert.fail("Expected Exception not thrown");
+        }
+        catch (ValidationException ve) {
+            Assert.assertNotNull(ve.getMessage());
+        }
+        Assert.assertEquals("MagnumPI", validationRule.getValid("", "MagnumPI"));
+
+    }
+
+    @Test
+    public void testWhitelistPattern_Invalid() throws ValidationException {
+
+        StringValidationRule validationRule = new StringValidationRule("");
+
+        //null white list patterns throw IllegalArgumentException
+        try {
+            String pattern = null;
+            validationRule.addWhitelistPattern(pattern);
+            Assert.fail("Expected Exception not thrown");
+        }
+        catch (IllegalArgumentException ie) {
+            Assert.assertNotNull(ie.getMessage());
+        }
+
+        try {
+            java.util.regex.Pattern pattern = null;
+            validationRule.addWhitelistPattern(pattern);
+            Assert.fail("Expected Exception not thrown");
+        }
+        catch (IllegalArgumentException ie) {
+            Assert.assertNotNull(ie.getMessage());
+        }
+
+        //invalid white list patterns throw PatternSyntaxException
+        try {
+            String pattern = "_][0}[";
+            validationRule.addWhitelistPattern(pattern);
+            Assert.fail("Expected Exception not thrown");
+        }
+        catch (IllegalArgumentException ie) {
+            Assert.assertNotNull(ie.getMessage());
+        }
+    }
+
+    @Test
+    public void testWhitelist() {
+        StringValidationRule validationRule = new StringValidationRule("");
+
+        char[] whitelistArray = new char[] {'a', 'b', 'c'};
+        Assert.assertEquals("abc", validationRule.whitelist("12345abcdef", whitelistArray));
+    }
+
+    @Test
+    public void testBlacklistPattern() throws ValidationException {
+
+        StringValidationRule validationRule = new StringValidationRule("NoAngleBrackets");
+
+        Assert.assertEquals("beg <script> end", validationRule.getValid("", "beg <script> end"));
+        validationRule.addBlacklistPattern("^.*(<|>).*");
+        try {
+            validationRule.getValid("", "beg <script> end");
+            Assert.fail("Expected Exception not thrown");
+        }
+        catch (ValidationException ve) {
+            Assert.assertNotNull(ve.getMessage());
+        }
+        Assert.assertEquals("beg script end", validationRule.getValid("", "beg script end"));
+    }
+
+    @Test
+    public void testBlacklistPattern_Invalid() throws ValidationException {
+
+        StringValidationRule validationRule = new StringValidationRule("");
+
+        //null black list patterns throw IllegalArgumentException
+        try {
+            String pattern = null;
+            validationRule.addBlacklistPattern(pattern);
+            Assert.fail("Expected Exception not thrown");
+        }
+        catch (IllegalArgumentException ie) {
+            Assert.assertNotNull(ie.getMessage());
+        }
+
+        try {
+            java.util.regex.Pattern pattern = null;
+            validationRule.addBlacklistPattern(pattern);
+            Assert.fail("Expected Exception not thrown");
+        }
+        catch (IllegalArgumentException ie) {
+            Assert.assertNotNull(ie.getMessage());
+        }
+
+        //invalid black list patterns throw PatternSyntaxException
+        try {
+            String pattern = "_][0}[";
+            validationRule.addBlacklistPattern(pattern);
+            Assert.fail("Expected Exception not thrown");
+        }
+        catch (IllegalArgumentException ie) {
+            Assert.assertNotNull(ie.getMessage());
+        }
+    }
+
+    @Test
+    public void testCheckLengths() throws ValidationException {
+
+        StringValidationRule validationRule = new StringValidationRule("Max12_Min2");
+        validationRule.setMinimumLength(2);
+        validationRule.setMaximumLength(12);
+
+        Assert.assertTrue(validationRule.isValid("", "12"));
+        Assert.assertTrue(validationRule.isValid("", "123456"));
+        Assert.assertTrue(validationRule.isValid("", "ABCDEFGHIJKL"));
+
+        Assert.assertFalse(validationRule.isValid("", "1"));
+        Assert.assertFalse(validationRule.isValid("", "ABCDEFGHIJKLM"));
+
+        ValidationErrorList errorList = new ValidationErrorList();
+        Assert.assertEquals("1234567890", validationRule.getValid("", "1234567890", errorList));
+        Assert.assertEquals(0, errorList.size());
+        Assert.assertEquals(null, validationRule.getValid("", "123456789012345", errorList));
+        Assert.assertEquals(1, errorList.size());
+    }
+
+    @Test
+    public void testAllowNull() throws ValidationException {
+
+        StringValidationRule validationRule = new StringValidationRule("");
+
+        Assert.assertFalse(validationRule.isAllowNull());
+        Assert.assertFalse(validationRule.isValid("", null));
+
+        validationRule.setAllowNull(true);
+        Assert.assertTrue(validationRule.isAllowNull());
+        Assert.assertTrue(validationRule.isValid("", null));
+    }
+
+    @Test
+    public void testSetCanonicalize() throws ValidationException {
+        String context = "test-scope";
+        String inputString = "SomeInputValue";
+        String encoderReturn = "MockReturnValue";
+        Encoder mockEncoder = Mockito.mock(Encoder.class);
+        Mockito.when(mockEncoder.canonicalize(inputString)).thenReturn(encoderReturn);
+        StringValidationRule testRule = new StringValidationRule(context, mockEncoder);
+        String valid = testRule.getValid(context, inputString);
+        Assert.assertEquals(encoderReturn, valid);
+        Mockito.verify(mockEncoder, Mockito.times(1)).canonicalize(inputString);
+        Mockito.reset(mockEncoder);
+
+        testRule.setCanonicalize(false);
         valid = testRule.getValid(context, inputString);
         Assert.assertEquals(inputString, valid);
         Mockito.verify(mockEncoder, Mockito.times(0)).canonicalize(inputString);
-	}
-	
+    }
+
 }
diff --git a/src/test/java/org/owasp/esapi/util/FileTestUtils.java b/src/test/java/org/owasp/esapi/util/FileTestUtils.java
index 2c0eda1..0181ba8 100644
--- a/src/test/java/org/owasp/esapi/util/FileTestUtils.java
+++ b/src/test/java/org/owasp/esapi/util/FileTestUtils.java
@@ -10,207 +10,207 @@ import java.util.Random;
  */
 public class FileTestUtils
 {
-	private static final Class<FileTestUtils> CLASS = FileTestUtils.class;
-	private static final String CLASS_NAME = CLASS.getName();
-	private static final String DEFAULT_PREFIX = CLASS_NAME + '.';
-	private static final String DEFAULT_SUFFIX = ".tmp";
-	private static final Random rand;
-
-	/*
-		Rational for switching from SecureRandom to Random:
-		
-		This is used for generating filenames for temporary
-		directories. Originally this was using SecureRandom for
-		this to make /tmp races harder. This is not necessary as
-		mkdir always returns false if if the directory already
-		exists.
-		
-		Additionally, SecureRandom for some reason on Linux
-		is appears to be reading from /dev/random instead of
-		/dev/urandom. As such, the many calls for temporary
-		directories in the unit tests quickly depletes the
-		entropy pool causing unit test runs to block until more
-		entropy is collected (this is why moving the mouse speeds
-		up unit tests).
-	*/
-	static
-	{
-		SecureRandom secRand = new SecureRandom();
-		rand = new Random(secRand.nextLong());
-	}
-
-	/** Private constructor as all methods are static. */
-	private FileTestUtils()
-	{
-	}
-
-	/**
-	 * Convert a long to it's hex representation. Unlike
-	 * {@link Long#toHexString(long)} this always returns 16 digits.
-	 * @param l The long to convert.
-	 * @return l in hex.
-	 */
-	public static String toHexString(long l)
-	{
-		String initial;
-		StringBuffer sb;
-
-		initial = Long.toHexString(l);
-		if(initial.length() == 16)
-			return initial;
-		sb = new StringBuffer(16);
-		sb.append(initial);
-		while(sb.length()<16)
-			sb.insert(0,'0');
-		return sb.toString();
-	}
-
-	/**
-	 * Create a temporary directory.
-	 * @param parent The parent directory for the temporary
-	 *	directory. If this is null, the system property
-	 * 	"java.io.tmpdir" is used.
-	 * @param prefix The prefix for the directory's name. If this
-	 * 	is null, the full class name of this class is used.
-	 * @param suffix The suffix for the directory's name. If this
-	 * 	is null, ".tmp" is used.
-	 * @return The newly created temporary directory.
-	 * @throws IOException if directory creation fails
-	 * @throws SecurityException if {@link File#mkdir()} throws one.
-	 */
-	public static File createTmpDirectory(File parent, String prefix, String suffix) throws IOException
-	{
-		String name;
-		File dir;
-
-		if(prefix == null)
-			prefix = DEFAULT_PREFIX;
-		else if(!prefix.endsWith("."))
-			prefix += '.';
-		if(suffix == null)
-			suffix = DEFAULT_SUFFIX;
-		else if(!suffix.startsWith("."))
-			suffix = "." + suffix;
-		if(parent == null)
-			parent = new File(System.getProperty("java.io.tmpdir"));
-		name = prefix + toHexString(rand.nextLong()) + suffix;
-		dir = new File(parent, name);
-		if(!dir.mkdir())
-			throw new IOException("Unable to create temporary directory " + dir);
-		return dir.getCanonicalFile();
-	}
-
-	/**
-	 * Create a temporary directory. This calls
-	 * {@link #createTmpDirectory(File, String, String)} with null
-	 * for parent and suffix.
-	 * @param prefix The prefix for the directory's name. If this
-	 * 	is null, the full class name of this class is used.
-	 * @return The newly created temporary directory.
-	 * @throws IOException if directory creation fails
-	 * @throws SecurityException if {@link File#mkdir()} throws one.
-	 */
-	public static File createTmpDirectory(String prefix) throws IOException
-	{
-		return createTmpDirectory(null, prefix, null);
-	}
-
-	/**
-	 * Create a temporary directory. This calls
-	 * {@link #createTmpDirectory(File, String, String)} with null
-	 * for all arguments.
-	 * @return The newly created temporary directory.
-	 * @throws IOException if directory creation fails
-	 * @throws SecurityException if {@link File#mkdir()} throws one.
-	 */
-	public static File createTmpDirectory() throws IOException
-	{
-	 	return createTmpDirectory(null,null,null);
-	}
-
-	/**
-	 * Checks that child is a directory and really a child of
-	 * parent. This verifies that the {@link File#getCanonicalFile()
-	 * canonical} child is actually a child of parent. This should
-	 * fail if the child is a symbolic link to another directory and
-	 * therefore should not be traversed in a recursive traversal of
-	 * a directory.
-	 * @param parent The supposed parent of the child
-	 * @param child The child to check
-	 * @return true if child is a directory and a direct decendant
-	 * 	of parent.
-	 * @throws IOException if {@link File#getCanonicalFile()} does
-	 * @throws NullPointerException if either parent or child
-	 * 	are null.
-	 */
-	public static boolean isChildSubDirectory(File parent, File child) throws IOException
-	{
-		File childsParent;
-
-		if(child==null)
-			throw new NullPointerException("child argument is null");
-		if(!child.isDirectory())
-			return false;
-		if(parent==null)
-			throw new NullPointerException("parent argument is null");
-		parent = parent.getCanonicalFile();
-		child = child.getCanonicalFile();
-		childsParent = child.getParentFile();
-		if(childsParent == null)
-			return false;	// sym link to /?
-		childsParent = childsParent.getCanonicalFile();	// just in case...
-		if(!parent.equals(childsParent))
-			return false;
-		return true;
-	}
-
-	/**
-	 * Delete a file. Unlinke {@link File#delete()}, this throws an
-	 * exception if deletion fails.
-	 * @param file The file to delete
-	 * @throws IOException if file is not null, exists but delete
-	 * 	fails.
-	 */
-	public static void delete(File file) throws IOException
-	{
-		if(file==null || !file.exists())
-			return;
-		if(!file.delete())
-			throw new IOException("Unable to delete file " + file.getAbsolutePath());
-	}
-
-	/**
-	 * Recursively delete a file. If file is a directory,
-	 * subdirectories and files are also deleted. Care is taken to
-	 * not traverse symbolic links in this process. A null file or
-	 * a file that does not exist is considered to already been
-	 * deleted.
-	 * @param file The file or directory to be deleted
-	 * @throws IOException if the file, or a descendant, cannot
-	 * 	be deleted.
-	 * @throws SecurityException if {@link File#delete()} does.
-	 */
-	public static void deleteRecursively(File file) throws IOException
-	{
-		File[] children;
-		File child;
-
-		if(file == null || !file.exists())
-			return;	// already deleted?
-		if(file.isDirectory())
-		{
-			children = file.listFiles();
-			for(int i=0;i<children.length;i++)
-			{
-				child = children[i];
-				if(isChildSubDirectory(file,child))
-					deleteRecursively(child);
-				else
-					delete(child);
-			}
-		}
-
-		// finally
-		delete(file);
-	}
+    private static final Class<FileTestUtils> CLASS = FileTestUtils.class;
+    private static final String CLASS_NAME = CLASS.getName();
+    private static final String DEFAULT_PREFIX = CLASS_NAME + '.';
+    private static final String DEFAULT_SUFFIX = ".tmp";
+    private static final Random rand;
+
+    /*
+        Rational for switching from SecureRandom to Random:
+
+        This is used for generating filenames for temporary
+        directories. Originally this was using SecureRandom for
+        this to make /tmp races harder. This is not necessary as
+        mkdir always returns false if if the directory already
+        exists.
+
+        Additionally, SecureRandom for some reason on Linux
+        is appears to be reading from /dev/random instead of
+        /dev/urandom. As such, the many calls for temporary
+        directories in the unit tests quickly depletes the
+        entropy pool causing unit test runs to block until more
+        entropy is collected (this is why moving the mouse speeds
+        up unit tests).
+    */
+    static
+    {
+        SecureRandom secRand = new SecureRandom();
+        rand = new Random(secRand.nextLong());
+    }
+
+    /** Private constructor as all methods are static. */
+    private FileTestUtils()
+    {
+    }
+
+    /**
+     * Convert a long to it's hex representation. Unlike
+     * {@link Long#toHexString(long)} this always returns 16 digits.
+     * @param l The long to convert.
+     * @return l in hex.
+     */
+    public static String toHexString(long l)
+    {
+        String initial;
+        StringBuffer sb;
+
+        initial = Long.toHexString(l);
+        if(initial.length() == 16)
+            return initial;
+        sb = new StringBuffer(16);
+        sb.append(initial);
+        while(sb.length()<16)
+            sb.insert(0,'0');
+        return sb.toString();
+    }
+
+    /**
+     * Create a temporary directory.
+     * @param parent The parent directory for the temporary
+     *    directory. If this is null, the system property
+     *     "java.io.tmpdir" is used.
+     * @param prefix The prefix for the directory's name. If this
+     *     is null, the full class name of this class is used.
+     * @param suffix The suffix for the directory's name. If this
+     *     is null, ".tmp" is used.
+     * @return The newly created temporary directory.
+     * @throws IOException if directory creation fails
+     * @throws SecurityException if {@link File#mkdir()} throws one.
+     */
+    public static File createTmpDirectory(File parent, String prefix, String suffix) throws IOException
+    {
+        String name;
+        File dir;
+
+        if(prefix == null)
+            prefix = DEFAULT_PREFIX;
+        else if(!prefix.endsWith("."))
+            prefix += '.';
+        if(suffix == null)
+            suffix = DEFAULT_SUFFIX;
+        else if(!suffix.startsWith("."))
+            suffix = "." + suffix;
+        if(parent == null)
+            parent = new File(System.getProperty("java.io.tmpdir"));
+        name = prefix + toHexString(rand.nextLong()) + suffix;
+        dir = new File(parent, name);
+        if(!dir.mkdir())
+            throw new IOException("Unable to create temporary directory " + dir);
+        return dir.getCanonicalFile();
+    }
+
+    /**
+     * Create a temporary directory. This calls
+     * {@link #createTmpDirectory(File, String, String)} with null
+     * for parent and suffix.
+     * @param prefix The prefix for the directory's name. If this
+     *     is null, the full class name of this class is used.
+     * @return The newly created temporary directory.
+     * @throws IOException if directory creation fails
+     * @throws SecurityException if {@link File#mkdir()} throws one.
+     */
+    public static File createTmpDirectory(String prefix) throws IOException
+    {
+        return createTmpDirectory(null, prefix, null);
+    }
+
+    /**
+     * Create a temporary directory. This calls
+     * {@link #createTmpDirectory(File, String, String)} with null
+     * for all arguments.
+     * @return The newly created temporary directory.
+     * @throws IOException if directory creation fails
+     * @throws SecurityException if {@link File#mkdir()} throws one.
+     */
+    public static File createTmpDirectory() throws IOException
+    {
+         return createTmpDirectory(null,null,null);
+    }
+
+    /**
+     * Checks that child is a directory and really a child of
+     * parent. This verifies that the {@link File#getCanonicalFile()
+     * canonical} child is actually a child of parent. This should
+     * fail if the child is a symbolic link to another directory and
+     * therefore should not be traversed in a recursive traversal of
+     * a directory.
+     * @param parent The supposed parent of the child
+     * @param child The child to check
+     * @return true if child is a directory and a direct decendant
+     *     of parent.
+     * @throws IOException if {@link File#getCanonicalFile()} does
+     * @throws NullPointerException if either parent or child
+     *     are null.
+     */
+    public static boolean isChildSubDirectory(File parent, File child) throws IOException
+    {
+        File childsParent;
+
+        if(child==null)
+            throw new NullPointerException("child argument is null");
+        if(!child.isDirectory())
+            return false;
+        if(parent==null)
+            throw new NullPointerException("parent argument is null");
+        parent = parent.getCanonicalFile();
+        child = child.getCanonicalFile();
+        childsParent = child.getParentFile();
+        if(childsParent == null)
+            return false;    // sym link to /?
+        childsParent = childsParent.getCanonicalFile();    // just in case...
+        if(!parent.equals(childsParent))
+            return false;
+        return true;
+    }
+
+    /**
+     * Delete a file. Unlinke {@link File#delete()}, this throws an
+     * exception if deletion fails.
+     * @param file The file to delete
+     * @throws IOException if file is not null, exists but delete
+     *     fails.
+     */
+    public static void delete(File file) throws IOException
+    {
+        if(file==null || !file.exists())
+            return;
+        if(!file.delete())
+            throw new IOException("Unable to delete file " + file.getAbsolutePath());
+    }
+
+    /**
+     * Recursively delete a file. If file is a directory,
+     * subdirectories and files are also deleted. Care is taken to
+     * not traverse symbolic links in this process. A null file or
+     * a file that does not exist is considered to already been
+     * deleted.
+     * @param file The file or directory to be deleted
+     * @throws IOException if the file, or a descendant, cannot
+     *     be deleted.
+     * @throws SecurityException if {@link File#delete()} does.
+     */
+    public static void deleteRecursively(File file) throws IOException
+    {
+        File[] children;
+        File child;
+
+        if(file == null || !file.exists())
+            return;    // already deleted?
+        if(file.isDirectory())
+        {
+            children = file.listFiles();
+            for(int i=0;i<children.length;i++)
+            {
+                child = children[i];
+                if(isChildSubDirectory(file,child))
+                    deleteRecursively(child);
+                else
+                    delete(child);
+            }
+        }
+
+        // finally
+        delete(file);
+    }
 }
diff --git a/src/test/java/org/owasp/esapi/util/ObjFactoryTest.java b/src/test/java/org/owasp/esapi/util/ObjFactoryTest.java
index 9a44b25..3a3065a 100644
--- a/src/test/java/org/owasp/esapi/util/ObjFactoryTest.java
+++ b/src/test/java/org/owasp/esapi/util/ObjFactoryTest.java
@@ -11,19 +11,19 @@ import javax.crypto.spec.SecretKeySpec;
 import org.owasp.esapi.errors.ConfigurationException;
 
 public class ObjFactoryTest extends TestCase {
-	
-	// Purpose of this is to prevent a default, no-arg, public CTOR to be generated.
-	// We want to prevent this so we can use this class to test the case of where
-	// ObjectFactory<T>.make() throws an IllegalAccessException.
-	@SuppressWarnings("unused")
-	private ObjFactoryTest(int i) { ; }
-	
+
+    // Purpose of this is to prevent a default, no-arg, public CTOR to be generated.
+    // We want to prevent this so we can use this class to test the case of where
+    // ObjectFactory<T>.make() throws an IllegalAccessException.
+    @SuppressWarnings("unused")
+    private ObjFactoryTest(int i) { ; }
+
     /**
-	 * Instantiates a new object factory test.
-	 * 
-	 * @param testName
-	 *            the test name
-	 */
+     * Instantiates a new object factory test.
+     *
+     * @param testName
+     *            the test name
+     */
     public ObjFactoryTest(String testName) {
         super(testName);
     }
@@ -33,7 +33,7 @@ public class ObjFactoryTest extends TestCase {
      * @throws Exception
      */
     protected void setUp() throws Exception {
-    	// none
+        // none
     }
 
     /**
@@ -41,153 +41,153 @@ public class ObjFactoryTest extends TestCase {
      * @throws Exception
      */
     protected void tearDown() throws Exception {
-    	// none
+        // none
     }
 
     /**
-	 * Run all the test cases in this suite.
+     * Run all the test cases in this suite.
      * This is to allow running from {@code org.owasp.esapi.AllTests}.
-	 * 
-	 * @return the test
-	 */
+     *
+     * @return the test
+     */
     public static Test suite() {
         TestSuite suite = new TestSuite(ObjFactoryTest.class);
         return suite;
     }
-    
+
     /** Test that NullCipher object is correctly returned. */
     public void testMakeNullCipher() throws ConfigurationException {
-    	String className = "javax.crypto.NullCipher";
-    	javax.crypto.Cipher nullCipher =
-    			ObjFactory.make(className, "NullCipher");
-    	assertTrue( nullCipher instanceof javax.crypto.NullCipher );
-    	System.out.println("W00t! Watch out NSA...we have a NullCipher and we're not afraid to use it!");
+        String className = "javax.crypto.NullCipher";
+        javax.crypto.Cipher nullCipher =
+                ObjFactory.make(className, "NullCipher");
+        assertTrue( nullCipher instanceof javax.crypto.NullCipher );
+        System.out.println("W00t! Watch out NSA...we have a NullCipher and we're not afraid to use it!");
     }
-    
+
     /** Test that InstantiationException is thrown as the root cause when the
      * specified class name is an abstract class or interface.
      */
     public void testInterface() throws ConfigurationException {
-    	Key key = null;  	
-    	try {
-    		key = ObjFactory.make("java.security.Key", "Key");
-    		assertFalse("Should not be reached - interface or abstract class", key != null);
-    	} catch(ConfigurationException ex) {
-    		Throwable cause = ex.getCause();
-    		assertTrue( cause instanceof InstantiationException);
-    	}
+        Key key = null;
+        try {
+            key = ObjFactory.make("java.security.Key", "Key");
+            assertFalse("Should not be reached - interface or abstract class", key != null);
+        } catch(ConfigurationException ex) {
+            Throwable cause = ex.getCause();
+            assertTrue( cause instanceof InstantiationException);
+        }
     }
-    
+
     /** Test that IllegalAccessException is thrown as the root cause when the
      *  specified class has no public, no-arg CTOR. Cipher has only a protected
      *  CTOR that takes multiple parameters.
-     *  
+     *
      *  FIXME: Need new test. This also throws an InstantiationException as the
      *  root cause. The goal is to have it throw IllegalAccessException.
      */
     public void testMakeNoPublicConstructor() throws ConfigurationException {
-    	ObjFactoryTest oft = null;	
-    	try {
-    		// CHECKME: As I read
-			//	  http://java.sun.com/docs/books/tutorial/reflect/member/ctorTrouble.html
-    		// this should cause an IllegalAccessException to be thrown because it has no public,
-    		// no-arg CTOR. However, it doesn't. It throws a InstantiationException instead.
-    		oft = ObjFactory.make(ObjFactoryTest.class.getName(), "ObjectFactoryTest");
-    		assertFalse("Should not be reached - no public CTOR", oft != null);
-    	} catch(ConfigurationException ex) {
-    		Throwable cause = ex.getCause();
-    		// assertTrue( cause instanceof IllegalAccessException);
-    		assertTrue( cause instanceof InstantiationException);
-    	}
+        ObjFactoryTest oft = null;
+        try {
+            // CHECKME: As I read
+            //      http://java.sun.com/docs/books/tutorial/reflect/member/ctorTrouble.html
+            // this should cause an IllegalAccessException to be thrown because it has no public,
+            // no-arg CTOR. However, it doesn't. It throws a InstantiationException instead.
+            oft = ObjFactory.make(ObjFactoryTest.class.getName(), "ObjectFactoryTest");
+            assertFalse("Should not be reached - no public CTOR", oft != null);
+        } catch(ConfigurationException ex) {
+            Throwable cause = ex.getCause();
+            // assertTrue( cause instanceof IllegalAccessException);
+            assertTrue( cause instanceof InstantiationException);
+        }
     }
-    
+
     /** Test that ClassNotFoundException is thrown as the root cause when
      * the class name to be created is not a class name that exists anywhere.
      */
     public void testMakeNoSuchClass() throws ConfigurationException {
-    	Object obj = null;
-    	
-    	try {
-    		obj = ObjFactory.make("kevin.wall.HasNoClass", "Object");
-    		assertFalse("Should not be reached - no such class", obj != null);
-    	} catch(ConfigurationException ex) {
-    		Throwable cause = ex.getCause();
-    		assertTrue( cause instanceof ClassNotFoundException);
-    	}
+        Object obj = null;
+
+        try {
+            obj = ObjFactory.make("kevin.wall.HasNoClass", "Object");
+            assertFalse("Should not be reached - no such class", obj != null);
+        } catch(ConfigurationException ex) {
+            Throwable cause = ex.getCause();
+            assertTrue( cause instanceof ClassNotFoundException);
+        }
     }
-    
+
     /** Test that ClassCastException is thrown as the root cause when the
      * created class is not a subclass / does not implement the specified type.
      * (In this case, String is not a subclass / does not implement Key.)
      */
     public void testMakeNotASubclass() throws ConfigurationException {
-    	Key key = null;
-    	try {
-    		key = ObjFactory.make("java.lang.String", "testMakeNotASubclass");
-    		assertFalse("Should not be reached - not a subclass", key != null);
-    	} catch(ConfigurationException ex) {
-    		Throwable cause = ex.getCause();
-    		System.out.println("DEBUG: Cause was: " + cause.getClass().getName());
-    		assertTrue( cause instanceof ClassCastException);
-    	} catch(ClassCastException ccex) {
-    		assertTrue("Caught expected class cast exception", true);
-    	}
+        Key key = null;
+        try {
+            key = ObjFactory.make("java.lang.String", "testMakeNotASubclass");
+            assertFalse("Should not be reached - not a subclass", key != null);
+        } catch(ConfigurationException ex) {
+            Throwable cause = ex.getCause();
+            System.out.println("DEBUG: Cause was: " + cause.getClass().getName());
+            assertTrue( cause instanceof ClassCastException);
+        } catch(ClassCastException ccex) {
+            assertTrue("Caught expected class cast exception", true);
+        }
     }
-    
+
     /** Test that IllegalArgumentException is thrown as the cause when the
      * class name is specified as an empty string.
      */
     public void testMakeEmptyClassName() throws ConfigurationException {
-    	Object obj = null;
-    	try {
-    		obj = ObjFactory.make("", "testMakeEmptyClassName");
-    		assertFalse("Should not be reached - not a subclass", obj != null);
-    	} catch(ConfigurationException ex) {
-    		Throwable cause = ex.getCause();
-    		assertTrue( cause instanceof IllegalArgumentException);
-    	}
+        Object obj = null;
+        try {
+            obj = ObjFactory.make("", "testMakeEmptyClassName");
+            assertFalse("Should not be reached - not a subclass", obj != null);
+        } catch(ConfigurationException ex) {
+            Throwable cause = ex.getCause();
+            assertTrue( cause instanceof IllegalArgumentException);
+        }
     }
-    
+
     /** Test that some other exception is thrown from the no-arg, public CTOR as the
      * root cause. Had to use special external class here because strangely, this didn't
      * work as an inner class. (Threw InstantiationException in that case instead.)
      */
     public void testMakeOtherException() throws ConfigurationException {
-    	@SuppressWarnings("unused")
-		ThePrefectClass ford = null;
-    	try {
-    		ford = ObjFactory.make("org.owasp.esapi.util.ThePrefectClass", "ThePrefectClass");
-    	} catch(ConfigurationException ex) {
-    		Throwable cause = ex.getCause();
-			assertTrue( cause instanceof UnsupportedOperationException);
-    	}
+        @SuppressWarnings("unused")
+        ThePrefectClass ford = null;
+        try {
+            ford = ObjFactory.make("org.owasp.esapi.util.ThePrefectClass", "ThePrefectClass");
+        } catch(ConfigurationException ex) {
+            Throwable cause = ex.getCause();
+            assertTrue( cause instanceof UnsupportedOperationException);
+        }
     }
-    
+
     /** Test case where typeName is null or empty string. */
     public void testNullorEmptyTypeName() throws ConfigurationException {
-    	String className = "javax.crypto.NullCipher";
-    	javax.crypto.Cipher nullCipher =
-    			ObjFactory.make(className, null);
-    	assertTrue( nullCipher instanceof javax.crypto.NullCipher );
-    	nullCipher =
-			ObjFactory.make(className, "");
-    	assertTrue( nullCipher instanceof javax.crypto.NullCipher );
+        String className = "javax.crypto.NullCipher";
+        javax.crypto.Cipher nullCipher =
+                ObjFactory.make(className, null);
+        assertTrue( nullCipher instanceof javax.crypto.NullCipher );
+        nullCipher =
+            ObjFactory.make(className, "");
+        assertTrue( nullCipher instanceof javax.crypto.NullCipher );
     }
-    
+
     /** Test case where no-arg CTOR does not exist. By all indications from
      * Javadoc for {@code Class.newInstance()} one would think this should
      * throw an {@code IllegalAccessException} because {@code SecretKeySpec}
      * has two public CTORs that both take arguments. */
     public void testMakeCipher() throws ConfigurationException {
-    	try {
-    		String className = "javax.crypto.spec.SecretKeySpec";
-    		javax.crypto.spec.SecretKeySpec skeySpec =
-    			(SecretKeySpec) ObjFactory.make(className, "SecretKeySpec");
+        try {
+            String className = "javax.crypto.spec.SecretKeySpec";
+            javax.crypto.spec.SecretKeySpec skeySpec =
+                (SecretKeySpec) ObjFactory.make(className, "SecretKeySpec");
             // Should not get to here. Exception is expected.
-    	} catch(ConfigurationException ex) {
-    		Throwable cause = ex.getCause();
-    		assertTrue( cause instanceof InstantiationException);
-    	}
+        } catch(ConfigurationException ex) {
+            Throwable cause = ex.getCause();
+            assertTrue( cause instanceof InstantiationException);
+        }
     }
 
     /** Test cache. Create 100k JavaEncryptor instances with cache enabled (the
diff --git a/src/test/java/org/owasp/esapi/util/TestUtils.java b/src/test/java/org/owasp/esapi/util/TestUtils.java
index f7f117f..ddc25ed 100644
--- a/src/test/java/org/owasp/esapi/util/TestUtils.java
+++ b/src/test/java/org/owasp/esapi/util/TestUtils.java
@@ -2,13 +2,13 @@ package org.owasp.esapi.util;
 
 public class TestUtils {
 
-	public static String generateStringOfLength(int length) {
-	    assert length >= 0 : "length must be >= 0";
-	    StringBuilder longString = new StringBuilder(length);
-	    for (int i = 0; i < length; i++) {
-	        longString.append("a");
-	    }
-	    return longString.toString();
-	}
+    public static String generateStringOfLength(int length) {
+        assert length >= 0 : "length must be >= 0";
+        StringBuilder longString = new StringBuilder(length);
+        for (int i = 0; i < length; i++) {
+            longString.append("a");
+        }
+        return longString.toString();
+    }
 
 }
diff --git a/src/test/java/org/owasp/esapi/util/ThePrefectClass.java b/src/test/java/org/owasp/esapi/util/ThePrefectClass.java
index 28b0f33..13275f3 100644
--- a/src/test/java/org/owasp/esapi/util/ThePrefectClass.java
+++ b/src/test/java/org/owasp/esapi/util/ThePrefectClass.java
@@ -4,9 +4,9 @@ package org.owasp.esapi.util;
 // For testing only. Doesn't work as an inner class in ObjFactoryTest.
 // Props to D. Adams for HG2G. RIP.
 public class ThePrefectClass {
-	private static final int lifeUniverseEverything = 42;
-	public ThePrefectClass() {
-		throw new UnsupportedOperationException("This public CTOR is not supported!");
-	}
-	public int getAnswer() { return lifeUniverseEverything; }
+    private static final int lifeUniverseEverything = 42;
+    public ThePrefectClass() {
+        throw new UnsupportedOperationException("This public CTOR is not supported!");
+    }
+    public int getAnswer() { return lifeUniverseEverything; }
 }
diff --git a/src/test/java/org/owasp/esapi/waf/AddHeaderTest.java b/src/test/java/org/owasp/esapi/waf/AddHeaderTest.java
index 36c1bde..2a1bc25 100644
--- a/src/test/java/org/owasp/esapi/waf/AddHeaderTest.java
+++ b/src/test/java/org/owasp/esapi/waf/AddHeaderTest.java
@@ -1,15 +1,15 @@
 /**
  * OWASP Enterprise Security API (ESAPI)
- * 
+ *
  * This file is part of the Open Web Application Security Project (OWASP)
  * Enterprise Security API (ESAPI) project. For details, please see
  * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
  *
  * Copyright (c) 2009 - The OWASP Foundation
- * 
+ *
  * The ESAPI is published by OWASP under the BSD license. You should read and accept the
  * LICENSE before you use, modify, and/or redistribute this software.
- * 
+ *
  * @author Arshan Dabirsiaghi <a href="http://www.aspectsecurity.com">Aspect Security</a>
  * @created 2009
  */
@@ -22,38 +22,38 @@ import org.owasp.esapi.http.MockHttpServletRequest;
 import junit.framework.TestSuite;
 
 public class AddHeaderTest extends WAFTestCase {
-	
-	public static TestSuite suite() {
-		return new TestSuite(AddHeaderTest.class);
-	}
-	
+
+    public static TestSuite suite() {
+        return new TestSuite(AddHeaderTest.class);
+    }
+
     /*
      * Test whether or not the WAF correctly adds the header to the response when it should and
      * when it shouldn't, based on paths specified in the WAF rules.
      */
     public void testShouldAddHeader() throws Exception {
-        
-    	System.out.println("addHeaderPolicy - Response should have FOO=BAR header added" );
 
-    	request = new MockHttpServletRequest( new URL( "http://www.example.com/addheader" ) );
-    	
-    	WAFTestUtility.createAndExecuteWAFTransaction("waf-policies/add-header-policy.xml", request, response );
-    	
+        System.out.println("addHeaderPolicy - Response should have FOO=BAR header added" );
+
+        request = new MockHttpServletRequest( new URL( "http://www.example.com/addheader" ) );
+
+        WAFTestUtility.createAndExecuteWAFTransaction("waf-policies/add-header-policy.xml", request, response );
+
         String foo = response.getHeader( "FOO" );
         assertTrue( foo != null && foo.equals( "BAR" ) );
-        
+
     }
-    
+
     public void testShouldNotAddHeader() throws Exception {
-    	System.out.println("addHeaderPolicy - Response should have FOO=BAR header added" );
+        System.out.println("addHeaderPolicy - Response should have FOO=BAR header added" );
+
+        request = new MockHttpServletRequest( new URL( "http://www.example.com/marketing/foo" ) );
+
+        WAFTestUtility.createAndExecuteWAFTransaction("waf-policies/add-header-policy.xml", request, response );
 
-    	request = new MockHttpServletRequest( new URL( "http://www.example.com/marketing/foo" ) );
-    	
-    	WAFTestUtility.createAndExecuteWAFTransaction("waf-policies/add-header-policy.xml", request, response );
-    	
         String foo = response.getHeader( "FOO" );
         assertTrue( foo == null );
-        
+
     }
 
 }
diff --git a/src/test/java/org/owasp/esapi/waf/BeanShellTest.java b/src/test/java/org/owasp/esapi/waf/BeanShellTest.java
index 65bdd47..5253e93 100644
--- a/src/test/java/org/owasp/esapi/waf/BeanShellTest.java
+++ b/src/test/java/org/owasp/esapi/waf/BeanShellTest.java
@@ -1,15 +1,15 @@
 /**
  * OWASP Enterprise Security API (ESAPI)
- * 
+ *
  * This file is part of the Open Web Application Security Project (OWASP)
  * Enterprise Security API (ESAPI) project. For details, please see
  * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
  *
  * Copyright (c) 2009 - The OWASP Foundation
- * 
+ *
  * The ESAPI is published by OWASP under the BSD license. You should read and accept the
  * LICENSE before you use, modify, and/or redistribute this software.
- * 
+ *
  * @author Arshan Dabirsiaghi <a href="http://www.aspectsecurity.com">Aspect Security</a>
  * @created 2009
  */
@@ -27,21 +27,21 @@ import junit.framework.TestSuite;
 
 public class BeanShellTest extends WAFTestCase {
 
-	public static TestSuite suite() {
-		return new TestSuite(BeanShellTest.class);
-	}
+    public static TestSuite suite() {
+        return new TestSuite(BeanShellTest.class);
+    }
+
+    public void testRedirectBeanShellRule() throws Exception {
+
+        request = new MockHttpServletRequest( new URL( "http://www.example.com/beanshelltest" ) );
 
-	public void testRedirectBeanShellRule() throws Exception {
+        WAFTestUtility.createAndExecuteWAFTransaction("waf-policies/bean-shell-policy.xml", request, response, new MockFilterChain() );
 
-		request = new MockHttpServletRequest( new URL( "http://www.example.com/beanshelltest" ) );
+        HttpSession session = request.getSession();
 
-    	WAFTestUtility.createAndExecuteWAFTransaction("waf-policies/bean-shell-policy.xml", request, response, new MockFilterChain() );
-    	
-    	HttpSession session = request.getSession();
-    	
-    	assert(session.getAttribute("simple_waf_test") != null);
-    	assert(response.getStatus() == HttpServletResponse.SC_MOVED_PERMANENTLY);
+        assert(session.getAttribute("simple_waf_test") != null);
+        assert(response.getStatus() == HttpServletResponse.SC_MOVED_PERMANENTLY);
 
-	}
+    }
 
 }
diff --git a/src/test/java/org/owasp/esapi/waf/DetectOutboundTest.java b/src/test/java/org/owasp/esapi/waf/DetectOutboundTest.java
index af71b49..1d74e24 100644
--- a/src/test/java/org/owasp/esapi/waf/DetectOutboundTest.java
+++ b/src/test/java/org/owasp/esapi/waf/DetectOutboundTest.java
@@ -1,15 +1,15 @@
 /**
  * OWASP Enterprise Security API (ESAPI)
- * 
+ *
  * This file is part of the Open Web Application Security Project (OWASP)
  * Enterprise Security API (ESAPI) project. For details, please see
  * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
  *
  * Copyright (c) 2009 - The OWASP Foundation
- * 
+ *
  * The ESAPI is published by OWASP under the BSD license. You should read and accept the
  * LICENSE before you use, modify, and/or redistribute this software.
- * 
+ *
  * @author Arshan Dabirsiaghi <a href="http://www.aspectsecurity.com">Aspect Security</a>
  * @created 2009
  */
@@ -25,39 +25,39 @@ import org.owasp.esapi.http.MockHttpServletRequest;
 import org.owasp.esapi.http.MockHttpServletResponse;
 
 public class DetectOutboundTest extends WAFTestCase {
-	
-	public static TestSuite suite() {
-		return new TestSuite(DetectOutboundTest.class);
-	}
-	
-	public void testBadDetectOutbound() throws Exception {
-	       
-    	System.out.println("detectOutboundPolicy - Fires if response has \"2008\" in it" );
-   	    
-    	request = new MockHttpServletRequest( new URL( "http://www.example.com/here_is_the_2008" ) );
-    	
-    	// this setting of the body gets overridden in the MockFilterChain =(. For a hack we put it in
-    	// the URI above, which gets reflected into the response body.
-    	response.setBody( "Now is the time for all good men 2008 to come to the aid of their country" );
-        
-    	WAFTestUtility.createAndExecuteWAFTransaction( "waf-policies/detect-outbound-policy.xml", request, response );
-    	
-    	assertTrue( response.getStatus() == HttpServletResponse.SC_MOVED_PERMANENTLY );
-        
+
+    public static TestSuite suite() {
+        return new TestSuite(DetectOutboundTest.class);
+    }
+
+    public void testBadDetectOutbound() throws Exception {
+
+        System.out.println("detectOutboundPolicy - Fires if response has \"2008\" in it" );
+
+        request = new MockHttpServletRequest( new URL( "http://www.example.com/here_is_the_2008" ) );
+
+        // this setting of the body gets overridden in the MockFilterChain =(. For a hack we put it in
+        // the URI above, which gets reflected into the response body.
+        response.setBody( "Now is the time for all good men 2008 to come to the aid of their country" );
+
+        WAFTestUtility.createAndExecuteWAFTransaction( "waf-policies/detect-outbound-policy.xml", request, response );
+
+        assertTrue( response.getStatus() == HttpServletResponse.SC_MOVED_PERMANENTLY );
+
     }
-	
-	public void testGoodDetectOutbound() throws Exception {
-	       
-    	System.out.println("detectOutboundPolicy - should not fire even if response has \"2008\" in it because the content type is image/jpeg" );
-   	    
-    	request = new MockHttpServletRequest( new URL( "http://www.example.com/here_is_the_2008" ) );
-    	response = new MockHttpServletResponse();
-    	response.setContentType("image/jpeg");
-    	response.setBody( "Now is the time for all good men 2008 to come to the aid of their country" );
-        
-    	WAFTestUtility.createAndExecuteWAFTransaction( "waf-policies/detect-outbound-policy.xml", request, response );
-    	
-    	assertTrue( response.getStatus() == HttpServletResponse.SC_OK );
-        
+
+    public void testGoodDetectOutbound() throws Exception {
+
+        System.out.println("detectOutboundPolicy - should not fire even if response has \"2008\" in it because the content type is image/jpeg" );
+
+        request = new MockHttpServletRequest( new URL( "http://www.example.com/here_is_the_2008" ) );
+        response = new MockHttpServletResponse();
+        response.setContentType("image/jpeg");
+        response.setBody( "Now is the time for all good men 2008 to come to the aid of their country" );
+
+        WAFTestUtility.createAndExecuteWAFTransaction( "waf-policies/detect-outbound-policy.xml", request, response );
+
+        assertTrue( response.getStatus() == HttpServletResponse.SC_OK );
+
     }
 }
diff --git a/src/test/java/org/owasp/esapi/waf/DynamicInsertionTest.java b/src/test/java/org/owasp/esapi/waf/DynamicInsertionTest.java
index 0d67dc5..672294d 100644
--- a/src/test/java/org/owasp/esapi/waf/DynamicInsertionTest.java
+++ b/src/test/java/org/owasp/esapi/waf/DynamicInsertionTest.java
@@ -1,15 +1,15 @@
 /**
  * OWASP Enterprise Security API (ESAPI)
- * 
+ *
  * This file is part of the Open Web Application Security Project (OWASP)
  * Enterprise Security API (ESAPI) project. For details, please see
  * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
  *
  * Copyright (c) 2009 - The OWASP Foundation
- * 
+ *
  * The ESAPI is published by OWASP under the BSD license. You should read and accept the
  * LICENSE before you use, modify, and/or redistribute this software.
- * 
+ *
  * @author Arshan Dabirsiaghi <a href="http://www.aspectsecurity.com">Aspect Security</a>
  * @created 2009
  */
@@ -31,40 +31,40 @@ import junit.framework.TestSuite;
 
 public class DynamicInsertionTest extends WAFTestCase {
 
-	public static TestSuite suite() {
-		return new TestSuite(DynamicInsertionTest.class);
-	}
-	
-	public void testShouldReplaceContent() throws Exception {
-		
-    	System.out.println("dynamicInsertionPolicy - replaces </body> with 'this is a test'" );
-   	    
-    	request = new MockHttpServletRequest( new URL( "https://www.example.com/here+</body>+there+everywhere" ) );
+    public static TestSuite suite() {
+        return new TestSuite(DynamicInsertionTest.class);
+    }
+
+    public void testShouldReplaceContent() throws Exception {
+
+        System.out.println("dynamicInsertionPolicy - replaces </body> with 'this is a test'" );
+
+        request = new MockHttpServletRequest( new URL( "https://www.example.com/here+</body>+there+everywhere" ) );
         request.setScheme("https");
         request.getSession(true).setAttribute("ESAPIUserSessionKey", user);
-    	WAFTestUtility.createAndExecuteWAFTransaction( "waf-policies/dynamic-insertion-policy.xml", request, response );
-    	
-    	assertTrue ( response.getStatus() == HttpServletResponse.SC_OK );
-    	String body = response.getBody();
-    	assertTrue ( body.indexOf("test") > -1 );
-    	System.out.println( body );
-   	
-	}
-	
-	public void testShouldNotReplaceContent() throws Exception {
-		
-		System.out.println("dynamicInsertionPolicy - should not replace '< /body>' or </body > or </bo dy> with anything" );
-   	    
-    	request = new MockHttpServletRequest( new URL( "https://www.example.com/here+<+/body></bo+dy>+</body+>+there+everywhere" ) );
-    	request.setScheme("https");
-    	request.getSession(true).setAttribute("ESAPIUserSessionKey", user);
-    	WAFTestUtility.createAndExecuteWAFTransaction( "waf-policies/dynamic-insertion-policy.xml", request, response );
-    	
-    	assertTrue ( response.getStatus() == HttpServletResponse.SC_OK );
-    	assertTrue ( response.getBody().indexOf("test") == -1 );
-    	System.out.println( response.getBody() );
-   		
-    	
-	}
-	
+        WAFTestUtility.createAndExecuteWAFTransaction( "waf-policies/dynamic-insertion-policy.xml", request, response );
+
+        assertTrue ( response.getStatus() == HttpServletResponse.SC_OK );
+        String body = response.getBody();
+        assertTrue ( body.indexOf("test") > -1 );
+        System.out.println( body );
+
+    }
+
+    public void testShouldNotReplaceContent() throws Exception {
+
+        System.out.println("dynamicInsertionPolicy - should not replace '< /body>' or </body > or </bo dy> with anything" );
+
+        request = new MockHttpServletRequest( new URL( "https://www.example.com/here+<+/body></bo+dy>+</body+>+there+everywhere" ) );
+        request.setScheme("https");
+        request.getSession(true).setAttribute("ESAPIUserSessionKey", user);
+        WAFTestUtility.createAndExecuteWAFTransaction( "waf-policies/dynamic-insertion-policy.xml", request, response );
+
+        assertTrue ( response.getStatus() == HttpServletResponse.SC_OK );
+        assertTrue ( response.getBody().indexOf("test") == -1 );
+        System.out.println( response.getBody() );
+
+
+    }
+
 }
diff --git a/src/test/java/org/owasp/esapi/waf/EnforceAuthenticationTest.java b/src/test/java/org/owasp/esapi/waf/EnforceAuthenticationTest.java
index 69169b4..80757fd 100644
--- a/src/test/java/org/owasp/esapi/waf/EnforceAuthenticationTest.java
+++ b/src/test/java/org/owasp/esapi/waf/EnforceAuthenticationTest.java
@@ -1,15 +1,15 @@
 /**
  * OWASP Enterprise Security API (ESAPI)
- * 
+ *
  * This file is part of the Open Web Application Security Project (OWASP)
  * Enterprise Security API (ESAPI) project. For details, please see
  * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
  *
  * Copyright (c) 2009 - The OWASP Foundation
- * 
+ *
  * The ESAPI is published by OWASP under the BSD license. You should read and accept the
  * LICENSE before you use, modify, and/or redistribute this software.
- * 
+ *
  * @author Arshan Dabirsiaghi <a href="http://www.aspectsecurity.com">Aspect Security</a>
  * @created 2009
  */
@@ -26,27 +26,27 @@ import org.owasp.esapi.http.MockHttpServletResponse;
 
 public class EnforceAuthenticationTest extends WAFTestCase {
 
-	public static TestSuite suite() {
-		return new TestSuite(EnforceAuthenticationTest.class);
-	}
-	
-	public void testAuthenticatedRequest() throws Exception {
-		// authentication test
-	    url = new URL( "https://www.example.com/authenticated" );
-		System.out.println( "\nTest good request (user in session): " + url );
-	    request = new MockHttpServletRequest( url );
-	    request.getSession().setAttribute("ESAPIUserSessionKey", user);
-		response = new MockHttpServletResponse();
-		createAndExecuteWAFResponseCodeTest( waf, request, response, HttpServletResponse.SC_OK );		
-	}
-
-	public void testUnauthenticatedRequest() throws Exception {
-	    // authentication test
-	    url = new URL( "http://www.example.com/authenticated" );
-		System.out.println( "\nTest bad request (no user in session): " + url );
-	    request = new MockHttpServletRequest( url );
-		response = new MockHttpServletResponse();
-		createAndExecuteWAFResponseCodeTest ( waf, request, response, HttpServletResponse.SC_MOVED_PERMANENTLY );		
-	}
+    public static TestSuite suite() {
+        return new TestSuite(EnforceAuthenticationTest.class);
+    }
+
+    public void testAuthenticatedRequest() throws Exception {
+        // authentication test
+        url = new URL( "https://www.example.com/authenticated" );
+        System.out.println( "\nTest good request (user in session): " + url );
+        request = new MockHttpServletRequest( url );
+        request.getSession().setAttribute("ESAPIUserSessionKey", user);
+        response = new MockHttpServletResponse();
+        createAndExecuteWAFResponseCodeTest( waf, request, response, HttpServletResponse.SC_OK );
+    }
+
+    public void testUnauthenticatedRequest() throws Exception {
+        // authentication test
+        url = new URL( "http://www.example.com/authenticated" );
+        System.out.println( "\nTest bad request (no user in session): " + url );
+        request = new MockHttpServletRequest( url );
+        response = new MockHttpServletResponse();
+        createAndExecuteWAFResponseCodeTest ( waf, request, response, HttpServletResponse.SC_MOVED_PERMANENTLY );
+    }
 
 }
\ No newline at end of file
diff --git a/src/test/java/org/owasp/esapi/waf/EnforceHTTPSTest.java b/src/test/java/org/owasp/esapi/waf/EnforceHTTPSTest.java
index 11950e8..05f66b1 100644
--- a/src/test/java/org/owasp/esapi/waf/EnforceHTTPSTest.java
+++ b/src/test/java/org/owasp/esapi/waf/EnforceHTTPSTest.java
@@ -1,15 +1,15 @@
 /**
  * OWASP Enterprise Security API (ESAPI)
- * 
+ *
  * This file is part of the Open Web Application Security Project (OWASP)
  * Enterprise Security API (ESAPI) project. For details, please see
  * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
  *
  * Copyright (c) 2009 - The OWASP Foundation
- * 
+ *
  * The ESAPI is published by OWASP under the BSD license. You should read and accept the
  * LICENSE before you use, modify, and/or redistribute this software.
- * 
+ *
  * @author Arshan Dabirsiaghi <a href="http://www.aspectsecurity.com">Aspect Security</a>
  * @created 2009
  */
@@ -26,43 +26,43 @@ import org.owasp.esapi.http.MockHttpServletResponse;
 
 public class EnforceHTTPSTest extends WAFTestCase {
 
-	public static TestSuite suite() {
-		return new TestSuite(EnforceHTTPSTest.class);
-	}
-	
-	public void setUp() throws Exception {
-		super.setUp();
-    	WAFTestUtility.setWAFPolicy( waf, "waf-policy.xml" );
-	}
+    public static TestSuite suite() {
+        return new TestSuite(EnforceHTTPSTest.class);
+    }
+
+    public void setUp() throws Exception {
+        super.setUp();
+        WAFTestUtility.setWAFPolicy( waf, "waf-policy.xml" );
+    }
+
+    public void testGoodSchemeSSLRequired() throws Exception {
+        // test good scheme
+        url = new URL( "https://www.example.com/" );
+        System.out.println( "\nTest good scheme (https): " + url );
+        request = new MockHttpServletRequest( url );
+        request.getSession(true);
+        response = new MockHttpServletResponse();
+        createAndExecuteWAFResponseCodeTest( waf, request, response, HttpServletResponse.SC_OK );
+    }
 
-	public void testGoodSchemeSSLRequired() throws Exception {
-	    // test good scheme
-		url = new URL( "https://www.example.com/" );
-		System.out.println( "\nTest good scheme (https): " + url );
-	    request = new MockHttpServletRequest( url );
-	    request.getSession(true);
-		response = new MockHttpServletResponse();
-		createAndExecuteWAFResponseCodeTest( waf, request, response, HttpServletResponse.SC_OK );		
-	}
 
-     
-	public void testBadSchemeSSLNotRequired () throws Exception {
-	    // test bad scheme
-	    url = new URL( "http://www.example.com/images/test.gif" );
-		System.out.println( "\nTest bad scheme (no ssl - but its not required): " + url );
-	    request = new MockHttpServletRequest( url );
-	    request.getSession(true);
-		response = new MockHttpServletResponse();
-		createAndExecuteWAFResponseCodeTest( waf, request, response, HttpServletResponse.SC_OK );		
-	}
+    public void testBadSchemeSSLNotRequired () throws Exception {
+        // test bad scheme
+        url = new URL( "http://www.example.com/images/test.gif" );
+        System.out.println( "\nTest bad scheme (no ssl - but its not required): " + url );
+        request = new MockHttpServletRequest( url );
+        request.getSession(true);
+        response = new MockHttpServletResponse();
+        createAndExecuteWAFResponseCodeTest( waf, request, response, HttpServletResponse.SC_OK );
+    }
 
-	public void testBadSchemeSSLRequired () throws Exception {
-	    // test bad scheme
-	    url = new URL( "http://www.example.com/secure" );
-		System.out.println( "\nTest bad scheme (no ssl - but its required): " + url );
-	    request = new MockHttpServletRequest( url );
-	    request.getSession(true);
-		response = new MockHttpServletResponse();
-		createAndExecuteWAFResponseCodeTest( waf, request, response, HttpServletResponse.SC_MOVED_PERMANENTLY );		
-	}
+    public void testBadSchemeSSLRequired () throws Exception {
+        // test bad scheme
+        url = new URL( "http://www.example.com/secure" );
+        System.out.println( "\nTest bad scheme (no ssl - but its required): " + url );
+        request = new MockHttpServletRequest( url );
+        request.getSession(true);
+        response = new MockHttpServletResponse();
+        createAndExecuteWAFResponseCodeTest( waf, request, response, HttpServletResponse.SC_MOVED_PERMANENTLY );
+    }
 }
diff --git a/src/test/java/org/owasp/esapi/waf/GoodRequestTest.java b/src/test/java/org/owasp/esapi/waf/GoodRequestTest.java
index 54dc036..25ae2b4 100644
--- a/src/test/java/org/owasp/esapi/waf/GoodRequestTest.java
+++ b/src/test/java/org/owasp/esapi/waf/GoodRequestTest.java
@@ -1,15 +1,15 @@
 /**
  * OWASP Enterprise Security API (ESAPI)
- * 
+ *
  * This file is part of the Open Web Application Security Project (OWASP)
  * Enterprise Security API (ESAPI) project. For details, please see
  * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
  *
  * Copyright (c) 2009 - The OWASP Foundation
- * 
+ *
  * The ESAPI is published by OWASP under the BSD license. You should read and accept the
  * LICENSE before you use, modify, and/or redistribute this software.
- * 
+ *
  * @author Arshan Dabirsiaghi <a href="http://www.aspectsecurity.com">Aspect Security</a>
  * @created 2009
  */
@@ -26,18 +26,18 @@ import org.owasp.esapi.http.MockHttpServletResponse;
 
 public class GoodRequestTest extends WAFTestCase {
 
-	public static TestSuite suite() {
-		return new TestSuite(GoodRequestTest.class);
-	}
-	
-	public void testGoodRequest() throws Exception {
-		// should pass
+    public static TestSuite suite() {
+        return new TestSuite(GoodRequestTest.class);
+    }
+
+    public void testGoodRequest() throws Exception {
+        // should pass
         url = new URL( "http://www.example.com/index.jsp" );
-		System.out.println( "Test good URL: " + url );
+        System.out.println( "Test good URL: " + url );
         request = new MockHttpServletRequest( url );
         request.getSession(true);
-    	response = new MockHttpServletResponse();
-    	createAndExecuteWAFResponseCodeTest( waf, request, response, HttpServletResponse.SC_OK );
-	}
-	
+        response = new MockHttpServletResponse();
+        createAndExecuteWAFResponseCodeTest( waf, request, response, HttpServletResponse.SC_OK );
+    }
+
 }
diff --git a/src/test/java/org/owasp/esapi/waf/HttpOnlyTest.java b/src/test/java/org/owasp/esapi/waf/HttpOnlyTest.java
index 74d5e6f..61bdffb 100644
--- a/src/test/java/org/owasp/esapi/waf/HttpOnlyTest.java
+++ b/src/test/java/org/owasp/esapi/waf/HttpOnlyTest.java
@@ -1,15 +1,15 @@
 /**
  * OWASP Enterprise Security API (ESAPI)
- * 
+ *
  * This file is part of the Open Web Application Security Project (OWASP)
  * Enterprise Security API (ESAPI) project. For details, please see
  * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
  *
  * Copyright (c) 2009 - The OWASP Foundation
- * 
+ *
  * The ESAPI is published by OWASP under the BSD license. You should read and accept the
  * LICENSE before you use, modify, and/or redistribute this software.
- * 
+ *
  * @author Arshan Dabirsiaghi <a href="http://www.aspectsecurity.com">Aspect Security</a>
  * @created 2009
  */
@@ -28,57 +28,57 @@ import org.owasp.esapi.http.MockFilterChain;
 import junit.framework.TestSuite;
 
 public class HttpOnlyTest extends WAFTestCase {
-	
-	public static TestSuite suite() {
-		return new TestSuite(HttpOnlyTest.class);
-	}
-	
+
+    public static TestSuite suite() {
+        return new TestSuite(HttpOnlyTest.class);
+    }
+
     /*
      * Test all aspects of the HTTPOnly protection. Note that attaching HTTPOnly to
-     * JSESSIONIDs requires a 3-step handshake, so the first 2 response codes should 
+     * JSESSIONIDs requires a 3-step handshake, so the first 2 response codes should
      * be 301, and on the 3rd response the cookie should be set. A lot of extra traffic
      * for HTTPOnly.
-     * 
+     *
      * That same 3-step handshake won't be needed for custom cookies generated by the
      * application with addCookie().
      */
 
-	// this has been commented because we decided not to try to make this work. too much
-	// hackery.
-	/*
+    // this has been commented because we decided not to try to make this work. too much
+    // hackery.
+    /*
     public void testAddHttpOnlyOnSessionCookie() throws Exception {
-    	
-     	System.out.println("addHttpOnlyPolicy - Response should have httpOnly set on the session ID (JSESSIONID) cookie added to response" );
-   	        	
-    	WAFTestUtility.createAndExecuteWAFTransaction( "waf-policies/add-httponly-policy.xml", request, response );
-    	
-    	assertTrue( response.getStatus() == HttpServletResponse.SC_MOVED_PERMANENTLY );
-    	
+
+         System.out.println("addHttpOnlyPolicy - Response should have httpOnly set on the session ID (JSESSIONID) cookie added to response" );
+
+        WAFTestUtility.createAndExecuteWAFTransaction( "waf-policies/add-httponly-policy.xml", request, response );
+
+        assertTrue( response.getStatus() == HttpServletResponse.SC_MOVED_PERMANENTLY );
+
     }
     */
-	
+
     public void testAddHttpOnlyOnCustomCookie() throws Exception {
-    	
-    	System.out.println("addHttpOnlyPolicy - Response should have httpOnly set on a custom cookie (FOOBAR) added to the response" );
-   	    
-    	request.getSession(true);
-    	
-    	WAFTestUtility.createAndExecuteWAFTransaction( "waf-policies/add-httponly-policy.xml", request, response, new HttpOnlyTestFilterChain() );
-    	
-    	//response.dump();
-     
-    	String foo = response.getHeader("Set-Cookie");
-    	assertTrue( response.getStatus() != HttpServletResponse.SC_MOVED_PERMANENTLY );
-    	assertTrue( foo.contains("HttpOnly") );
-    	
+
+        System.out.println("addHttpOnlyPolicy - Response should have httpOnly set on a custom cookie (FOOBAR) added to the response" );
+
+        request.getSession(true);
+
+        WAFTestUtility.createAndExecuteWAFTransaction( "waf-policies/add-httponly-policy.xml", request, response, new HttpOnlyTestFilterChain() );
+
+        //response.dump();
+
+        String foo = response.getHeader("Set-Cookie");
+        assertTrue( response.getStatus() != HttpServletResponse.SC_MOVED_PERMANENTLY );
+        assertTrue( foo.contains("HttpOnly") );
+
     }
-    
+
     class HttpOnlyTestFilterChain extends MockFilterChain {
-		public void doFilter(ServletRequest arg0, ServletResponse arg1)
-				throws IOException, ServletException {
-			HttpServletResponse response = (HttpServletResponse)arg1;
-			response.addCookie( new Cookie("FOO", "BAR" ) );
-		}
+        public void doFilter(ServletRequest arg0, ServletResponse arg1)
+                throws IOException, ServletException {
+            HttpServletResponse response = (HttpServletResponse)arg1;
+            response.addCookie( new Cookie("FOO", "BAR" ) );
+        }
     }
-    
+
 }
diff --git a/src/test/java/org/owasp/esapi/waf/MockWafFilterConfig.java b/src/test/java/org/owasp/esapi/waf/MockWafFilterConfig.java
index c1515e3..9ba84e7 100644
--- a/src/test/java/org/owasp/esapi/waf/MockWafFilterConfig.java
+++ b/src/test/java/org/owasp/esapi/waf/MockWafFilterConfig.java
@@ -8,11 +8,11 @@ import org.owasp.esapi.http.MockFilterConfig;
 
 public class MockWafFilterConfig extends MockFilterConfig {
 
-	public MockWafFilterConfig(Map map) {
-		super(map);
-	}
+    public MockWafFilterConfig(Map map) {
+        super(map);
+    }
 
-	public ServletContext getServletContext() {
-    	return new MockWafServletContext();
+    public ServletContext getServletContext() {
+        return new MockWafServletContext();
     }
 }
diff --git a/src/test/java/org/owasp/esapi/waf/MockWafServletContext.java b/src/test/java/org/owasp/esapi/waf/MockWafServletContext.java
index e42c1ae..4e61a59 100644
--- a/src/test/java/org/owasp/esapi/waf/MockWafServletContext.java
+++ b/src/test/java/org/owasp/esapi/waf/MockWafServletContext.java
@@ -5,10 +5,10 @@ import org.owasp.esapi.http.MockServletContext;
 
 public class MockWafServletContext extends MockServletContext {
 
-	public String getRealPath(String s) {
-		
-		return ESAPI.securityConfiguration().getResourceFile( "" ).getAbsolutePath() + "/" + s;
-		
-	}
-	
+    public String getRealPath(String s) {
+
+        return ESAPI.securityConfiguration().getResourceFile( "" ).getAbsolutePath() + "/" + s;
+
+    }
+
 }
diff --git a/src/test/java/org/owasp/esapi/waf/MustMatchTest.java b/src/test/java/org/owasp/esapi/waf/MustMatchTest.java
index d830109..d23d9d6 100644
--- a/src/test/java/org/owasp/esapi/waf/MustMatchTest.java
+++ b/src/test/java/org/owasp/esapi/waf/MustMatchTest.java
@@ -1,15 +1,15 @@
 /**
  * OWASP Enterprise Security API (ESAPI)
- * 
+ *
  * This file is part of the Open Web Application Security Project (OWASP)
  * Enterprise Security API (ESAPI) project. For details, please see
  * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
  *
  * Copyright (c) 2009 - The OWASP Foundation
- * 
+ *
  * The ESAPI is published by OWASP under the BSD license. You should read and accept the
  * LICENSE before you use, modify, and/or redistribute this software.
- * 
+ *
  * @author Arshan Dabirsiaghi <a href="http://www.aspectsecurity.com">Aspect Security</a>
  * @created 2009
  */
@@ -25,31 +25,31 @@ import org.owasp.esapi.http.MockHttpServletRequest;
 import org.owasp.esapi.http.MockHttpServletResponse;
 
 public class MustMatchTest extends WAFTestCase {
-	
-	public static TestSuite suite() {
-		return new TestSuite(MustMatchTest.class);
-	}
-	
-	public void testUnauthorizedRequest () throws Exception {
+
+    public static TestSuite suite() {
+        return new TestSuite(MustMatchTest.class);
+    }
+
+    public void testUnauthorizedRequest () throws Exception {
         // Test bad request (no x-roles header)
         url = new URL( "https://www.example.com/admin/config" );
-		System.out.println( "\nTest bad request (request has no x-roles header): " + url );
+        System.out.println( "\nTest bad request (request has no x-roles header): " + url );
         request = new MockHttpServletRequest( url );
         request.setRemoteAddr("192.168.1.5"); // necessary to pass IPRule
         request.getSession().setAttribute("ESAPIUserSessionKey", user);
-    	response = new MockHttpServletResponse();
-    	createAndExecuteWAFResponseCodeTest( waf, request, response, HttpServletResponse.SC_MOVED_PERMANENTLY );
-	}
-	
-	public void testAuthorizedRequest() throws Exception {
+        response = new MockHttpServletResponse();
+        createAndExecuteWAFResponseCodeTest( waf, request, response, HttpServletResponse.SC_MOVED_PERMANENTLY );
+    }
+
+    public void testAuthorizedRequest() throws Exception {
         // Test good request (request has x-roles header)
         url = new URL( "https://www.example.com/admin/config" );
-		System.out.println( "\nTest good request (request has x-roles header): " + url );
+        System.out.println( "\nTest good request (request has x-roles header): " + url );
         request = new MockHttpServletRequest( url );
         request.addHeader("x-roles", "admin" );
         request.setRemoteAddr("192.168.1.100");
         request.getSession().setAttribute("ESAPIUserSessionKey", user);
-    	response = new MockHttpServletResponse();
-    	createAndExecuteWAFResponseCodeTest( waf, request, response, HttpServletResponse.SC_OK );
-	}
+        response = new MockHttpServletResponse();
+        createAndExecuteWAFResponseCodeTest( waf, request, response, HttpServletResponse.SC_OK );
+    }
 }
diff --git a/src/test/java/org/owasp/esapi/waf/RestrictContentTypeTest.java b/src/test/java/org/owasp/esapi/waf/RestrictContentTypeTest.java
index 49fe814..8088bbc 100644
--- a/src/test/java/org/owasp/esapi/waf/RestrictContentTypeTest.java
+++ b/src/test/java/org/owasp/esapi/waf/RestrictContentTypeTest.java
@@ -1,15 +1,15 @@
 /**
  * OWASP Enterprise Security API (ESAPI)
- * 
+ *
  * This file is part of the Open Web Application Security Project (OWASP)
  * Enterprise Security API (ESAPI) project. For details, please see
  * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
  *
  * Copyright (c) 2009 - The OWASP Foundation
- * 
+ *
  * The ESAPI is published by OWASP under the BSD license. You should read and accept the
  * LICENSE before you use, modify, and/or redistribute this software.
- * 
+ *
  * @author Arshan Dabirsiaghi <a href="http://www.aspectsecurity.com">Aspect Security</a>
  * @created 2009
  */
@@ -21,31 +21,31 @@ import junit.framework.TestSuite;
 
 public class RestrictContentTypeTest extends WAFTestCase {
 
-	public static TestSuite suite() {
-		return new TestSuite(RestrictContentTypeTest.class);
-	}
-
-	public void testNoContentType() throws Exception {
-
-		WAFTestUtility.createAndExecuteWAFTransaction( "waf-policies/restrict-content-type-policy.xml", request, response );
-    	
-		assert(response.getStatus() == HttpServletResponse.SC_OK);
-	}
-	
-	public void testGoodContentType() throws Exception {
-		request.addHeader("Content-Type","text/html");
-		
-		WAFTestUtility.createAndExecuteWAFTransaction( "waf-policies/restrict-content-type-policy.xml", request, response );
-    	
-		assert(response.getStatus() == HttpServletResponse.SC_OK);
-	}
-	
-	public void testBadContentType() throws Exception {
-		request.addHeader("Content-Type","multipart/form-upload");
-		
-		WAFTestUtility.createAndExecuteWAFTransaction( "waf-policies/restrict-content-type-policy.xml", request, response );
-    	
-		assert(response.getStatus() == HttpServletResponse.SC_MOVED_PERMANENTLY);
-	}
-	
+    public static TestSuite suite() {
+        return new TestSuite(RestrictContentTypeTest.class);
+    }
+
+    public void testNoContentType() throws Exception {
+
+        WAFTestUtility.createAndExecuteWAFTransaction( "waf-policies/restrict-content-type-policy.xml", request, response );
+
+        assert(response.getStatus() == HttpServletResponse.SC_OK);
+    }
+
+    public void testGoodContentType() throws Exception {
+        request.addHeader("Content-Type","text/html");
+
+        WAFTestUtility.createAndExecuteWAFTransaction( "waf-policies/restrict-content-type-policy.xml", request, response );
+
+        assert(response.getStatus() == HttpServletResponse.SC_OK);
+    }
+
+    public void testBadContentType() throws Exception {
+        request.addHeader("Content-Type","multipart/form-upload");
+
+        WAFTestUtility.createAndExecuteWAFTransaction( "waf-policies/restrict-content-type-policy.xml", request, response );
+
+        assert(response.getStatus() == HttpServletResponse.SC_MOVED_PERMANENTLY);
+    }
+
 }
diff --git a/src/test/java/org/owasp/esapi/waf/RestrictExtensionTest.java b/src/test/java/org/owasp/esapi/waf/RestrictExtensionTest.java
index 18ded97..eb7884e 100644
--- a/src/test/java/org/owasp/esapi/waf/RestrictExtensionTest.java
+++ b/src/test/java/org/owasp/esapi/waf/RestrictExtensionTest.java
@@ -1,15 +1,15 @@
 /**
  * OWASP Enterprise Security API (ESAPI)
- * 
+ *
  * This file is part of the Open Web Application Security Project (OWASP)
  * Enterprise Security API (ESAPI) project. For details, please see
  * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
  *
  * Copyright (c) 2009 - The OWASP Foundation
- * 
+ *
  * The ESAPI is published by OWASP under the BSD license. You should read and accept the
  * LICENSE before you use, modify, and/or redistribute this software.
- * 
+ *
  * @author Arshan Dabirsiaghi <a href="http://www.aspectsecurity.com">Aspect Security</a>
  * @created 2009
  */
@@ -26,32 +26,32 @@ import org.owasp.esapi.http.MockHttpServletResponse;
 
 public class RestrictExtensionTest extends WAFTestCase {
 
-	public static TestSuite suite() {
-		return new TestSuite(RestrictExtensionTest.class);
-	}
-	
-	public void testGoodExtension() throws Exception {
-        
-    	System.out.println("restrictExtensionPolicy - approve this URL (doesn't end in .log or anything else evil)" );
+    public static TestSuite suite() {
+        return new TestSuite(RestrictExtensionTest.class);
+    }
+
+    public void testGoodExtension() throws Exception {
+
+        System.out.println("restrictExtensionPolicy - approve this URL (doesn't end in .log or anything else evil)" );
 
         request = new MockHttpServletRequest( new URL( "http://www.example.com/logfiles/12192009.jpg" ) );
         request.getSession(true); // pass HttpOnly test...
-    	response = new MockHttpServletResponse();
-        
+        response = new MockHttpServletResponse();
+
         WAFTestUtility.createAndExecuteWAFTransaction( "waf-policies/restrict-extension-policy.xml", request, response );
-    	
-    	assertTrue( response.getStatus() != HttpServletResponse.SC_MOVED_PERMANENTLY );
+
+        assertTrue( response.getStatus() != HttpServletResponse.SC_MOVED_PERMANENTLY );
     }
 
-	public void testBadExtension() throws Exception {
-        
-    	System.out.println("restrictExtensionPolicy - reject any URL ending in .log" );
+    public void testBadExtension() throws Exception {
+
+        System.out.println("restrictExtensionPolicy - reject any URL ending in .log" );
 
         MockHttpServletRequest request = new MockHttpServletRequest( new URL( "http://www.example.com/logfiles/12192009.log" ) );
-    	MockHttpServletResponse response = new MockHttpServletResponse();
-        
+        MockHttpServletResponse response = new MockHttpServletResponse();
+
         WAFTestUtility.createAndExecuteWAFTransaction( "waf-policies/restrict-extension-policy.xml", request, response );
-    	
-    	assertTrue( response.getStatus() == HttpServletResponse.SC_MOVED_PERMANENTLY );
+
+        assertTrue( response.getStatus() == HttpServletResponse.SC_MOVED_PERMANENTLY );
     }
 }
diff --git a/src/test/java/org/owasp/esapi/waf/RestrictMethodTest.java b/src/test/java/org/owasp/esapi/waf/RestrictMethodTest.java
index 380ee02..bdb89f7 100644
--- a/src/test/java/org/owasp/esapi/waf/RestrictMethodTest.java
+++ b/src/test/java/org/owasp/esapi/waf/RestrictMethodTest.java
@@ -1,15 +1,15 @@
 /**
  * OWASP Enterprise Security API (ESAPI)
- * 
+ *
  * This file is part of the Open Web Application Security Project (OWASP)
  * Enterprise Security API (ESAPI) project. For details, please see
  * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
  *
  * Copyright (c) 2009 - The OWASP Foundation
- * 
+ *
  * The ESAPI is published by OWASP under the BSD license. You should read and accept the
  * LICENSE before you use, modify, and/or redistribute this software.
- * 
+ *
  * @author Arshan Dabirsiaghi <a href="http://www.aspectsecurity.com">Aspect Security</a>
  * @created 2009
  */
@@ -25,32 +25,32 @@ import org.owasp.esapi.http.MockHttpServletRequest;
 import org.owasp.esapi.http.MockHttpServletResponse;
 
 public class RestrictMethodTest extends WAFTestCase {
-	
-	public static TestSuite suite() {
-		return new TestSuite(RestrictMethodTest.class);
-	}
-	
-	public void testGoodMethod() throws Exception {
-		// test good method
-	    url = new URL( "http://www.example.com/index.jsp" );
-		System.out.println( "\nTest good method: " + url );
-	    request = new MockHttpServletRequest( url );
-	    request.setMethod( "TRACE" );
-	    request.getSession(true); // so the app will pass the HttpOnly test...
-	    
-		response = new MockHttpServletResponse();
-		createAndExecuteWAFResponseCodeTest(waf, request, response, HttpServletResponse.SC_OK );
-	}
-	
-	public void testBadMethod() throws Exception {
-		// test bad method
-	    url = new URL( "http://www.example.com/index.jsp" );
-		System.out.println( "\nTest bad method: " + url );
-	    request = new MockHttpServletRequest( url );
-	    request.setMethod( "JEFF" );
-	    request.getSession(true); // so the app will pass the HttpOnly test...
-	    
-		response = new MockHttpServletResponse();
-		createAndExecuteWAFResponseCodeTest( waf, request, response, HttpServletResponse.SC_MOVED_PERMANENTLY );
-	}    
+
+    public static TestSuite suite() {
+        return new TestSuite(RestrictMethodTest.class);
+    }
+
+    public void testGoodMethod() throws Exception {
+        // test good method
+        url = new URL( "http://www.example.com/index.jsp" );
+        System.out.println( "\nTest good method: " + url );
+        request = new MockHttpServletRequest( url );
+        request.setMethod( "TRACE" );
+        request.getSession(true); // so the app will pass the HttpOnly test...
+
+        response = new MockHttpServletResponse();
+        createAndExecuteWAFResponseCodeTest(waf, request, response, HttpServletResponse.SC_OK );
+    }
+
+    public void testBadMethod() throws Exception {
+        // test bad method
+        url = new URL( "http://www.example.com/index.jsp" );
+        System.out.println( "\nTest bad method: " + url );
+        request = new MockHttpServletRequest( url );
+        request.setMethod( "JEFF" );
+        request.getSession(true); // so the app will pass the HttpOnly test...
+
+        response = new MockHttpServletResponse();
+        createAndExecuteWAFResponseCodeTest( waf, request, response, HttpServletResponse.SC_MOVED_PERMANENTLY );
+    }
 }
diff --git a/src/test/java/org/owasp/esapi/waf/RestrictUserAgentTest.java b/src/test/java/org/owasp/esapi/waf/RestrictUserAgentTest.java
index 79d865a..f1c1939 100644
--- a/src/test/java/org/owasp/esapi/waf/RestrictUserAgentTest.java
+++ b/src/test/java/org/owasp/esapi/waf/RestrictUserAgentTest.java
@@ -1,15 +1,15 @@
 /**
  * OWASP Enterprise Security API (ESAPI)
- * 
+ *
  * This file is part of the Open Web Application Security Project (OWASP)
  * Enterprise Security API (ESAPI) project. For details, please see
  * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
  *
  * Copyright (c) 2009 - The OWASP Foundation
- * 
+ *
  * The ESAPI is published by OWASP under the BSD license. You should read and accept the
  * LICENSE before you use, modify, and/or redistribute this software.
- * 
+ *
  * @author Arshan Dabirsiaghi <a href="http://www.aspectsecurity.com">Aspect Security</a>
  * @created 2009
  */
@@ -20,27 +20,27 @@ import javax.servlet.http.HttpServletResponse;
 import junit.framework.TestSuite;
 
 public class RestrictUserAgentTest extends WAFTestCase {
-	
-	public static TestSuite suite() {
-		return new TestSuite(RestrictUserAgentTest.class);
-	}
-	
-	public void testBadUserAgent() throws Exception {
-		
-		request.addHeader("User-Agent","GoogleBot");
-		
-		WAFTestUtility.createAndExecuteWAFTransaction( "waf-policies/restrict-user-agent-policy.xml", request, response );
-		
-		assert(response.getStatus() == 403);
-	}
-	
-	public void testGoodUserAgent() throws Exception {
-		
-		request.addHeader("User-Agent","MSIE NT Compatible");
-		
-		WAFTestUtility.createAndExecuteWAFTransaction( "waf-policies/restrict-user-agent-policy.xml", request, response );
-    	
-		assert(response.getStatus() == HttpServletResponse.SC_OK);
-	}
-	
+
+    public static TestSuite suite() {
+        return new TestSuite(RestrictUserAgentTest.class);
+    }
+
+    public void testBadUserAgent() throws Exception {
+
+        request.addHeader("User-Agent","GoogleBot");
+
+        WAFTestUtility.createAndExecuteWAFTransaction( "waf-policies/restrict-user-agent-policy.xml", request, response );
+
+        assert(response.getStatus() == 403);
+    }
+
+    public void testGoodUserAgent() throws Exception {
+
+        request.addHeader("User-Agent","MSIE NT Compatible");
+
+        WAFTestUtility.createAndExecuteWAFTransaction( "waf-policies/restrict-user-agent-policy.xml", request, response );
+
+        assert(response.getStatus() == HttpServletResponse.SC_OK);
+    }
+
 }
diff --git a/src/test/java/org/owasp/esapi/waf/VirtualPatchTest.java b/src/test/java/org/owasp/esapi/waf/VirtualPatchTest.java
index 375c596..981fea5 100644
--- a/src/test/java/org/owasp/esapi/waf/VirtualPatchTest.java
+++ b/src/test/java/org/owasp/esapi/waf/VirtualPatchTest.java
@@ -1,15 +1,15 @@
 /**
  * OWASP Enterprise Security API (ESAPI)
- * 
+ *
  * This file is part of the Open Web Application Security Project (OWASP)
  * Enterprise Security API (ESAPI) project. For details, please see
  * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
  *
  * Copyright (c) 2009 - The OWASP Foundation
- * 
+ *
  * The ESAPI is published by OWASP under the BSD license. You should read and accept the
  * LICENSE before you use, modify, and/or redistribute this software.
- * 
+ *
  * @author Arshan Dabirsiaghi <a href="http://www.aspectsecurity.com">Aspect Security</a>
  * @created 2009
  */
@@ -26,35 +26,35 @@ import junit.framework.TestSuite;
 
 public class VirtualPatchTest extends WAFTestCase {
 
-	public static TestSuite suite() {
-		return new TestSuite(VirtualPatchTest.class);
-	}
-	
-	public void testNonAttacktAfterVirtualPatch() throws Exception {
-		// should pass
+    public static TestSuite suite() {
+        return new TestSuite(VirtualPatchTest.class);
+    }
+
+    public void testNonAttacktAfterVirtualPatch() throws Exception {
+        // should pass
         url = new URL( "https://www.example.com/virtualpatch.jsp" );
-		System.out.println( "Testing non-attack after virtual patch on URL: " + url );
+        System.out.println( "Testing non-attack after virtual patch on URL: " + url );
         request = new MockHttpServletRequest( url );
         request.getSession(true);
         request.setScheme("https");
         request.getSession().setAttribute("ESAPIUserSessionKey", user);
         request.addParameter("bar", "09124asd135r123irh2938rh9c82hr3hareohvw"); // alphanums are allowed
         request.addParameter("foo", "<script>' oR 1=1-- bad.attax.google.com jar:"); // this parameter should not be touched by the patch
-    	response = new MockHttpServletResponse();
-    	createAndExecuteWAFResponseCodeTest( waf, request, response, HttpServletResponse.SC_OK );
-	}
-	
-	public void testAttackAfterVirtualPatch() throws Exception {
-		// should fail
+        response = new MockHttpServletResponse();
+        createAndExecuteWAFResponseCodeTest( waf, request, response, HttpServletResponse.SC_OK );
+    }
+
+    public void testAttackAfterVirtualPatch() throws Exception {
+        // should fail
         url = new URL( "https://www.example.com/foo.jsp" );
-		System.out.println( "Testing attack after virtual patch on URL: " + url );
+        System.out.println( "Testing attack after virtual patch on URL: " + url );
         request = new MockHttpServletRequest( url );
         request.getSession(true);
         request.setScheme("https");
         request.getSession().setAttribute("ESAPIUserSessionKey", user);
         request.addParameter("bar", "09124asd135r123ir>h2938rh9c82hr3hareohvw"); // non-alphanums are not allowed (there is 1 in the middle)
         request.addParameter("foo", "SADFSDfSDFSDF123123123"); // this parameter should not be touched by the patch
-    	response = new MockHttpServletResponse();
-    	createAndExecuteWAFResponseCodeTest( waf, request, response, HttpServletResponse.SC_MOVED_PERMANENTLY );
-	}
+        response = new MockHttpServletResponse();
+        createAndExecuteWAFResponseCodeTest( waf, request, response, HttpServletResponse.SC_MOVED_PERMANENTLY );
+    }
 }
diff --git a/src/test/java/org/owasp/esapi/waf/WAFFilterTest.java b/src/test/java/org/owasp/esapi/waf/WAFFilterTest.java
index 5750bc4..3f008ae 100644
--- a/src/test/java/org/owasp/esapi/waf/WAFFilterTest.java
+++ b/src/test/java/org/owasp/esapi/waf/WAFFilterTest.java
@@ -1,15 +1,15 @@
 /**
  * OWASP Enterprise Security API (ESAPI)
- * 
+ *
  * This file is part of the Open Web Application Security Project (OWASP)
  * Enterprise Security API (ESAPI) project. For details, please see
  * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
  *
  * Copyright (c) 2009 - The OWASP Foundation
- * 
+ *
  * The ESAPI is published by OWASP under the BSD license. You should read and accept the
  * LICENSE before you use, modify, and/or redistribute this software.
- * 
+ *
  * @author Jeff Williams <a href="http://www.aspectsecurity.com">Aspect Security</a>
  * @author Arshan Dabirsiaghi <a href="http://www.aspectsecurity.com">Aspect Security</a>
  * @created 2009
@@ -24,34 +24,34 @@ import junit.framework.TestSuite;
  * This is the main TestSuite for all the WAF tests. Some of the WAF
  * tests utilize a large policy file containing a bunch of unrelated
  * rules, and some use very small policy files that only exercise
- * specific functionality. Some may use both. 
- * 
- * There is an unlimited combination of rules to be exercised together, 
+ * specific functionality. Some may use both.
+ *
+ * There is an unlimited combination of rules to be exercised together,
  * so the small policy files test the strict functionality, while the
- * larger policy files (hopefully) give us assurance that the rules 
+ * larger policy files (hopefully) give us assurance that the rules
  * won't interfere with each other.
  */
 
 public class WAFFilterTest extends TestCase {
-    
+
     /**
-	 * Instantiates a new WAF test.
-	 * 
-	 * @param testName the test name
-	 */
+     * Instantiates a new WAF test.
+     *
+     * @param testName the test name
+     */
     public WAFFilterTest(String testName) {
         super(testName);
     }
 
 
     /**
-	 * Suite.
-	 * 
-	 * @return the test
-	 */
+     * Suite.
+     *
+     * @return the test
+     */
     public static Test suite() {
 
-    	TestSuite suite = new TestSuite(WAFFilterTest.class);
+        TestSuite suite = new TestSuite(WAFFilterTest.class);
 
         suite.addTest(AddHeaderTest.suite());
         suite.addTest(BeanShellTest.suite());
@@ -67,14 +67,14 @@ public class WAFFilterTest extends TestCase {
         suite.addTest(RestrictMethodTest.suite());
         suite.addTest(RestrictUserAgentTest.suite());
         suite.addTest(VirtualPatchTest.suite());
-        
+
         return suite;
     }
-    
+
     public void testConfigurationCanBeRead() throws Exception {
-    	
-    	ESAPIWebApplicationFirewallFilter waf = new ESAPIWebApplicationFirewallFilter();
-    	WAFTestUtility.setWAFPolicy(waf, "waf-policy.xml");
+
+        ESAPIWebApplicationFirewallFilter waf = new ESAPIWebApplicationFirewallFilter();
+        WAFTestUtility.setWAFPolicy(waf, "waf-policy.xml");
 
     }
 
diff --git a/src/test/java/org/owasp/esapi/waf/WAFTestCase.java b/src/test/java/org/owasp/esapi/waf/WAFTestCase.java
index df72f92..ba773ff 100644
--- a/src/test/java/org/owasp/esapi/waf/WAFTestCase.java
+++ b/src/test/java/org/owasp/esapi/waf/WAFTestCase.java
@@ -1,15 +1,15 @@
 /**
  * OWASP Enterprise Security API (ESAPI)
- * 
+ *
  * This file is part of the Open Web Application Security Project (OWASP)
  * Enterprise Security API (ESAPI) project. For details, please see
  * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
  *
  * Copyright (c) 2009 - The OWASP Foundation
- * 
+ *
  * The ESAPI is published by OWASP under the BSD license. You should read and accept the
  * LICENSE before you use, modify, and/or redistribute this software.
- * 
+ *
  * @author Jeff Williams <a href="http://www.aspectsecurity.com">Aspect Security</a>
  * @author Arshan Dabirsiaghi <a href="http://www.aspectsecurity.com">Aspect Security</a>
  * @created 2009
@@ -29,37 +29,37 @@ import junit.framework.TestCase;
 
 public abstract class WAFTestCase extends TestCase {
 
-	protected MockHttpServletRequest request;
-	protected MockHttpServletResponse response;
-	protected URL url;
-	protected ESAPIWebApplicationFirewallFilter waf;
-	
-	protected static User user = null;
-	
-	public void setUp() throws Exception {
-	    // setup the user in session
-		
-		if ( user == null ) {
-			String accountName = ESAPI.randomizer().getRandomString(8, EncoderConstants.CHAR_ALPHANUMERICS);
-			Authenticator instance = ESAPI.authenticator();
-			String password = instance.generateStrongPassword();
-			instance.setCurrentUser(user);
-			user = instance.createUser(accountName, password, password);
-			user.enable();
-		}
-		
-		request = new MockHttpServletRequest( new URL( "http://www.example.com/index" ) );
+    protected MockHttpServletRequest request;
+    protected MockHttpServletResponse response;
+    protected URL url;
+    protected ESAPIWebApplicationFirewallFilter waf;
+
+    protected static User user = null;
+
+    public void setUp() throws Exception {
+        // setup the user in session
+
+        if ( user == null ) {
+            String accountName = ESAPI.randomizer().getRandomString(8, EncoderConstants.CHAR_ALPHANUMERICS);
+            Authenticator instance = ESAPI.authenticator();
+            String password = instance.generateStrongPassword();
+            instance.setCurrentUser(user);
+            user = instance.createUser(accountName, password, password);
+            user.enable();
+        }
+
+        request = new MockHttpServletRequest( new URL( "http://www.example.com/index" ) );
         response = new MockHttpServletResponse();
         waf = new ESAPIWebApplicationFirewallFilter();
-        
+
         WAFTestUtility.setWAFPolicy(waf, "/waf-policy.xml");
-	}
-    
-	public void createAndExecuteWAFResponseCodeTest( ESAPIWebApplicationFirewallFilter waf, MockHttpServletRequest request, MockHttpServletResponse response, int expectedResult ) throws Exception {
-    	assertEquals ( expectedResult, WAFTestUtility.createAndExecuteWAFTransaction( waf, request, response) );	
-	}
-    
+    }
+
+    public void createAndExecuteWAFResponseCodeTest( ESAPIWebApplicationFirewallFilter waf, MockHttpServletRequest request, MockHttpServletResponse response, int expectedResult ) throws Exception {
+        assertEquals ( expectedResult, WAFTestUtility.createAndExecuteWAFTransaction( waf, request, response) );
+    }
+
     public void createAndExecuteWAFResponseCodeTest( String policy, MockHttpServletRequest request, MockHttpServletResponse response, int expectedResult ) throws Exception {
-    	assertEquals ( expectedResult, WAFTestUtility.createAndExecuteWAFTransaction( policy, request, response) );	
-	}
+        assertEquals ( expectedResult, WAFTestUtility.createAndExecuteWAFTransaction( policy, request, response) );
+    }
 }
diff --git a/src/test/java/org/owasp/esapi/waf/WAFTestUtility.java b/src/test/java/org/owasp/esapi/waf/WAFTestUtility.java
index 205d0d5..b80bfa4 100644
--- a/src/test/java/org/owasp/esapi/waf/WAFTestUtility.java
+++ b/src/test/java/org/owasp/esapi/waf/WAFTestUtility.java
@@ -1,17 +1,17 @@
 /**
  * OWASP Enterprise Security API (ESAPI)
- * 
+ *
  * This file is part of the Open Web Application Security Project (OWASP)
  * Enterprise Security API (ESAPI) project. For details, please see
  * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
  *
  * Copyright (c) 2009 - The OWASP Foundation
- * 
+ *
  * The ESAPI is published by OWASP under the BSD license. You should read and accept the
  * LICENSE before you use, modify, and/or redistribute this software.
- * 
+ *
  * @author Arshan Dabirsiaghi <a href="http://www.aspectsecurity.com">Aspect Security</a>
- * 
+ *
  * @created 2009
  */
 package org.owasp.esapi.waf;
@@ -38,54 +38,66 @@ public class WAFTestUtility {
 
     public static void setWAFPolicy( ESAPIWebApplicationFirewallFilter waf, String policyFile ) throws Exception {
         Map map = new HashMap();
-    	map.put( "configuration", policyFile );
-    	map.put( "log_settings", "../log4j.xml");
-    	FilterConfig mfc = new MockWafFilterConfig( map );
-    	waf.init( mfc );
+        map.put( "configuration", policyFile );
+
+            // As of ESAPI 2.5.0.0 (when Log4J 1 dependency was removed), thsi
+            // init parameter is not ignored. However, it will produce a warning
+            // log message that looks something like this:
+            //
+            // [2022-07-11 00:25:45] [org.owasp.esapi.waf.ESAPIWebApplicationFirewallFilter] [EVENT FAILURE Anonymous:90471@unknown -> 10.1.43.6:80/ExampleApplication/org.owasp.esapi.waf.ESAPIWebApplicationFirewallFilter] >> Since ESAPI 2.5.0.0, ESAPI WAF ignoring parameter 'log_settings; for further details, see https://github.com/ESAPI/esapi-java-legacy/blob/develop/documentation/esapi4java-core-2.5.0.0-release-notes.txt
+            //
+            // Without getting really fancy and making this test way more
+            // complicated than I want though, I am not sure how to test for
+            // some specicif log output. It's been manually verified (once).
+            // Hopefully, that is good enough.      -kwwall
+            //
+        map.put( "log_settings", "parameter-now-ignored!!!");
+        FilterConfig mfc = new MockWafFilterConfig( map );
+        waf.init( mfc );
     }
-    
+
     public static int checkWAFResult( ESAPIWebApplicationFirewallFilter waf, MockHttpServletRequest request, MockHttpServletResponse response, MockFilterChain chain ) throws Exception {
 
         //request.dump();
-    	waf.doFilter(request, response, chain);
+        waf.doFilter(request, response, chain);
         //response.dump();
-        
+
         return response.getStatus();
-       
-    }  
+
+    }
 
     public static int createAndExecuteWAFTransaction ( ESAPIWebApplicationFirewallFilter waf, MockHttpServletRequest request, MockHttpServletResponse response ) throws Exception {
 
-		MockFilterChain chain = new MockFilterChain();
-		
-		return WAFTestUtility.checkWAFResult(waf, request, response, chain);
-		
-	}
+        MockFilterChain chain = new MockFilterChain();
+
+        return WAFTestUtility.checkWAFResult(waf, request, response, chain);
+
+    }
 
     public static int createAndExecuteWAFTransaction ( ESAPIWebApplicationFirewallFilter waf, MockHttpServletRequest request, MockHttpServletResponse response, MockFilterChain filterChain ) throws Exception {
 
 
-    	return WAFTestUtility.checkWAFResult(waf, request, response, filterChain);
-		
-	}
-    
+        return WAFTestUtility.checkWAFResult(waf, request, response, filterChain);
+
+    }
+
     public static int createAndExecuteWAFTransaction ( String policy, MockHttpServletRequest request, MockHttpServletResponse response ) throws Exception {
 
-    	ESAPIWebApplicationFirewallFilter waf = new ESAPIWebApplicationFirewallFilter();
-    	File f = ESAPI.securityConfiguration().getResourceFile(policy);
-    	waf.setConfiguration(f.getAbsolutePath(),"");
+        ESAPIWebApplicationFirewallFilter waf = new ESAPIWebApplicationFirewallFilter();
+        File f = ESAPI.securityConfiguration().getResourceFile(policy);
+        waf.setConfiguration(f.getAbsolutePath(),"");
+
+        return createAndExecuteWAFTransaction(waf, request, response );
+
+    }
 
-		return createAndExecuteWAFTransaction(waf, request, response );
-		
-	}
-    
     public static int createAndExecuteWAFTransaction ( String policy, MockHttpServletRequest request, MockHttpServletResponse response, MockFilterChain filterChain ) throws Exception {
 
-    	ESAPIWebApplicationFirewallFilter waf = new ESAPIWebApplicationFirewallFilter();
-    	File f = ESAPI.securityConfiguration().getResourceFile(policy);        
-    	waf.setConfiguration(f.getAbsolutePath(),"");
+        ESAPIWebApplicationFirewallFilter waf = new ESAPIWebApplicationFirewallFilter();
+        File f = ESAPI.securityConfiguration().getResourceFile(policy);
+        waf.setConfiguration(f.getAbsolutePath(),"");
 
-		return createAndExecuteWAFTransaction(waf, request, response, filterChain );
-		
-	}
+        return createAndExecuteWAFTransaction(waf, request, response, filterChain );
+
+    }
 }
diff --git a/src/test/java/org/owasp/esapi/waf/internal/InterceptingHttpServletRequestTest.java b/src/test/java/org/owasp/esapi/waf/internal/InterceptingHttpServletRequestTest.java
index c70e14a..06bd860 100644
--- a/src/test/java/org/owasp/esapi/waf/internal/InterceptingHttpServletRequestTest.java
+++ b/src/test/java/org/owasp/esapi/waf/internal/InterceptingHttpServletRequestTest.java
@@ -27,11 +27,11 @@ import org.owasp.esapi.http.MockHttpServletRequest;
 public class InterceptingHttpServletRequestTest extends TestCase {
 
     /**
-	 * Instantiates a new test.
-	 *
-	 * @param testName
-	 *            the test name
-	 */
+     * Instantiates a new test.
+     *
+     * @param testName
+     *            the test name
+     */
     public InterceptingHttpServletRequestTest(String testName) {
         super(testName);
     }
@@ -41,7 +41,7 @@ public class InterceptingHttpServletRequestTest extends TestCase {
      * @throws Exception
      */
     protected void setUp() throws Exception {
-    	// none
+        // none
     }
 
     /**
@@ -49,14 +49,14 @@ public class InterceptingHttpServletRequestTest extends TestCase {
      * @throws Exception
      */
     protected void tearDown() throws Exception {
-    	// none
+        // none
     }
 
     /**
-	 * Suite.
-	 *
-	 * @return the test
-	 */
+     * Suite.
+     *
+     * @return the test
+     */
     public static Test suite() {
         TestSuite suite = new TestSuite(InterceptingHttpServletRequestTest.class);
         return suite;
@@ -64,12 +64,12 @@ public class InterceptingHttpServletRequestTest extends TestCase {
 
 
     /**
-	 * Test.
+     * Test.
      */
     public void testRequest() throws Exception {
         System.out.println("InterceptingHTTPServletRequest");
-   	    MockHttpServletRequest mreq = new MockHttpServletRequest();
-   	    mreq.setMethod( "GET" );
+           MockHttpServletRequest mreq = new MockHttpServletRequest();
+           mreq.setMethod( "GET" );
         InterceptingHTTPServletRequest ireq = new InterceptingHTTPServletRequest(mreq);
         assertEquals( mreq.getMethod(), ireq.getMethod() );
     }
diff --git a/src/test/java/org/owasp/esapi/waf/internal/InterceptingHttpServletResponseTest.java b/src/test/java/org/owasp/esapi/waf/internal/InterceptingHttpServletResponseTest.java
index 6dd6e49..bee1c8f 100644
--- a/src/test/java/org/owasp/esapi/waf/internal/InterceptingHttpServletResponseTest.java
+++ b/src/test/java/org/owasp/esapi/waf/internal/InterceptingHttpServletResponseTest.java
@@ -1,15 +1,15 @@
 /**
  * OWASP Enterprise Security API (ESAPI)
- * 
+ *
  * This file is part of the Open Web Application Security Project (OWASP)
  * Enterprise Security API (ESAPI) project. For details, please see
  * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
  *
  * Copyright (c) 2007 - The OWASP Foundation
- * 
+ *
  * The ESAPI is published by OWASP under the BSD license. You should read and accept the
  * LICENSE before you use, modify, and/or redistribute this software.
- * 
+ *
  * @author Jeff Williams <a href="http://www.aspectsecurity.com">Aspect Security</a>
  * @created 2007
  */
@@ -27,13 +27,13 @@ import org.owasp.esapi.http.MockHttpServletResponse;
  * @author Jeff Williams (jeff.williams@aspectsecurity.com)
  */
 public class InterceptingHttpServletResponseTest extends TestCase {
-    
+
     /**
-	 * Instantiates a new test.
-	 * 
-	 * @param testName
-	 *            the test name
-	 */
+     * Instantiates a new test.
+     *
+     * @param testName
+     *            the test name
+     */
     public InterceptingHttpServletResponseTest(String testName) {
         super(testName);
     }
@@ -43,7 +43,7 @@ public class InterceptingHttpServletResponseTest extends TestCase {
      * @throws Exception
      */
     protected void setUp() throws Exception {
-    	// none
+        // none
     }
 
     /**
@@ -51,26 +51,26 @@ public class InterceptingHttpServletResponseTest extends TestCase {
      * @throws Exception
      */
     protected void tearDown() throws Exception {
-    	// none
+        // none
     }
 
     /**
-	 * Suite.
-	 * 
-	 * @return the test
-	 */
+     * Suite.
+     *
+     * @return the test
+     */
     public static Test suite() {
         TestSuite suite = new TestSuite(InterceptingHttpServletResponseTest.class);
         return suite;
     }
 
-    
+
     /**
-	 * Test.
+     * Test.
      */
     public void testRequest() throws Exception {
         System.out.println("InterceptingHTTPServletResponse");
-   	    MockHttpServletResponse mres = new MockHttpServletResponse();
+           MockHttpServletResponse mres = new MockHttpServletResponse();
         InterceptingHTTPServletResponse ires = new InterceptingHTTPServletResponse(mres, false, new ArrayList() );
         // isos.println( "Hello" );
         // ires.getOutputStream().println( "Hello" );
diff --git a/src/test/resources/esapi/ESAPI-CommaValidatorFileChecker.properties b/src/test/resources/esapi/ESAPI-CommaValidatorFileChecker.properties
index 5f10329..9e6d676 100644
--- a/src/test/resources/esapi/ESAPI-CommaValidatorFileChecker.properties
+++ b/src/test/resources/esapi/ESAPI-CommaValidatorFileChecker.properties
@@ -104,10 +104,7 @@ ESAPI.Encryptor=org.owasp.esapi.reference.crypto.JavaEncryptor
 ESAPI.Executor=org.owasp.esapi.reference.DefaultExecutor
 ESAPI.HTTPUtilities=org.owasp.esapi.reference.DefaultHTTPUtilities
 ESAPI.IntrusionDetector=org.owasp.esapi.reference.DefaultIntrusionDetector
-# Log4JFactory Requires log4j.xml or log4j.properties in classpath - http://www.laliluna.de/log4j-tutorial.html
-ESAPI.Logger=org.owasp.esapi.logging.log4j.Log4JLogFactory
-#ESAPI.Logger=org.owasp.esapi.reference.JavaLogFactory
-#ESAPI.Logger=org.owasp.esapi.reference.ExampleExtendedLog4JLogFactory
+ESAPI.Logger=org.owasp.esapi.logging.java.JavaLogFactory
 ESAPI.Randomizer=org.owasp.esapi.reference.DefaultRandomizer
 ESAPI.Validator=org.owasp.esapi.reference.DefaultValidator
 
diff --git a/src/test/resources/esapi/ESAPI-DualValidatorFileChecker.properties b/src/test/resources/esapi/ESAPI-DualValidatorFileChecker.properties
index 74e645a..6250716 100644
--- a/src/test/resources/esapi/ESAPI-DualValidatorFileChecker.properties
+++ b/src/test/resources/esapi/ESAPI-DualValidatorFileChecker.properties
@@ -104,10 +104,7 @@ ESAPI.Encryptor=org.owasp.esapi.reference.crypto.JavaEncryptor
 ESAPI.Executor=org.owasp.esapi.reference.DefaultExecutor
 ESAPI.HTTPUtilities=org.owasp.esapi.reference.DefaultHTTPUtilities
 ESAPI.IntrusionDetector=org.owasp.esapi.reference.DefaultIntrusionDetector
-# Log4JFactory Requires log4j.xml or log4j.properties in classpath - http://www.laliluna.de/log4j-tutorial.html
-ESAPI.Logger=org.owasp.esapi.logging.log4j.Log4JLogFactory
-#ESAPI.Logger=org.owasp.esapi.reference.JavaLogFactory
-#ESAPI.Logger=org.owasp.esapi.reference.ExampleExtendedLog4JLogFactory
+ESAPI.Logger=org.owasp.esapi.logging.java.JavaLogFactory
 ESAPI.Randomizer=org.owasp.esapi.reference.DefaultRandomizer
 ESAPI.Validator=org.owasp.esapi.reference.DefaultValidator
 
diff --git a/src/test/resources/esapi/ESAPI-QuotedValidatorFileChecker.properties b/src/test/resources/esapi/ESAPI-QuotedValidatorFileChecker.properties
index 4b0a8a3..46784ce 100644
--- a/src/test/resources/esapi/ESAPI-QuotedValidatorFileChecker.properties
+++ b/src/test/resources/esapi/ESAPI-QuotedValidatorFileChecker.properties
@@ -103,10 +103,7 @@ ESAPI.Encryptor=org.owasp.esapi.reference.crypto.JavaEncryptor
 ESAPI.Executor=org.owasp.esapi.reference.DefaultExecutor
 ESAPI.HTTPUtilities=org.owasp.esapi.reference.DefaultHTTPUtilities
 ESAPI.IntrusionDetector=org.owasp.esapi.reference.DefaultIntrusionDetector
-# Log4JFactory Requires log4j.xml or log4j.properties in classpath - http://www.laliluna.de/log4j-tutorial.html
-ESAPI.Logger=org.owasp.esapi.logging.log4j.Log4JLogFactory
-#ESAPI.Logger=org.owasp.esapi.reference.JavaLogFactory
-#ESAPI.Logger=org.owasp.esapi.reference.ExampleExtendedLog4JLogFactory
+ESAPI.Logger=org.owasp.esapi.logging.java.JavaLogFactory
 ESAPI.Randomizer=org.owasp.esapi.reference.DefaultRandomizer
 ESAPI.Validator=org.owasp.esapi.reference.DefaultValidator
 
diff --git a/src/test/resources/esapi/ESAPI-SingleValidatorFileChecker.properties b/src/test/resources/esapi/ESAPI-SingleValidatorFileChecker.properties
index 462d047..f3742ce 100644
--- a/src/test/resources/esapi/ESAPI-SingleValidatorFileChecker.properties
+++ b/src/test/resources/esapi/ESAPI-SingleValidatorFileChecker.properties
@@ -103,10 +103,7 @@ ESAPI.Encryptor=org.owasp.esapi.reference.crypto.JavaEncryptor
 ESAPI.Executor=org.owasp.esapi.reference.DefaultExecutor
 ESAPI.HTTPUtilities=org.owasp.esapi.reference.DefaultHTTPUtilities
 ESAPI.IntrusionDetector=org.owasp.esapi.reference.DefaultIntrusionDetector
-# Log4JFactory Requires log4j.xml or log4j.properties in classpath - http://www.laliluna.de/log4j-tutorial.html
-ESAPI.Logger=org.owasp.esapi.logging.log4j.Log4JLogFactory
-#ESAPI.Logger=org.owasp.esapi.reference.JavaLogFactory
-#ESAPI.Logger=org.owasp.esapi.reference.ExampleExtendedLog4JLogFactory
+ESAPI.Logger=org.owasp.esapi.logging.java.JavaLogFactory
 ESAPI.Randomizer=org.owasp.esapi.reference.DefaultRandomizer
 ESAPI.Validator=org.owasp.esapi.reference.DefaultValidator
 
diff --git a/src/test/resources/esapi/ESAPI.properties b/src/test/resources/esapi/ESAPI.properties
index 29bc7b3..d9e12ce 100644
--- a/src/test/resources/esapi/ESAPI.properties
+++ b/src/test/resources/esapi/ESAPI.properties
@@ -96,9 +96,6 @@ ESAPI.Encryptor=org.owasp.esapi.reference.crypto.JavaEncryptor
 ESAPI.Executor=org.owasp.esapi.reference.DefaultExecutor
 ESAPI.HTTPUtilities=org.owasp.esapi.reference.DefaultHTTPUtilities
 ESAPI.IntrusionDetector=org.owasp.esapi.reference.DefaultIntrusionDetector
-# Log4JFactory Requires log4j.xml or log4j.properties in classpath - http://www.laliluna.de/log4j-tutorial.html
-# Note that this is now considered deprecated!
-#ESAPI.Logger=org.owasp.esapi.logging.log4j.Log4JLogFactory
 ESAPI.Logger=org.owasp.esapi.logging.java.JavaLogFactory
 # To use the new SLF4J logger in ESAPI (see GitHub issue #129), set
 #    ESAPI.Logger=org.owasp.esapi.logging.slf4j.Slf4JLogFactory
diff --git a/src/test/resources/log4j.dtd b/src/test/resources/log4j.dtd
deleted file mode 100644
index 1aabd96..0000000
--- a/src/test/resources/log4j.dtd
+++ /dev/null
@@ -1,227 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<!--
- Licensed to the Apache Software Foundation (ASF) under one or more
- contributor license agreements.  See the NOTICE file distributed with
- this work for additional information regarding copyright ownership.
- The ASF licenses this file to You under the Apache License, Version 2.0
- (the "License"); you may not use this file except in compliance with
- the License.  You may obtain a copy of the License at
-
-      http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-
-<!-- Authors: Chris Taylor, Ceki Gulcu. -->
-
-<!-- Version: 1.2 -->
-
-<!-- A configuration element consists of optional renderer
-elements,appender elements, categories and an optional root
-element. -->
-
-<!ELEMENT log4j:configuration (renderer*, appender*,plugin*, (category|logger)*,root?,
-                               (categoryFactory|loggerFactory)?)>
-
-<!-- The "threshold" attribute takes a level value below which -->
-<!-- all logging statements are disabled. -->
-
-<!-- Setting the "debug" enable the printing of internal log4j logging   -->
-<!-- statements.                                                         -->
-
-<!-- By default, debug attribute is "null", meaning that we not do touch -->
-<!-- internal log4j logging settings. The "null" value for the threshold -->
-<!-- attribute can be misleading. The threshold field of a repository	 -->
-<!-- cannot be set to null. The "null" value for the threshold attribute -->
-<!-- simply means don't touch the threshold field, the threshold field   --> 
-<!-- keeps its old value.                                                -->
-     
-<!ATTLIST log4j:configuration
-  xmlns:log4j              CDATA #FIXED "http://jakarta.apache.org/log4j/" 
-  threshold                (all|trace|debug|info|warn|error|fatal|off|null) "null"
-  debug                    (true|false|null)  "null"
-  reset                    (true|false) "false"
->
-
-<!-- renderer elements allow the user to customize the conversion of  -->
-<!-- message objects to String.                                       -->
-
-<!ELEMENT renderer EMPTY>
-<!ATTLIST renderer
-  renderedClass  CDATA #REQUIRED
-  renderingClass CDATA #REQUIRED
->
-
-<!-- Appenders must have a name and a class. -->
-<!-- Appenders may contain an error handler, a layout, optional parameters -->
-<!-- and filters. They may also reference (or include) other appenders. -->
-<!ELEMENT appender (errorHandler?, param*,
-      rollingPolicy?, triggeringPolicy?, connectionSource?,
-      layout?, filter*, appender-ref*)>
-<!ATTLIST appender
-  name 		CDATA 	#REQUIRED
-  class 	CDATA	#REQUIRED
->
-
-<!ELEMENT layout (param*)>
-<!ATTLIST layout
-  class		CDATA	#REQUIRED
->
-
-<!ELEMENT filter (param*)>
-<!ATTLIST filter
-  class		CDATA	#REQUIRED
->
-
-<!-- ErrorHandlers can be of any class. They can admit any number of -->
-<!-- parameters. -->
-
-<!ELEMENT errorHandler (param*, root-ref?, logger-ref*,  appender-ref?)> 
-<!ATTLIST errorHandler
-   class        CDATA   #REQUIRED 
->
-
-<!ELEMENT root-ref EMPTY>
-
-<!ELEMENT logger-ref EMPTY>
-<!ATTLIST logger-ref
-  ref CDATA #REQUIRED
->
-
-<!ELEMENT param EMPTY>
-<!ATTLIST param
-  name		CDATA   #REQUIRED
-  value		CDATA	#REQUIRED
->
-
-
-<!-- The priority class is org.apache.log4j.Level by default -->
-<!ELEMENT priority (param*)>
-<!ATTLIST priority
-  class   CDATA	#IMPLIED
-  value	  CDATA #REQUIRED
->
-
-<!-- The level class is org.apache.log4j.Level by default -->
-<!ELEMENT level (param*)>
-<!ATTLIST level
-  class   CDATA	#IMPLIED
-  value	  CDATA #REQUIRED
->
-
-
-<!-- If no level element is specified, then the configurator MUST not -->
-<!-- touch the level of the named category. -->
-<!ELEMENT category (param*,(priority|level)?,appender-ref*)>
-<!ATTLIST category
-  class         CDATA   #IMPLIED
-  name		CDATA	#REQUIRED
-  additivity	(true|false) "true"  
->
-
-<!-- If no level element is specified, then the configurator MUST not -->
-<!-- touch the level of the named logger. -->
-<!ELEMENT logger (level?,appender-ref*)>
-<!ATTLIST logger
-  name		CDATA	#REQUIRED
-  additivity	(true|false) "true"  
->
-
-
-<!ELEMENT categoryFactory (param*)>
-<!ATTLIST categoryFactory 
-   class        CDATA #REQUIRED>
-
-<!ELEMENT loggerFactory (param*)>
-<!ATTLIST loggerFactory
-   class        CDATA #REQUIRED>
-
-<!ELEMENT appender-ref EMPTY>
-<!ATTLIST appender-ref
-  ref CDATA #REQUIRED
->
-
-<!-- plugins must have a name and class and can have optional parameters -->
-<!ELEMENT plugin (param*, connectionSource?)>
-<!ATTLIST plugin
-  name 		CDATA 	   #REQUIRED
-  class 	CDATA  #REQUIRED
->
-
-<!ELEMENT connectionSource (dataSource?, param*)>
-<!ATTLIST connectionSource
-  class        CDATA  #REQUIRED
->
-
-<!ELEMENT dataSource (param*)>
-<!ATTLIST dataSource
-  class        CDATA  #REQUIRED
->
-
-<!ELEMENT triggeringPolicy ((param|filter)*)>
-<!ATTLIST triggeringPolicy
-  name 		CDATA  #IMPLIED
-  class 	CDATA  #REQUIRED
->
-
-<!ELEMENT rollingPolicy (param*)>
-<!ATTLIST rollingPolicy
-  name 		CDATA  #IMPLIED
-  class 	CDATA  #REQUIRED
->
-
-
-<!-- If no priority element is specified, then the configurator MUST not -->
-<!-- touch the priority of root. -->
-<!-- The root category always exists and cannot be subclassed. -->
-<!ELEMENT root (param*, (priority|level)?, appender-ref*)>
-
-
-<!-- ==================================================================== -->
-<!--                       A logging event                                -->
-<!-- ==================================================================== -->
-<!ELEMENT log4j:eventSet (log4j:event*)>
-<!ATTLIST log4j:eventSet
-  xmlns:log4j             CDATA #FIXED "http://jakarta.apache.org/log4j/" 
-  version                (1.1|1.2) "1.2" 
-  includesLocationInfo   (true|false) "true"
->
-
-
-
-<!ELEMENT log4j:event (log4j:message, log4j:NDC?, log4j:throwable?, 
-                       log4j:locationInfo?, log4j:properties?) >
-
-<!-- The timestamp format is application dependent. -->
-<!ATTLIST log4j:event
-    logger     CDATA #REQUIRED
-    level      CDATA #REQUIRED
-    thread     CDATA #REQUIRED
-    timestamp  CDATA #REQUIRED
-    time       CDATA #IMPLIED
->
-
-<!ELEMENT log4j:message (#PCDATA)>
-<!ELEMENT log4j:NDC (#PCDATA)>
-
-<!ELEMENT log4j:throwable (#PCDATA)>
-
-<!ELEMENT log4j:locationInfo EMPTY>
-<!ATTLIST log4j:locationInfo
-  class  CDATA	#REQUIRED
-  method CDATA	#REQUIRED
-  file   CDATA	#REQUIRED
-  line   CDATA	#REQUIRED
->
-
-<!ELEMENT log4j:properties (log4j:data*)>
-
-<!ELEMENT log4j:data EMPTY>
-<!ATTLIST log4j:data
-  name   CDATA	#REQUIRED
-  value  CDATA	#REQUIRED
->
diff --git a/src/test/resources/log4j.xml b/src/test/resources/log4j.xml
deleted file mode 100644
index 9b06c2a..0000000
--- a/src/test/resources/log4j.xml
+++ /dev/null
@@ -1,70 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
-<!--
-        #     #    #    ######  #     #   ###   #     #  #####
-        #  #  #   # #   #     # ##    #    #    ##    # #     #
-        #  #  #  #   #  #     # # #   #    #    # #   # #
-        #  #  # #     # ######  #  #  #    #    #  #  # #  ####
-        #  #  # ####### #   #   #   # #    #    #   # # #     #
-        #  #  # #     # #    #  #    ##    #    #    ## #     #
-         ## ##  #     # #     # #     #   ###   #     #  #####
-
-        WARNING:    Log4j 1.x has been deprecated in ESAPI since 2020-07-23 in
-                    release 2.2.1.0.  It will be removed in a future release.
-                    The new default for ESAPI logging is JUL.  Either switch
-                    to JUL or SLF4J (which can support log4j 2). See the latest
-                    release notes for further details.
-  -->
-<!-- main resources -->
-<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">
-
-  <appender name="console" class="org.apache.log4j.ConsoleAppender"> 
-    <param name="Target" value="System.out"/> 
-    <layout class="org.apache.log4j.PatternLayout"> 
-      <param name="ConversionPattern" value="%-5p %m%n"/> 
-    </layout> 
-  </appender>
-
-    <appender name="file" class="org.apache.log4j.FileAppender">
-        <param name="File" value="target/unit-tests.log"/>
-        <layout class="org.apache.log4j.PatternLayout">
-          <param name="ConversionPattern" value="%-5p %m%n"/>
-        </layout>
-    </appender>
-
-  <logger name="org.owasp.esapi.reference.TestTrace">
-    <level value="trace"/>
-  </logger>
-
-  <logger name="org.owasp.esapi.reference.TestDebug">
-    <level value="debug"/>
-  </logger>
-
-  <logger name="org.owasp.esapi.reference.TestInfo">
-    <level value="info"/>
- </logger>
-
-  <logger name="org.owasp.esapi.reference.TestWarning">
-    <level value="warn"/>
-  </logger>
-
-  <logger name="org.owasp.esapi.reference.TestError">
-    <level value="error"/>
-  </logger>
-
-  <logger name="org.owasp.esapi.reference.TestFatal">
-    <level value="fatal"/>
-  </logger>
-
-  <logger name="org.owasp.esapi.reference">
-    <level value="info"/>
-  </logger>
-
-  <root>
-    <priority value="debug" />
-    <appender-ref ref="file" />
-  </root>
-
-  <loggerFactory class="org.owasp.esapi.logging.log4j.Log4JLoggerFactory"/>
-
-</log4j:configuration>
diff --git a/suppressions.xml b/suppressions.xml
index a51a816..876c4fa 100644
--- a/suppressions.xml
+++ b/suppressions.xml
@@ -1,122 +1,49 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <!-- OWASP Dependency Check suppression file for ESAPI. -->
 <suppressions xmlns="https://jeremylong.github.io/DependencyCheck/dependency-suppression.1.3.xsd">
-    <suppress>
-        <notes><![CDATA[
-            This suppresses CVE-2019-17571 for the log4j-1.2.17.jar dependency. ESAPI does
-            not use it in a manner that makes it exploitable and ESAPI is unable to
-            eliminate the dependency completely because our our deprecation policy. That specific
-            CVE is the Java deserialization CVE reported in Log4J 1's SocketServer class which ESAPI
-            doesn't use.
 
-            For further details, please see:
-                https://nvd.nist.gov/vuln/detail/CVE-2019-17571,
-                ESAPI GitHub Issue #538 (https://github.com/ESAPI/esapi-java-legacy/issues/538),
-                and the ESAPI security advisory #2, "documentation/ESAPI-security-bulletin2.pdf", which
-                provides a detailed analysis of this issue in ESAPI.
-        ]]></notes>
-        <gav regex="true">^log4j:log4j:1\.2\.17$</gav>
-        <cpe>cpe:/a:apache:log4j</cpe>
-        <cve>CVE-2019-17571</cve>
-    </suppress>
+        <!-- NOTE: These 4 suppression rules are redundant. Will decide later which one to keep. -->
     <suppress>
         <notes><![CDATA[
-            This suppresses CVE-2020-9488 for the log4j-1.2.17.jar dependency. ESAPI does
-            not use it in a manner that makes it exploitable and ESAPI is unable to
-            eliminate the dependency completely because our our deprecation policy. That specific
-            CVE is the Java deserialization CVE reported in Log4J 1's SocketServer class which ESAPI
-            doesn't use.
-
-            For further details, please see:
-                https://nvd.nist.gov/vuln/detail/CVE-2020-9488,
-                ESAPI GitHub Issue #534 (https://github.com/ESAPI/esapi-java-legacy/issues/534),
-                and the ESAPI security advisory #4, "documentation/ESAPI-security-bulletin4.pdf", which
-                provides a detailed analysis of this issue in ESAPI.
-        ]]></notes>
-        <gav regex="true">^log4j:log4j:1\.2\.17$</gav>
-        <cpe>cpe:/a:apache:log4j</cpe>
-        <cve>CVE-2020-9488</cve>
+            CVE-2017-10355 in library xercesImpl-2.12.2.jar, which is a transitive dependency, pulled in via AntiSamy.
+            It is a Denial of Service vulnerability with a CVSSv3 score of 5.9.
+
+            We are suppressing this because it is believed by the ESAPI and AntiSamy teams that it is a false positive.
+            Dependency Check itself doesn't flag this and neither does Snyk. Dependency Check reports it because it is reported
+            directly by Sonatype's OSS Index. For futher details, see
+            https://ossindex.sonatype.org/vulnerability/sonatype-2017-0348?component-type=maven&component-name=xerces%2FxercesImpl
+
+            OSS Index seems to have the wrong CPE. They have 'cpe:2.3:a:xerces:xercesImpl:2.12.2:*:*:*:*:*:*:*', whereas the CPE IDs
+            associated with NVD are 'cpe:2.3:a:apache:xerces-j:2.12.2:*:*:*:*:*:*:*' and
+            'cpe:2.3:a:apache:xerces2_java:2.12.2:*:*:*:*:*:*:*'.
+
+            Note also that this has been reported as GitHub issue #a 4614
+            https://github.com/jeremylong/DependencyCheck/issues/4614
+            ]]></notes>
+        <sha1>f051f988aa2c9b4d25d05f95742ab0cc3ed789e2</sha1>
+       <cpe>cpe:/a:apache:xerces-j</cpe>
     </suppress>
     <suppress>
+       <notes><![CDATA[
+            CVE-2017-10355 in xercesImpl. See above for details.
+       ]]></notes>
+       <sha1>f051f988aa2c9b4d25d05f95742ab0cc3ed789e2</sha1>
+       <cpe>cpe:/a:apache:xerces2_java</cpe>
+   </suppress>
+   <suppress>
         <notes><![CDATA[
-            This suppresses CVE-2021-4104 for the log4j-1.2.17.jar dependency. ESAPI's
-            default configuration uses ConsoleAppender rather than JMSAppender and
-            thus does not use Log4J 1 in a manner that makes it exploitable. ESAPI is unable to
-            eliminate the dependency completely because our our deprecation policy.
+            CVE-2017-10355 in xercesImpl. See above for details.
 
-            For further details, please see:
-                https://nvd.nist.gov/vuln/detail/CVE-2021-4104 and
-                the ESAPI security advisory #6, "documentation/ESAPI-security-bulletin6.pdf", which
-                provides a detailed analysis of this issue in ESAPI.
+            This is the one that matches the OSS Index
         ]]></notes>
-        <gav regex="true">^log4j:log4j:1\.2\.17$</gav>
-        <cpe>cpe:/a:apache:log4j</cpe>
-        <cve>CVE-2021-4104</cve>
+        <packageUrl regex="true">^pkg:maven/xerces/xercesImpl@.*$</packageUrl>
+        <vulnerabilityName>CVE-2017-10355</vulnerabilityName> 
     </suppress>
     <suppress>
         <notes><![CDATA[
-            This suppresses CVE-2022-23305 for the log4j-1.2.17.jar dependency. ESAPI's
-            default configuration uses ConsoleAppender rather than JDBCAppender and
-            thus does not use Log4J 1 in a manner that makes it exploitable. ESAPI is unable to
-            eliminate the dependency completely because our our deprecation policy.
-
-            For further details, please see:
-                https://nvd.nist.gov/vuln/detail/CVE-2022-23305 and
-                the ESAPI security advisory #7, "documentation/ESAPI-security-bulletin7.pdf", which
-                provides a detailed analysis of this issue in ESAPI.
+            FP per Dependency Check GitHub issue #4614
         ]]></notes>
-        <gav regex="true">^log4j:log4j:1\.2\.17$</gav>
-        <cpe>cpe:/a:apache:log4j</cpe>
-        <cve>CVE-2022-23305</cve>
+        <cve>CVE-2017-10355</cve>
     </suppress>
-<!--
-java-8 Integration - content required for successful owasp dependency-check execution
-MISSING Security Bulletin content!
 
-    <suppress>
-        <notes><![CDATA[
-            This suppresses CVE-2022-23307 for the log4j-1.2.17.jar dependency. ESAPI's
-            default configuration uses ConsoleAppender rather than Chainsaw and
-            thus does not use Log4J 1 in a manner that makes it exploitable. ESAPI is unable to
-            eliminate the dependency completely because our our deprecation policy.
-
-            For further details, please see:
-                https://nvd.nist.gov/vuln/detail/CVE-2022-23307 and
-
--> NEEDS BULLETIN REFERENCE
-
-        ]]></notes>
-        <gav regex="true">^log4j:log4j:1\.2\.17$</gav>
-        <cpe>cpe:/a:apache:log4j</cpe>
-        <cve>CVE-2022-23307</cve>
-    </suppress>
-    <suppress>
-        <notes><![CDATA[
-            This suppresses CVE-2022-23302 for the log4j-1.2.17.jar dependency. ESAPI's
-            default configuration uses ConsoleAppender rather than JMSAppender and
-            thus does not use Log4J 1 in a manner that makes it exploitable. ESAPI is unable to
-            eliminate the dependency completely because our our deprecation policy.
-            By virtue of not using a JMSAppender, the exploitable nature of the JMSSink implementation
-            referenced by this CVE is also mitigated.
-
-            For further details, please see:
-                https://nvd.nist.gov/vuln/detail/CVE-2022-23302
--> NEEDS BULLETIN REFERENCE
-
-        ]]></notes>
-        <gav regex="true">^log4j:log4j:1\.2\.17$</gav>
-        <cpe>cpe:/a:apache:log4j</cpe>
-        <cve>CVE-2022-23302</cve>
-    </suppress>
--->
-    <suppress>
-        <notes><![CDATA[
-            ESAPI does not use this jar directly. It is a transitive dependency of AntiSamy and (as per Dave Wichers on
-            the AntiSamy team), it does not impact AntiSamy, and therefore does not impact ESAPI.
-
-             file name: batik-i18n-1.14.jar
-        ]]></notes>
-        <packageUrl regex="true">^pkg:maven/org\.apache\.xmlgraphics/batik\-i18n@.*$</packageUrl>
-        <cve>CVE-2020-7791</cve>
-    </suppress>
 </suppressions>

Debdiff

[The following lists of changes regard files as different if they have different names, permissions or owners.]

Files in second set of .debs but not in first

-rw-r--r--  root/root   /usr/share/maven-repo/org/owasp/esapi/esapi/2.5.2.0-SNAPSHOT/esapi-2.5.2.0-SNAPSHOT.pom
lrwxrwxrwx  root/root   /usr/share/java/esapi-2.5.2.0-SNAPSHOT.jar -> esapi.jar
lrwxrwxrwx  root/root   /usr/share/maven-repo/org/owasp/esapi/esapi/2.5.2.0-SNAPSHOT/esapi-2.5.2.0-SNAPSHOT.jar -> ../../../../../../java/esapi.jar

Files in first set of .debs but not in second

-rw-r--r--  root/root   /usr/share/maven-repo/org/owasp/esapi/esapi/2.4.0.0-SNAPSHOT/esapi-2.4.0.0-SNAPSHOT.pom
lrwxrwxrwx  root/root   /usr/share/java/esapi-2.4.0.0-SNAPSHOT.jar -> esapi.jar
lrwxrwxrwx  root/root   /usr/share/maven-repo/org/owasp/esapi/esapi/2.4.0.0-SNAPSHOT/esapi-2.4.0.0-SNAPSHOT.jar -> ../../../../../../java/esapi.jar

Control files: lines which differ (wdiff format)

  • Depends: libbsh-java (>= 2.0b4), libcommons-beanutils-java (>= 1.9.4), libcommons-collections4-java (>= 4.2), libcommons-configuration-java, libcommons-fileupload-java, libcommons-io-java (>= 2.11.0), libcommons-lang-java (>= 2.6), libjaxp1.3-java, liblog4j1.2-java (>= 1.2.17), libowasp-antisamy-java (>= 1.5.3), libslf4j-java (>= 1.7.32), libxom-java

More details

Full run details