1
2
3
4
5
6
7
8
9
10
11
12
13 package com.eviware.soapui.impl.wsdl.support.wsdl;
14
15 import java.util.ArrayList;
16 import java.util.Iterator;
17 import java.util.List;
18 import java.util.Map;
19
20 import javax.wsdl.Binding;
21 import javax.wsdl.BindingFault;
22 import javax.wsdl.BindingOperation;
23 import javax.wsdl.Part;
24 import javax.wsdl.Port;
25 import javax.wsdl.Service;
26 import javax.wsdl.extensions.mime.MIMEContent;
27 import javax.xml.namespace.QName;
28
29 import org.apache.log4j.Logger;
30 import org.apache.xmlbeans.SchemaGlobalElement;
31 import org.apache.xmlbeans.SchemaType;
32 import org.apache.xmlbeans.XmlCursor;
33 import org.apache.xmlbeans.XmlError;
34 import org.apache.xmlbeans.XmlException;
35 import org.apache.xmlbeans.XmlLineNumber;
36 import org.apache.xmlbeans.XmlObject;
37 import org.apache.xmlbeans.XmlOptions;
38 import org.apache.xmlbeans.XmlValidationError;
39 import org.w3c.dom.Element;
40
41 import com.eviware.soapui.SoapUI;
42 import com.eviware.soapui.impl.wsdl.WsdlOperation;
43 import com.eviware.soapui.impl.wsdl.submit.WsdlMessageExchange;
44 import com.eviware.soapui.impl.wsdl.teststeps.assertions.AssertionError;
45 import com.eviware.soapui.model.iface.Attachment;
46 import com.eviware.soapui.settings.WsdlSettings;
47
48 /***
49 * Class for validating SOAP requests/responses against their definition and schema, requires that
50 * the messages follow basic-profile requirements
51 *
52 * @author Ole.Matzura
53 */
54
55 public class WsdlValidator
56 {
57 private final WsdlContext wsdlContext;
58 private final static Logger log = Logger.getLogger( WsdlValidator.class );
59
60 public WsdlValidator( WsdlContext wsdlContext )
61 {
62 this.wsdlContext = wsdlContext;
63 }
64
65 @SuppressWarnings("unchecked")
66 public AssertionError [] assertRequest( WsdlMessageExchange messageExchange, boolean envelopeOnly )
67 {
68 List<XmlError> errors = new ArrayList<XmlError>();
69 try
70 {
71 String requestContent = messageExchange.getRequestContent();
72 wsdlContext.getSoapVersion().validateSoapEnvelope(requestContent, errors);
73
74 if (errors.isEmpty() && !envelopeOnly )
75 {
76 wsdlContext.getSoapVersion().validateSoapEnvelope(requestContent, errors);
77 WsdlOperation operation = messageExchange.getOperation();
78 String operationName = operation.getBindingOperationName();
79 BindingOperation bindingOperation = findBindingOperation(operationName);
80 if (bindingOperation == null)
81 {
82 errors.add(XmlError.forMessage("Missing operation ["
83 + operationName + "] in wsdl definition"));
84 }
85 else
86 {
87 Part[] inputParts = WsdlUtils.getInputParts(bindingOperation);
88 validateMessage(messageExchange, requestContent, bindingOperation, inputParts, errors, false);
89
90 }
91 }
92 }
93 catch( XmlException e )
94 {
95 errors.addAll( e.getErrors() );
96 errors.add( XmlError.forMessage( e.getMessage() ));
97 }
98 catch (Exception e)
99 {
100 errors.add( XmlError.forMessage( e.getMessage() ));
101 }
102
103 return convertErrors( errors );
104 }
105
106 private void validateInputAttachments(WsdlMessageExchange messageExchange, List<XmlError> errors, BindingOperation bindingOperation, Part[] inputParts)
107 {
108 for( Part part : inputParts )
109 {
110 MIMEContent[] contents = WsdlUtils.getInputMultipartContent( part, bindingOperation );
111 if( contents.length == 0 )
112 continue;
113
114 Attachment [] attachments = messageExchange.getRequestAttachmentsForPart( part.getName() );
115 if( attachments.length == 0 )
116 {
117 errors.add(XmlError.forMessage("Missing attachment for part [" + part.getName() + "]" ));
118 }
119 else if( attachments.length == 1 )
120 {
121 Attachment attachment = attachments[0];
122 String types = "";
123 for( MIMEContent content : contents )
124 {
125 String type = content.getType();
126 if( type.equals( attachment.getContentType() ) || type.toUpperCase().startsWith( "MULTIPART" ))
127 {
128 types = null;
129 break;
130 }
131 if( types.length() > 0 )
132 types += ",";
133
134 types += type;
135 }
136
137 if( types != null )
138 {
139 String msg = "Missing attachment for part [" + part.getName() +"] with content-type [" + types + "]," +
140 " content type is [" + attachment.getContentType() + "]";
141
142 if( SoapUI.getSettings().getBoolean( WsdlSettings.ALLOW_INCORRECT_CONTENTTYPE ))
143 log.warn( msg );
144 else
145 errors.add(XmlError.forMessage(msg ));
146 }
147 }
148 else
149 {
150 String types = "";
151 for( MIMEContent content : contents )
152 {
153 String type = content.getType();
154 if( type.toUpperCase().startsWith( "MULTIPART" ))
155 {
156 types = null;
157 break;
158 }
159 if( types.length() > 0 )
160 types += ",";
161
162 types += type;
163 }
164
165 if( types == null )
166 {
167 String msg = "To many attachments for part [" + part.getName() + "] with content-type [" + types + "]";
168 if( SoapUI.getSettings().getBoolean( WsdlSettings.ALLOW_INCORRECT_CONTENTTYPE ))
169 log.warn( msg );
170 else
171 errors.add(XmlError.forMessage(msg ));
172 }
173 }
174 }
175 }
176
177 private void validateOutputAttachments(WsdlMessageExchange messageExchange, XmlObject xml, List<XmlError> errors, BindingOperation bindingOperation, Part[] outputParts) throws Exception
178 {
179 for( Part part : outputParts )
180 {
181 MIMEContent[] contents = WsdlUtils.getOutputMultipartContent( part, bindingOperation );
182 if( contents.length == 0 )
183 continue;
184
185 Attachment [] attachments = messageExchange.getResponseAttachmentsForPart( part.getName() );
186
187
188 if( attachments.length == 0 && WsdlUtils.isRpc( wsdlContext.getDefinition(), bindingOperation ))
189 {
190 XmlObject[] rpcBodyPart = getRpcBodyPart( bindingOperation, xml, true );
191 if( rpcBodyPart.length == 1 )
192 {
193 XmlObject[] children = rpcBodyPart[0].selectChildren( new QName( part.getName() ));
194 if( children.length == 1 )
195 {
196 String href = ((Element)children[0].getDomNode()).getAttribute( "href" );
197 if( href != null )
198 {
199 if( href.startsWith( "cid:" ))
200 href = href.substring( 4 );
201
202 attachments = messageExchange.getResponseAttachmentsForPart( href );
203 }
204 }
205 }
206 }
207
208 if( attachments.length == 0 )
209 {
210 errors.add(XmlError.forMessage("Missing attachment for part [" + part.getName() + "]" ));
211 }
212 else if( attachments.length == 1 )
213 {
214 Attachment attachment = attachments[0];
215 String types = "";
216 for( MIMEContent content : contents )
217 {
218 String type = content.getType();
219 if( type.equals( attachment.getContentType() ) || type.toUpperCase().startsWith( "MULTIPART" ))
220 {
221 types = null;
222 break;
223 }
224
225 if( types.length() > 0 )
226 types += ",";
227
228 types += type;
229 }
230
231 if( types != null)
232 {
233 String msg = "Missing attachment for part [" + part.getName() +
234 "] with content-type [" + types + "], content type is [" + attachment.getContentType() + "]";
235
236 if( SoapUI.getSettings().getBoolean( WsdlSettings.ALLOW_INCORRECT_CONTENTTYPE ))
237 log.warn( msg );
238 else
239 errors.add(XmlError.forMessage(msg ));
240 }
241 }
242 else
243 {
244 String types = "";
245 for( MIMEContent content : contents )
246 {
247 String type = content.getType();
248 if( type.toUpperCase().startsWith( "MULTIPART" ))
249 {
250 types = null;
251 break;
252 }
253
254 if( types.length() > 0 )
255 types += ",";
256
257 types += type;
258 }
259
260 if( types != null )
261 {
262 String msg = "To many attachments for part [" + part.getName() + "] with content-type [" + types + "]";
263
264 if( SoapUI.getSettings().getBoolean( WsdlSettings.ALLOW_INCORRECT_CONTENTTYPE ))
265 log.warn( msg );
266 else
267 errors.add(XmlError.forMessage(msg ));
268 }
269 }
270 }
271 }
272
273 public XmlObject [] getInputParts( String request, String operationName ) throws Exception
274 {
275 BindingOperation bindingOperation = findBindingOperation(operationName);
276 if (bindingOperation == null)
277 {
278 throw new Exception("Missing operation [" + operationName + "] in wsdl definition");
279 }
280
281 if( !wsdlContext.hasSchemaTypes() )
282 {
283 throw new Exception("Missing schema types for message");
284 }
285
286 XmlObject msgXml = XmlObject.Factory.parse( request );
287 Part[] inputParts = WsdlUtils.getInputParts(bindingOperation);
288 if( inputParts == null || inputParts.length == 0 )
289 throw new Exception( "Missing input parts for operation [" + operationName + "]" );
290
291 List<XmlObject> result = new ArrayList<XmlObject>();
292
293 if( WsdlUtils.isRpc( wsdlContext.getDefinition(), bindingOperation ))
294 {
295
296 XmlObject[] paths = msgXml.selectPath( "declare namespace env='" +
297 wsdlContext.getSoapVersion().getEnvelopeNamespace() + "';" +
298 "declare namespace ns='" + wsdlContext.getDefinition().getTargetNamespace() + "';" +
299 "$this/env:Envelope/env:Body/ns:" + bindingOperation.getName() );
300
301 if( paths.length != 1 )
302 {
303 throw new Exception("Missing message wrapper element [" +
304 wsdlContext.getDefinition().getTargetNamespace() + "@" + bindingOperation.getName() );
305 }
306 else
307 {
308 XmlObject wrapper = paths[0];
309
310 for (int i = 0; i < inputParts.length; i++)
311 {
312 Part part = inputParts[i];
313 if( WsdlUtils.isAttachmentInputPart( part, bindingOperation ))
314 continue;
315
316 QName partName = part.getElementName();
317 if( partName == null )
318 partName = new QName( part.getName() );
319
320 XmlObject[] children = wrapper.selectChildren( partName );
321 if( children.length != 1 )
322 {
323 log.error("Missing message part [" + part.getName() + "]" );
324 }
325 else
326 {
327 QName typeName = part.getTypeName();
328 if( typeName == null )
329 {
330 typeName = partName;
331 SchemaGlobalElement type = wsdlContext.getSchemaTypeLoader().findElement( typeName );
332
333 if( type != null )
334 {
335 result.add( children[0].copy().changeType( type.getType() ));
336 }
337 else log.error( "Missing element [" + typeName + "] in associated schema for part [" + part.getName() + "]" );
338 }
339 else
340 {
341 SchemaType type = wsdlContext.getSchemaTypeLoader().findType( typeName );
342 if( type != null )
343 {
344 result.add( children[0].copy().changeType( type ));
345 }
346 else log.error( "Missing type [" + typeName + "] in associated schema for part [" + part.getName() + "]" );
347 }
348 }
349 }
350 }
351 }
352 else
353 {
354 Part part = inputParts[0];
355 QName elementName = part.getElementName();
356 if( elementName != null )
357 {
358
359 XmlObject[] paths = msgXml.selectPath( "declare namespace env='" +
360 wsdlContext.getSoapVersion().getEnvelopeNamespace() + "';" +
361 "declare namespace ns='" + elementName.getNamespaceURI() + "';" +
362 "$this/env:Envelope/env:Body/ns:" + elementName.getLocalPart() );
363
364 if( paths.length == 1 )
365 {
366 SchemaGlobalElement elm = wsdlContext.getSchemaTypeLoader().findElement( elementName );
367 if( elm != null )
368 {
369 result.add( paths[0].copy().changeType( elm.getType() ));
370 }
371 else throw new Exception("Missing part type in associated schema" );
372 }
373 else throw new Exception("Missing message part with name [" + elementName + "]" );
374 }
375 }
376
377 return result.toArray( new XmlObject[result.size()] );
378 }
379
380
381 @SuppressWarnings({ "unchecked", "unchecked" })
382 public void validateXml(String request, List<XmlError> errors )
383 {
384 try
385 {
386 XmlOptions xmlOptions = new XmlOptions();
387 xmlOptions.setLoadLineNumbers();
388 xmlOptions.setErrorListener(errors);
389 xmlOptions.setLoadLineNumbers(XmlOptions.LOAD_LINE_NUMBERS_END_ELEMENT);
390 XmlObject.Factory.parse(request, xmlOptions);
391 }
392 catch( XmlException e )
393 {
394 errors.addAll( e.getErrors() );
395 errors.add( XmlError.forMessage( e.getMessage() ));
396 }
397 catch (Exception e)
398 {
399 errors.add( XmlError.forMessage( e.getMessage() ));
400 }
401 }
402
403 private AssertionError[] convertErrors(List<XmlError> errors)
404 {
405 if( errors.size() > 0 )
406 {
407 List<AssertionError> response = new ArrayList<AssertionError>();
408 for (Iterator<XmlError> i = errors.iterator(); i.hasNext();)
409 {
410 XmlError error = i.next();
411
412 if( error instanceof XmlValidationError )
413 {
414 XmlValidationError e = ((XmlValidationError)error);
415 QName offendingQName = e.getOffendingQName();
416 if( offendingQName != null )
417 {
418 if( offendingQName.equals( new QName( wsdlContext.getSoapVersion().getEnvelopeNamespace(), "encodingStyle")))
419 {
420 log.debug( "ignoring encodingStyle validation..");
421 continue;
422 }
423 else if( offendingQName.equals( new QName( wsdlContext.getSoapVersion().getEnvelopeNamespace(), "mustUnderstand")))
424 {
425 log.debug( "ignoring mustUnderstand validation..");
426 continue;
427 }
428 }
429 }
430
431 AssertionError assertionError = new AssertionError(error);
432 if( !response.contains( assertionError ))
433 response.add( assertionError );
434 }
435
436 return response.toArray( new AssertionError[response.size()] );
437 }
438
439 return new AssertionError[0];
440 }
441
442 @SuppressWarnings("unchecked")
443 public void validateMessage( WsdlMessageExchange messageExchange, String message, BindingOperation bindingOperation, Part [] parts, List<XmlError> errors, boolean isResponse )
444 {
445 try
446 {
447 if( !wsdlContext.hasSchemaTypes() )
448 {
449 errors.add( XmlError.forMessage( "Missing schema types for message"));
450 }
451 else
452 {
453 if( !WsdlUtils.isOutputSoapEncoded( bindingOperation))
454 {
455 XmlOptions xmlOptions = new XmlOptions();
456 xmlOptions.setLoadLineNumbers();
457 xmlOptions.setLoadLineNumbers(XmlOptions.LOAD_LINE_NUMBERS_END_ELEMENT);
458 XmlObject xml = XmlObject.Factory.parse( message, xmlOptions );
459
460 XmlObject[] paths = xml.selectPath( "declare namespace env='" +
461 wsdlContext.getSoapVersion().getEnvelopeNamespace() + "';" +
462 "$this/env:Envelope/env:Body/env:Fault");
463
464 if( paths.length > 0 )
465 {
466 validateSoapFault( bindingOperation, paths[0], errors );
467 }
468 else if( WsdlUtils.isRpc( wsdlContext.getDefinition(), bindingOperation ))
469 {
470 validateRpcLiteral( bindingOperation, parts, xml, errors, isResponse );
471 }
472 else
473 {
474 validateDocLiteral( bindingOperation, parts, xml, errors, isResponse );
475 }
476
477 if( isResponse )
478 validateOutputAttachments( messageExchange, xml, errors, bindingOperation, parts );
479 else
480 validateInputAttachments( messageExchange, errors, bindingOperation, parts );
481 }
482 else errors.add( XmlError.forMessage( "Validation of SOAP-Encoded messages not supported"));
483 }
484 }
485 catch ( XmlException e )
486 {
487 errors.addAll( e.getErrors() );
488 errors.add( XmlError.forMessage( e.getMessage() ));
489 }
490 catch (Exception e)
491 {
492 errors.add( XmlError.forMessage( e.getMessage() ));
493 }
494 }
495
496 private BindingOperation findBindingOperation(String operationName) throws Exception
497 {
498 Map services = wsdlContext.getDefinition().getAllServices();
499 Iterator i = services.keySet().iterator();
500 while( i.hasNext() )
501 {
502 Service service = (Service) wsdlContext.getDefinition().getService( (QName) i.next());
503 Map ports = service.getPorts();
504
505 Iterator iterator = ports.keySet().iterator();
506 while( iterator.hasNext() )
507 {
508 Port port = (Port) service.getPort( (String) iterator.next() );
509 BindingOperation bindingOperation = port.getBinding().getBindingOperation( operationName, null, null );
510 if( bindingOperation != null ) return bindingOperation;
511 }
512 }
513
514 Map bindings = wsdlContext.getDefinition().getAllBindings();
515 i = bindings.keySet().iterator();
516 while( i.hasNext() )
517 {
518 Binding binding = (Binding) bindings.get( i.next() );
519 BindingOperation bindingOperation = binding.getBindingOperation( operationName, null, null );
520 if( bindingOperation != null ) return bindingOperation;
521 }
522
523 return null;
524 }
525
526 @SuppressWarnings("unchecked")
527 public AssertionError [] assertResponse( WsdlMessageExchange messageExchange, boolean envelopeOnly )
528 {
529 List<XmlError> errors = new ArrayList<XmlError>();
530 try
531 {
532 String response = messageExchange.getResponseContent();
533 wsdlContext.getSoapVersion().validateSoapEnvelope(response, errors);
534
535 if (errors.isEmpty() && !envelopeOnly )
536 {
537 WsdlOperation operation = messageExchange.getOperation();
538 String operationName = operation.getBindingOperationName();
539 BindingOperation bindingOperation = findBindingOperation(operationName);
540 if (bindingOperation == null)
541 {
542 errors.add(XmlError.forMessage("Missing operation ["
543 + operationName + "] in wsdl definition"));
544 }
545 else
546 {
547 Part[] outputParts = WsdlUtils.getOutputParts(bindingOperation);
548 validateMessage(messageExchange, response, bindingOperation, outputParts, errors, true);
549 }
550 }
551 }
552 catch ( XmlException e )
553 {
554 errors.addAll( e.getErrors() );
555 errors.add( XmlError.forMessage( e.getMessage() ));
556 }
557 catch (Exception e)
558 {
559 errors.add( XmlError.forMessage( e.getMessage() ));
560 }
561
562 return convertErrors( errors );
563 }
564
565 private void validateDocLiteral(BindingOperation bindingOperation, Part[] parts, XmlObject msgXml, List<XmlError> errors, boolean isResponse) throws Exception
566 {
567 Part part = null;
568
569
570 for( int c = 0; c < parts.length; c++ )
571 {
572
573 if( (isResponse && !WsdlUtils.isAttachmentOutputPart( parts[c], bindingOperation )) ||
574 (!isResponse && !WsdlUtils.isAttachmentInputPart( parts[c], bindingOperation )))
575 {
576
577 if( part != null )
578 {
579 errors.add( XmlError.forMessage("DocLiteral message must contain 1 body part definition" ));
580 return;
581 }
582
583 part = parts[c];
584 }
585 }
586
587 QName elementName = part.getElementName();
588 if( elementName != null )
589 {
590
591 XmlObject[] paths = msgXml.selectPath( "declare namespace env='" +
592 wsdlContext.getSoapVersion().getEnvelopeNamespace() + "';" +
593 "declare namespace ns='" + elementName.getNamespaceURI() + "';" +
594 "$this/env:Envelope/env:Body/ns:" + elementName.getLocalPart() );
595
596 if( paths.length == 1 )
597 {
598 SchemaGlobalElement elm = wsdlContext.getSchemaTypeLoader().findElement( elementName );
599 if( elm != null )
600 {
601 validateMessageBody(errors, elm.getType(), paths[0]);
602 }
603 else errors.add( XmlError.forMessage("Missing part type in associated schema") );
604 }
605 else errors.add( XmlError.forMessage("Missing message part with name [" + elementName + "]" ));
606 }
607 else if( part.getTypeName() != null )
608 {
609 QName typeName = part.getTypeName();
610
611 XmlObject[] paths = msgXml.selectPath( "declare namespace env='" +
612 wsdlContext.getSoapVersion().getEnvelopeNamespace() + "';" +
613 "declare namespace ns='" + typeName.getNamespaceURI() + "';" +
614 "$this/env:Envelope/env:Body/ns:" + part.getName() );
615
616 if( paths.length == 1 )
617 {
618 SchemaType type = wsdlContext.getSchemaTypeLoader().findType( typeName );
619 if( type != null )
620 {
621 validateMessageBody( errors, type, paths[0] );
622
623
624 }
625 else errors.add(XmlError.forMessage( "Missing part type in associated schema") );
626 }
627 else errors.add( XmlError.forMessage("Missing message part with name:type [" +
628 part.getName() + ":" + typeName + "]" ));
629 }
630 }
631
632 private void validateMessageBody(List<XmlError> errors, SchemaType type, XmlObject msg) throws XmlException
633 {
634
635
636 XmlOptions xmlOptions = new XmlOptions();
637 xmlOptions.setLoadLineNumbers();
638 xmlOptions.setLoadLineNumbers(XmlOptions.LOAD_LINE_NUMBERS_END_ELEMENT);
639
640 String xmlText = msg.copy().changeType( type ).xmlText( xmlOptions.setSaveOuter());
641 XmlObject obj = type.getTypeSystem().parse( xmlText, type, xmlOptions );
642 obj = obj.changeType( type );
643
644
645 List list = new ArrayList();
646
647 xmlOptions = new XmlOptions();
648 xmlOptions.setErrorListener( list );
649 xmlOptions.setValidateTreatLaxAsSkip();
650 obj.validate( xmlOptions );
651
652
653 for( int c = 0; c < list.size(); c++ )
654 {
655 XmlError error = (XmlError) list.get( c );
656
657 if( error instanceof XmlValidationError )
658 {
659 XmlValidationError validationError = ((XmlValidationError)error);
660
661 if( wsdlContext.getSoapVersion().shouldIgnore( validationError ))
662 continue;
663
664
665 if( validationError.getErrorCode().equals( "base64Binary") || validationError.getErrorCode().equals( "hexBinary"))
666 {
667 XmlCursor cursor = validationError.getCursorLocation();
668 if( cursor.toParent() )
669 {
670 String text = cursor.getTextValue();
671
672
673 if( text.startsWith( "cid:" ) || text.startsWith( "file:" ))
674 {
675
676 continue;
677 }
678 }
679 }
680 }
681
682 int line = error.getLine() == -1 ? 0 : error.getLine()-1;
683 errors.add( XmlError.forLocation( error.getMessage(), error.getSourceName(),
684 getLine( msg ) + line, error.getColumn(), error.getOffset() ));
685 }
686 }
687
688 private int getLine(XmlObject object)
689 {
690 List list = new ArrayList();
691 object.newCursor().getAllBookmarkRefs( list );
692 for( int c = 0; c < list.size(); c++ )
693 {
694 if( list.get( c ) instanceof XmlLineNumber )
695 {
696 return ((XmlLineNumber)list.get(c)).getLine();
697 }
698 }
699
700 return -1;
701 }
702
703 private void validateRpcLiteral(BindingOperation bindingOperation, Part[] parts, XmlObject msgXml, List<XmlError> errors, boolean isResponse ) throws Exception
704 {
705 if( parts.length == 0 )
706 return;
707
708 XmlObject[] bodyParts = getRpcBodyPart(bindingOperation, msgXml, isResponse);
709
710 if( bodyParts.length != 1 )
711 {
712 errors.add( XmlError.forMessage("Missing message wrapper element [" +
713 wsdlContext.getDefinition().getTargetNamespace() + "@" + bindingOperation.getName()
714 + (isResponse ? "Response" : "" )));
715 }
716 else
717 {
718 XmlObject wrapper = bodyParts[0];
719
720 for (int i = 0; i < parts.length; i++)
721 {
722 Part part = parts[i];
723
724
725 if( isResponse )
726 {
727 if( WsdlUtils.isAttachmentOutputPart( part, bindingOperation ) )
728 continue;
729 }
730 else
731 {
732 if( WsdlUtils.isAttachmentInputPart( part, bindingOperation ) )
733 continue;
734 }
735
736
737 XmlObject[] children = wrapper.selectChildren( new QName( part.getName() ));
738
739
740 if( children.length != 1 )
741 {
742
743 QName elementName = part.getElementName();
744 if( elementName != null )
745 {
746 bodyParts = msgXml.selectPath( "declare namespace env='" +
747 wsdlContext.getSoapVersion().getEnvelopeNamespace() + "';" +
748 "declare namespace ns='" + wsdlContext.getDefinition().getTargetNamespace() + "';" +
749 "declare namespace ns2='" + elementName.getNamespaceURI() + "';" +
750 "$this/env:Envelope/env:Body/ns:" + bindingOperation.getName() + (isResponse ? "Response" : "" ) +
751 "/ns2:" + elementName.getLocalPart() );
752
753 if( bodyParts.length == 1 )
754 {
755 SchemaGlobalElement elm = wsdlContext.getSchemaTypeLoader().findElement( elementName );
756 if( elm != null )
757 {
758 validateMessageBody(errors, elm.getType(), bodyParts[0]);
759 }
760 else errors.add( XmlError.forMessage("Missing part type in associated schema for [" + elementName + "]" ) );
761 }
762 else errors.add( XmlError.forMessage("Missing message part with name [" + elementName + "]" ));
763 }
764 else
765 {
766 errors.add( XmlError.forMessage("Missing message part [" + part.getName() + "]" ));
767 }
768 }
769 else
770 {
771 QName typeName = part.getTypeName();
772 SchemaType type = wsdlContext.getSchemaTypeLoader().findType( typeName );
773 if( type != null )
774 {
775 validateMessageBody( errors, type, children[0]);
776 }
777 else errors.add( XmlError.forMessage("Missing type in associated schema for part [" + part.getName() + "]" ));
778 }
779 }
780 }
781 }
782
783 private XmlObject[] getRpcBodyPart(BindingOperation bindingOperation, XmlObject msgXml, boolean isResponse) throws Exception
784 {
785
786 String ns = WsdlUtils.getSoapBodyNamespace( isResponse ?
787 bindingOperation.getBindingOutput().getExtensibilityElements() :
788 bindingOperation.getBindingInput().getExtensibilityElements() );
789
790 if( ns == null || ns.trim().length() == 0 )
791 ns = wsdlContext.getDefinition().getTargetNamespace();
792
793
794 XmlObject[] paths = msgXml.selectPath( "declare namespace env='" + wsdlContext.getSoapVersion().getEnvelopeNamespace() + "';" +
795 "declare namespace ns='" + ns + "';" + "$this/env:Envelope/env:Body/ns:" +
796 bindingOperation.getName() + (isResponse ? "Response" : "" ));
797 return paths;
798 }
799
800 @SuppressWarnings("unchecked")
801 private void validateSoapFault(BindingOperation bindingOperation, XmlObject msgXml, List<XmlError> errors) throws Exception
802 {
803 Map faults = bindingOperation.getBindingFaults();
804 Iterator<BindingFault> i = faults.values().iterator();
805
806 while( i.hasNext() )
807 {
808 BindingFault bindingFault = i.next();
809 String faultName = bindingFault.getName();
810
811 Part[] faultParts = WsdlUtils.getFaultParts( bindingOperation, faultName );
812 if( faultParts.length != 1 )
813 {
814 log.info( "Missing fault parts in wsdl for fault [" + faultName + "]" );
815 continue;
816 }
817
818 Part part = faultParts[0];
819 QName elementName = part.getElementName();
820 if( elementName != null )
821 {
822 XmlObject[] paths = msgXml.selectPath( "declare namespace env='" +
823 wsdlContext.getSoapVersion().getEnvelopeNamespace() + "';" +
824 "declare namespace ns='" + elementName.getNamespaceURI() + "';" +
825 "//env:Envelope/env:Body/env:Fault/detail/ns:" + elementName.getLocalPart() );
826
827 if( paths.length == 1 )
828 {
829 SchemaGlobalElement elm = wsdlContext.getSchemaTypeLoader().findElement( elementName );
830 if( elm != null )
831 {
832 validateMessageBody( errors, elm.getType(), paths[0]);
833 break;
834 }
835 else errors.add( XmlError.forMessage("Missing fault part type in associated schema") );
836 }
837 else log.info("Missing fault part in message with name [" + elementName + "]");
838 }
839
840 else if( part.getTypeName() != null )
841 {
842 QName typeName = part.getTypeName();
843
844 XmlObject[] paths = msgXml.selectPath( "declare namespace env='" +
845 wsdlContext.getSoapVersion().getEnvelopeNamespace() + "';" +
846 "declare namespace ns='" + typeName.getNamespaceURI() + "';" +
847 "$this/env:Envelope/env:Fault/detail/ns:" + part.getName() );
848
849 if( paths.length == 1 )
850 {
851 SchemaType type = wsdlContext.getSchemaTypeLoader().findType( typeName );
852 if( type != null )
853 {
854 validateMessageBody( errors, type, paths[0]);
855 }
856 else errors.add( XmlError.forMessage( "Missing part type in associated schema" ) );
857 }
858 else log.info("Missing message part with name:type [" + part.getName() + ":" + typeName + "]");
859 }
860 }
861 }
862 }