Skip to content
Skip to breadcrumbs
Skip to header menu
Skip to action menu
Skip to quick search
Quick Search
Browse
Pages
Blog
Labels
Attachments
Mail
Advanced
What’s New
Space Directory
Feed Builder
Keyboard Shortcuts
Confluence Gadgets
Log In
Dashboard
Grails
Copy Page
You are not logged in. Any changes you make will be marked as
anonymous
. You may want to
Log In
if you already have an account. You can also
Sign Up
for a new account.
This page is being edited by
.
Paragraph
Paragraph
Heading 1
Heading 2
Heading 3
Heading 4
Heading 5
Heading 6
Preformatted
Quote
Bold
Italic
Underline
More colours
Strikethrough
Subscript
Superscript
Monospace
Clear Formatting
Bullet list
Numbered list
Outdent
Indent
Align left
Align center
Align right
Link
Table
Insert
Insert Content
Image
Link
Attachment
Symbol
Emoticon
Wiki Markup
Horizontal rule
tinymce.confluence.insert_menu.macro_desc
Info
JIRA Issue
Status
Gallery
Tasklist
Table of Contents
Other Macros
Page Layout
No Layout
Two column (simple)
Two column (simple, left sidebar)
Two column (simple, right sidebar)
Three column (simple)
Two column
Two column (left sidebar)
Two column (right sidebar)
Three column
Three column (left and right sidebars)
Undo
Redo
Find/Replace
Keyboard Shortcuts Help
<h1>Grails + CXF Example</h1> <p>Ok, we've been trying to get full fledged web services (providing) working in Grails for quite a while, it felt like it should be easy, as all the bits were there, but all of the plugins to date were more proof of concept vs Enterprise ready (e.g. no control over namespaces).</p> <p>So, the target was to get CXF running with the following key requirements:</p> <ul> <li>WSDL First</li> <li>Minimal change required to CXF generated interface classes</li> <li>Bound to Grails services so we can re-use business logic and interact with domain classes</li> </ul> <h2>Step 1: Grails App + CXF</h2> <p>Create a simple Grails application (working from the ground up is the best way to explain it, rather than trying to explain our existing application), create a simple domain class, controller and service.</p> <p>Download Apache CXF (I used 2.1): <a href="http://cxf.apache.org/">http://cxf.apache.org/ </a> and extract somewhere on your PC.</p> <p>Copy the following libraries from the CXF Installation over into your Grails application lib folder:</p> <table class="wysiwyg-macro" data-macro-name="panel" style="background-image: url(/plugins/servlet/confluence/placeholder/macro-heading?definition=e3BhbmVsfQ&locale=en_GB&version=2); background-repeat: no-repeat;" data-macro-body-type="RICH_TEXT"><tr><td class="wysiwyg-macro-body"> <p>XmlSchema-1.4.2.jar<br /> commons-logging-1.1.1.jar<br /> cxf-2.1.jar<br /> cxf-manifest.jar<br /> geronimo-activation_1.1_spec-1.0.2.jar<br /> geronimo-annotation_1.0_spec-1.1.1.jar<br /> geronimo-javamail_1.4_spec-1.3.jar<br /> geronimo-jms_1.1_spec-1.1.1.jar<br /> geronimo-servlet_2.5_spec-1.2.jar<br /> geronimo-stax-api_1.0_spec-1.0.1.jar<br /> geronimo-ws-metadata_2.0_spec-1.1.2.jar<br /> jaxb-api-2.1.jar<br /> jaxb-impl-2.1.6.jar<br /> jaxb-xjc-2.1.6.jar<br /> jaxws-api-2.1-1.jar<br /> neethi-2.0.4.jar<br /> saaj-api-1.3.jar<br /> saaj-impl-1.3.jar<br /> wstx-asl-3.2.4.jar<br /> xml-resolver-1.2.jar<br /> asm-2.2.3.jar<br /> stax-utils-20060502.jar<br /> jaxen-1.1.jar<br /> jdom-1.0.jar</p></td></tr></table> <p>Next, add a resources.xml file to your grails-app/conf/Spring folder:</p> <table class="wysiwyg-macro" data-macro-name="code" style="background-image: url(/plugins/servlet/confluence/placeholder/macro-heading?definition=e2NvZGV9&locale=en_GB&version=2); background-repeat: no-repeat;" data-macro-body-type="PLAIN_TEXT"><tr><td class="wysiwyg-macro-body"><pre> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:simple="http://cxf.apache.org/simple" xmlns:lang="http://www.springframework.org/schema/lang" xmlns:jaxws="http://cxf.apache.org/jaxws" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/lang http://www.springframework.org/schema/lang/spring-lang-2.0.xsd http://cxf.apache.org/simple http://cxf.apache.org/schemas/simple.xsd http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd"> <import resource="classpath:META-INF/cxf/cxf.xml" /> <import resource="classpath:META-INF/cxf/cxf-extension-soap.xml" /> <import resource="classpath:META-INF/cxf/cxf-servlet.xml" /> </beans> </pre></td></tr></table> <p>Next, install templates for your app (grails install-templates), then go into src/templates/war and edit web.xml, add the following:</p> <table class="wysiwyg-macro" data-macro-name="code" style="background-image: url(/plugins/servlet/confluence/placeholder/macro-heading?definition=e2NvZGV9&locale=en_GB&version=2); background-repeat: no-repeat;" data-macro-body-type="PLAIN_TEXT"><tr><td class="wysiwyg-macro-body"><pre> <servlet> <servlet-name>CXFServlet</servlet-name> <display-name>CXF Servlet</display-name> <servlet-class> org.apache.cxf.transport.servlet.CXFServlet </servlet-class> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>CXFServlet</servlet-name> <url-pattern>/ws/*</url-pattern> </servlet-mapping> </pre></td></tr></table> <p>Next, ensure that you turn off the inbuilt URL Mapping for the /ws/* in conf/UrlMapping.groovy:</p> <table class="wysiwyg-macro" data-macro-name="code" style="background-image: url(/plugins/servlet/confluence/placeholder/macro-heading?definition=e2NvZGV9&locale=en_GB&version=2); background-repeat: no-repeat;" data-macro-body-type="PLAIN_TEXT"><tr><td class="wysiwyg-macro-body"><pre> class UrlMappings { static mappings = { "/$controller/$action?/$id?"{ constraints { // apply constraints here controller(matches:/.*[^(ws)].*/) } } "500"(view:'/error') } } </pre></td></tr></table> <p>Ok, now you should be able to start up your application (do this just to make sure you haven't broken anything).</p> <h2>Step 2: WSDL First CXF Service</h2> <p>Now, grab a WSDL, in this case I will use <a class="confluence-link unresolved" data-filename="currencyConverterService.wsdl" data-linked-resource-default-alias="currencyConverterService.wsdl" href="#">currencyConverterService.wsdl</a>that comes with one of the many services frameworks I downloaded recently. Go into the bin folder of the Apache CXF folder (where you saved it), and run the following command:</p> <table class="wysiwyg-macro" data-macro-name="code" style="background-image: url(/plugins/servlet/confluence/placeholder/macro-heading?definition=e2NvZGV9&locale=en_GB&version=2); background-repeat: no-repeat;" data-macro-body-type="PLAIN_TEXT"><tr><td class="wysiwyg-macro-body"><pre> wsdl2java -d <outputFolder> -impl <pathtoWSDL>/currencyConverterService.wsdl </pre></td></tr></table> <p>This generates an interface, an implementation and classes for all of the types - all properly marked up and configured. Copy everything generated into the src/java folder in your Grails app (from the com folder up).</p> <p>Now comes the fun bit!</p> <h2>Step 3: Bind the CXF Service into your Grails Application</h2> <p>Ok, now what we need to do is to tell our Grails application that we have a service, and more importantly bind that service into an existing Grails service.</p> <p>First we need to edit our Grails service, so that it implements the interface generated by CXF, and then add the methods of that interface with some code:</p> <table class="wysiwyg-macro" data-macro-name="code" style="background-image: url(/plugins/servlet/confluence/placeholder/macro-heading?definition=e2NvZGV9&locale=en_GB&version=2); background-repeat: no-repeat;" data-macro-body-type="PLAIN_TEXT"><tr><td class="wysiwyg-macro-body"><pre> class ConverterService implements com.examplewebservice.CurrencyConvert { com.examplewebservice.types.ConversionResponse convert( com.examplewebservice.types.ConversionRequest part1 ) { def resp = new com.examplewebservice.types.ConversionResponse() // We could do interesting things here, get a domain class etc. // Just return something resp.amount = 123.00 return resp } } </pre></td></tr></table> <p>Ok, good so far. Next step is to do a very small edit to the CXF Service Implementation to do the following things:</p> <ol> <li>We need to add a placeholder so that we can get Spring to inject the Grails Service into this class so that we can pass through the requests from the CXF class to the Grails service.</li> <li>Add code to the service method so that it passes through to the Grails Service</li> </ol> <p>The complete code is below:</p> <table class="wysiwyg-macro" data-macro-name="code" style="background-image: url(/plugins/servlet/confluence/placeholder/macro-heading?definition=e2NvZGV9&locale=en_GB&version=2); background-repeat: no-repeat;" data-macro-body-type="PLAIN_TEXT"><tr><td class="wysiwyg-macro-body"><pre> /** * Please modify this class to meet your needs * This class is not complete */ package com.examplewebservice; import java.util.logging.Logger; import javax.jws.WebMethod; import javax.jws.WebParam; import javax.jws.WebResult; import javax.jws.WebService; import javax.jws.soap.SOAPBinding; import javax.jws.soap.SOAPBinding.ParameterStyle; import javax.xml.bind.annotation.XmlSeeAlso; /** * This class was generated by Apache CXF 2.1 * Sun Jun 01 14:00:47 BST 2008 * Generated source version: 2.1 * */ @javax.jws.WebService(name = "CurrencyConvert", serviceName = "currencyConverterService", portName = "converterSoapPort", targetNamespace = "http://www.examplewebservice.com", wsdlLocation = "file:test/currencyConverterService.wsdl", endpointInterface = "com.examplewebservice.CurrencyConvert") public class CurrencyConvertImpl implements CurrencyConvert { // CHANGE 1. HERE // Link to Groovy Object - this is required for all Grails service implementations private CurrencyConvert groovyObject; public void setGroovyObject(CurrencyConvert groovyInstance) { this.groovyObject = groovyInstance; } private static final Logger LOG = Logger.getLogger(CurrencyConvertImpl.class.getName()); /* (non-Javadoc) * @see com.examplewebservice.CurrencyConvert#convert(com.examplewebservice.types.ConversionRequest part1 )* */ public com.examplewebservice.types.ConversionResponse convert(com.examplewebservice.types.ConversionRequest part1) { LOG.info("Executing operation convert"); System.out.println(part1); try { // CHANGE 2. HERE // pass through requests to the Groovy/Grails Service com.examplewebservice.types.ConversionResponse _return = groovyObject.convert(part1); return _return; } catch (Exception ex) { ex.printStackTrace(); throw new RuntimeException(ex); } } } </pre></td></tr></table> <p>Next, we need to go back to our resources.xml and tell CXF that we now have a service, and provide the magic that injects the Grails service into the CXF one to link them together (add the following code inside the <beans> element of the file, under the CXF imports:</p> <table class="wysiwyg-macro" data-macro-name="code" style="background-image: url(/plugins/servlet/confluence/placeholder/macro-heading?definition=e2NvZGV9&locale=en_GB&version=2); background-repeat: no-repeat;" data-macro-body-type="PLAIN_TEXT"><tr><td class="wysiwyg-macro-body"><pre> <!--create the bean for the service, link to groovy service bean --> <bean id="currencyConverter" class="com.examplewebservice.CurrencyConvertImpl"> <property name="groovyObject" ref="converterService" /> </bean> <!--create CXF service--> <simple:server serviceClass="com.examplewebservice.CurrencyConvert" address="/ConverterService"> <simple:serviceBean> <ref bean="currencyConverter" /> </simple:serviceBean> </simple:server> </pre></td></tr></table> <p>The key thing here is the bean creation, that injects the link to the Groovy Service (which is just another Bean once Grails is running) into the groovyObject property of our CXF service. The other piece is just the simple method of creating a CXF service.<br class="atl-forced-newline" /></p> <table class="wysiwyg-macro" data-macro-name="panel" style="background-image: url(/plugins/servlet/confluence/placeholder/macro-heading?definition=e3BhbmVsfQ&locale=en_GB&version=2); background-repeat: no-repeat;" data-macro-body-type="RICH_TEXT"><tr><td class="wysiwyg-macro-body"> <p><strong>Note:</strong><br /> It is possible (in some cases - I haven't figured out why it works sometimes), to not use the intermediate Java Impl class, but rather configure the CXF Service to point straight at the Grails Service bean (provided it implements the interface). This makes it much faster, as you don't need to change the generated code at all (ideal).</p> <p> <br /> In this case, the resources.xml would not have the <bean ...> and <ref bean="currencyConverter" /> becomes <ref bean="converterService"/>. Further exploration may explain why it works sometimes but not others (I get a strange error during startup of a Null parameter to CXF).</p> </td></tr></table> <h2>Step 4: Test!</h2> <p>When you run the application, you should see something like this appearing in the log:</p> <table class="wysiwyg-macro" data-macro-name="code" style="background-image: url(/plugins/servlet/confluence/placeholder/macro-heading?definition=e2NvZGV9&locale=en_GB&version=2); background-repeat: no-repeat;" data-macro-body-type="PLAIN_TEXT"><tr><td class="wysiwyg-macro-body"><pre> 01-Jun-2008 17:07:52 org.apache.cxf.service.factory.ReflectionServiceFactoryBean buildServiceFromClass INFO: Creating Service {http://examplewebservice.com/}CurrencyConvert from class com.examplewebservice.CurrencyConvert 01-Jun-2008 17:07:52 org.apache.cxf.endpoint.ServerImpl initDestination INFO: Setting the server's publish address to be /ConverterService 01-Jun-2008 17:07:53 org.apache.cxf.transport.servlet.CXFServlet loadSpringBus INFO: Load the bus with application context 01-Jun-2008 17:07:53 org.apache.cxf.bus.spring.BusApplicationContext getConfigResources INFO: No cxf.xml configuration file detected, relying on defaults. 01-Jun-2008 17:07:53 org.apache.cxf.transport.servlet.AbstractCXFServlet replaceDestinationFactory INFO: Servlet transport factory already registered </pre></td></tr></table> <p>Then, when you browse to: <a href="http://localhost:8080/wstest/ws/services">http://localhost:8080/wstest/ws/services</a> you should get the list of services (in this case just one), and then be able to view the generated WSDL (which should have all the same namespaces etc. as the original).</p> <p>Here are some pictures to prove that it works <img class="emoticon emoticon-smile" data-emoticon-name="smile" border="0" src="/s/en_GB/3278/15/_/images/icons/emoticons/smile.png" alt="(smile)" title="(smile)" /> <img class="confluence-embedded-image" src="/download/attachments/230400747/currencyservice.PNG?version=1&modificationDate=1369052551981" data-image-src="/download/attachments/230400747/currencyservice.PNG?version=1&modificationDate=1369052551981" data-linked-resource-id="230565331" data-linked-resource-type="attachment" data-linked-resource-default-alias="currencyservice.PNG" data-base-url="http://docs.codehaus.org" data-linked-resource-container-id="230400747" title="null > currencyservice.PNG"></p> <p><br class="atl-forced-newline" /> <img class="confluence-embedded-image" src="/download/attachments/230400747/soapuicurrencyservice.PNG?version=1&modificationDate=1369052551968" data-image-src="/download/attachments/230400747/soapuicurrencyservice.PNG?version=1&modificationDate=1369052551968" data-linked-resource-id="230565330" data-linked-resource-type="attachment" data-linked-resource-default-alias="soapuicurrencyservice.PNG" data-base-url="http://docs.codehaus.org" data-linked-resource-container-id="230400747" title="null > soapuicurrencyservice.PNG"><br /> </p> <h2>Next ... ?</h2> <ul> <li>No idea if this is the best way to do it, or if it will cause issues later on with respect to trying to use any of the more complex features of CXF. </li> <li>Also haven't done much testing to make sure it doesn't break other plugins, and we can still deploy it to OC4J with all the new libraries</li> </ul> <p>Clearly, any comments or feedback welcome!</p>
Please type the word appearing in the picture.
Attachments
Labels
Location
Watch this page
< Edit
Preview >
Loading…
Save
Cancel
Next hint
search
attachments
weblink
advanced