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