X

Best Practices from Oracle Development's A‑Team

Sites Vanity URLs and error handling

Dolf Dijkstra
Cloud Solutions Architect

Recently I worked with a customer that is using WebCenter Sites with the new Vanity URLs feature from version 11.1.1.8. They reported that when a request was initiated for a resource that was not defined, Sites would respond with a 404 response status, but the error handler as defined in the web application was not invoked. As a consequence they could not define a error page in the same look and feel as the rest of the website.

It turns out that the servlet filter (WebReferenceFilter) that is taking care of resolving the Vanity URL based on the incoming request, is using javax.servlet.http.HttpServletResponse.setStatus(404) instead of javax.servlet.http.HttpServletResponse.sendError(404). This means that the defined error handler in the web application is not called. The work around is simple: intercept the setStatus() call and translate that to a sendError() call. This can be done through a javax.servlet.Filter and a    javax.servlet.http.HttpServletResponseWrapper.

To accomplish this two classes are needed and some additional configuration in web.xml. Below is the sample code that shows the construct on how to intercept the setStatus() call. First the filter is decorating each request and wrapping the response in a ResponseWrapper. This  ResponseWrapper overrides the setStatus() method and changes the behavior if a status of 404 is passed in. This is the method and argument that the WebReferenceFilter is invoking. The code is very simple:

if (sc == HttpServletResponse.SC_NOT_FOUND) {    try {       sendError(sc);    } catch (IOException e) {       LOG.info(e);    } } else {    super.setStatus(sc); }

 

The web.xml file also needs to be changed and deployed. It is important that the 404Handler filter is configured before the Sites out-of-the-box WebReferenceFilter. If the order is incorrect, the response wrapping is not happing correct, it is done after the  WebReferenceFilter has executed and that is too late.


[….]
<error-page>
<error-code>404</error-code>
<location>/senderror-404.jsp</location>
</error-page>
[….]
<filter>
<filter-name>404Handler</filter-name>
<filter-class>com.oracle.ateam.sites.filter.status.Send404ErrorFilter</filter-class>
</filter>
[….]
<filter-mapping>
<filter-name>404Handler</filter-name>
<url-pattern>/*</url-pattern>
<dispatcher>REQUEST</dispatcher>
<dispatcher>FORWARD</dispatcher>
<dispatcher>INCLUDE</dispatcher>
</filter-mapping>
[….]

The (sample) code below is also checking some preconditions and adds some logging.

 

package com.oracle.ateam.sites.filter.status; import java.io.IOException; import java.util.Enumeration; import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; public class Send404ErrorFilter implements Filter { private static Log LOG = LogFactory.getLog(Send404ErrorFilter.class.getPackage().getName());     public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {         if (req instanceof HttpServletRequest) {             HttpServletRequest request = (HttpServletRequest) req;             HttpServletResponse response = (HttpServletResponse) res;             LOG.debug("Entering 404 handler " + request.getRequestURL());             if (LOG.isTraceEnabled()) {                 for (Enumeration enumerator = request.getAttributeNames(); enumerator.hasMoreElements();) {                 String key = enumerator.nextElement();                 Object value = request.getAttribute(key);                 LOG.trace("request attribute: " + key + "=" + value);             }         }          HttpServletResponse wrapper = new SendErrorServletResponse(response);          chain.doFilter(request, wrapper);          } else {              chain.doFilter(req, res);          }     }     public void init(FilterConfig config) throws ServletException {     }     public void destroy() {     // empty     } }

 

package com.oracle.ateam.sites.filter.status; import java.io.IOException; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponseWrapper; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; public class SendErrorServletResponse extends HttpServletResponseWrapper {     private static Log LOG = LogFactory.getLog(SendErrorServletResponse.class.getPackage().getName());     public SendErrorServletResponse(HttpServletResponse response) {          super(response);     }     @Override     public void setStatus(int sc) {         if (LOG.isDebugEnabled())            LOG.debug("setStatus " + sc);         if (getResponse().isCommitted()) {            LOG.debug("response is committed, can't set the status anymore");            return;         }         if (sc == HttpServletResponse.SC_NOT_FOUND) {            try {                LOG.debug("calling sendError " + sc);                sendError(sc);            } catch (IOException e) {              LOG.info(e);           }         } else {             super.setStatus(sc);         }      } }

Be the first to comment

Comments ( 0 )
Please enter your name.Please provide a valid email address.Please enter a comment.CAPTCHA challenge response provided was incorrect. Please try again.Captcha