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