Enterprise Integration Zone is brought to you in partnership with:

Pascal is a senior JEE Developer and Architect at 4Synergy in The Netherlands. Pascal has been designing and building J2EE applications since 2001. He is particularly interested in Open Source toolstack (Mule, Spring Framework, JBoss) and technologies like Web Services, SOA and Cloud technologies. Specialties: JEE XML Web Services Mule ESB Maven Cloud Technology Pascal is a DZone MVB and is not an employee of DZone and has posted 55 posts at DZone. You can read more from them at their website. View Full User Profile

Validating XML message in Mule 3

11.22.2013
| 6876 views |
  • submit to reddit

mulesoft-logo
A common use case Mule ESB flows is validating if an XML document is valid against a corresponding XSD. It can be quite annoying to find out you have spent a lot of time fixing an issue when it was actually caused by another system that was supplying invalid XML, especially if a project is in the development/test stage.

The ‘standard’ way to do this in Mule is by using the schema-validation-filter, usually in combination with the message-filter. For example, the following configuration will send all non-valid messages to the ‘process-invalid-xml’ flow:

<message-filter onUnaccepted="process-invalid-xml" throwOnUnaccepted="true">
    <xml:schema-validation-filter .../>
</message-filter>

In the ‘process-invalid-xml’ flow you can then create a response message (if applicable) to tell the sender of the original message that it contains invalid XML. This was the case in my situation and I also wanted to show the user what was wrong in the XML. To do this, I created my own SAX ErrorHandler and supplied that to the schema-validation-filter like this:

<spring:bean id="xmlErrorHandler" class="net.pascalalma.xml.handlers.MySaxErrorHandler" />
 <message-filter onUnaccepted="invalidRelationXmlFlow" throwOnUnaccepted="false">
     <mulexml:schema-validation-filter errorHandler-ref="xmlErrorHandler"  schemaLocations="xsd/my-schema.xsd"/>
</message-filter>

However, no matter what I did my error handler wasn’t being called by the filter. After some debugging I only got it working by extending the original schema-validation-filter and set the error-handler on the created Validator like this:

public class MySchemaValidationFilter extends SchemaValidationFilter
{
  static Logger logger = Logger.getLogger(MySchemaValidationFilter.class);
 
  public Validator createValidator() throws SAXException
  {
    Validator validator = super.createValidator();
    validator.setErrorHandler(getErrorHandler());
    return validator;
  }
}

I am not sure if this is a bug in the original schema-validation-filter or if there is another way to make use of the errorHandler, but this was the only way for me to get it working.

I use my version of the filter with the following configuration:

<custom-filter class="net.pascalalma.xml.filters.MySchemaValidationFilter" >
  <spring:property name="schemaLocations" value="xsd/my-schema.xsd"/>
  <spring:property name="returnResult" value="false"/>
  <spring:property name="errorHandler" ref="xmlErrorHandler"/>
</custom-filter>

This way I can collect all errors in my error handler and put them with a outbound property on the message and return them to the calling client.

Here is the source code of my error handler:

public class MyErrorHandler implements ErrorHandler {
 
    static Logger logger = Logger.getLogger(MyErrorHandler.class);
 
    public List<String> getErrors() {
        return errors;
    }
    public void setErrors(List<String> errors) {
        this.errors = errors;
    }
    private List<String> errors = new ArrayList<String>();
    @Override
    public void warning(SAXParseException e) throws SAXException {
        logger.warn(e.getLineNumber() + "/" + e.getColumnNumber() + ": " + e.getMessage());
    }
    @Override
    public void fatalError(SAXParseException e) throws SAXException {
        logger.debug("fatalError occurred: " + e.toString());
        errors.add(e.getLineNumber() +"/" + e.getColumnNumber() + ": " + e.getMessage());
    }
    @Override
    public void error(SAXParseException e) throws SAXException {
        logger.debug("error occurred: " + e.toString());
        errors.add(e.getLineNumber() +"/" + e.getColumnNumber() + ": " + e.getMessage());
    }
}



Published at DZone with permission of Pascal Alma, author and DZone MVB. (source)

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)