Beak’s Blog
Random comments about technology and life in Mexico

Archive for November, 2008

Testing a SOAP interface using the Apache Axis2 Plugin

Monday, November 17th, 2008

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.

Grails documentation is not the holy grail

Monday, November 17th, 2008

Well, I obviously haven’t had much to write about this year.  That is probably going to change.  A new client I am working with is using Groovy and Grails and I’m in the process of learning them both.  It’s been about 4 weeks, and one thing is clear – beyond the introduction tutorial, the Grails documentation sucks.

The documentation at grails.org is available online in Wiki format.  This means that the community can help to make it suck less.  However, whoever wrote the Wiki software obviously thought that useless Ajax functionality was more important than important things like edit timestamps and revision comments.

Nonetheless, I’ll do my part to update the documentation when I find it outdated, missing essential information, or just plain wrong.

Besides the first tutorial on creating a Grails application, the grails.org website has not been the primary source of information for me to learn about Grails.  Most of my information comes from nabble.com and markmail.org, usually found with numerous Google searches.  I’ll also recommend the Pragmatic Bookshelf Groovy Recipes book, it’s a great resource for example code.

Ok, time for me to stop complaining and get back to work.