Saturday, April 2, 2011

Grails 1.3.6 and JBossWS work well together

JBossWS may not be the first option that comes to mind when you think of adding SOAP web services to your grails application, but if you are deploying to a JBoss server, this choice works very well and should be considered.

I will describe how to build a PingService using a bottom-up approach. The ping service has one method, greet, which takes a string argument representing a name and returns a friendly greeting.

The example is very simple and the solution is more complicated than it needs to be in order to show how java code (the JBossWS method) can call a Grails Service. In a real world scenario, this would be a suitable approach.

We will begin by creating a Grails Application named demo:

grails create-app demo

Next we will create a Grails Service named PingService:

grails create-service com.javabilities.demo.ws.Ping

Despite the name, this class is a grails service (spring bean) and not a web service. This method will be called by the web service.

class PingService {
static transactional = true

String greet(String name) {
"Hello ${name}!"
}
}

Create an annotated POJO named Ping in the com.javabilities.demo.ws package of the src/java directory:

@WebService(targetNamespace = "https://www.javabilities.com/demo/services",
serviceName = "PingService")
@SOAPBinding(style = SOAPBinding.Style.RPC)
public class Ping {
}

Add the annotated greet method:

@WebMethod
@WebResult(name="greeting")
public String greet(@WebParam(name="name") String name) {
}

NOTE: the WebResult annotation gives a meaningful name to the return variable in the generated WSDL.

Now the greet method in the JBossWS need to call the Grails PingService. Add the following to the greet method of the JBossWS:

ApplicationContext ctx = (ApplicationContext)ApplicationHolder.getApplication().getMainContext();
PingService service = (PingService)ctx.getBean("pingService");
String greeting = service.greet(name);
return greeting;

This retrieves the spring context from the Grails ApplicationHolder, then the PingService spring bean from the spring context and then finally calls the greet method on the PingService spring bean.

We are done with the coding now, we just need to define the servlet and its mapping in the web.xml. Grails generates the web.xml from a template, so we will need to run the grails install-templates target:

grails install-templates

You will notice a new src/templates directory. You can remove the artifacts and scaffolding folders underneath the templates directory.

Add servlet and servlet mapping to the src/templates/web.xml file:

<servlet>
<servlet-name>PingService</servlet-name>
<servlet-class>com.javabilities.demo.ws.Ping</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>PingService</servlet-name>
<url-pattern>/services/PingService</url-pattern>
</servlet-mapping>

We can now deploy our Grails application to a JBoss AS configuration.

After you have deployed your web application, you can view the WSDL for your web application at:

http://localhost:8080/demo/services/PingService?wsdl

and access the web service at:

http://localhost:8080/demo/services/PingService

What we have accomplished is that we have mixed the conveniences of JBossWS and JBoss AS with the conveniences of the Groovy language and the Grails framework and have quickly created a web service. This example also shows how well Groovy and Grails work in the Java world.

The disadvantage of this approach is that when we run the application from our IDE, we will not be able to test our web services because of our dependency on the JBossAS to generate our web services. We can get around this by just using/testing the web services by calling the grails service methods when running in development mode.