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;
14  
15  import java.util.ArrayList;
16  import java.util.HashMap;
17  import java.util.List;
18  import java.util.Map;
19  
20  import javax.swing.ImageIcon;
21  import javax.wsdl.Binding;
22  import javax.wsdl.BindingOperation;
23  import javax.wsdl.BindingOutput;
24  import javax.wsdl.Definition;
25  import javax.wsdl.Message;
26  import javax.wsdl.extensions.mime.MIMEContent;
27  import javax.wsdl.extensions.mime.MIMEMultipartRelated;
28  import javax.wsdl.extensions.mime.MIMEPart;
29  import javax.xml.namespace.QName;
30  
31  import org.apache.log4j.Logger;
32  import org.apache.xmlbeans.SchemaType;
33  
34  import com.eviware.soapui.SoapUI;
35  import com.eviware.soapui.config.CallConfig;
36  import com.eviware.soapui.config.OperationConfig;
37  import com.eviware.soapui.config.PartsConfig.Part;
38  import com.eviware.soapui.impl.wsdl.support.soap.SoapMessageBuilder;
39  import com.eviware.soapui.impl.wsdl.support.wsdl.WsdlContext;
40  import com.eviware.soapui.impl.wsdl.support.wsdl.WsdlUtils;
41  import com.eviware.soapui.impl.wsdl.support.wsdl.WsdlUtils.SoapHeader;
42  import com.eviware.soapui.model.iface.MessagePart;
43  import com.eviware.soapui.model.iface.Operation;
44  import com.eviware.soapui.model.iface.Request;
45  import com.eviware.soapui.model.iface.MessagePart.FaultPart;
46  import com.eviware.soapui.support.UISupport;
47  
48  /***
49   * WSDL implementation of Operation, maps to a WSDL BindingOperation
50   * 
51   * @author Ole.Matzura
52   */
53  
54  public class WsdlOperation extends AbstractWsdlModelItem<OperationConfig> implements Operation
55  {
56     public static final String STYLE_DOCUMENT = "Document";
57  	public static final String STYLE_RPC = "RPC";
58  	
59  	public final static Logger log = Logger.getLogger( WsdlOperation.class );
60  	private List<WsdlRequest> requests = new ArrayList<WsdlRequest>();
61     private WsdlInterface iface;
62  	private ImageIcon oneWayIcon;
63  
64     public WsdlOperation( WsdlInterface iface, OperationConfig operationConfig )
65     {
66     	super( operationConfig, iface, "/operation.gif" );
67        this.iface = iface;
68        
69        if( operationConfig.isSetIsOneWay())
70        {
71        	operationConfig.setIsOneWay( false );
72        }
73        
74        List<CallConfig> requestConfigs = getConfig().getCallList();
75        for (CallConfig config : requestConfigs)
76        {
77           requests.add( new WsdlRequest( this, config));
78        }
79        
80        oneWayIcon = UISupport.createImageIcon( "/onewayoperation.gif" );
81     }
82     
83  	public String getAction()
84     {
85        return getConfig().getAction();
86     }
87  
88     public WsdlRequest getRequestAt(int index)
89     {
90        return requests.get( index );
91     }
92     
93     public WsdlRequest getRequestByName(String requestName)
94  	{
95  		return (WsdlRequest) getWsdlModelItemByName( requests, requestName );
96  	}
97  
98  	public int getRequestCount()
99     {
100       return requests.size();
101    }
102 
103    public ImageIcon getIcon()
104 	{
105 		if( isOneWay() )
106 			return oneWayIcon;
107 		else
108 			return super.getIcon();
109 	}
110 
111 	public WsdlRequest addNewRequest( String name )
112    {
113       WsdlRequest requestImpl = new WsdlRequest( this, getConfig().addNewCall() );
114       requestImpl.setName( name );
115       requests.add( requestImpl );
116       ((WsdlInterface)getInterface()).fireRequestAdded( requestImpl );
117       return requestImpl;
118    }
119 
120    public WsdlInterface getInterface()
121    {
122       return iface;
123    }
124 
125    public void setAction(String soapAction)
126    {
127       String old = getAction();
128       getConfig().setAction( soapAction );
129       notifyPropertyChanged( ACTION_PROPERTY, old, soapAction );
130    }
131 
132    public String createRequest( boolean buildOptional )
133    {
134       if( iface.getBindingName() == null )
135       {
136       	UISupport.showErrorMessage( "Missing binding name, please try to refresh " +
137                "Interface\nfor request generation to work correctly" );
138          return null;
139       }
140       
141       if( getBindingOperationName() == null )
142       {
143       	UISupport.showErrorMessage(  "Missing bindingOperation name, please try to refresh " +
144                "Interface\nfor request generation to work correctly" );
145          return null;
146       }
147       
148       try
149       {
150          SoapMessageBuilder builder = (SoapMessageBuilder) iface.getMessageBuilder();
151          BindingOperation bindingOperation = findBindingOperation( iface.getWsdlContext().getDefinition() );
152          
153          if( bindingOperation == null )
154          {
155          	UISupport.showErrorMessage( "Failed to find bindingOperation, please try to refresh " +
156                   "Interface\nfor request generation to work correctly" );
157             return null;
158          }
159          
160 			return builder.buildSoapRequest( bindingOperation, buildOptional );
161       }
162       catch (Exception e)
163       {
164          SoapUI.logError( e );
165          return null;
166       }
167    }
168    
169    public String createResponse( boolean buildOptional )
170    {
171       if( iface.getBindingName() == null )
172       {
173       	UISupport.showErrorMessage( "Missing binding name, please try to refresh " +
174                "Interface\nfor request generation to work correctly" );
175          return null;
176       }
177       
178       if( getBindingOperationName() == null )
179       {
180       	UISupport.showErrorMessage(  "Missing bindingOperation name, please try to refresh " +
181                "Interface\nfor request generation to work correctly" );
182          return null;
183       }
184       
185       try
186       {
187          SoapMessageBuilder builder = (SoapMessageBuilder) iface.getMessageBuilder();
188          BindingOperation bindingOperation = findBindingOperation( iface.getWsdlContext().getDefinition() );
189          
190          if( bindingOperation == null )
191          {
192          	UISupport.showErrorMessage( "Failed to find bindingOperation, please try to refresh " +
193                   "Interface\nfor request generation to work correctly" );
194             return null;
195          }
196          
197 			return builder.buildSoapResponse( bindingOperation, buildOptional );
198       }
199       catch (Exception e)
200       {
201          SoapUI.logError( e );
202          return null;
203       }
204    }
205    
206    public BindingOperation findBindingOperation(Definition definition)
207    {
208       Binding binding = definition.getBinding( iface.getBindingName() );
209       if( binding == null )
210       	return null;
211       
212 		String inputName = getInputName();
213 		String outputName = getOutputName();
214 		
215 		if( inputName == null )
216 			inputName = ":none";
217 		
218 		if( outputName == null )
219 			outputName = ":none";
220 		
221 		BindingOperation result = binding.getBindingOperation( getConfig().getBindingOperationName(), inputName, outputName );
222 
223 		if( result == null && (inputName.equals( ":none" ) || outputName.equals( ":none" )))
224 		{
225 			// fall back to this behaviour for WSDL4j 1.5.0 compatibility
226 			result = binding.getBindingOperation( getConfig().getBindingOperationName(), 
227 						inputName.equals( ":none" ) ? null : inputName, outputName.equals( ":none" ) ? null : outputName ); 
228 		}
229 		return result;
230    }
231   
232    public void removeRequest( WsdlRequest request )
233    {
234       int ix = requests.indexOf( request );
235       requests.remove( ix );
236 
237       try
238       {
239       	((WsdlInterface)getInterface()).fireRequestRemoved( request );
240       }
241       finally
242       {
243 	      request.release();
244 	      getConfig().removeCall( ix );
245       }
246    }
247 
248    public String getBindingOperationName()
249    {
250       return getConfig().getBindingOperationName();
251    }
252    
253    public void setBindingOperationName( String name )
254    {
255       getConfig().setBindingOperationName( name );
256    }
257    
258    public void setInputName( String name )
259    {
260    	getConfig().setInputName( name );
261    }
262 
263    public String getInputName()
264    {
265    	String inputName = getConfig().getInputName();
266    	return inputName == null || inputName.trim().length() == 0 ? null : inputName;
267    }
268    
269    public void setOutputName( String name )
270    {
271    	if( name == null )
272    	{
273    		if( getConfig().isSetOutputName() )
274    			getConfig().unsetOutputName();
275    	}
276    	else
277    		getConfig().setOutputName( name );
278    }
279 
280    public String getOutputName()
281    {
282    	String outputName = getConfig().getOutputName();
283    	return outputName == null || outputName.trim().length() == 0 ? null : outputName;
284    }
285    
286    public void setOneWay( boolean isOneWay )
287    {
288    	getConfig().setIsOneWay( isOneWay );
289    }
290    
291    public boolean isOneWay()
292    {
293    	return getConfig().getIsOneWay();
294    }
295    
296 	public void initFromBindingOperation(BindingOperation operation, boolean notifyUpdate )
297 	{
298       setAction( WsdlUtils.getSoapAction( operation ));
299       setName( operation.getOperation().getName() );
300       setBindingOperationName( operation.getName() );
301       setInputName( operation.getBindingInput().getName() );
302       
303       BindingOutput bindingOutput = operation.getBindingOutput();
304       
305       // bindingOutput is null for oneway operations
306 		if( bindingOutput != null )
307       	setOutputName( bindingOutput.getName() );
308 		else
309 			setOutputName( null );
310 
311       setOneWay( bindingOutput == null );
312       
313       initAttachments(operation);
314       
315       if( notifyUpdate )
316       {
317       	iface.fireOperationUpdated( this );
318       }
319 	}
320 
321 	@SuppressWarnings("unchecked")
322 	private void initAttachments(BindingOperation operation)
323 	{
324 		if( getConfig().isSetRequestParts() )
325 			getConfig().unsetRequestParts();
326 		
327 		if( getConfig().isSetResponseParts() )
328 			getConfig().unsetResponseParts();
329 		
330 		BindingOutput bindingOutput = operation.getBindingOutput();
331 		
332 		if( bindingOutput != null )
333 	   {
334 		   MIMEMultipartRelated multipartOutput = (MIMEMultipartRelated) WsdlUtils.getExtensiblityElement( 
335 		    		bindingOutput.getExtensibilityElements(), MIMEMultipartRelated.class );
336 		 
337 		   getConfig().setReceivesAttachments( multipartOutput != null );
338 		   if( multipartOutput != null )
339 	      {
340 	      	List<MIMEPart> parts = multipartOutput.getMIMEParts();
341 	      	Map<String,Part> partMap = new HashMap<String,Part>();
342 
343 	      	for( int c = 0; c < parts.size(); c++ )
344 	      	{
345 		      	List<MIMEContent> contentParts = WsdlUtils.getExtensiblityElements( parts.get(c).getExtensibilityElements(), MIMEContent.class );
346 		      	
347 		      	for( MIMEContent content : contentParts )
348 		      	{
349 		      		Part part = partMap.get( content.getPart());
350 		      		if( part != null )
351 		      		{ 
352 		      			if( !part.getContentTypeList().contains( content.getType() ))
353 		      				part.addContentType( content.getType() );
354 		      		}
355 		      		else
356 		      		{
357 		      			if( !getConfig().isSetResponseParts() )
358 		      				getConfig().addNewResponseParts();
359 		      			
360 		      			Part responsePart = getConfig().getResponseParts().addNewPart();
361 		      			responsePart.addContentType( content.getType() );
362 		      			responsePart.setName( content.getPart() );
363 		      			
364 		      			partMap.put( responsePart.getName(), responsePart );
365 		      		}
366 		      	}
367 	      	}
368 	      }
369 	   }
370 		
371 		MIMEMultipartRelated multipartInput = (MIMEMultipartRelated) WsdlUtils.getExtensiblityElement( 
372       		operation.getBindingInput().getExtensibilityElements(), MIMEMultipartRelated.class );
373  
374       getConfig().setSendsAttachments( multipartInput != null );
375       if( multipartInput != null )
376       {
377       	List<MIMEPart> parts = multipartInput.getMIMEParts();
378       	Map<String,Part> partMap = new HashMap<String,Part>();
379 
380       	for( int c = 0; c < parts.size(); c++ )
381       	{
382 	      	List<MIMEContent> contentParts = WsdlUtils.getExtensiblityElements( parts.get(c).getExtensibilityElements(), MIMEContent.class );
383 	      	
384 	      	for( MIMEContent content : contentParts )
385 	      	{
386 	      		Part part = partMap.get( content.getPart());
387 	      		if( part != null )
388 	      		{ 
389 	      			if( !part.getContentTypeList().contains( content.getType() ))
390 	      				part.addContentType( content.getType() );
391 	      		}
392 	      		else
393 	      		{
394 	      			if( !getConfig().isSetRequestParts() )
395 	      				getConfig().addNewRequestParts();
396 	      			
397 	      			Part requestPart = getConfig().getRequestParts().addNewPart();
398 	      			requestPart.addContentType( content.getType() );
399 	      			requestPart.setName( content.getPart() );
400 	      			
401 	      			partMap.put( requestPart.getName(), requestPart );
402 	      		}
403 	      	}
404       	}
405       }
406 	}
407 	
408 	public boolean getReceivesAttachments()
409 	{
410 		return getConfig().getReceivesAttachments();
411 	}
412 	
413 	public boolean getSendsAttachments()
414 	{
415 		return getConfig().getSendsAttachments();
416 	}
417 	
418 	@SuppressWarnings("unchecked")
419 	public QName getRequestBodyElementQName() throws Exception
420 	{
421 		WsdlInterface iface = (WsdlInterface) getInterface();
422 		
423 		Definition definition = iface.getWsdlContext().getDefinition();
424 		BindingOperation bindingOperation = findBindingOperation( definition );
425 		if( WsdlUtils.isRpc( definition, bindingOperation))
426 		{
427 			String ns = WsdlUtils.getSoapBodyNamespace( bindingOperation.getBindingInput().getExtensibilityElements() );
428 	      if( ns == null )
429 	      {
430 	      	ns = definition.getTargetNamespace();
431 	      }
432 			
433 			return new QName( ns, bindingOperation.getName() );
434 		}
435 		else
436 		{
437 			List<javax.wsdl.Part> parts = bindingOperation.getOperation().getInput().getMessage().getOrderedParts( null );
438 			if( parts == null || parts.isEmpty() )
439 				return null;
440 			
441 			javax.wsdl.Part part = parts.get( 0 );
442 			
443 			if( part.getElementName() != null )
444 			{
445 				return part.getElementName();
446 			}
447 			else
448 			{
449 				return new QName( definition.getTargetNamespace(), part.getName() );	
450 			}
451 		}
452 	}
453 	
454 	@SuppressWarnings("unchecked")
455 	public QName getResponseBodyElementQName() throws Exception
456 	{
457 		if( isOneWay() )
458 			return null;
459 		
460 		WsdlInterface iface = (WsdlInterface) getInterface();
461 		
462 		Definition definition = iface.getWsdlContext().getDefinition();
463 		BindingOperation bindingOperation = findBindingOperation( definition );
464 		if( WsdlUtils.isRpc( definition, bindingOperation))
465 		{
466 			String ns = WsdlUtils.getSoapBodyNamespace( bindingOperation.getBindingOutput().getExtensibilityElements() );
467 	      if( ns == null )
468 	      {
469 	      	ns = definition.getTargetNamespace();
470 	      }
471 			
472 			return new QName( ns, bindingOperation.getName() + "Response" );
473 		}
474 		else
475 		{
476 			List<javax.wsdl.Part> parts = bindingOperation.getOperation().getOutput().getMessage().getOrderedParts( null );
477 			if( parts == null || parts.isEmpty() )
478 				return null;
479 			
480 			javax.wsdl.Part part = parts.get( 0 );
481 			
482 			if( part.getElementName() != null )
483 			{
484 				return part.getElementName();
485 			}
486 			else
487 			{
488 				return new QName( definition.getTargetNamespace(), part.getName() );	
489 			}
490 		}
491 	}
492 	
493 	public String getStyle()
494 	{
495 		WsdlContext wsdlContext = iface.getWsdlContext();
496 		if( !wsdlContext.isLoaded() )
497 			return "<not loaded>";
498 		
499 		try
500 		{
501 			Definition definition = wsdlContext.getDefinition();
502 			BindingOperation bindingOperation = findBindingOperation( definition);
503 			
504 			if( bindingOperation == null )
505 				return "<missing bindingOperation>";
506 			
507 			if( WsdlUtils.isRpc( definition, bindingOperation ))
508 			{
509 				return WsdlOperation.STYLE_RPC;
510 			}
511 			else
512 			{
513 				return WsdlOperation.STYLE_DOCUMENT;
514 			}
515 		}
516 		catch (Exception e)
517 		{
518 			SoapUI.logError( e );
519 			return "<error>";
520 		}
521 	}
522 
523 	public void release()
524 	{
525 		super.release();
526 		
527 		for( WsdlRequest request : requests )
528 			request.release();
529 	}
530 
531 	public BindingOperation getBindingOperation()
532 	{
533 		try
534 		{
535 			return findBindingOperation( ((WsdlInterface)getInterface()).getWsdlContext().getDefinition() );
536 		}
537 		catch( Exception e )
538 		{
539 			SoapUI.logError( e );
540 			return null;
541 		}
542 	}
543 
544 	public List<Request> getRequests()
545 	{
546 		return new ArrayList<Request>( requests );
547 	}
548 
549 	public MessagePart[] getDefaultRequestParts()
550 	{
551 		try
552 		{
553 			// init
554 			List<MessagePart> result = new ArrayList<MessagePart>();
555 			WsdlContext wsdlContext = getInterface().getWsdlContext();
556 			BindingOperation bindingOperation = findBindingOperation(wsdlContext.getDefinition());
557 			
558 			if( bindingOperation == null )
559 				return new MessagePart[0];
560 			
561 			// header parts
562 			List<SoapHeader> headers = WsdlUtils.getSoapHeaders( bindingOperation.getBindingInput()
563 		            .getExtensibilityElements());
564 
565 	      for (int i = 0; i < headers.size(); i++)
566 	      {
567 	      	SoapHeader header = headers.get( i );
568 	         
569 	         Message message = wsdlContext.getDefinition().getMessage( header.getMessage() );
570 	         if( message == null )
571 	         {
572 	         	log.error( "Missing message for header: " + header.getMessage() );
573 	         	continue;
574 	         }
575 	         
576 				javax.wsdl.Part part = message.getPart( header.getPart() );
577 
578 	         if( part != null )
579 	         {
580 	         	SchemaType schemaType = WsdlUtils.getSchemaTypeForPart( wsdlContext, part );
581 					if( schemaType != null )
582 						result.add( new WsdlHeaderPart( part.getName(), schemaType, part.getElementName() ));
583 	         }
584 	         else
585 	         	log.error( "Missing part for header; " + header.getPart() );
586 	      }
587 	
588 			// content parts
589 			javax.wsdl.Part[] parts = WsdlUtils.getInputParts( bindingOperation );
590 			
591 			for( int i = 0; i < parts.length; i++ )
592 	      {
593 	      	javax.wsdl.Part part = parts[i];
594 	      	
595 				if( !WsdlUtils.isAttachmentInputPart( part, bindingOperation ))
596 	      	{
597 					SchemaType schemaType = WsdlUtils.getSchemaTypeForPart( wsdlContext, part );
598 					if( schemaType != null )
599 						result.add( new WsdlContentPart( part.getName(), schemaType, part.getElementName() ));
600       	   }
601 	      }
602 			
603 			return result.toArray( new MessagePart[result.size()] );
604 		}
605 		catch (Exception e)
606 		{
607 			SoapUI.logError( e );
608 			return new MessagePart [0];
609 		}		
610 	}
611 	
612 	public MessagePart[] getDefaultResponseParts()
613 	{
614 		try
615 		{
616 			// init
617 			List<MessagePart> result = new ArrayList<MessagePart>();
618 			WsdlContext wsdlContext = getInterface().getWsdlContext();
619 			BindingOperation bindingOperation = findBindingOperation(wsdlContext.getDefinition());
620 			
621 			if( bindingOperation == null )
622 				return new MessagePart[0];
623 			
624 			// header parts
625 			List<SoapHeader> headers = WsdlUtils.getSoapHeaders( bindingOperation.getBindingOutput()
626 			            .getExtensibilityElements());
627 
628 	      for (int i = 0; i < headers.size(); i++)
629 	      {
630 	      	SoapHeader header = headers.get( i );
631 	         
632 	         Message message = wsdlContext.getDefinition().getMessage( header.getMessage() );
633 	         if( message == null )
634 	         {
635 	         	log.error( "Missing message for header: " + header.getMessage() );
636 	         	continue;
637 	         }
638 	         
639 				javax.wsdl.Part part = message.getPart( header.getPart() );
640 
641 	         if( part != null )
642 	         {
643 	         	SchemaType schemaType = WsdlUtils.getSchemaTypeForPart( wsdlContext, part );
644 					if( schemaType != null )
645 						result.add( new WsdlHeaderPart( part.getName(), schemaType, part.getElementName() ));
646 	         }
647 	         else
648 	         	log.error( "Missing part for header; " + header.getPart() );
649 	      }
650 	
651 			// content parts
652 			javax.wsdl.Part[] parts = WsdlUtils.getOutputParts( bindingOperation );
653 			
654 			for( int i = 0; i < parts.length; i++ )
655 	      {
656 	      	javax.wsdl.Part part = parts[i];
657 	      	
658 				if( !WsdlUtils.isAttachmentOutputPart( part, bindingOperation ))
659 	      	{
660 					SchemaType schemaType = WsdlUtils.getSchemaTypeForPart( wsdlContext, part );
661 					if( schemaType != null )
662 						result.add( new WsdlContentPart( part.getName(), schemaType, part.getElementName() ));
663       	   }
664 	      }
665 			
666 			return result.toArray( new MessagePart[result.size()] );
667 		}
668 		catch (Exception e)
669 		{
670 			SoapUI.logError( e );
671 			return new MessagePart [0];
672 		}		
673 	}
674 	
675 	public MessagePart [] getFaultParts()
676 	{
677 		BindingOperation bindingOperation = getBindingOperation();
678 		Map bindingFaults = bindingOperation.getBindingFaults();
679 
680 		List<MessagePart> result = new ArrayList<MessagePart>();
681 		for( Object key : bindingFaults.keySet() )
682 		{
683 			result.add( new WsdlFaultPart( (String)key ));
684 		}
685 	
686 		return result.toArray( new MessagePart[result.size()] );
687 	}
688 	
689 	private class WsdlFaultPart extends FaultPart
690 	{
691 		private final String name;
692 
693 		public WsdlFaultPart( String name )
694 		{
695 			this.name = name;
696 		}
697 
698 		@Override
699 		public javax.wsdl.Part[] getWsdlParts()
700 		{
701 			try
702 			{
703 				return WsdlUtils.getFaultParts( getBindingOperation(), name );
704 			}
705 			catch( Exception e )
706 			{
707 				log.error( e.toString(), e );
708 			}
709 			
710 			return new javax.wsdl.Part[0];
711 		}
712 
713 		@Override
714 		public QName getPartElement()
715 		{
716 			return null;
717 		}
718 
719 		public String getDescription()
720 		{
721 			return null;
722 		}
723 
724 		public String getName()
725 		{
726 			return name;
727 		}
728 
729 		@Override
730 		public SchemaType getSchemaType()
731 		{
732 			return null;
733 		}}
734 
735 	@Override
736 	public void onSave()
737 	{
738 		for( WsdlRequest request : requests )
739 			request.onSave();
740 	}
741 }