Announcement Announcement Module
Collapse
No announcement yet.
Unable to Validate when MTOM is used with PayloadValidatingInterceptor Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Unable to Validate when MTOM is used with PayloadValidatingInterceptor

    Hi,

    I am unable to validate using the PayloadValidatingInterceptor class when using an MTOM attachment. When I try to do this I get the following error message:

    2009-05-15 15:43:50,953 DEBUG [org.springframework.ws.soap.server.endpoint.interc eptor.SoapEnvelopeLoggingInterceptor] - Fault: <SOAP-ENV:Envelope xmlns:SOAP-ENV="http://
    schemas.xmlsoap.org/soap/envelope/"><SOAP-ENV:Header/><SOAP-ENV:Body><SOAP-ENV:Fault><faultcode>SOAP-ENV:Client</faultcode><faultstring xml:lang="en">Validation error</fa
    ultstring><detail><spring-ws:ValidationError xmlns:spring-ws="http://springframework.org/spring-ws">cvc-type.3.1.2: Element 'ns2:content' is a simple type, so it must hav
    e no element information item [children].</spring-ws:ValidationError></detail></SOAP-ENV:Fault></SOAP-ENV:Body></SOAP-ENV:Envelope>
    2009-05-15 15:43:50,953 DEBUG [org.springframework.ws.server.MessageTracing.sent] - Sent response [SaajSoapMessage {http://schemas.xmlsoap.org/soap/envelope/}Fault] for r
    equest [SaajSoapMessage {http://oracle.com/mtom}TestRequest]

    Here is my schema:

    <?xml version="1.0" encoding="UTF-8"?>
    <schema xmlns="http://www.w3.org/2001/XMLSchema"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    xmlns:tns="http://oracle.com/mtom"
    xmlns:xmime="http://www.w3.org/2005/05/xmlmime"
    targetNamespace="http://oracle.com/mtom"
    elementFormDefault="qualified">
    <complexType name="Attachment">
    <sequence>
    <element name="name" type="string"/>
    <element name="content" type="base64Binary" xmime:expectedContentTypes="*/*"/>
    </sequence>
    </complexType>
    <complexType name="Package">
    <sequence>
    <element name="PackageTitle" type="string"/>
    <element name="Recipient1" type="string"/>
    <element name="Recipient2" type="string"/>
    <element name="Recipient3" type="string"/>
    <element name="StartDate" type="xs:date" minOccurs="0" maxOccurs="1"/>
    <element name="EndDate" type="xs:date" minOccurs="0" maxOccurs="1"/>
    <element name="Optional1" type="string" minOccurs="0" maxOccurs="1"/>
    <element name="Attachment" type="tns:Attachment" minOccurs="0" maxOccurs="unbounded"/>
    </sequence>
    </complexType>
    <element name="TestRequest" type="tns:Package"/>
    <complexType name="PackageResponse">
    <sequence>
    <element name="Results" type="string"/>
    <element name="ArchiveDate" type="xs:date" minOccurs="0" maxOccurs="1"/>
    </sequence>
    </complexType>
    <element name="TestResponse" type="tns:PackageResponse"/>
    </schema>

    Is there a different way I should declare MTOM attachment elements in the schema?

  • #2
    Unable to Validate when MTOM is used with PayloadValidatingInterceptor

    Here is the SOAP request:

    <SOAP-ENV:Envelope xmlns:SOAP-ENV="http:
    //schemas.xmlsoap.org/soap/envelope/"><SOAP-ENV:Header/><SOAP-ENV:Body><ns2:TestRequest xmlns:ns2="http://oracle.com/mtom"><ns2:PackageTitle>Policy-xyz</ns2:PackageTitle>
    <ns2:Recipient1>Insured</ns2:Recipient1><ns2:Recipient2>Agent</ns2:Recipient2><ns2:Recipient3>Carrier</ns2:Recipient3><ns2:StartDate>2009-05-15Z</ns2:StartDate><ns2:EndDa
    te>2009-06-14Z</ns2:EndDate><ns2:Attachment><ns2:name>iwip_find.gi f</ns2:name><ns2:content><xop:Include xmlns:xop="http://www.w3.org/2004/08/xop/include" href="cid:46ba5f
    28-987a-4add-bef6-a51331c92ac9%40oracle.com"/></ns2:content></ns2:Attachment></ns2:TestRequest></SOAP-ENV:Body></SOAP-ENV:Envelope>

    Comment


    • #3
      A workaround to Validate with MTOM

      Since no one replied to my questions, probably because there are other threads with similar questions answering that this is not possible with the current version of JAXP and that it really should be a JAXP / JAXB2 bug, I figured I would try to contribute something and show how I created a workaround so I can still validate the payload against the schema, but skip the MTOM elements:

      Basically,

      The idea is to take advantage of the setErrorHandler method in the javax.xml.validation.Validator class. By implementing my own ErrorHandler class, I can check for exceptions and skip the ones for the MTOM elements.

      Here is what I did:

      1 - Implement the ErrorHandler interface:

      Code:
      package com.oracle.validation.handler;
      
      import java.io.IOException;
      import java.util.ArrayList;
      import java.util.List;
      import org.xml.sax.ErrorHandler;
      import org.xml.sax.SAXException;
      import org.xml.sax.SAXParseException;
      
      public class ValidationErrorHandler implements ErrorHandler {
      
          private List errors = new ArrayList();
          
          private String [] elements;
          
          public SAXParseException[] getErrors() {
              return (SAXParseException[]) errors.toArray(new SAXParseException[errors.size()]);
          }
          
          public void skipElements(String[] elements){
              this.elements = elements; 
              
          }
          
          public void warning(SAXParseException ex) throws SAXException {
          }
      
          public void error(SAXParseException ex) throws SAXException {      
              String text = ex.getMessage();
              
              for (int i=0; elements != null && i < elements.length; i++){
                  if (text.contains(elements[i])){
                      System.out.println("Skipping validation for XSD element <" + elements[i] + ">.");
                      return;
                  }
              }
              System.out.println("*****************Error**************************"); 
              ex.printStackTrace();
              System.out.println("************************************************");
              errors.add(ex);
          }
      
          public void fatalError(SAXParseException ex) throws SAXException {
              System.out.println("******************Fatal Error***************************"); 
              ex.printStackTrace();
              System.out.println("********************************************************");
              errors.add(ex);
          }
      }
      2 - Modify the AbstractValidatingInterceptor class for the server side by adding the following instance variables and methods:

      Code:
          private String errorHandler;
          
          private String skipElements; 
      
          public void setErrorHandler(String errorHandler){
              this.errorHandler = errorHandler;  
          }
          
          public String getErrorHandler(){
              return errorHandler;
          }
          
          public void setSkipElements(String skipElements){
              this.skipElements = skipElements;
          }
          
          public String getSkipElements(){
              return skipElements;
          }
      
          private ErrorHandler getErrorHandlerFor(String errorHandler){
              ErrorHandler handler = null;
              if (errorHandler != null && errorHandler.trim().length() > 0){
                  System.out.println("*****Setting custom error handler <" + errorHandler + ">.");
                  try{
                      Class _class = Class.forName(errorHandler);
                      handler = (ErrorHandler)_class.newInstance();
                      
                  }catch(Exception e){
                      e.printStackTrace();
                  }    
              }
              return handler;
          }
      3 - Modify the following methods in the same class (AbstractValidatingInterceptor):

      Code:
          public void setXsdSchema(XsdSchema schema) throws IOException {
              this.validator = schema.createValidator();
              ErrorHandler handler = getErrorHandlerFor(errorHandler);
              if (handler != null){
                  this.validator.setErrorHandler(handler);
              }
              if (skipElements != null && skipElements.trim().length() > 0){
                  this.validator.setSkipElements(skipElements);
              }
          }
      
          public void setXsdSchemaCollection(XsdSchemaCollection schemaCollection) throws IOException {
              this.validator = schemaCollection.createValidator();
              ErrorHandler handler = getErrorHandlerFor(errorHandler);
              if (handler != null){
                  this.validator.setErrorHandler(handler);
              }                          
              if (skipElements != null && skipElements.trim().length() > 0){
                  this.validator.setSkipElements(skipElements);
              }
          }
      
          public void afterPropertiesSet() throws Exception {
              if (validator == null && !ObjectUtils.isEmpty(schemas)) {
                  Assert.hasLength(schemaLanguage, "schemaLanguage is required");
                  for (int i = 0; i < schemas.length; i++) {
                      Assert.isTrue(schemas[i].exists(), "schema [" + schemas[i] + "] does not exist");
                  }
                  if (logger.isInfoEnabled()) {
                      logger.info("Validating using " + StringUtils.arrayToCommaDelimitedString(schemas));
                  }
                  
                  validator = XmlValidatorFactory.createValidator(schemas, schemaLanguage);
                  ErrorHandler handler = getErrorHandlerFor(errorHandler);
                  if (handler != null){
                      this.validator.setErrorHandler(handler);
                  }
                  if (skipElements != null && skipElements.trim().length() > 0){
                      this.validator.setSkipElements(skipElements);
                  }
              }
              Assert.notNull(validator, "Setting 'schema', 'schemas', 'xsdSchema', or 'xsdSchemaCollection' is required");
          }
      4 - Modify the Jaxp13ValidatorFactory class as follows:

      Code:
          4.1 Inside the Jaxp13Validator static class, add the following instance variables and methods:
      
          private ErrorHandler handler;
              
          private String [] skipElements;
             
          private Method _getErrorsMethod;
             
          private Method _skipElementsMethod;
      
          public void setErrorHandler(ErrorHandler handler){
                  System.out.println("*****Setting Jaxp 1.3 error handler.");
                  this.handler = handler;
                  try{
                      _getErrorsMethod = handler.getClass().getMethod("getErrors", //Method name
                                                                       null);      //Arguments
                      _skipElementsMethod = handler.getClass().getMethod("skipElements",
                                                                         new Class[] { String[].class });
                                                                                                                                        
                  }catch(Exception e){
                      e.printStackTrace();
                  }       
              }
              
              public void setSkipElements(String skipElements){
                  this.skipElements = skipElements == null? null : skipElements.split(",");
              }
      4.2 - Inside the same class, modify the validate method as follows:

      Code:
          public SAXParseException[] validate(Source source) throws IOException {
                       validator = schema.newValidator();
                  try {
                  
                      if (handler == null){    
                          handler = new ValidationErrorHandler();
                          _getErrorsMethod = handler.getClass().getMethod("getErrors",   //Method name
                                                                          null);         //Arguments  
                          _skipElementsMethod = handler.getClass().getMethod("skipElements",
                                                                             new Class[] { String[].class });                                                                    
                      }
                      
                      if (skipElements != null){
                          if (_skipElementsMethod != null){
                              _skipElementsMethod.invoke(handler, 
                                                         new Object[] { skipElements });
                          }
                      } 
                      
                      validator.setErrorHandler(handler); 
                      
                      validator.validate(source);                           
                      
                      return _getErrorsMethod == null? (SAXParseException[])new ArrayList().toArray(new SAXParseException[0]): (SAXParseException[])_getErrorsMethod.invoke(handler, null);  
                      
                  }catch (Exception ex) {
                      throw new XmlValidationException("Could not validate source: " + ex.getMessage(), ex);
                  }
              }
      4.3 - Inside the same class, modify the ValidationErrorHandler class as follows:

      Code:
          private static class ValidationErrorHandler implements ErrorHandler {
      
              private List errors = new ArrayList();
              
              
              public ValidationErrorHandler(){
                  System.out.println("*****Creating default Jaxp1.3 Validation Error Handler.");
              }
              
              public SAXParseException[] getErrors() {
                  return (SAXParseException[]) errors.toArray(new SAXParseException[errors.size()]);
              }
              
              public void skipElements(String[] elements){
                  //Do nothing
              }
              
              public void warning(SAXParseException ex) throws SAXException {
              }
      
              public void error(SAXParseException ex) throws SAXException {
                  errors.add(ex);
              }
      
              public void fatalError(SAXParseException ex) throws SAXException {
                  errors.add(ex);
              }
          }
      continues on the next post.....
      Last edited by Arjen Poutsma; Mar 24th, 2011, 04:14 AM. Reason: Added code tags

      Comment


      • #4
        A workaround to Validate with MTOM (continued)

        Here is the rest:


        5 - Add the following methods to the XMLValidator interface:
        Code:
            void setErrorHandler(ErrorHandler handler);     
            
            void setSkipElements(String skipElements);
        6 - Configure the validating interceptor bean with the new error handler and a comma delimited list of elements to skip, when a SAXParserException occurs for them:

        Code:
        <bean id="validatingInterceptor" class="org.springframework.ws.soap.server.endpoint.interceptor.PayloadValidatingInterceptor">
                <property name="schema" value="/WEB-INF/schema.xsd"/>
                <property name="validateRequest" value="true"/>
                <property name="validateResponse" value="true"/>
                <property name="errorHandler" value="com.oracle.validation.handler.ValidationErrorHandler"/>  
                <property name="skipElements" value="content"/>
            </bean>
        7 - Here is the schema file schema.xsd:

        Code:
        <?xml version="1.0" encoding="UTF-8"?>
        <schema xmlns="http://www.w3.org/2001/XMLSchema" 
                xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
                xmlns:tns="http://oracle.com/mtom" 
                xmlns:xmime="http://www.w3.org/2005/05/xmlmime" 
                targetNamespace="http://oracle.com/mtom" 
                elementFormDefault="qualified">
        	<complexType name="Attachment">
        		<sequence>
        			<element name="name" type="string"/>
        			<element name="content" type="base64Binary" xmime:expectedContentTypes="*/*"/>
        		</sequence>
        	</complexType>
        	<complexType name="Package">
        		<sequence>
        			<element name="PackageTitle" type="xsd:string"/>
        			<element name="Recipient1" type="xsd:string"/>
        			<element name="Recipient2" type="xsd:string"/>
        			<element name="Recipient3" type="xsd:string"/>  
        			<element name="StartDate" type="xsd:date" minOccurs="0" maxOccurs="1"/>
        			<element name="EndDate" type="xsd:date" minOccurs="0" maxOccurs="1"/>
        			<element name="Attachment" type="tns:Attachment" minOccurs="0" maxOccurs="unbounded"/> 
        			<element name="Optional1" type="xsd:string" minOccurs="0" maxOccurs="1"/>
        		</sequence>
        	</complexType>
        	<element name="TestRequest" type="tns:Package"/>
        	<complexType name="PackageResponse">
        	    <sequence>
        	        <element name="Results" type="string"/>
        	        <element name="ArchiveDate" type="xsd:date" minOccurs="0" maxOccurs="1"/>
        	    </sequence>
        	</complexType>
        	<element name="TestResponse" type="tns:PackageResponse"/>
        </schema>
        Last edited by Arjen Poutsma; Mar 24th, 2011, 04:15 AM. Reason: Added code tags

        Comment

        Working...
        X