This is a sample class using Rhino (1.7R4). I need it because in the context of JSON Schema, regexes should be ECMA 262. One requirement is that it is thread safe, and it is.
But I'm not sure I actually use it correctly. Can you comment?
public final class RhinoHelper
{
/**
* JavaScript scriptlet defining functions {@link #regexIsValid}
* and {@link #regMatch}
*/
private static final String jsAsString
= "function regexIsValid(re)"
+ '{'
+ " try {"
+ " new RegExp(re);"
+ " return true;"
+ " } catch (e) {"
+ " return false;"
+ " }"
+ '}'
+ ""
+ "function regMatch(re, input)"
+ '{'
+ " return new RegExp(re).test(input);"
+ '}';
/**
* Script context to use
*/
private static final Context ctx;
/**
* Script scope
*/
private static final Scriptable sharedScope;
/**
* Reference to Javascript function for regex validation
*/
private static final Function regexIsValid;
/**
* Reference to Javascript function for regex matching
*/
private static final Function regMatch;
private RhinoHelper()
{
}
static {
ctx = Context.enter();
sharedScope = ctx.initStandardObjects();
ctx.evaluateString(sharedScope, jsAsString, "re", 1, null);
regexIsValid = (Function) sharedScope.get("regexIsValid", sharedScope);
regMatch = (Function) sharedScope.get("regMatch", sharedScope);
ctx.seal(null);
}
/**
* Validate that a regex is correct
*
* @param regex the regex to validate
* @return true if the regex is valid
*/
public static boolean regexIsValid(final String regex)
{
final Context context = Context.enter();
try {
final Scriptable scope = context.newObject(sharedScope);
scope.setPrototype(sharedScope);
scope.setParentScope(null);
return (Boolean) regexIsValid.call(context, scope, scope,
new Object[]{ regex });
} finally {
Context.exit();
}
}
/**
* <p>Matches an input against a given regex, in the <b>real</b> sense
* of matching, that is, the regex can match anywhere in the input. Java's
* {@link java.util.regex} makes the unfortunate mistake to make people
* believe that matching is done on the whole input... Which is not true.
* </p>
*
* <p>Also note that the regex MUST have been validated at this point
* (using {@link #regexIsValid(String)}).</p>
*
* @param regex the regex to use
* @param input the input to match against (and again, see description)
* @return true if the regex matches the input
*/
public static boolean regMatch(final String regex, final String input)
{
final Context context = Context.enter();
try {
final Scriptable scope = context.newObject(sharedScope);
scope.setPrototype(sharedScope);
scope.setParentScope(null);
return (Boolean) regMatch.call(context, scope, scope,
new Object[]{ regex, input });
} finally {
Context.exit();
}
}
}