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