Details
Description
From the Jakarta ORO Javadocs (http://jakarta.apache.org/oro/api/org/apache/oro/text/regex/Perl5Matcher.html):
"Perl5Compiler and Perl5Matcher are designed with the intent that you use a separate instance of each per thread to avoid the overhead of both synchronization and concurrent access (e.g., a match that takes a long time in one thread will block the progress of another thread with a shorter match). If you want to use a single instance of each in a concurrent program, you must appropriately protect access to the instances with critical sections. If you want to share Perl5Pattern instances between concurrently executing instances of Perl5Matcher, you must compile the patterns with Perl5Compiler.READ_ONLY_MASK."
Tapestry 4.0 violates this in two ways:
1) The class org.apache.tapestry.form.validator.ValidatorFactoryImpl is a singleton, and uses a single org.apache.tapestry.util.RegexpMatcher for matching "validators" binding strings. This in turn uses a single Perl5Matcher. If multiple pages/components that use a "validators" binding are instantiated simultaneously, a race condition exception can occur.
2) A singleton RegexpMatcher is potentially using the same cached compiled pattern on multiple threads simultaneously, yet they are not compiled with Perl5Compiler.READ_ONLY_MASK.
My project has run into #1 by running a load test (using Grinder) rendering a single page over and over that contains a component with a "validators" binding. Frequently, StringIndexOutOfBoundsException would be thrown from inside the Perl5Matcher stack. I was able to stop this by putting a synchronized block around the call to _matcher.getMatches in ValidatorFactoryImpl.constructValidatorList, but this is not likely the best solution, and requires a patch as it doesn't seem straightforward to override ValidatorFactoryImpl in the hivemodule files.