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.soap;
14  
15  import java.io.StringWriter;
16  import java.util.List;
17  import java.util.Map;
18  
19  import javax.wsdl.BindingOperation;
20  import javax.wsdl.Message;
21  import javax.wsdl.Part;
22  import javax.xml.namespace.QName;
23  
24  import org.apache.log4j.Logger;
25  import org.apache.xmlbeans.SchemaGlobalElement;
26  import org.apache.xmlbeans.SchemaType;
27  import org.apache.xmlbeans.XmlCursor;
28  import org.apache.xmlbeans.XmlObject;
29  import org.apache.xmlbeans.XmlOptions;
30  import org.w3c.dom.Document;
31  import org.w3c.dom.Node;
32  
33  import com.eviware.soapui.impl.wsdl.WsdlInterface;
34  import com.eviware.soapui.impl.wsdl.support.Constants;
35  import com.eviware.soapui.impl.wsdl.support.wsdl.WsdlContext;
36  import com.eviware.soapui.impl.wsdl.support.wsdl.WsdlUtils;
37  import com.eviware.soapui.impl.wsdl.support.wsdl.WsdlUtils.SoapHeader;
38  import com.eviware.soapui.impl.wsdl.support.xsd.SampleXmlUtil;
39  import com.eviware.soapui.model.iface.Interface;
40  import com.eviware.soapui.model.iface.MessageBuilder;
41  import com.eviware.soapui.model.iface.Operation;
42  import com.eviware.soapui.model.iface.Request;
43  import com.eviware.soapui.model.iface.MessagePart.FaultPart;
44  import com.eviware.soapui.settings.WsdlSettings;
45  import com.eviware.soapui.support.xml.XmlUtils;
46  
47  /***
48   * Builds SOAP requests according to WSDL/XSD definitions
49   * 
50   * @author Ole.Matzura
51   */
52  
53  public class SoapMessageBuilder implements MessageBuilder
54  {
55     private final static Logger log = Logger.getLogger( SoapMessageBuilder.class );
56  
57     private WsdlContext wsdlContext;
58     private WsdlInterface iface;
59     
60     public SoapMessageBuilder(WsdlInterface iface) throws Exception
61     {
62        this.iface = iface;
63        this.wsdlContext = iface.getWsdlContext();
64     }
65  
66     public SoapMessageBuilder(WsdlContext wsdlContext)
67     {
68        this.wsdlContext = wsdlContext;
69     }
70     
71     public Interface getInterface()
72     {
73        return iface;
74     }
75  
76     public String buildFault( String faultcode, String faultstring )
77     {
78     	SampleXmlUtil generator = new SampleXmlUtil( false );
79     	generator.setTypeComment( false );
80     	generator.setIgnoreOptional( true );
81     	
82     	String emptyResponse = buildEmptyFault( generator );
83  
84     	emptyResponse = XmlUtils.setXPathContent( emptyResponse, "//faultcode", faultcode );
85     	emptyResponse = XmlUtils.setXPathContent( emptyResponse, "//faultstring", faultstring );
86     	
87  		return emptyResponse;
88  	}
89     
90     public String buildEmptyFault()
91  	{
92     	SampleXmlUtil generator = new SampleXmlUtil( false );
93     	
94     	String emptyResponse = buildEmptyFault( generator );
95  		
96  		return emptyResponse;
97  	}
98  
99  	private String buildEmptyFault( SampleXmlUtil generator )
100 	{
101 		SoapVersion soapVersion = iface.getSoapVersion();
102 		String emptyResponse = iface.getMessageBuilder().buildEmptyMessage();
103 		try
104 		{
105 			XmlObject xmlObject = XmlObject.Factory.parse( emptyResponse );
106 			XmlCursor cursor = xmlObject.newCursor();
107 			
108 			if( cursor.toChild( soapVersion.getEnvelopeQName() ) && cursor.toChild( soapVersion.getBodyQName() ))
109 			{
110 				SchemaType faultType = soapVersion.getFaultType();
111 				Node bodyNode = cursor.getDomNode();
112 				Document dom = XmlUtils.parseXml( generator.createSample( faultType ) );
113 				bodyNode.appendChild( bodyNode.getOwnerDocument().importNode( dom.getDocumentElement(), true ) );
114 			}
115 			
116 			cursor.dispose();
117 			emptyResponse = xmlObject.toString();
118 		}
119 		catch( Exception e )
120 		{
121 			e.printStackTrace();
122 		}
123 		return emptyResponse;
124 	}
125    
126    public String buildEmptyMessage()
127 	{
128    	SampleXmlUtil generator = new SampleXmlUtil( false );
129    	generator.setTypeComment( false );
130    	generator.setIgnoreOptional( true );
131    	return generator.createSample( iface.getSoapVersion().getEnvelopeType() );
132 	}
133 
134 	public Request buildRequest(Operation operation, Map params)
135    {
136       return null;
137    }
138 
139    public String buildSoapRequest(BindingOperation bindingOperation, boolean buildOptional ) throws Exception
140    {
141       boolean inputSoapEncoded = WsdlUtils.isInputSoapEncoded( bindingOperation );
142       SampleXmlUtil xmlGenerator = new SampleXmlUtil(inputSoapEncoded);
143       xmlGenerator.setIgnoreOptional( !buildOptional );
144       
145       XmlObject object = XmlObject.Factory.newInstance();
146       XmlCursor cursor = object.newCursor();
147       cursor.toNextToken();
148       cursor.beginElement( wsdlContext.getSoapVersion().getEnvelopeQName() );
149 
150       if( inputSoapEncoded )
151       {
152          cursor.insertNamespace( "xsi", Constants.XSI_NS );
153          cursor.insertNamespace( "xsd", Constants.XSD_NS );
154       }
155       
156       cursor.toFirstChild();
157 
158       cursor.beginElement(wsdlContext.getSoapVersion().getBodyQName());
159       cursor.toFirstChild();
160      
161       if( WsdlUtils.isRpc( wsdlContext.getDefinition(), bindingOperation ))
162       {
163          buildRpcRequest( bindingOperation, cursor, xmlGenerator );
164       }
165       else 
166       {
167          buildDocumentRequest( bindingOperation, cursor, xmlGenerator );
168       }   
169       
170       addHeaders( WsdlUtils.getSoapHeaders( bindingOperation.getBindingInput().getExtensibilityElements()), 
171       			cursor, xmlGenerator);
172       cursor.dispose();
173 
174       try
175       {
176          StringWriter writer = new StringWriter();
177          XmlUtils.serializePretty( object, writer );
178          return writer.toString();
179       }
180       catch( Exception e )
181       {
182          e.printStackTrace();
183          return object.xmlText();
184       }
185    }
186 
187    private void buildMultipartRequest(BindingOperation bindingOperation, XmlCursor cursor, SampleXmlUtil xmlGenerator) throws Exception
188 	{
189    	buildDocumentRequest( bindingOperation, cursor, xmlGenerator );
190 	}
191 
192 	private void addHeaders(List<SoapHeader> headers, XmlCursor cursor, SampleXmlUtil xmlGenerator) throws Exception
193    {
194       // reposition
195       cursor.toStartDoc();
196       cursor.toChild(wsdlContext.getSoapVersion().getEnvelopeQName());
197       cursor.toFirstChild();
198       
199       cursor.beginElement(wsdlContext.getSoapVersion().getHeaderQName());
200       cursor.toFirstChild();
201 
202       for (int i = 0; i < headers.size(); i++)
203       {
204          SoapHeader header = (SoapHeader) headers.get(i);
205          
206          Message message = wsdlContext.getDefinition().getMessage( header.getMessage() );
207          if( message == null )
208          {
209          	log.error( "Missing message for header: " + header.getMessage() );
210          	continue;
211          }
212          
213 			Part part = message.getPart( header.getPart() );
214 
215          if( part != null )
216          	createElementForPart( part, cursor, xmlGenerator );
217          else
218          	log.error( "Missing part for header; " + header.getPart() );
219       }
220    }
221 
222    public void createElementForPart(Part part, XmlCursor cursor, SampleXmlUtil xmlGenerator ) throws Exception
223    {
224       QName elementName = part.getElementName();
225       QName typeName = part.getTypeName();
226       
227       if( elementName != null )
228       {
229          cursor.beginElement(elementName);
230    
231          if( wsdlContext.hasSchemaTypes() )
232          {
233             SchemaGlobalElement elm = wsdlContext.getSchemaTypeLoader().findElement(elementName);
234             if( elm != null )
235             {
236                cursor.toFirstChild();
237                xmlGenerator.createSampleForType(elm.getType(), cursor);
238             }
239             else log.error( "Could not find element [" + elementName + "] specified in part [" + part.getName() + "]" );
240          }
241 
242          cursor.toParent();
243       }
244       else 
245       {
246          cursor.beginElement( new QName( wsdlContext.getDefinition().getTargetNamespace(), part.getName() ));
247          if( typeName != null && wsdlContext.hasSchemaTypes() )
248          {
249             SchemaType type = wsdlContext.getSchemaTypeLoader().findType( typeName );
250             
251             if( type != null )
252             {
253                cursor.toFirstChild();
254                xmlGenerator.createSampleForType( type, cursor );
255             }
256             else log.error( "Could not find type [" + typeName + "] specified in part [" + part.getName() + "]" );
257          }
258 
259          cursor.toParent();
260       }
261    }
262 
263    private void buildDocumentRequest(BindingOperation bindingOperation, XmlCursor cursor, SampleXmlUtil xmlGenerator) throws Exception
264    {
265       Part[] parts = WsdlUtils.getInputParts( bindingOperation );
266       
267       for( int i = 0; i < parts.length; i++ )
268       {
269       	if( !WsdlUtils.isAttachmentInputPart( parts[i], bindingOperation ))
270       	{
271 		      XmlCursor c = cursor.newCursor();
272 		      c.toLastChild();
273 		      createElementForPart( parts[i], c, xmlGenerator );
274 		      c.dispose();
275       	}
276       }
277    }
278 
279    private void buildDocumentResponse(BindingOperation bindingOperation, XmlCursor cursor, SampleXmlUtil xmlGenerator) throws Exception
280    {
281       Part[] parts = WsdlUtils.getOutputParts( bindingOperation );
282       
283       for( int i = 0; i < parts.length; i++ )
284       {
285       	if( !WsdlUtils.isAttachmentOutputPart( parts[i], bindingOperation ))
286       	{
287 		      XmlCursor c = cursor.newCursor();
288 		      c.toLastChild();
289 		      createElementForPart( parts[i], c, xmlGenerator );
290 		      c.dispose();
291       	}
292       }
293    }
294    
295    private void buildRpcRequest(BindingOperation bindingOperation, XmlCursor cursor, SampleXmlUtil xmlGenerator) throws Exception
296    {
297       // rpc requests use the operation name as root element
298       String ns = WsdlUtils.getSoapBodyNamespace( bindingOperation.getBindingInput()
299                .getExtensibilityElements() );
300       if( ns == null )
301       {
302       	ns = wsdlContext.getDefinition().getTargetNamespace();
303       	log.warn( "missing namespace on soapbind:body, using targetNamespace instead (BP violation)" );
304       }
305       
306       cursor.beginElement( new QName( ns, bindingOperation.getName() ));
307       if( xmlGenerator.isSoapEnc()  )
308          cursor.insertAttributeWithValue( new QName( wsdlContext.getSoapVersion().getEnvelopeNamespace(), "encodingStyle" ), 
309          		wsdlContext.getSoapVersion().getEncodingNamespace() );
310       
311       Part[] inputParts = WsdlUtils.getInputParts( bindingOperation );
312       for (int i = 0; i < inputParts.length; i++)
313       {
314          Part part = inputParts[i];
315          if( WsdlUtils.isAttachmentInputPart( part, bindingOperation ))
316          {
317          	if( iface.getSettings().getBoolean( WsdlSettings.ATTACHMENT_PARTS ))
318          	{
319          		XmlCursor c = cursor.newCursor();
320    	         c.toLastChild();
321    	         c.beginElement( part.getName() );
322    	         c.insertAttributeWithValue( "href", part.getName() + "Attachment" );
323    	         c.dispose();
324          	}
325          }
326          else
327          {
328 	         if( wsdlContext.hasSchemaTypes() )
329 	         {
330 	            QName typeName = part.getTypeName();
331 	            if( typeName != null )
332 	            {
333 						SchemaType type = wsdlContext.findType( typeName );
334 		            
335 		            if( type != null )
336 		            {
337 		            	XmlCursor c = cursor.newCursor();
338 		   	         c.toLastChild();
339 		   	         c.insertElement( part.getName() );
340 		   	         c.toPrevToken();
341 		   	         
342 		               xmlGenerator.createSampleForType( type, c );
343 		               c.dispose();
344 		            }
345 		            else
346 		               log.warn( "Failed to find type [" + typeName + "]" );
347 	            }
348 	            else
349 	            {
350 	            	SchemaGlobalElement element = wsdlContext.getSchemaTypeLoader().findElement( part.getElementName() );
351 	            	if( element != null )
352 	            	{
353 	            		XmlCursor c = cursor.newCursor();
354 	      	         c.toLastChild();
355 	      	         c.insertElement( element.getName() );
356 	      	         c.toPrevToken();
357 	      	         
358 	            		xmlGenerator.createSampleForType( element.getType(), c );
359 	            		c.dispose();
360 	            	}
361 		            else
362 		               log.warn( "Failed to find element [" + part.getElementName() + "]" );
363 	            }
364 	         }
365          }
366       }
367    }
368    
369    private void buildRpcResponse(BindingOperation bindingOperation, XmlCursor cursor, SampleXmlUtil xmlGenerator) throws Exception
370    {
371       // rpc requests use the operation name as root element
372    	String ns = WsdlUtils.getSoapBodyNamespace( bindingOperation.getBindingOutput()
373                 .getExtensibilityElements() );
374        
375    	if( ns == null )
376       {
377        	ns = wsdlContext.getDefinition().getTargetNamespace();
378        	log.warn( "missing namespace on soapbind:body, using targetNamespace instead (BP violation)" );
379       }
380       
381       cursor.beginElement( new QName( ns, bindingOperation.getName() + "Response" ));
382       if( xmlGenerator.isSoapEnc()  )
383          cursor.insertAttributeWithValue( new QName( wsdlContext.getSoapVersion().getEnvelopeNamespace(), "encodingStyle" ), 
384          		wsdlContext.getSoapVersion().getEncodingNamespace() );
385       
386       Part[] inputParts = WsdlUtils.getOutputParts( bindingOperation );
387       for (int i = 0; i < inputParts.length; i++)
388       {
389          Part part = inputParts[i];
390          if( WsdlUtils.isAttachmentOutputPart( part, bindingOperation ))
391          {
392          	if( iface.getSettings().getBoolean( WsdlSettings.ATTACHMENT_PARTS ))
393          	{
394          		XmlCursor c = cursor.newCursor();
395    	         c.toLastChild();
396    	         c.beginElement( part.getName() );
397    	         c.insertAttributeWithValue( "href", part.getName() + "Attachment" );
398    	         c.dispose();
399          	}
400          }
401          else
402          {
403 	         if( wsdlContext.hasSchemaTypes() )
404 	         {
405 	            QName typeName = part.getTypeName();
406 	            if( typeName != null )
407 	            {
408 						SchemaType type = wsdlContext.findType( typeName );
409 		            
410 		            if( type != null )
411 		            {
412 		            	XmlCursor c = cursor.newCursor();
413 		   	         c.toLastChild();
414 		   	         c.insertElement( part.getName() );
415 		   	         c.toPrevToken();
416 		   	         
417 		               xmlGenerator.createSampleForType( type, c );
418 		               c.dispose();
419 		            }
420 		            else
421 		               log.warn( "Failed to find type [" + typeName + "]" );
422 	            }
423 	            else
424 	            {
425 	            	SchemaGlobalElement element = wsdlContext.getSchemaTypeLoader().findElement( part.getElementName() );
426 	            	if( element != null )
427 	            	{
428 	            		XmlCursor c = cursor.newCursor();
429 	      	         c.toLastChild();
430 	      	         c.insertElement( element.getName() );
431 	      	         c.toPrevToken();
432 	      	         
433 	            		xmlGenerator.createSampleForType( element.getType(), c );
434 	            		c.dispose();
435 	            	}
436 		            else
437 		               log.warn( "Failed to find element [" + part.getElementName() + "]" );
438 	            }
439 	         }
440          }
441       }
442    }
443    
444    public void setWsdlContext( WsdlContext wsdlContext )
445    {
446    	this.wsdlContext = wsdlContext;
447    }
448 
449 	public void setInterface(WsdlInterface iface )
450 	{
451 		this.iface = iface;
452 	}
453 
454 	public String buildSoapResponse( BindingOperation bindingOperation, boolean buildOptional ) throws Exception
455 	{
456 		boolean inputSoapEncoded = WsdlUtils.isInputSoapEncoded( bindingOperation );
457       SampleXmlUtil xmlGenerator = new SampleXmlUtil(inputSoapEncoded);
458       xmlGenerator.setIgnoreOptional( !buildOptional );
459       
460       XmlObject object = XmlObject.Factory.newInstance();
461       XmlCursor cursor = object.newCursor();
462       cursor.toNextToken();
463       cursor.beginElement( wsdlContext.getSoapVersion().getEnvelopeQName() );
464 
465       if( inputSoapEncoded )
466       {
467          cursor.insertNamespace( "xsi", Constants.XSI_NS );
468          cursor.insertNamespace( "xsd", Constants.XSD_NS );
469       }
470       
471       cursor.toFirstChild();
472 
473       cursor.beginElement(wsdlContext.getSoapVersion().getBodyQName());
474       cursor.toFirstChild();
475      
476       if( WsdlUtils.isRpc( wsdlContext.getDefinition(), bindingOperation ))
477       {
478          buildRpcResponse( bindingOperation, cursor, xmlGenerator );
479       }
480       else 
481       {
482          buildDocumentResponse( bindingOperation, cursor, xmlGenerator );
483       }   
484       
485       addHeaders(WsdlUtils.getSoapHeaders( bindingOperation.getBindingOutput()
486                .getExtensibilityElements() ), cursor, xmlGenerator);
487       cursor.dispose();
488 
489       try
490       {
491          StringWriter writer = new StringWriter();
492          XmlUtils.serializePretty( object, writer );
493          return writer.toString();
494       }
495       catch( Exception e )
496       {
497          e.printStackTrace();
498          return object.xmlText();
499       }
500 	}
501 	
502 
503 	public String buildFault( FaultPart faultPart )
504 	{
505 		SampleXmlUtil generator = new SampleXmlUtil( false );
506 		generator.setExampleContent( false );
507 		generator.setTypeComment( false );
508 		String faultResponse = iface.getMessageBuilder().buildEmptyFault();
509 	
510 		XmlCursor cursor = null;
511 		try
512 		{
513 			XmlObject xmlObject = XmlObject.Factory.parse( faultResponse );
514 			XmlObject[] detail = xmlObject.selectPath( "//detail" );
515 			cursor  = detail[0].newCursor();
516 			
517 			cursor.toFirstContentToken();
518 
519 			generator.setTypeComment( true );
520 			generator.setIgnoreOptional( iface.getSettings().getBoolean( WsdlSettings.XML_GENERATION_ALWAYS_INCLUDE_OPTIONAL_ELEMENTS ) );
521 
522 			for( Part part : faultPart.getWsdlParts() )
523 				createElementForPart( part, cursor, generator );
524 			
525 			faultResponse = xmlObject.xmlText( new XmlOptions().setSaveAggressiveNamespaces().setSavePrettyPrint());
526 		}
527 		catch( Exception e1 )
528 		{
529 			e1.printStackTrace();
530 		} 
531 		finally
532 		{
533 			if( cursor != null )
534 				cursor.dispose();
535 		}
536 		
537 		return faultResponse;
538 	}
539 }