Monthly Archives: September 2011

Handling POX Errors in Spring-WS Part 2

In part one of this post, I showed you how to communicate XSD validation errors back to a Spring-WS POX client. In this part, I demonstrate how to tell the client they’ve submitted corrupt XML.

Let’s post some corrupt XML by leaving the closing Contacts XML element out of a ContactStore call.

Corrupt XML

<?xml version="1.0" encoding="UTF-8"?>
  <Contacts xmlns="http://www.springframework.org/spring-ws/samples/pox">
    <Contact>
       <Name>Jenny</Name>
     <Phone>8675309</Phone>
  </Contact>

If you’re using Tomcat for a servlet container, you get a big nasty error like this:

Tomcat's Bad XML Error

The HTTP response says that the problem is “XML document structures must start and end within the same entity.”   OK, that tells us what the client did wrong, but it’s not in a form that our ContactStore service can handle.   We need some way to catch the error and reformat it as an XML that fits the ContactStore XSD.

So what next?   Close examination of the stack trace gives us an idea where we can catch that error:

 com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderImpl.parse(DocumentBuilderImpl.java:283)
 javax.xml.parsers.DocumentBuilder.parse(DocumentBuilder.java:124)
 org.springframework.ws.pox.dom.DomPoxMessageFactory.createWebServiceMessage(DomPoxMessageFactory.java:87)
 org.springframework.ws.transport.AbstractWebServiceConnection.receive(AbstractWebServiceConnection.java:90)
 org.springframework.ws.transport.support.WebServiceMessageReceiverObjectSupport.handleConnection(WebServiceMessageReceiverObjectSupport.java:86)
 org.springframework.ws.transport.http.WebServiceMessageReceiverHandlerAdapter.handle(WebServiceMessageReceiverHandlerAdapter.java:57)
 org.springframework.ws.transport.http.MessageDispatcherServlet.doService(MessageDispatcherServlet.java:230)
 org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:571)
 org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:511)
 javax.servlet.http.HttpServlet.service(HttpServlet.java:637)
 javax.servlet.http.HttpServlet.service(HttpServlet.java:717)

The Spring-WS MessageDispatcherServlet is the main servlet for handling all Spring-WS requests, and the exception passes through its doService method before it bubbles up to the servlet container. So we can subclass MessageDispatcherServlet and override doService to provide custom exception handling.

package org.springframework.ws.samples.pox.ws;

import ...

/**
 * Custom MessageDispatcherServlet that can handle DomPoxMessageExceptions
 *
 * @author lreeder
 */
public class PoxMessageDispatcherServlet extends MessageDispatcherServlet
{
   protected void doService(HttpServletRequest request,
                         HttpServletResponse response)
                  throws Exception
   {
      try
      {
         super.doService(request, response);
      }
      catch (DomPoxMessageException domMessageException)
      {
          final String NAMESPACE_URI = "http://www.springframework.org/spring-ws/samples/pox";
          final String ENCODING = "UTF-8";
          String error = domMessageException.getMessage();
          //Create an error message for DomPoxMessageExceptions that
          // validates against the XSD.
          //
          //TODO - escape XML characters in the error
          String errorXml =  "<!--?xml version=\"1.0\" encoding=\"" + ENCODING + "\"?-->\n"  +
                  "\n" +
                  error +
                  "\n";
          response.setStatus(HttpServletResponse.SC_OK);
          response.setContentType("text/xml");
          response.getWriter().write(errorXml);
          response.getWriter().flush();
      }
   }
}

And now we just need to update web.xml to use our new dispatcher servlet:

<!-- PoxMessageDispatcherServlet wraps the default MessageDispatcherServlet
 and provides customer exception handling -->
 <servlet>
   <servlet-name>spring-ws</servlet-name>
   <servlet-class>org.springframework.ws.samples.pox.ws.PoxMessageDispatcherServlet</servlet-class>
 </servlet>

What happens when we  post our invalid XML to the updated MessageDispatcherServlet?

<?xml version="1.0" encoding="UTF-8"?>
  <error xmlns="http://www.springframework.org/spring-ws/samples/pox">
Could not parse request message; nested exception is org.xml.sax.SAXParseException: XML document structures must start and end within the same entity.
</error>

Now we’ve got an error message that an XML client can handle.

Well, that’s it for this post.   I hope it’s given you some idea about how you can implement more flexible error handling with a POX service built with Spring-WS.