View Javadoc

1   /*
2    *  soapui, copyright (C) 2005 Ole Matzura / eviware.com 
3    *
4    *  SoapUI is free software; you can redistribute it and/or modify it under the 
5    *  terms of the GNU Lesser General Public License as published by the Free Software Foundation; 
6    *  either version 2.1 of the License, or (at your option) any later version.
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;
14  
15  import java.io.StringWriter;
16  import java.util.Map;
17  
18  import javax.wsdl.BindingOperation;
19  import javax.wsdl.Part;
20  import javax.wsdl.extensions.ExtensibilityElement;
21  import javax.wsdl.extensions.soap.SOAPBody;
22  import javax.wsdl.extensions.soap.SOAPHeader;
23  import javax.xml.namespace.QName;
24  
25  import org.apache.commons.logging.Log;
26  import org.apache.commons.logging.LogFactory;
27  import org.apache.xmlbeans.SchemaGlobalElement;
28  import org.apache.xmlbeans.SchemaType;
29  import org.apache.xmlbeans.XmlCursor;
30  import org.apache.xmlbeans.XmlObject;
31  
32  import com.eviware.soapui.impl.wsdl.WsdlInterface;
33  import com.eviware.soapui.model.iface.Interface;
34  import com.eviware.soapui.model.iface.Operation;
35  import com.eviware.soapui.model.iface.Request;
36  import com.eviware.soapui.model.iface.RequestBuilder;
37  import com.eviware.soapui.support.XmlUtils;
38  
39  /***
40   * Builds SOAP requests according to WSDL/XSD definitions
41   * 
42   * @author Ole.Matzura
43   */
44  
45  public class SoapRequestBuilder implements RequestBuilder
46  {
47     private final static Log log = LogFactory.getLog( SoapRequestBuilder.class );
48  
49     private final QName envelopeQName  = new QName("http://schemas.xmlsoap.org/soap/envelope/", "Envelope");
50  
51     private final QName bodyQName = new QName("http://schemas.xmlsoap.org/soap/envelope/", "Body");
52  
53     private final QName headerQName = new QName("http://schemas.xmlsoap.org/soap/envelope/", "Header");
54  
55     private WsdlContext wsdlContext;
56  
57     private WsdlInterface iface;
58     
59     public SoapRequestBuilder(WsdlInterface iface) throws Exception
60     {
61        this.iface = iface;
62        this.wsdlContext = iface.getWsdlContext();
63     }
64  
65     public SoapRequestBuilder(WsdlContext wsdlContext)
66     {
67        this.wsdlContext = wsdlContext;
68     }
69     
70     public Interface getInterface()
71     {
72        return iface;
73     }
74  
75     public Request buildRequest(Operation operation, Map params)
76     {
77        return null;
78     }
79  
80     public String buildSoapRequest(BindingOperation bindingOperation, boolean buildOptional ) throws Exception
81     {
82        boolean inputSoapEncoded = WsdlUtils.isInputSoapEncoded( bindingOperation );
83        SampleXmlUtil xmlGenerator = new SampleXmlUtil(inputSoapEncoded);
84        xmlGenerator.setIgnoreOptional( !buildOptional );
85        
86        XmlObject object = XmlObject.Factory.newInstance();
87        XmlCursor cursor = object.newCursor();
88        cursor.toNextToken();
89        cursor.beginElement(envelopeQName);
90  
91        if( inputSoapEncoded )
92        {
93           cursor.insertNamespace( "xsi", "http://www.w3.org/2001/XMLSchema-instance" );
94           cursor.insertNamespace( "xsd", "http://www.w3.org/2001/XMLSchema" );
95        }
96        
97        cursor.toFirstChild();
98  
99        cursor.beginElement(bodyQName);
100       cursor.toFirstChild();
101 
102       if( WsdlUtils.isRpc( wsdlContext.getDefinition(), bindingOperation ))
103       {
104          buildRpcRequest( bindingOperation, cursor, xmlGenerator );
105       }
106       else 
107       {
108          buildDocumentRequest( bindingOperation, cursor, xmlGenerator );
109       }   
110       
111       addHeaders(bindingOperation, cursor, xmlGenerator);
112       cursor.dispose();
113 
114       try
115       {
116          StringWriter writer = new StringWriter();
117          XmlUtils.serializePretty( object, writer );
118          return writer.toString();
119       }
120       catch( Exception e )
121       {
122          e.printStackTrace();
123          return object.xmlText();
124       }
125    }
126 
127    private void addHeaders(BindingOperation bindingOperation, XmlCursor cursor, SampleXmlUtil xmlGenerator) throws Exception
128    {
129       ExtensibilityElement[] headers = WsdlUtils.getExtensiblityElements(bindingOperation.getBindingInput()
130             .getExtensibilityElements(), SOAPHeader.class);
131       if (headers.length > 0)
132       {
133          // reposition
134          cursor.toStartDoc();
135          cursor.toChild(envelopeQName);
136          cursor.toFirstChild();
137          
138          cursor.beginElement(headerQName);
139          cursor.toFirstChild();
140 
141          for (int i = 0; i < headers.length; i++)
142          {
143             SOAPHeader header = (SOAPHeader) headers[i];
144             
145       //      String partName = header.getPart();
146 
147             Part part = wsdlContext.getDefinition().getMessage( header.getMessage() ).getPart( header.getPart() );
148 
149             //Part part = bindingOperation.getOperation().getInput().getMessage().getPart(partName);
150 
151             if( part != null )
152             	createElementForPart( part, cursor, xmlGenerator );
153             else
154             	log.error( "Missing part for header; " + header.getPart() );
155          }
156       }
157    }
158 
159    private void createElementForPart(Part part, XmlCursor cursor, SampleXmlUtil xmlGenerator ) throws Exception
160    {
161       QName elementName = part.getElementName();
162       QName typeName = part.getTypeName();
163       
164       if( elementName != null )
165       {
166          cursor.beginElement(elementName);
167    
168          if( wsdlContext.hasSchemaTypes() )
169          {
170             SchemaGlobalElement elm = wsdlContext.getSchemaTypes().findElement(elementName);
171             if( elm != null )
172             {
173                cursor.toFirstChild();
174                xmlGenerator.createSampleForType(elm.getType(), cursor);
175                cursor.toParent();
176             }
177          }
178       }
179       else 
180       {
181          cursor.beginElement( new QName( wsdlContext.getDefinition().getTargetNamespace(), part.getName() ));
182          if( typeName != null && wsdlContext.hasSchemaTypes() )
183          {
184             SchemaType type = wsdlContext.getSchemaTypes().findType( typeName );
185             
186             if( type != null )
187             {
188                cursor.toFirstChild();
189                xmlGenerator.createSampleForType( type, cursor );
190             }
191             else log.error( "Could not find type [" + typeName + "] specified in part [" + part.getName() + "]" );
192          }
193       }
194    }
195 
196    private void buildDocumentRequest(BindingOperation bindingOperation, XmlCursor cursor, SampleXmlUtil xmlGenerator) throws Exception
197    {
198       Part[] parts = WsdlUtils.getInputParts( bindingOperation );
199       if( parts.length > 1 )
200          log.warn( "document style operation should not have more than one part" );
201       
202       for (int i = 0; i < parts.length; i++)
203       {
204          XmlCursor c = cursor.newCursor();
205          c.toLastChild();
206          createElementForPart( parts[i], c, xmlGenerator );
207          c.dispose();
208       }
209    }
210 
211    private void buildRpcRequest(BindingOperation bindingOperation, XmlCursor cursor, SampleXmlUtil xmlGenerator) throws Exception
212    {
213       // rpc requests use the operation name as root element
214       SOAPBody body = (SOAPBody) WsdlUtils.getExtensiblityElement(bindingOperation.getBindingInput()
215             .getExtensibilityElements(), SOAPBody.class);
216       
217       String ns = wsdlContext.getDefinition().getTargetNamespace();
218       if( body != null && body.getNamespaceURI() != null )
219          ns = body.getNamespaceURI();
220       
221       cursor.beginElement( new QName( ns, bindingOperation.getName() ));
222       if( xmlGenerator.isSoapEnc() )
223          cursor.insertAttributeWithValue( new QName( "http://schemas.xmlsoap.org/soap/envelope/", "encodingStyle" ), 
224             "http://schemas.xmlsoap.org/soap/encoding/");
225       
226       Part[] inputParts = WsdlUtils.getInputParts( bindingOperation );
227       for (int i = 0; i < inputParts.length; i++)
228       {
229          Part part = inputParts[i];
230          XmlCursor c = cursor.newCursor();
231          c.toLastChild();
232          c.insertElement( part.getName() );
233          c.toPrevToken();
234          
235          if( wsdlContext.hasSchemaTypes() )
236          {
237             SchemaType type = wsdlContext.findType( part.getTypeName() );
238             if( type != null )
239                xmlGenerator.createSampleForType( type, c );
240             else
241                log.error( "Failed to find type [" + part.getTypeName() + "]" );
242          }
243          
244          c.dispose();
245       }
246    }
247    
248    public void setWsdlContext( WsdlContext wsdlContext )
249    {
250    	this.wsdlContext = wsdlContext;
251    }
252 }