On Nov 10, 2009, at 10:15 AM, Casper Bang wrote:
> Hey Jersey list,
>
> Currently, resource mapping for Jersey revolves around regular
> expressions. This is simple and powerful of course, however it makes
> it
> hard to assist the user in regard to correct syntax usage. I require
> complex expressions, inspired by the Google Charts API, to fetch and
> chart meter data in a flexible fashion. To do this, I model a form of
> AST by combining regular expressions as tokens, along the line of this
> (simplified):
>
> public final static String registration_type_expression =
> "(" + registration_type + "|" + registration_type_list +
> ")";
>
> public final static String meter_list =
> "\\(" + METER +
> "("+
> COMMA +
> METER +
> "){0,4}" +
> "\\)";
>
> public final static String meter_registration =
> "(" + METER + "|" + meter_list + ")" +
> "(" +
> ":" +
> registration_type_expression +
> ")?";
>
> public final static String meterRegistrationsExpression =
> meter_registration +
> "("+
> COMMA +
> meter_registration +
> "){0,4}";
>
>
> Now, in the WADL this becomes relatively useless but it does serve to
> validate the expression:
>
> <resource path="meters/{meterRegistrationsExpression:
> (\d{1,10}|\(\d{1,10}(,\d{1,10}){0,4}\))(:(([mM][eE][tT][eE][rR][vV]
> [aA][lL][uU][eE]|[tT][eE][mM][pP]/
> [eE][rR][aA][tT][uU][rR][eE][cC][uU][rR][rR][eE][nN][tT]|[dD][eE][wW]
> [pP][oO][iI][nN][tT]|[hH][uU]/
> [mM][iI][dD][iI][tT][yY]|[cC][oO][nN][sS][uU][mM][pP][tT][iI][oO]
> [nN])|\(([mM][eE][tT][eE][rR][vV][aA]/
> [lL][uU][eE]|[tT][eE][mM][pP][eE][rR][aA][tT][uU][rR][eE][cC][uU][rR]
> [rR][eE][nN][tT]|[dD][eE][wW]/
> [pP][oO][iI][nN][tT]|[hH][uU][mM][iI][dD][iI][tT][yY]|[cC][oO][nN]
> [sS][uU][mM][pP][tT][iI][oO][nN])(,/
> ([mM][eE][tT][eE][rR][vV][aA][lL][uU][eE]|[tT][eE][mM][pP][eE][rR]
> [aA][tT][uU][rR][eE][cC][uU][rR]/
> [rR][eE][nN][tT]|[dD][eE][wW][pP][oO][iI][nN][tT]|[hH][uU][mM][iI]
> [dD][iI][tT][yY]|[cC][oO][nN][sS]/
> [uU][mM][pP][tT][iI][oO][nN])){0,4}\)))?(,(\d{1,10}|\(\d{1,10}(,
> \d{1,10}){0,4}\))(:(([mM][eE][tT][eE]/
> [rR][vV][aA][lL][uU][eE]|[tT][eE][mM][pP][eE][rR][aA][tT][uU][rR][eE]
> [cC][uU][rR][rR][eE][nN][tT]|/
> [dD][eE][wW][pP][oO][iI][nN][tT]|[hH][uU][mM][iI][dD][iI][tT][yY]|
> [cC][oO][nN][sS][uU][mM][pP][tT]/
> [iI][oO][nN])|\(([mM][eE][tT][eE][rR][vV][aA][lL][uU][eE]|[tT][eE]
> [mM][pP][eE][rR][aA][tT][uU][rR][eE]/
> [cC][uU][rR][rR][eE][nN][tT]|[dD][eE][wW][pP][oO][iI][nN][tT]|[hH]
> [uU][mM][iI][dD][iI][tT][yY]|[cC]/
> [oO][nN][sS][uU][mM][pP][tT][iI][oO][nN])(,([mM][eE][tT][eE][rR][vV]
> [aA][lL][uU][eE]|[tT][eE][mM]/
> [pP][eE][rR][aA][tT][uU][rR][eE][cC][uU][rR][rR][eE][nN][tT]|[dD][eE]
> [wW][pP][oO][iI][nN][tT]|[hH]/
> [uU][mM][iI][dD][iI][tT][yY]|[cC][oO][nN][sS][uU][mM][pP][tT][iI][oO]
> [nN])){0,4}\)))?){0,4}}.png">
>
Holy regex batman!
When there is a match, and if it helps, you can also obtain the
MatchResult to extract group parameters by injecting ExtendedUriInfo:
https://jersey.dev.java.net/nonav/apidocs/1.1.2-ea/jersey/com/sun/jersey/api/core/ExtendedUriInfo.html
> However, the problem is how to guide the user. When Jersey can't
> match a
> query to a resource, it ends in a pretty useless 404.
>
> So here's the question: Is it possible to hook into the resource
> mapping
> itself, in a fail-fast fashion such that I can point out to the user
> what went wrong? I guess this this will be hard right, realizing that
> this is not a classical lookahead(1) parser but done exclusively with
> large regular expressions? So perhaps the most obvious thing to do
> is to
> replace the default 404 handler with a custom error-recovery parser?
>
There are potentially a few options:
1) Do not to use Jersey's regex matching for such an expression.
Jersey matches a super set and your
application refines the match and returns an appropriate
response, 404 or otherwise. You can
re-uses Jerseys matching facilities if you like (see UriTemplate).
2) If the matching algorithm fails to find a match for a request URI
it will throw a NotFoundException.
You can use an ExceptionMapper to map this exception but it will
not give you the template that
failed to match.
3) Use a resource filter to inspect a response for a 404 for certain
paths
@404Inspect
@Path(/my very complex expression :-)/)
...
The resource filter can check for the annotation @404Inspect,
then obtain the @Path value and add
a container response filter that checks for 404 and if so can
potentially return something meaningful.
Hth,
Paul.