I have a servlet filter in my Java app to ensure that users are using up-to-date URI for articles and categories. The problem is, that according to the profiler results this filter takes (self) about 40% of the total time for request (even for simple URI “/”) (the inner actions are non-trivial, its dynamic web page with huge menu, article ranking etc.).
public class NameFilter implements Filter {
private ArticleServiceIface articleService;
private CategoryServiceIface categoryService;
private UrlRewriteServiceIface urlRewriteService;
private Pattern pattern = Pattern.compile("^(?>.*?)/(article|category)/(\\d+)/(?>.*)$");
public void init(FilterConfig filterConfig) throws ServletException {
ApplicationContext ctx = WebApplicationContextUtils.getRequiredWebApplicationContext(filterConfig.getServletContext());
articleService = (ArticleServiceIface) ctx.getBean("articleService");
categoryService = (CategoryServiceIface) ctx.getBean("categoryService");
urlRewriteService = (UrlRewriteServiceIface) ctx.getBean("urlRewriteService");
}
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
String uri = ((HttpServletRequest) request).getRequestURI();
Matcher matcher = pattern.matcher(uri);
String currUri;
if (matcher.matches()) {
if (matcher.group(1).equals("article")) {
Long articleId = Long.valueOf(matcher.group(2));
ArticleDTO a = articleService.getById(articleId);
currUri = urlRewriteService.getUrl(a.getId());
} else {
Long categoryId = Long.valueOf(matcher.group(2));
CategoryDTO c = categoryService.getById(categoryId);
currUri = urlRewriteService.getCategoryUrl(c.getId());
}
} else { //does not match neighter article nor category
chain.doFilter(request, response);
return;
}
if (currUri.equals(uri)) {
chain.doFilter(request, response);
} else {
HttpServletResponse res = (HttpServletResponse) response;
res.setStatus(HttpServletResponse.SC_MOVED_PERMANENTLY);
res.setHeader("Location", currUri);
res.getWriter().close();
}
}
public void destroy() {
}
}
I have spend few hours debugging and profiling it, tried many different ways to formulate the regexp, but the results are always the same.
The bottlenect seems to be in the matches method, which gets called resursively and at some point it calls pattern matching iteratively (few thousand times) for some reason…
Thanks for any suggestions.
edit: Profiler results (seems pretty strange to me…according to debugger this should be parsing of URI == “/” )
EDIT2: current regexp:
private static Pattern pattern = Pattern.compile(".*?/(article|category)/(\\d+)/.*");
the results are still the same. I’ll try to measure it with
System.out.print(System.currTimeMillis - time)
EDIT3: conclusion: its probably netbeans profiler bug…
I have tried this code and URI “/”
long time = System.currentTimeMillis();
if (matcher.matches()) {
if (matcher.group(1).equals("article")) {
Long articleId = Long.valueOf(matcher.group(2));
ArticleDTO a = articleService.getById(articleId);
currUri = urlRewriteService.getUrl(a.getId());
} else {
Long categoryId = Long.valueOf(matcher.group(2));
CategoryDTO c = categoryService.getById(categoryId);
currUri = urlRewriteService.getCategoryUrl(c.getId());
}
} else { //does not match neighter article nor category
System.out.println(System.currentTimeMillis() - time);
....
The output is allways 0. So it seems to me that netbeans profiler is adding time to this method for some reason.
But thank you all for your help and cooperation, I have learned few regex tricks.
There is no need to use Lookbehinds in your pattern actually. Following code works for me and in fairly quick time:
OUTPUT
EDIT Try find() intead of matches() like this: