Grails Web Services

In this blog we’ll expose a Grails service as a SOAP service. According to good practice we’ll build the WSDL first and then write the implementation code.
First things first. Let’s create a new grails application and call it grails-soap

grails> create-app grails-soap

 

CXF

For SOAP support we’ll be using the Grails CXF plugin. Just add the following line in the plugin section of your BuildConfig.groovy file to enable the plugin. Documentation for the plugin can be found here.

compile ':cxf:1.1.1'

 

WSDL

We’ll start with building the WSDL for the service. The service will be called DepartmentService and will return some Department data for a given id. We’ll place the WSDL in the src/java folder.

<?xml version="1.0" encoding="UTF-8"?>
<wsdl:definitions name="DepartmentService"
	targetNamespace="http://devjournal/DepartmentService" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
	xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap12="http://schemas.xmlsoap.org/wsdl/soap12s/"
	xmlns:tns="http://devjournal/DepartmentService">
	<wsdl:types>
		<xsd:schema xmlns="http://www.w3.org/2001/XMLSchema">
			<import namespace="http://devjournal/DepartmentService"
				schemaLocation="DepartmentService.xsd" />
		</xsd:schema>
	</wsdl:types>
	<wsdl:message name="DepartmentServiceRequestMessage">
		<wsdl:part name="in" element="tns:DepartmentServiceRequest" />
	</wsdl:message>
	<wsdl:message name="DepartmentServiceResponseMessage">
		<wsdl:part name="out" element="tns:DepartmentServiceResponse" />
	</wsdl:message>
	<wsdl:portType name="GetDepartmentById">
		<wsdl:operation name="getDepartmentById">
			<wsdl:input message="tns:DepartmentServiceRequestMessage" />
			<wsdl:output message="tns:DepartmentServiceResponseMessage" />
		</wsdl:operation>
	</wsdl:portType>
	<wsdl:binding name="GetDepartmentByIdSoap12" type="tns:GetDepartmentById">
		<soap12:binding transport="http://schemas.xmlsoap.org/soap/http"
			style="document" />
		<wsdl:operation name="getDepartmentById">
			<soap12:operation
				soapAction="http://whitehorses.nl/Whitebook_SOA_UT/DepartmentService/GetDepartmentById"
				style="document" />
			<wsdl:input>
				<soap12:body use="literal" parts="in" />
			</wsdl:input>
			<wsdl:output>
				<soap12:body use="literal" parts="out" />
			</wsdl:output>
		</wsdl:operation>
	</wsdl:binding>
	<wsdl:service name="DepartmentService">
		<wsdl:port binding="tns:GetDepartmentByIdSoap12" name="GetDepartmentByIdSoap12">
			<soap12:address location="http://www.example.org/" />
		</wsdl:port>
	</wsdl:service>
</wsdl:definitions>

The underlying xml schema file contains the response element. This file will also be placed in the src/java folder.

<?xml version="1.0" encoding="UTF-8"?>
<schema attributeFormDefault="unqualified" elementFormDefault="qualified"
        targetNamespace="http://devjournal/DepartmentService"
        xmlns:tns="http://devjournal/DepartmentService"
        xmlns="http://www.w3.org/2001/XMLSchema">
 <element name="DepartmentServiceRequest">
  <complexType>
   <sequence>
    <element name="Id" type="int"/>
   </sequence>
  </complexType>
 </element>
 <element name="DepartmentServiceResponse">
  <complexType>
   <sequence>
    <element name="Department" type="tns:departmentType" maxOccurs="1"
             minOccurs="0"/>
   </sequence>
  </complexType>
 </element>
 <complexType name="departmentType">
  <sequence>
   <element name="Id" type="int"/>
   <element name="Name" type="string"/>
   <element name="Location" type="string"/>
  </sequence>
 </complexType>
</schema>

 

wsdl2java

Now that we have the WSDL it’s time to generate the Java stubs. Although the CXF plug-in comes with a wsdl-to-java command it kept giving me a “GroovyCastException” when I tried to run it. To workaround this problem, I downloaded the latest apache-cxf distribution here (2.7.11 at the time of this writing) and used its wsdl2java command to generate the stubs.

$ $CXF_HOME/apache-cxf-2.7.11/bin/wsdl2java DepartmentService.wsdl

After running this command from within the /src/java directory, the following stub classes are added to your grails application:

wsdl2java classes

wsdl2java classes

 

service

Now everything is in place, we can start implementing the service. First create a new grails service component called DepartmentService

grails> create-service department

We’ll have this service implement the generated @WebService interface GetDepartmentById and override the getDepartmentById method (corresponding with the SOAP operation of the same name) For simplicity sake, we’ll just hardcode a response:

package grails.soap

import javax.jws.WebService

import org.grails.cxf.utils.EndpointType

import devjournal.departmentservice.DepartmentServiceRequest
import devjournal.departmentservice.DepartmentServiceResponse
import devjournal.departmentservice.DepartmentType
import devjournal.departmentservice.GetDepartmentById


@WebService(targetNamespace = "http://devjournal/DepartmentService", name = "GetDepartmentById", serviceName = 'DepartmentService',
portName = 'GetDepartmentById')
class DepartmentService implements GetDepartmentById {

	static expose = EndpointType.JAX_WS_WSDL
	static soap12 = true
	static address = 'DepartmentService'
	
	def serviceMethod() {
	}

	@Override
	public DepartmentServiceResponse getDepartmentById(
			DepartmentServiceRequest departmentServiceRequest) {

		DepartmentType department = new DepartmentType(id: departmentServiceRequest.id, location:'Amsterdam', name: 'Sales')
		return new DepartmentServiceResponse(department:department)
	}
}

As you can see in the code above, we’ve implemented the GetDepartmentById interface and added the @WebService annotation to the service. With the serviceName and portName attributes we can influence the WSDL that’s eventually being served.
The cxf-plugin allows further configuration by means of static properties. Setting the soap12 property to “true” makes the DepartmentService adhere to the SOAP 1.2 specification. With the address property we can adjust the endpoint of the service. By default it would be the default address of the grails service, i.e. “/services/department”. In the above example the endpoint will be “/services/DepartmentService”. Refer to the cxf-plugin documentation for an overview of available properties.
 

Testing the web service

Now let’s fire up the application and give it a spin

grails> run-app

The WSDL should be available at http://localhost:8080/services/DepartmentService?WSDL and can be tested with SoapUI. The screenshot below shows the result.

DepartmentService Test

DepartmentService Test


 

Conclusion

In this blog I’ve shown how easy it is to expose a grails service via SOAP. Although the service had been turned into a SOAP service it’s still available as a normal grail service to the rest of the application, so there’s no violation of the DRY principle and code can be reused.

Advertisements
%d bloggers like this: