View Javadoc

1   /*
2    *  soapUI, copyright (C) 2004-2007 eviware.com 
3    *
4    *  soapUI is free software; you can redistribute it and/or modify it under the 
5    *  terms of version 2.1 of the GNU Lesser General Public License as published by 
6    *  the Free Software Foundation.
7    *
8    *  soapUI is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without 
9    *  even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 
10   *  See the GNU Lesser General Public License for more details at gnu.org.
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.BindingOutput;
24  import javax.wsdl.Definition;
25  import javax.wsdl.Fault;
26  import javax.wsdl.Message;
27  import javax.wsdl.Operation;
28  import javax.wsdl.Part;
29  import javax.wsdl.Port;
30  import javax.wsdl.Service;
31  import javax.wsdl.extensions.ExtensibilityElement;
32  import javax.wsdl.extensions.mime.MIMEContent;
33  import javax.wsdl.extensions.mime.MIMEMultipartRelated;
34  import javax.wsdl.extensions.mime.MIMEPart;
35  import javax.wsdl.extensions.soap.SOAPAddress;
36  import javax.wsdl.extensions.soap.SOAPBinding;
37  import javax.wsdl.extensions.soap.SOAPBody;
38  import javax.wsdl.extensions.soap.SOAPFault;
39  import javax.wsdl.extensions.soap.SOAPHeader;
40  import javax.wsdl.extensions.soap.SOAPOperation;
41  import javax.wsdl.extensions.soap12.SOAP12Address;
42  import javax.wsdl.extensions.soap12.SOAP12Binding;
43  import javax.wsdl.extensions.soap12.SOAP12Body;
44  import javax.wsdl.extensions.soap12.SOAP12Fault;
45  import javax.wsdl.extensions.soap12.SOAP12Header;
46  import javax.wsdl.extensions.soap12.SOAP12Operation;
47  import javax.wsdl.factory.WSDLFactory;
48  import javax.wsdl.xml.WSDLReader;
49  import javax.xml.namespace.QName;
50  
51  import org.apache.log4j.Logger;
52  import org.apache.xmlbeans.SchemaGlobalElement;
53  import org.apache.xmlbeans.SchemaType;
54  
55  import com.eviware.soapui.impl.wsdl.WsdlRequest;
56  
57  /***
58   * Wsdl-related tools
59   * 
60   * @author Ole.Matzura
61   */
62  
63  public class WsdlUtils
64  {
65     private final static Logger log = Logger.getLogger( WsdlUtils.class );
66  	private static WSDLReader wsdlReader;
67     
68     public static <T extends ExtensibilityElement> T getExtensiblityElement(List list, Class<T> clazz )
69     {
70        List<T> elements = getExtensiblityElements( list, clazz );
71        return elements.isEmpty() ? null : elements.get( 0 );
72     }
73     
74     public static <T extends ExtensibilityElement> List<T> getExtensiblityElements(List list, Class<T> clazz )
75     {
76        List<T> result = new ArrayList<T>();
77        
78        for( Iterator<T> i = list.iterator(); i.hasNext(); )
79        {
80           T elm = (T) i.next();
81           if( clazz.isAssignableFrom( elm.getClass() ) )
82           {
83              result.add( elm );
84           }
85        }
86  
87        return result;
88     }
89     
90     public static String getSoapAction(BindingOperation operation)
91     {
92        List list = operation.getExtensibilityElements();
93        SOAPOperation soapOperation = (SOAPOperation) WsdlUtils.getExtensiblityElement( list, SOAPOperation.class );
94        if( soapOperation != null )
95        	return soapOperation.getSoapActionURI();
96        
97        SOAP12Operation soap12Operation = (SOAP12Operation) WsdlUtils.getExtensiblityElement( list, SOAP12Operation.class );
98        if( soap12Operation != null )
99        	return soap12Operation.getSoapActionURI();
100       
101       return null;
102    }
103    
104    public static String[] getEndpointsForBinding(Definition definition, Binding binding)
105    {
106       List<String> result = new ArrayList<String>(); 
107       Map map = definition.getAllServices();
108       for( Iterator i = map.values().iterator(); i.hasNext(); )
109       {
110          Service service = (Service) i.next();
111          Map portMap = service.getPorts();
112          for( Iterator i2 = portMap.values().iterator(); i2.hasNext(); )
113          {
114             Port port = (Port) i2.next();
115             if( port.getBinding() == binding )
116             {
117             	String endpoint = WsdlUtils.getSoapEndpoint( port );
118             	if( endpoint != null )
119             		result.add( endpoint );
120             }
121          }
122       }
123       
124       return result.toArray( new String[result.size()]);
125    }
126    
127    public static Binding findBindingForOperation(Definition definition, BindingOperation bindingOperation)
128    {
129       Map services = definition.getAllServices();
130       Iterator<Service> s = services.values().iterator();
131       
132       while( s.hasNext())
133       {
134          Map ports = s.next().getPorts();
135          Iterator<Port> p = ports.values().iterator();
136          while( p.hasNext())
137          {
138             Binding binding = p.next().getBinding();
139             List bindingOperations = binding.getBindingOperations();
140             for (Iterator iter = bindingOperations.iterator(); iter.hasNext();)
141             {
142                BindingOperation op = (BindingOperation) iter.next();
143                if( op.getName().equals( bindingOperation.getName() ))
144                   return binding;
145             }
146          }
147       }
148       
149       Map bindings = definition.getAllBindings();
150       Iterator<QName> names = bindings.keySet().iterator();
151       while( names.hasNext() ) 
152       {
153       	Binding binding = definition.getBinding( names.next() );
154       	List bindingOperations = binding.getBindingOperations();
155          for (Iterator iter = bindingOperations.iterator(); iter.hasNext();)
156          {
157             BindingOperation op = (BindingOperation) iter.next();
158             if( op.getName().equals( bindingOperation.getName() ))
159                return binding;
160          }
161       }
162       
163       return null;
164    }
165    
166    public static boolean isInputSoapEncoded(BindingOperation bindingOperation)
167    {
168       SOAPBody soapBody = (SOAPBody) WsdlUtils.getExtensiblityElement(bindingOperation.getBindingInput()
169             .getExtensibilityElements(), SOAPBody.class);
170       
171       if( soapBody != null )
172       {
173       	return soapBody.getUse() != null && soapBody.getUse().equalsIgnoreCase( "encoded" ) &&
174       		(soapBody.getEncodingStyles() == null || soapBody.getEncodingStyles().contains( "http://schemas.xmlsoap.org/soap/encoding/" ));
175       }
176       
177       SOAP12Body soap12Body = (SOAP12Body) WsdlUtils.getExtensiblityElement(bindingOperation.getBindingInput()
178                .getExtensibilityElements(), SOAP12Body.class);
179          
180       if( soap12Body != null )
181       {
182       	return soap12Body.getUse() != null && soap12Body.getUse().equalsIgnoreCase( "encoded" ) &&
183       		(soap12Body.getEncodingStyle() == null || soap12Body.getEncodingStyle().equals( "http://schemas.xmlsoap.org/soap/encoding/" ));
184       }
185       
186       return false;
187    }
188    
189    public static boolean isOutputSoapEncoded(BindingOperation bindingOperation)
190    {
191       BindingOutput bindingOutput = bindingOperation.getBindingOutput();
192       if( bindingOutput == null )
193       	return false;
194       
195 		SOAPBody soapBody = (SOAPBody) WsdlUtils.getExtensiblityElement(bindingOutput
196             .getExtensibilityElements(), SOAPBody.class);
197       
198 		if( soapBody != null )
199 		{
200 			return soapBody.getUse() != null && soapBody.getUse().equalsIgnoreCase( "encoded" ) &&
201       		(soapBody.getEncodingStyles() == null || soapBody.getEncodingStyles().contains( "http://schemas.xmlsoap.org/soap/encoding/" ));
202 		}
203 		
204 		SOAP12Body soap12Body = (SOAP12Body) WsdlUtils.getExtensiblityElement(bindingOutput
205 	            .getExtensibilityElements(), SOAP12Body.class);
206 	      
207 		if( soap12Body != null )
208 		{
209 			return soap12Body.getUse() != null && soap12Body.getUse().equalsIgnoreCase( "encoded" ) &&
210       		(soap12Body.getEncodingStyle() == null || soap12Body.getEncodingStyle().equals( "http://schemas.xmlsoap.org/soap/encoding/" ));
211 		}
212 		
213 		return false;
214    }
215    
216    public static boolean isRpc(Definition definition, BindingOperation bindingOperation)
217    {
218       SOAPOperation soapOperation = (SOAPOperation) WsdlUtils.getExtensiblityElement( 
219             bindingOperation.getExtensibilityElements(), SOAPOperation.class );
220       
221       if( soapOperation != null && soapOperation.getStyle() != null )
222          return soapOperation.getStyle().equalsIgnoreCase("rpc");
223       
224       SOAP12Operation soap12Operation = (SOAP12Operation) WsdlUtils.getExtensiblityElement( 
225                bindingOperation.getExtensibilityElements(), SOAP12Operation.class );
226          
227       if( soap12Operation != null && soap12Operation.getStyle() != null )
228          return soap12Operation.getStyle().equalsIgnoreCase("rpc");
229       
230       Binding binding = findBindingForOperation( definition, bindingOperation );
231       if( binding == null ) 
232       {
233          log.error( "Failed to find binding for operation [" + bindingOperation.getName() + "] in definition [" + 
234                definition.getDocumentBaseURI() + "]" );
235          return false;
236       }
237       
238       return isRpc(binding);
239    }
240 
241 	public static boolean isRpc(Binding binding)
242 	{
243 		SOAPBinding soapBinding = (SOAPBinding) WsdlUtils.getExtensiblityElement( 
244             binding.getExtensibilityElements(), SOAPBinding.class );
245       
246 		if( soapBinding != null )
247 			return "rpc".equalsIgnoreCase( soapBinding.getStyle());
248 		
249 		SOAP12Binding soap12Binding = (SOAP12Binding) WsdlUtils.getExtensiblityElement( 
250 	            binding.getExtensibilityElements(), SOAP12Binding.class );
251 	      
252 		if( soap12Binding != null )
253 			return "rpc".equalsIgnoreCase( soap12Binding.getStyle());
254 		
255 		return false;
256 	}
257    
258    /***
259     * Returns a list of parts for the specifed operation, either as specified in body or all
260     */
261    
262    public static Part[] getInputParts(BindingOperation operation)
263    {
264       List<Part> result = new ArrayList<Part>();
265       Message msg = operation.getOperation().getInput().getMessage();
266       SOAPBody soapBody = (SOAPBody) WsdlUtils.getExtensiblityElement(operation.getBindingInput()
267             .getExtensibilityElements(), SOAPBody.class);
268 
269       if (soapBody == null || soapBody.getParts() == null)
270       {
271       	SOAP12Body soap12Body = (SOAP12Body) WsdlUtils.getExtensiblityElement(operation.getBindingInput()
272       	            .getExtensibilityElements(), SOAP12Body.class);
273       	
274       	if (soap12Body == null || soap12Body.getParts() == null)
275          {
276       		if( msg != null )
277       			result.addAll( msg.getOrderedParts( null ));
278          }
279       	else
280       	{
281       		Iterator i = soap12Body.getParts().iterator();
282             while (i.hasNext())
283             {
284                String partName = (String) i.next();
285                Part part = msg.getPart( partName );
286                
287                result.add(part);
288             }
289       	}
290       }
291       else
292       {
293          Iterator i = soapBody.getParts().iterator();
294          while (i.hasNext())
295          {
296             String partName = (String) i.next();
297             Part part = msg.getPart( partName );
298             
299             result.add(part);
300          }
301       }
302 
303       return result.toArray(new Part[result.size()]);
304    }
305    
306    public static boolean isAttachmentInputPart( Part part, BindingOperation operation )
307    {
308    	return getInputMultipartContent(part, operation).length > 0;
309    }
310    
311    public static boolean isAttachmentOutputPart( Part part, BindingOperation operation )
312    {
313    	return getOutputMultipartContent(part, operation).length > 0;
314    }
315 
316    public static MIMEContent[] getOutputMultipartContent( Part part, BindingOperation operation )
317    {
318    	MIMEMultipartRelated multipartOutput = (MIMEMultipartRelated) WsdlUtils.getExtensiblityElement( 
319       		operation.getBindingOutput().getExtensibilityElements(), MIMEMultipartRelated.class );
320    	
321    	return getContentParts(part, multipartOutput);
322    }
323    
324    public static MIMEContent[] getInputMultipartContent( Part part, BindingOperation operation )
325    {
326    	MIMEMultipartRelated multipartInput = (MIMEMultipartRelated) WsdlUtils.getExtensiblityElement( 
327       		operation.getBindingInput().getExtensibilityElements(), MIMEMultipartRelated.class );
328    	
329    	return getContentParts(part, multipartInput);
330    }
331    
332 	public static MIMEContent[] getContentParts(Part part, MIMEMultipartRelated multipart)
333 	{
334 		List<MIMEContent> result = new ArrayList<MIMEContent>();
335 		
336 		if( multipart != null )
337    	{
338    		List<MIMEPart> parts = multipart.getMIMEParts();
339 
340       	for( int c = 0; c < parts.size(); c++ )
341       	{
342 	      	List<MIMEContent> contentParts = WsdlUtils.getExtensiblityElements( parts.get(c).getExtensibilityElements(), MIMEContent.class );
343 	      	
344 	      	for( MIMEContent content : contentParts )
345 	      	{
346 	      		if( content.getPart().equals( part.getName() ))
347 	      		  result.add( content );
348 	      	}
349       	}
350    	}
351    	
352    	return result.toArray( new MIMEContent[result.size()] );
353 	}
354    
355    public static Part[] getFaultParts(BindingOperation bindingOperation, String faultName) throws Exception
356    {
357       List<Part> result = new ArrayList<Part>();
358       
359       BindingFault bindingFault = bindingOperation.getBindingFault( faultName );
360       SOAPFault soapFault = (SOAPFault) WsdlUtils.getExtensiblityElement(bindingFault
361             .getExtensibilityElements(), SOAPFault.class);
362 
363       Operation operation = bindingOperation.getOperation();
364 		if (soapFault != null && soapFault.getName() != null )
365       {
366          Fault fault = operation.getFault( soapFault.getName() );
367          if( fault == null ) 
368          	throw new Exception( "Missing Fault [" + soapFault.getName() + "] in operation [" + operation.getName() + "]" );
369 			result.addAll( fault.getMessage().getOrderedParts( null ));
370       }
371       else
372       {
373       	SOAP12Fault soap12Fault = (SOAP12Fault) WsdlUtils.getExtensiblityElement(bindingFault
374                   .getExtensibilityElements(), SOAP12Fault.class);
375       	
376       	 if (soap12Fault != null && soap12Fault.getName() != null )
377           {
378              result.addAll( operation.getFault( soap12Fault.getName() ).getMessage().getOrderedParts( null ));
379           }
380           else
381           {
382          	 result.addAll( operation.getFault( faultName ).getMessage().getOrderedParts( null ));
383           }
384       }
385       
386       return result.toArray(new Part[result.size()]);
387    }
388    
389    public static Part[] getOutputParts(BindingOperation operation)
390    {
391    	BindingOutput bindingOutput = operation.getBindingOutput();
392    	if( bindingOutput == null )
393    		return new Part[0];
394    	
395       List<Part> result = new ArrayList<Part>();
396       Message msg = operation.getOperation().getOutput().getMessage();
397 		SOAPBody soapBody = (SOAPBody) WsdlUtils.getExtensiblityElement(bindingOutput
398             .getExtensibilityElements(), SOAPBody.class);
399 
400       if (soapBody == null || soapBody.getParts() == null)
401       {
402       	SOAP12Body soap12Body = (SOAP12Body) WsdlUtils.getExtensiblityElement(bindingOutput
403                   .getExtensibilityElements(), SOAP12Body.class);
404       	
405       	if(soap12Body == null || soap12Body.getParts() == null)
406       	{
407       		result.addAll( msg.getOrderedParts( null ));
408       	}
409       	else
410       	{
411       		Iterator i = soap12Body.getParts().iterator();
412             while (i.hasNext())
413             {
414                String partName = (String) i.next();
415                Part part = msg.getPart( partName );
416                
417                result.add(part);
418             }
419       	}
420       }
421       else
422       {
423          Iterator i = soapBody.getParts().iterator();
424          while (i.hasNext())
425          {
426             String partName = (String) i.next();
427             Part part = msg.getPart( partName );
428             
429             result.add(part);
430          }
431       }
432 
433       return result.toArray(new Part[result.size()]);
434    }
435 
436 	public static boolean isMultipartRequest(Definition definition, BindingOperation bindingOperation)
437 	{
438 		return (MIMEMultipartRelated) WsdlUtils.getExtensiblityElement(
439 					bindingOperation.getBindingInput().getExtensibilityElements(), MIMEMultipartRelated.class ) != null;
440 	}
441 
442 	public static String getSoapEndpoint( Port port )
443 	{
444 		SOAPAddress soapAddress = (SOAPAddress) WsdlUtils.getExtensiblityElement( port.getExtensibilityElements(), SOAPAddress.class );
445       if( soapAddress != null )
446       	return soapAddress.getLocationURI();
447       
448       SOAP12Address soap12Address = (SOAP12Address) WsdlUtils.getExtensiblityElement( port.getExtensibilityElements(), SOAP12Address.class );
449       if( soap12Address != null )
450       	return soap12Address.getLocationURI();
451       
452       return null;
453 	}
454 
455 	public static String getSoapBodyNamespace( List list )
456 	{
457 		SOAPBody soapBody = (SOAPBody) WsdlUtils.getExtensiblityElement( list, SOAPBody.class);
458 		if( soapBody != null )
459 			return soapBody.getNamespaceURI();
460 		
461 		SOAP12Body soap12Body = (SOAP12Body) WsdlUtils.getExtensiblityElement( list, SOAP12Body.class);
462 		if( soap12Body != null )
463 			return soap12Body.getNamespaceURI();
464 	      
465 		return null;
466 	}
467 	
468 	/***
469 	 * A SOAP-Header wrapper
470 	 * 
471 	 * @author ole.matzura
472 	 */
473 	
474 	public interface SoapHeader
475 	{
476 		public QName getMessage();
477 		
478 		public String getPart();
479 	}
480 	
481 	/***
482 	 * SOAP 1.1 Header implementation
483 	 * 
484 	 * @author ole.matzura
485 	 */
486 	
487 	public static class Soap11Header implements SoapHeader
488 	{
489 		private final SOAPHeader soapHeader;
490 
491 		public Soap11Header( SOAPHeader soapHeader )
492 		{
493 			this.soapHeader = soapHeader;}
494 		
495 		public QName getMessage()
496 		{
497 			return soapHeader.getMessage();
498 		}
499 
500 		public String getPart()
501 		{
502 			return soapHeader.getPart();
503 		}
504 	}
505 	
506 	/***
507 	 * SOAP 1.2 Header implementation
508 	 * 
509 	 * @author ole.matzura
510 	 */
511 
512 	public static class Soap12Header implements SoapHeader
513 	{
514 		private final SOAP12Header soapHeader;
515 
516 		public Soap12Header( SOAP12Header soapHeader )
517 		{
518 			this.soapHeader = soapHeader;}
519 		
520 		public QName getMessage()
521 		{
522 			return soapHeader.getMessage();
523 		}
524 
525 		public String getPart()
526 		{
527 			return soapHeader.getPart();
528 		}
529 	}
530 
531 	public static List<SoapHeader> getSoapHeaders( List list )
532 	{
533 		List<SoapHeader> result = new ArrayList<SoapHeader>();
534 		
535 		List<SOAPHeader> soapHeaders = WsdlUtils.getExtensiblityElements( list, SOAPHeader.class);
536 		if( soapHeaders != null && !soapHeaders.isEmpty() )
537 		{
538 			for( SOAPHeader header : soapHeaders )
539 				result.add( new Soap11Header( header ));
540 		}
541 		else
542 		{
543 			List<SOAP12Header> soap12Headers = WsdlUtils.getExtensiblityElements( list, SOAP12Header.class);
544 			if( soap12Headers != null && !soap12Headers.isEmpty() )
545 			{
546 				for( SOAP12Header header : soap12Headers )
547 					result.add( new Soap12Header( header ));
548 			}
549 		}
550 		
551 		return result;
552 	}
553 
554 	public static synchronized Definition readDefinition( String wsdlUrl ) throws Exception 
555 	{
556 		if( wsdlReader == null )
557 		{
558 		   WSDLFactory factory = WSDLFactory.newInstance();
559 		   wsdlReader = factory.newWSDLReader();
560 		   wsdlReader.setFeature("javax.wsdl.verbose", true);
561 		   wsdlReader.setFeature("javax.wsdl.importDocuments", true);
562 		}
563 		
564 	   return wsdlReader.readWSDL( new UrlWsdlLoader( wsdlUrl ) );
565 	}
566 
567 	public static SchemaType getSchemaTypeForPart( WsdlContext wsdlContext, javax.wsdl.Part part) throws Exception
568 	{
569 		SchemaType schemaType = null;
570 		QName elementName = part.getElementName();
571 		
572 		if( elementName != null )
573 		{
574 		   SchemaGlobalElement elm = wsdlContext.getSchemaTypeLoader().findElement(elementName);
575 		   if( elm != null )
576 		   {
577 		   	schemaType = elm.getType();
578 		   }
579 		   else WsdlRequest.log.error( "Could not find element [" + elementName + "] specified in part [" + part.getName() + "]" );
580 		}
581 		else 
582 		{
583 			QName typeName = part.getTypeName();
584 			
585 		   if( typeName != null  )
586 		   {
587 		      schemaType = wsdlContext.getSchemaTypeLoader().findType( typeName );
588 		      
589 		      if( schemaType == null )
590 		      {
591 		      	WsdlRequest.log.error( "Could not find type [" + typeName + "] specified in part [" + part.getName() + "]" );
592 		      }
593 		   }
594 		}
595 		return schemaType;
596 	}
597 }