WsdlValidator.java :  » Web-Services » soapui-1.7.5 » com » eviware » soapui » impl » wsdl » support » wsdl » Java Open Source

Java Open Source » Web Services » soapui 1.7.5 
soapui 1.7.5 » com » eviware » soapui » impl » wsdl » support » wsdl » WsdlValidator.java
/*
 *  soapUI, copyright (C) 2004-2007 eviware.com 
 *
 *  soapUI is free software; you can redistribute it and/or modify it under the 
 *  terms of version 2.1 of the GNU Lesser General Public License as published by 
 *  the Free Software Foundation.
 *
 *  soapUI is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without 
 *  even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 
 *  See the GNU Lesser General Public License for more details at gnu.org.
 */

package com.eviware.soapui.impl.wsdl.support.wsdl;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import javax.wsdl.Binding;
import javax.wsdl.BindingFault;
import javax.wsdl.BindingOperation;
import javax.wsdl.Part;
import javax.wsdl.Port;
import javax.wsdl.Service;
import javax.wsdl.extensions.mime.MIMEContent;
import javax.xml.namespace.QName;

import org.apache.log4j.Logger;
import org.apache.xmlbeans.SchemaGlobalElement;
import org.apache.xmlbeans.SchemaType;
import org.apache.xmlbeans.XmlCursor;
import org.apache.xmlbeans.XmlError;
import org.apache.xmlbeans.XmlException;
import org.apache.xmlbeans.XmlLineNumber;
import org.apache.xmlbeans.XmlObject;
import org.apache.xmlbeans.XmlOptions;
import org.apache.xmlbeans.XmlValidationError;
import org.w3c.dom.Element;

import com.eviware.soapui.SoapUI;
import com.eviware.soapui.impl.wsdl.WsdlOperation;
import com.eviware.soapui.impl.wsdl.submit.WsdlMessageExchange;
import com.eviware.soapui.impl.wsdl.teststeps.assertions.AssertionError;
import com.eviware.soapui.model.iface.Attachment;
import com.eviware.soapui.settings.WsdlSettings;
import com.eviware.soapui.support.xml.XmlUtils;

/**
 * Class for validating SOAP requests/responses against their definition and schema, requires that
 * the messages follow basic-profile requirements
 *  
 * @author Ole.Matzura
 */

public class WsdlValidator
{
  private final WsdlContext wsdlContext;
   private final static Logger log = Logger.getLogger( WsdlValidator.class );
   
  public WsdlValidator( WsdlContext wsdlContext )
   {
    this.wsdlContext = wsdlContext;
  }
  
  @SuppressWarnings("unchecked")
  public AssertionError [] assertRequest( WsdlMessageExchange messageExchange, boolean envelopeOnly )
  {
    List<XmlError> errors = new ArrayList<XmlError>(); 
    try
    {
      String requestContent = messageExchange.getRequestContent();
      wsdlContext.getSoapVersion().validateSoapEnvelope(requestContent, errors);

      if (errors.isEmpty() && !envelopeOnly )
      {
        wsdlContext.getSoapVersion().validateSoapEnvelope(requestContent, errors);
        WsdlOperation operation = messageExchange.getOperation();
        String operationName = operation.getBindingOperationName();
        BindingOperation bindingOperation = findBindingOperation(operationName);
        if (bindingOperation == null)
        {
          errors.add(XmlError.forMessage("Missing operation ["
              + operationName + "] in wsdl definition"));
        }
        else
        {
          Part[] inputParts = WsdlUtils.getInputParts(bindingOperation);
          validateMessage(messageExchange, requestContent, bindingOperation, inputParts, errors, false);
//          validateInputAttachments(request, errors, bindingOperation, inputParts);
        }
      }
    }
      catch( XmlException e )
      {
        errors.addAll( e.getErrors() );
        errors.add( XmlError.forMessage( e.getMessage() ));
      }
    catch (Exception e)
    {
      errors.add( XmlError.forMessage( e.getMessage() ));
    }
    
    return convertErrors( errors );
  }

  private void validateInputAttachments(WsdlMessageExchange messageExchange, List<XmlError> errors, BindingOperation bindingOperation, Part[] inputParts)
  {
    for( Part part : inputParts )
    {
      MIMEContent[] contents = WsdlUtils.getInputMultipartContent( part, bindingOperation );
      if( contents.length == 0 )
        continue;
      
      Attachment [] attachments = messageExchange.getRequestAttachmentsForPart( part.getName() );
      if( attachments.length == 0 )
      {
        errors.add(XmlError.forMessage("Missing attachment for part [" + part.getName() + "]" ));
      }
      else if( attachments.length == 1 )
      {
        Attachment attachment = attachments[0];
        String types = "";
        for( MIMEContent content : contents )
        {
          String type = content.getType();
          if( type.equals( attachment.getContentType() ) || type.toUpperCase().startsWith( "MULTIPART" ))
          {
            types = null;
            break;
          }
          if( types.length() > 0 )
            types += ",";
          
          types += type;
        }
        
        if( types != null )
        {      
          String msg = "Missing attachment for part [" + part.getName() +"] with content-type [" + types + "]," +
              " content type is [" + attachment.getContentType() + "]";
          
          if( SoapUI.getSettings().getBoolean( WsdlSettings.ALLOW_INCORRECT_CONTENTTYPE ))
            log.warn( msg );
          else
            errors.add(XmlError.forMessage(msg ));
        }
      }
      else
      {
        String types = "";
        for( MIMEContent content : contents )
        {
          String type = content.getType();
          if( type.toUpperCase().startsWith( "MULTIPART" ))
          {
            types = null;
            break;
          }
          if( types.length() > 0 )
            types += ",";
          
          types += type;
        }

        if( types == null )
        {
          String msg = "Too many attachments for part [" + part.getName() + "] with content-type [" + types + "]";
          if( SoapUI.getSettings().getBoolean( WsdlSettings.ALLOW_INCORRECT_CONTENTTYPE ))
            log.warn( msg );
          else
            errors.add(XmlError.forMessage(msg ));
        }
      }
      
      if( attachments.length > 0 )
        validateAttachmentsReadability( errors, attachments );
    }
  }
  
  private void validateOutputAttachments(WsdlMessageExchange messageExchange, XmlObject xml, List<XmlError> errors, BindingOperation bindingOperation, Part[] outputParts) throws Exception
  {
    for( Part part : outputParts )
    {
      MIMEContent[] contents = WsdlUtils.getOutputMultipartContent( part, bindingOperation );
      if( contents.length == 0 )
        continue;
      
      Attachment [] attachments = messageExchange.getResponseAttachmentsForPart( part.getName() );
      
      // check for rpc
      if( attachments.length == 0 && WsdlUtils.isRpc( wsdlContext.getDefinition(), bindingOperation ))
      {
        XmlObject[] rpcBodyPart = getRpcBodyPart( bindingOperation, xml, true );
        if( rpcBodyPart.length == 1 )
        {
          XmlObject[] children = rpcBodyPart[0].selectChildren( new QName( part.getName() ));
          if( children.length == 1 )
          {
            String href = ((Element)children[0].getDomNode()).getAttribute( "href" );
            if( href != null )
            {
              if( href.startsWith( "cid:" ))
                href = href.substring( 4 );
              
              attachments = messageExchange.getResponseAttachmentsForPart( href );
            }
          }
        }
      }
      
      if( attachments.length == 0 )
      {
        errors.add(XmlError.forMessage("Missing attachment for part [" + part.getName() + "]" ));
      }
      else if( attachments.length == 1 )
      {
        Attachment attachment = attachments[0];
        String types = "";
        for( MIMEContent content : contents )
        {
          String type = content.getType();
          if( type.equals( attachment.getContentType() ) || type.toUpperCase().startsWith( "MULTIPART" ))
          {
            types = null;
            break;
          }
          
          if( types.length() > 0 )
            types += ",";
          
          types += type;
        }
        
        if( types != null)
        {
          String msg = "Missing attachment for part [" + part.getName() + 
                      "] with content-type [" + types + "], content type is [" + attachment.getContentType() + "]";
          
          if( SoapUI.getSettings().getBoolean( WsdlSettings.ALLOW_INCORRECT_CONTENTTYPE ))
            log.warn( msg );
          else
            errors.add(XmlError.forMessage(msg ));
        }
      }
      else
      {
        String types = "";
        for( MIMEContent content : contents )
        {
          String type = content.getType();
          if( type.toUpperCase().startsWith( "MULTIPART" ))
          {
            types = null;
            break;
          }

          if( types.length() > 0 )
            types += ",";
          
          types += type;
        }
        
        if( types != null )
        {
          String msg = "Too many attachments for part [" + part.getName() + "] with content-type [" + types + "]";
          
          if( SoapUI.getSettings().getBoolean( WsdlSettings.ALLOW_INCORRECT_CONTENTTYPE ))
            log.warn( msg );
          else
            errors.add(XmlError.forMessage(msg ));
        }
      }
      
      if( attachments.length > 0 )
        validateAttachmentsReadability( errors, attachments );
    }
  }

  private void validateAttachmentsReadability( List<XmlError> errors, Attachment[] attachments )
  {
    for( Attachment attachment : attachments )
    {
      try
      {
        attachment.getInputStream();
      }
      catch( Exception e )
      {
        errors.add(XmlError.forMessage(e.toString() ));
      }
    }
  }
   
   public XmlObject [] getMessageParts( String messageContent, String operationName, boolean isResponse ) throws Exception
   {
     BindingOperation bindingOperation = findBindingOperation(operationName);
    if (bindingOperation == null)
    {
      throw new Exception("Missing operation ["  + operationName + "] in wsdl definition");
    }

     if( !wsdlContext.hasSchemaTypes() )
       {
       throw new Exception("Missing schema types for message");
       }
    
       XmlObject msgXml = XmlObject.Factory.parse( messageContent );
       Part[] parts = isResponse ? WsdlUtils.getOutputParts( bindingOperation ) : WsdlUtils.getInputParts(bindingOperation);
       if( parts == null || parts.length == 0 )
         throw new Exception( "Missing parts for operation [" + operationName + "]" );
        
       List<XmlObject> result = new ArrayList<XmlObject>();
       
       if( WsdlUtils.isRpc( wsdlContext.getDefinition(), bindingOperation ))
       {
         //     get root element
          XmlObject[] paths = msgXml.selectPath( "declare namespace env='" + 
                       wsdlContext.getSoapVersion().getEnvelopeNamespace() + "';" +
                "declare namespace ns='" + wsdlContext.getDefinition().getTargetNamespace() + "';" +
                "$this/env:Envelope/env:Body/ns:" + bindingOperation.getName() + (isResponse ? "Response" : ""));
          
          if( paths.length != 1 )
          {
            throw new Exception("Missing message wrapper element [" + 
                   wsdlContext.getDefinition().getTargetNamespace() + "@" + bindingOperation.getName() + (isResponse ? "Response" : ""));
          }  
          else
          {
             XmlObject wrapper = paths[0];
             
             for (int i = 0; i < parts.length; i++)
             {
                Part part = parts[i];
                if( (isResponse && WsdlUtils.isAttachmentOutputPart( part, bindingOperation )) ||
                   (!isResponse && WsdlUtils.isAttachmentInputPart( part, bindingOperation )))
                  continue; 
                
                QName partName = part.getElementName();
                if( partName == null )
                  partName = new QName( part.getName() );
                
                XmlObject[] children = wrapper.selectChildren( partName );
                if( children.length != 1 )
                {
                   log.error("Missing message part [" + part.getName() + "]" );
                }
                else
                {
                   QName typeName = part.getTypeName();
                   if( typeName == null )
                   {
                     typeName = partName;
                     SchemaGlobalElement type = wsdlContext.getSchemaTypeLoader().findElement( typeName );
                     
                     if( type != null )
                     {
                        result.add( children[0].copy().changeType( type.getType() ));
                     }
                     else log.error( "Missing element [" + typeName + "] in associated schema for part [" + part.getName() + "]" );
                   }
                   else
                   {
                     SchemaType type = wsdlContext.getSchemaTypeLoader().findType( typeName );
                     if( type != null )
                     {
                        result.add( children[0].copy().changeType( type ));
                     }
                     else log.error( "Missing type [" + typeName + "] in associated schema for part [" + part.getName() + "]" );
                   }
                }
             }
          }
       }
       else
       {
          Part part = parts[0];
          QName elementName = part.getElementName();
          if( elementName != null )
          {
            // just check for correct message element, other elements are avoided (should create an error)
             XmlObject[] paths = msgXml.selectPath( "declare namespace env='" + 
                       wsdlContext.getSoapVersion().getEnvelopeNamespace() + "';" +
                   "declare namespace ns='" + elementName.getNamespaceURI() + "';" +
                   "$this/env:Envelope/env:Body/ns:" + elementName.getLocalPart() );
             
             if( paths.length == 1 )
             {
                SchemaGlobalElement elm = wsdlContext.getSchemaTypeLoader().findElement( elementName );
                if( elm != null )
                {
              result.add( paths[0].copy().changeType( elm.getType() ));
                }
                else throw new Exception("Missing part type in associated schema" );
             }
             else throw new Exception("Missing message part with name [" + elementName + "]" );
          }
       }
     
     return result.toArray( new XmlObject[result.size()] );
   }


  @SuppressWarnings({ "unchecked", "unchecked" })
  public void validateXml(String request, List<XmlError> errors )
  {
    try
    {
      XmlOptions xmlOptions = new XmlOptions();
      xmlOptions.setLoadLineNumbers();
      xmlOptions.setErrorListener(errors);
      xmlOptions.setLoadLineNumbers(XmlOptions.LOAD_LINE_NUMBERS_END_ELEMENT);
      XmlObject.Factory.parse(request, xmlOptions);
    }
      catch( XmlException e )
      {
        errors.addAll( e.getErrors() );
        errors.add( XmlError.forMessage( e.getMessage() ));
      }
    catch (Exception e)
    {
      errors.add( XmlError.forMessage( e.getMessage() ));
    }
  }

  private AssertionError[] convertErrors(List<XmlError> errors)
  {
      if( errors.size() > 0 )
      {
         List<AssertionError> response = new ArrayList<AssertionError>();
         for (Iterator<XmlError> i = errors.iterator(); i.hasNext();)
         {
            XmlError error = i.next();
            
            if( error instanceof XmlValidationError )
            {
              XmlValidationError e = ((XmlValidationError)error);
          QName offendingQName = e.getOffendingQName();
          if( offendingQName != null )
          {
            if( offendingQName.equals( new QName( wsdlContext.getSoapVersion().getEnvelopeNamespace(), "encodingStyle")))
            {
              log.debug( "ignoring encodingStyle validation..");
              continue;
            }
            else if( offendingQName.equals( new QName( wsdlContext.getSoapVersion().getEnvelopeNamespace(), "mustUnderstand")))
            {
              log.debug( "ignoring mustUnderstand validation..");
              continue;
            }
          }
            }
            
        AssertionError assertionError = new AssertionError(error);
            if( !response.contains( assertionError ))
              response.add( assertionError );
         }
         
         return response.toArray( new AssertionError[response.size()] );
      }
      
      return new AssertionError[0];
  }

  @SuppressWarnings("unchecked")
  public void validateMessage( WsdlMessageExchange messageExchange, String message, BindingOperation bindingOperation, Part [] parts, List<XmlError> errors, boolean isResponse )
  {
    try
      {
         if( !wsdlContext.hasSchemaTypes() )
         {
            errors.add( XmlError.forMessage( "Missing schema types for message"));
         }
         else
         {
           if( !WsdlUtils.isOutputSoapEncoded( bindingOperation))
            {
             XmlOptions xmlOptions = new XmlOptions();
               xmlOptions.setLoadLineNumbers();
               xmlOptions.setLoadLineNumbers(XmlOptions.LOAD_LINE_NUMBERS_END_ELEMENT);
               XmlObject xml = XmlObject.Factory.parse( message, xmlOptions );
            
               XmlObject[] paths = xml.selectPath( "declare namespace env='" + 
                   wsdlContext.getSoapVersion().getEnvelopeNamespace() + "';" + 
                     "$this/env:Envelope/env:Body/env:Fault");
               
               if( paths.length > 0 )
               {
                  validateSoapFault( bindingOperation, paths[0], errors );
               }
               else if( WsdlUtils.isRpc( wsdlContext.getDefinition(), bindingOperation ))
               {
                  validateRpcLiteral( bindingOperation, parts, xml, errors, isResponse );
               }
               else
               {
                  validateDocLiteral( bindingOperation, parts, xml, errors, isResponse );
               }
               
               if( isResponse )
                 validateOutputAttachments( messageExchange, xml, errors, bindingOperation, parts );
               else
                 validateInputAttachments( messageExchange, errors, bindingOperation, parts );
            }
           else errors.add( XmlError.forMessage( "Validation of SOAP-Encoded messages not supported"));
         }
      }
      catch ( XmlException e )
      {
        errors.addAll( e.getErrors() );
        errors.add( XmlError.forMessage( e.getMessage() ));
      }
      catch (Exception e)
      {
        errors.add( XmlError.forMessage( e.getMessage() ));
      }
  }
  
  private BindingOperation findBindingOperation(String operationName) throws Exception
  {
    Map services = wsdlContext.getDefinition().getAllServices();
    Iterator i = services.keySet().iterator();
    while( i.hasNext() )
    {
      Service service = (Service) wsdlContext.getDefinition().getService( (QName) i.next());
      Map ports = service.getPorts();
      
      Iterator iterator = ports.keySet().iterator();
      while( iterator.hasNext() )
      {
        Port port = (Port) service.getPort( (String) iterator.next() );
        BindingOperation bindingOperation = port.getBinding().getBindingOperation( operationName, null, null );
        if( bindingOperation != null ) return bindingOperation;
      }
    }
    
    Map bindings = wsdlContext.getDefinition().getAllBindings();
    i = bindings.keySet().iterator();
    while( i.hasNext() )
    {
      Binding binding = (Binding) bindings.get( i.next() );
      BindingOperation bindingOperation = binding.getBindingOperation( operationName, null, null );
      if( bindingOperation != null ) return bindingOperation;
    }
    
    return null;
  }

  @SuppressWarnings("unchecked")
  public AssertionError [] assertResponse( WsdlMessageExchange messageExchange, boolean envelopeOnly ) 
  {
    List<XmlError> errors = new ArrayList<XmlError>(); 
    try
    {
      String response = messageExchange.getResponseContent();
      wsdlContext.getSoapVersion().validateSoapEnvelope(response, errors);
      
      if (errors.isEmpty() && !envelopeOnly )
      {
        WsdlOperation operation = messageExchange.getOperation();
        String operationName = operation.getBindingOperationName();
        BindingOperation bindingOperation = findBindingOperation(operationName);
        if (bindingOperation == null)
        {
          errors.add(XmlError.forMessage("Missing operation ["
              + operationName + "] in wsdl definition"));
        }
        else
        {
          Part[] outputParts = WsdlUtils.getOutputParts(bindingOperation);
          validateMessage(messageExchange, response, bindingOperation, outputParts, errors, true);
        }
      }
    }
      catch ( XmlException e )
      {
        errors.addAll( e.getErrors() );
        errors.add( XmlError.forMessage( e.getMessage() ));
      }
      catch (Exception e)
      {
        errors.add( XmlError.forMessage( e.getMessage() ));
      }
    
    return convertErrors( errors );
  }
  
  private void validateDocLiteral(BindingOperation bindingOperation, Part[] parts, XmlObject msgXml, List<XmlError> errors, boolean isResponse) throws Exception
   {
    Part part = null;
    
    // start by finding body part
    for( int c = 0; c < parts.length; c++ )
    {
      // content part?
      if( (isResponse && !WsdlUtils.isAttachmentOutputPart( parts[c], bindingOperation )) ||
         (!isResponse && !WsdlUtils.isAttachmentInputPart( parts[c], bindingOperation )))
      {
        // already found?
        if( part != null )
        {
             errors.add( XmlError.forMessage("DocLiteral message must contain 1 body part definition" ));
             return;
        }
        
        part = parts[c];
      }
    }
    
      QName elementName = part.getElementName();
      if( elementName != null )
      {
        // just check for correct message element, other elements are avoided (should create an error)
         XmlObject[] paths = msgXml.selectPath( "declare namespace env='" + 
                   wsdlContext.getSoapVersion().getEnvelopeNamespace() + "';" +
               "declare namespace ns='" + elementName.getNamespaceURI() + "';" +
               "$this/env:Envelope/env:Body/ns:" + elementName.getLocalPart() );
         
         if( paths.length == 1 )
         {
            SchemaGlobalElement elm = wsdlContext.getSchemaTypeLoader().findElement( elementName );
            if( elm != null )
            {
          validateMessageBody(errors, elm.getType(), paths[0]);
            }
            else errors.add( XmlError.forMessage("Missing part type in associated schema") );
         }
         else errors.add( XmlError.forMessage("Missing message part with name [" + elementName + "]" ));
      }
      else if( part.getTypeName() != null )
      {
         QName typeName = part.getTypeName();
         
         XmlObject[] paths = msgXml.selectPath( "declare namespace env='" + 
                   wsdlContext.getSoapVersion().getEnvelopeNamespace() + "';" +
               "declare namespace ns='" + typeName.getNamespaceURI() + "';" +
               "$this/env:Envelope/env:Body/ns:" + part.getName() );
         
         if( paths.length == 1 )
         {
            SchemaType type = wsdlContext.getSchemaTypeLoader().findType( typeName );
            if( type != null )
            {
              validateMessageBody( errors, type, paths[0] );
               //XmlObject obj = paths[0].copy().changeType( type );
               //obj.validate( new XmlOptions().setErrorListener( errors ));
            }
            else errors.add(XmlError.forMessage( "Missing part type in associated schema") );
         }
         else errors.add( XmlError.forMessage("Missing message part with name:type [" + 
               part.getName() + ":" + typeName + "]" ));
      }
   }

  private void validateMessageBody(List<XmlError> errors, SchemaType type, XmlObject msg) throws XmlException
  {
    // need to create new body element of correct type from xml text
    // since we want to retain line-numbers
    XmlOptions xmlOptions = new XmlOptions();
    xmlOptions.setLoadLineNumbers();
    xmlOptions.setLoadLineNumbers(XmlOptions.LOAD_LINE_NUMBERS_END_ELEMENT);

    String xmlText = msg.copy().changeType( type ).xmlText( xmlOptions.setSaveOuter());
    XmlObject obj = type.getTypeSystem().parse( xmlText, type, xmlOptions );
    obj = obj.changeType( type );
    
    // create internal error list
    List list = new ArrayList();
    
    xmlOptions = new XmlOptions();
    xmlOptions.setErrorListener( list );
    xmlOptions.setValidateTreatLaxAsSkip();
    obj.validate( xmlOptions );
    
    // transfer errors for "real" line numbers
    for( int c = 0; c < list.size(); c++ )
    {
      XmlError error = (XmlError) list.get( c );
      
      if( error instanceof XmlValidationError )
      {
        XmlValidationError validationError = ((XmlValidationError)error);
        
        if( wsdlContext.getSoapVersion().shouldIgnore( validationError ))
          continue;
        
        // ignore cid: related errors
        if( validationError.getErrorCode().equals( "base64Binary") || validationError.getErrorCode().equals( "hexBinary"))
        {
          XmlCursor cursor = validationError.getCursorLocation();
          if( cursor.toParent() )
          {
            String text = cursor.getTextValue();
            
            // special handling for soapui/MTOM -> add option for disabling?
            if( text.startsWith( "cid:" ) || text.startsWith( "file:" ))
            {
              // ignore
              continue;
            }
          }
        }
      }
      
       int line = error.getLine() == -1 ? 0 : error.getLine()-1;
      errors.add( XmlError.forLocation( error.getMessage(), error.getSourceName(), 
           getLine( msg ) + line, error.getColumn(), error.getOffset() ));
    }
  }

   private int getLine(XmlObject object)
  {
     List list = new ArrayList();
    object.newCursor().getAllBookmarkRefs( list );
    for( int c = 0; c < list.size(); c++ )
    {
      if( list.get( c ) instanceof XmlLineNumber )
      {
        return ((XmlLineNumber)list.get(c)).getLine();
      }
    }
    
    return -1;
  }

  private void validateRpcLiteral(BindingOperation bindingOperation, Part[] parts, XmlObject msgXml, List<XmlError> errors, boolean isResponse ) throws Exception
   {
      if( parts.length == 0 )
         return;
      
      XmlObject[] bodyParts = getRpcBodyPart(bindingOperation, msgXml, isResponse);
      
      if( bodyParts.length != 1 )
      {
         errors.add( XmlError.forMessage("Missing message wrapper element [" + 
               wsdlContext.getDefinition().getTargetNamespace() + "@" + bindingOperation.getName() 
               + (isResponse ? "Response" : "" )));
      }  
      else
      {
         XmlObject wrapper = bodyParts[0];
         
         for (int i = 0; i < parts.length; i++)
         {
            Part part = parts[i];
            
            // skip attachment parts
            if( isResponse )
            {
              if( WsdlUtils.isAttachmentOutputPart( part, bindingOperation ) )
                continue;
            }
            else
            {
              if( WsdlUtils.isAttachmentInputPart( part, bindingOperation ) )
                continue;
            }
            
            // find part in message
            XmlObject[] children = wrapper.selectChildren( new QName( part.getName() ));
            
            // not found?
            if( children.length != 1 )
            {
              // try element name (loophole in basic-profile spec?)
              QName elementName = part.getElementName();
              if( elementName != null )
              {
                bodyParts = msgXml.selectPath( "declare namespace env='" + 
                      wsdlContext.getSoapVersion().getEnvelopeNamespace() + "';" +
                        "declare namespace ns='" + wsdlContext.getDefinition().getTargetNamespace() + "';" +
                        "declare namespace ns2='" + elementName.getNamespaceURI() + "';" +
                        "$this/env:Envelope/env:Body/ns:" + bindingOperation.getName() + (isResponse ? "Response" : "" ) + 
                        "/ns2:" + elementName.getLocalPart() ); 
                  
                if( bodyParts.length == 1 )
                {
                   SchemaGlobalElement elm = wsdlContext.getSchemaTypeLoader().findElement( elementName );
                   if( elm != null )
                   {
                 validateMessageBody(errors, elm.getType(), bodyParts[0]);
                   }
                   else errors.add( XmlError.forMessage("Missing part type in associated schema for [" + elementName + "]" ) );
                }
                else errors.add( XmlError.forMessage("Missing message part with name [" + elementName + "]" ));                
              }
              else
              {
                errors.add( XmlError.forMessage("Missing message part [" + part.getName() + "]" ));
              }
            }
            else
            {
               QName typeName = part.getTypeName();
               SchemaType type = wsdlContext.getSchemaTypeLoader().findType( typeName );
               if( type != null )
               {
                 validateMessageBody( errors, type, children[0]);
               }
               else errors.add( XmlError.forMessage("Missing type in associated schema for part [" + part.getName() + "]" ));
            }
         }
      }
   }

  private XmlObject[] getRpcBodyPart(BindingOperation bindingOperation, XmlObject msgXml, boolean isResponse) throws Exception
  {
    // rpc requests should use the operation name as root element and soapbind namespaceuri attribute as ns 
    String ns = WsdlUtils.getSoapBodyNamespace( isResponse ? 
        bindingOperation.getBindingOutput().getExtensibilityElements() :
          bindingOperation.getBindingInput().getExtensibilityElements() );
    
    if( ns == null || ns.trim().length() == 0 )
         ns = wsdlContext.getDefinition().getTargetNamespace();
      
      // get root element
      XmlObject[] paths = msgXml.selectPath( "declare namespace env='" + wsdlContext.getSoapVersion().getEnvelopeNamespace() + "';" +
            "declare namespace ns='" + ns + "';" + "$this/env:Envelope/env:Body/ns:" + 
            bindingOperation.getName() + (isResponse ? "Response" : "" ));
    return paths;
  }

   @SuppressWarnings("unchecked")
  private void validateSoapFault(BindingOperation bindingOperation, XmlObject msgXml, List<XmlError> errors) throws Exception
   {
      Map faults = bindingOperation.getBindingFaults();
      Iterator<BindingFault> i = faults.values().iterator();
      
      while( i.hasNext() )
      {
         BindingFault bindingFault = i.next();
         String faultName = bindingFault.getName();
      
         Part[] faultParts = WsdlUtils.getFaultParts( bindingOperation, faultName );
         if( faultParts.length == 0 ) 
         {
           log.warn( "Missing fault parts in wsdl for fault [" + faultName + "] in bindingOperation [" + bindingOperation.getName() + "]" );
           continue;
         }
         
         if( faultParts.length != 1 ) 
         {
           log.info( "Too many fault parts in wsdl for fault [" + faultName + "] in bindingOperation [" + bindingOperation.getName() + "]" );
           continue;
         }
         
        Part part = faultParts[0];
         QName elementName = part.getElementName();
         if( elementName != null )
         {
            XmlObject[] paths = msgXml.selectPath( "declare namespace env='" + 
                   wsdlContext.getSoapVersion().getEnvelopeNamespace() + "';" +
                  "declare namespace ns='" + elementName.getNamespaceURI() + "';" +
                  "//env:Fault/detail/ns:" + elementName.getLocalPart() );
            
            if( paths.length == 1 )
            {
               SchemaGlobalElement elm = wsdlContext.getSchemaTypeLoader().findElement( elementName );
               if( elm != null )
               {
                 validateMessageBody( errors, elm.getType(), paths[0]);
               }
               else errors.add( XmlError.forMessage("Missing fault part element [" + elementName + "] for fault [" + 
                     part.getName() + "] in associated schema") );
               
               return;
            }
         }
         // this is not allowed by Basic Profile.. remove?
         else if( part.getTypeName() != null )
         {
            QName typeName = part.getTypeName();
            
            XmlObject[] paths = msgXml.selectPath( "declare namespace env='" + 
                   wsdlContext.getSoapVersion().getEnvelopeNamespace() + "';" +
                  "declare namespace ns='" + typeName.getNamespaceURI() + "';" +
                  "//env:Fault/detail/ns:" + part.getName() );
            
            if( paths.length == 1 )
            {
               SchemaType type = wsdlContext.getSchemaTypeLoader().findType( typeName );
               if( type != null )
               {
                 validateMessageBody( errors, type, paths[0]);
               }
               else errors.add( XmlError.forMessage("Missing fault part type [" + typeName + "] for fault [" + 
                     part.getName() + "] in associated schema") );
               
               return;
            }
         }
      }

      // if we get here, no matching fault was found.. this is not an error but should be warned.. 
      XmlObject[] paths = msgXml.selectPath( "declare namespace env='" + 
             wsdlContext.getSoapVersion().getEnvelopeNamespace() + "';" +
            "//env:Fault/detail" );
      
      if( paths.length == 0 )
        log.warn( "Missing matching Fault in wsdl for bindingOperation [" + bindingOperation.getName() + "]" );
      else
        log.warn( "Missing matching Fault in wsdl for Fault Detail element [" + 
              XmlUtils.getFirstChildElement( ( Element ) paths[0].getDomNode() ).getNodeName() + 
              "] in bindingOperation [" + bindingOperation.getName() + "]" );
   }
}
java2s.com  | Contact Us | Privacy Policy
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.