Testing a SOAP interface using the Apache Axis2 Plugin
There’s a lot of information online about using various frameworks to add SOAP functionality to a Grails application, but not much for performing a simple test of your new SOAP service.
Before starting this sample, it is necessary for you to create a Book domain object as described in the Grails Quick Start tutorial. Create one or two books for testing purposes.
After you initialize your data and have your application up and running, we can proceed. Let’s create a SOAP service to access this data. For this example, I utilized the Apache Axis2 plugin instructions to create my service.
To test, we can use the command line utility curl. To do so, we first need to create a simple XML document to pass to our service. Create a file called availableBooks.xml
<soap:Envelope
xmlns:soap="http://www.w3.org/2003/05/soap-envelope"
xmlns:axis="http://ws.apache.org/axis2">
<soap:Header/>
<soap:Body>
<axis:availableBooks />
</soap:Body>
</soap:Envelope>
We can now try passing this document to our service:
curl --header "Content-type: application/soap+xml" -i \
--data @availableBooks.xml -X POST http://localhost:8080/soap-proto/services/test
The default plugin configuration will give you this error:
Please enable REST support in WEB-INF/conf/axis2.xml and WEB-INF/web.xml
You can’t just follow the instructions here because the Grails plugin framework has changed the location of this parameter. Locate the file Axis2GrailsPlugin.groovy, and update the disableREST parameter:
"disRest"(org.wso2.spring.ws.beans.ParameterBean) {
name = "disableREST"
value = "false"
locked = "false"
}
You may have to perform a “grails clean” and a restart of your application for this setting to take effect.
Retry your curl command from earlier. You should now get the desired response (formatted for readability):
HTTP/1.1 200 OK Content-Type: multipart/related; boundary=MIMEBoundaryurn_uuid_6A2C4C79E6979D3E371226968077707; type="application/soap+xml"; start="<0.urn:uuid:6A2C4C79E6979D3E371226968077708@apache.org>"; action="urn:availableBooksResponse" Transfer-Encoding: chunked Server: Jetty(6.1.4)
--MIMEBoundaryurn_uuid_6A2C4C79E6979D3E371226968077707
Content-Type: application/soap+xml; charset=UTF-8
Content-Transfer-Encoding: 8bit
Content-ID: <0.urn:uuid:6A2C4C79E6979D3E371226968077708@apache.org>
<?xml version='1.0' encoding='UTF-8'?>
<soapenv:Envelope
xmlns:soapenv="http://www.w3.org/2003/05/soap-envelope">
<soapenv:Body>
<ns:getBookByIdResponse xmlns:ns="http://ws.apache.org/axis2">
<ns:return xmlns:ax21="http://ws.apache.org/axis2/xsd" type="Book">
<ax21:author>John</ax21:author>
<ax21:id>1</ax21:id>
<ax21:name>HOWTO Program</ax21:name>
<ax21:version>0</ax21:version>
</ns:return>
</ns:getBookByIdResponse>
</soapenv:Body>
</soapenv:Envelope>
--MIMEBoundaryurn_uuid_6A2C4C79E6979D3E371226968077707--
You can try the same thing if you need to pass a parameter by modifying the XML request:
<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:axis="http://ws.apache.org/axis2"> <soap:Header/> <soap:Body> <axis:getBookById> <axis:id>1</axis:id> </axis:getBookById> </soap:Body> </soap:Envelope>
Please note that we need to set the content type header for curl to “application/soap+xml”. Without setting it, your application won’t know how to deal with the XML document. Here are some common errors for other content types that I tried. They don’t work with axis2, but they may work for other SOAP libraries:
"application/xml": <faultstring>The endpoint reference (EPR) for the Operation not found is /soap-proto/services/test and the WSA Action = null</faultstring>
"text/xml" - <faultstring>com.ctc.wstx.exc.WstxEOFException: Unexpected EOF in prolog
at [row,col {unknown-source}]: [1,0]</faultstring>
I’ve included those error messages because it was near impossible to find the reason for them elsewhere. Hopefully they help solve your problem.
If you are looking for a way to test your SOAP API through a Grails application, you can do so by creating a simple Controller:
class TestController {
def index = {
def soapRequest = """ <soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:axis="http://ws.apache.org/axis2"> <soap:Header/> <soap:Body> <axis:availableBooks /> </soap:Body> </soap:Envelope> """ def soapUrl =
new URL("http://localhost:8080/my-project/services/test")
def connection = soapUrl.openConnection()
connection.setRequestMethod("POST" )
connection.setRequestProperty("Content-Type" ,
"application/soap+xml" )
connection.doOutput = true Writer writer = new OutputStreamWriter(connection.outputStream) writer.write(soapRequest) writer.flush() writer.close() connection.connect() def soapResponse = connection.content.text render(soapResponse)
}
}
Change the XML document as necessary. Notice the “application/soap+xml” content type being set here as well.
Hopefully someone else benefits from my experience piecing together this puzzle. If so, let me know by leaving a comment.
November 18th, 2008 at 6:45 pm
Great article. Why did you choose to use Axis instead of the more commonly referenced XFire plugin? I have played with the latter and found some issues with session scoped services and was unable to get any help on the mail list.
November 18th, 2008 at 8:08 pm
I have actually played around with XFire, Axis2, and CXF. From the discussion lists I’ve read, it appears that XFire support is being phased out, and will be replaced with CXF. Axis2 is built on top of CXF and comes as a plugin for Grails, that’s why I chose this path. All three frameworks are severly lacking good tutorials, although XFire probably has the best because it’s the oldest.
The work I was performing was for a SOAP prototype. At the moment, we have no plans to actually use it – we just wanted to see that it _could_ work if necessary. I did not need to fully implement WSDL stubs, thus the reason for the approaches taken in this post – quick and dirty.
March 2nd, 2009 at 3:01 pm
Can you post the code of the Service class?
April 5th, 2010 at 12:23 am
[...] soap Beak's Blog Blog Archive Testing a SOAP interface using …Testing a SOAP interface using the Apache Axis2 Plugin. There's a lot of information … I utilized [...]