A quite common use case in a flow in the Mule ESB is validating if an XML document is valid against a corresponding XSD. Especially if a project is in the development/test stage 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 which was supplying invalid XML.
The ‘standard’ way to do this in Mule is by using the schema-validation-filter and especially 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; } }
Update 31-01-2014: Please note that this implementation is NOT thread safe since the errorHandler is defined at class level. To make this filter thread-safe I have also overwritten the ‘accept()’ method so I get an ‘errorHandler’ instance per ‘validator’ instance.
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()); } }
How are you setting the validation errors into the message?
Can u please explain that
Hi Deep,
Here is ‘an’ implementation for that. I override the ‘accept’ method in the ValidationFilter like this:
I hope this helps!
If you have more questions let me know.