Contract first CXF

CXF is an apache framework for developing web services. It implements the JAX-WS APIs and claims to be significantly easier to use than the reference implementation. A lot of the information around this framework focuses on developing java-first webservices. However contract-first should offer better stability of the interface so here is a short tutorial for getting a prototype contract-first webservice up and running.

Generate a simple maven project

mvn archetype:generate

  1. Select the default archetype, maven-archetype-quickstart (I couldnt find a specifc archetype for CXF contract-first)
  2. Fill in the parameters:

version = 6
groupId = com.yourcompany.sample
artifactId = sample-ws
version = 1.0-SNAPSHOT
package = com.yourcompany.sample

 

Add the CXF dependencies to your pom.xml

<dependency>
 <groupId>org.apache.cxf</groupId>
 <artifactId>cxf-rt-frontend-jaxws</artifactId>
 <version>2.3.1</version>
 <type>jar</type>
 <scope>runtime</scope>
 </dependency>
 <dependency>
 <groupId>org.apache.cxf</groupId>
 <artifactId>cxf-rt-transports-http</artifactId>
 <version>2.3.1</version>
 <type>jar</type>
 <scope>runtime</scope>
 </dependency>

Add your wsdl

I have created a very simple wsdl, registry.wsdl. It has one operation, retreive, which retreives a registry item based on id. Place the file under /sample-ws/src/main/wsdl/


<?xml version="1.0" encoding="UTF-8" standalone="no"?><wsdl:definitions xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:sch="http://sample.yourcompany.com/ns" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:tns="http://sample.yourcompany.com/ns" targetNamespace="http://sample.yourcompany.com/ns">
 <wsdl:types>
 <xs:schema xmlns:sk="http://sample.yourcompany.com/ns" xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified" targetNamespace="http://sample.yourcompany.com/ns">
 <xs:element name="RegistryRequestType">
 <xs:complexType>
 <xs:all>
 <xs:element ref="sk:Id"/>
 </xs:all>
 </xs:complexType>
 </xs:element>
 <xs:element name="RegistryResponseType">
 <xs:complexType>
 <xs:all>
 <xs:element name="Registry" type="sk:RegistryType"/>
 </xs:all>
 </xs:complexType>
 </xs:element>
 <xs:complexType name="RegistryType">
 <xs:sequence>
 <xs:element ref="sk:Id"/>
 <xs:element ref="sk:Name"/>
 </xs:sequence>
 </xs:complexType>
 <xs:element name="Id" type="xs:integer"/>
 <xs:element name="Name" type="xs:NCName"/>
</xs:schema>
 </wsdl:types>
 <wsdl:message name="RegistryRequestMsg">
 <wsdl:part element="tns:RegistryRequestType" name="RegistryRequest">
 </wsdl:part>
 </wsdl:message>
 <wsdl:message name="RegistryResponseMsg">
 <wsdl:part element="tns:RegistryResponseType" name="RegistryResponse">
 </wsdl:part>
 </wsdl:message>
 <wsdl:portType name="RegistryResource">
 <wsdl:operation name="retreive">
 <wsdl:input message="tns:RegistryRequestMsg" name="RegistryRequest">
 </wsdl:input>
 <wsdl:output message="tns:RegistryResponseMsg" name="RegistryResponse">
 </wsdl:output>
 </wsdl:operation>
 </wsdl:portType>
 <wsdl:binding name="RegistryResourceSoap" type="tns:RegistryResource">
 <soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/>
 <wsdl:operation name="retreive">
 <soap:operation />
 <wsdl:input>
 <soap:body parts="RegistryRequest"/>
 </wsdl:input>
 <wsdl:output>
 <soap:body parts="RegistryResponse"/>
 </wsdl:output>
 </wsdl:operation>
 </wsdl:binding>
 <wsdl:service name="RegistryResourceService">
 <wsdl:port binding="tns:RegistryResourceSoap" name="RegistryResourceSoap">
 <soap:address location="/registryService/"/>
 </wsdl:port>
 </wsdl:service>
</wsdl:definitions>

Add the cxf-codegen-plugin

This plugin will be used to generate an implementation stub based on your webservices wsdl. You need fill the wsdl element with the location of your wsdl file. The extraarg elements, -impl and – verbose specify that implementation starting point should be generated and the code generation should be verbose respectively.

<plugin>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-codegen-plugin</artifactId>
<version>2.3.1</version>
<executions>
<execution>
<id>generate-sources</id>
<configuration>
<wsdlOptions>
<wsdlOption>
<wsdl>${basedir}/src/main/wsdl/registry.wsdl</wsdl>
<extraargs>
<extraarg>-impl</extraarg>
<extraarg>-verbose</extraarg>
</extraargs>
</wsdlOption>
</wsdlOptions>
</configuration>
<goals>
<goal>wsdl2java</goal>
</goals>
</execution>
</executions>
</plugin>

Include generated sources

In order to complete the implmentation the generated stubs must be included in the souce of the maven build. Add the generated files by adding the build-helper-maven-plugin referring to the path of the generated files /target/generated/src/main/java.

Note: M2Eclipse doesnt seem to pick up on this source folder so you will have to add it manually in eclipse.


<plugin>
 <groupId>org.codehaus.mojo</groupId>
 <artifactId>build-helper-maven-plugin</artifactId>
 <version>1.5</version>
 <executions>
 <execution>
 <id>add-source</id>
 <phase>generate-sources</phase>
 <goals>
 <goal>add-source</goal>
 </goals>
 <configuration>
 <sources>
 <source>${basedir}/target/generated/src/main/java</source>
 </sources>
 </configuration>
 </execution>
 </executions>
 </plugin>

Implement the service

Next move the generated implementation (RegistryResourceImpl) to your normal source folder src/main/java. My naive implementation simple returns a registry object with the same id as the request and the name “Registry Name”

/**
 * Please modify this class to meet your needs
 * This class is not complete
 */

package com.yourcompany.sample.ws.impl;

import java.util.logging.Logger;

import com.yourcompany.sample.ns.RegistryRequestType;
import com.yourcompany.sample.ns.RegistryResource;
import com.yourcompany.sample.ns.RegistryResponseType;
import com.yourcompany.sample.ns.RegistryType;

/**
 * This class was generated by Apache CXF 2.3.1
 * Tue Feb 01 14:56:51 CET 2011
 * Generated source version: 2.3.1
 *
 */

@javax.jws.WebService(
 serviceName = "RegistryResourceService",
 portName = "RegistryResourceSoap",
 targetNamespace = "http://sample.yourcompany.com/ns",
 wsdlLocation = "file:/D:/Projects/EFP/samples/sample-ws/src/main/wsdl/registry.wsdl",
 endpointInterface = "com.yourcompany.sample.ns.RegistryResource")

public class RegistryResourceImpl implements RegistryResource {

 private static final Logger LOG = Logger.getLogger(RegistryResourceImpl.class.getName());

 /* (non-Javadoc)
 * @see com.yourcompany.sample.ns.RegistryResource#retreive(com.yourcompany.sample.ns.RegistryRequestType  registryRequest )*
 */
 public RegistryResponseType retreive(RegistryRequestType registryRequest) {
 LOG.info("Executing operation retreive");
 try {
 RegistryResponseType registryResponse = new RegistryResponseType();
 RegistryType registryType = new RegistryType();
 registryType.setId(registryRequest.getId());
 registryType.setName("Registry Name");
 registryResponse.setRegistry(registryType);
 return registryResponse;
 } catch (Exception ex) {
 ex.printStackTrace();
 throw new RuntimeException(ex);
 }
 }

}

Create and deploy war

Next add the web.xml under the expected maven structure src/main/webapp/WEB-INF/web.xml. It declares that the CXFServlet should be responsile for dealing with requests and initialises the spring context.

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"
 version="2.4">

 <display-name>Contract-First CXF Web Service</display-name>

 <listener>
 <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
 </listener>

 <context-param>
 <param-name>contextConfigLocation</param-name>
 <param-value>classpath:application-context.xml</param-value>
 </context-param>

 <servlet>
 <servlet-name>CXFServlet</servlet-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>/*</url-pattern>
 </servlet-mapping>

</web-app>

The spring application centext should import the cxf beans and define the jaxws endpoint:


<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
 xmlns:jee="http://www.springframework.org/schema/jee" xmlns:jaxws="http://cxf.apache.org/jaxws"
 xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-2.5.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd
http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd">

 <context:annotation-config />

 <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" />

 <!-- JAX-WS Service Endpoint -->
 <jaxws:endpoint id="registryWS" implementor="#registryResource" address="/registryService" />

 <bean id="registryResource">
 </bean>

</beans>

Add the maven-war-plugin to the pom.xml and set the output directory to your weblogic profiles autodeploy directory. Add change the packaging to be war.

<plugin>
 <groupId>org.apache.maven.plugins</groupId>
 <artifactId>maven-war-plugin</artifactId>
 <version>2.1.1</version>
 <configuration>
 <outputDirectory>D:/path/to/profile/autodeploy</outputDirectory>
 </configuration>
 </plugin>

After that a simple mvn clean install should deploy the webservice on your running weblogic server.Here is a sample request and response:


<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns="http://sample.yourcompany.com/ns">
 <soapenv:Header/>
 <soapenv:Body>
 <ns:RegistryRequestType>
 <ns:Id>1</ns:Id>
 </ns:RegistryRequestType>
 </soapenv:Body>
</soapenv:Envelope>

<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
 <soap:Body>
 <RegistryResponseType xmlns="http://sample.yourcompany.com/ns">
 <Registry>
 <Id>1</Id>
 <Name>Registry Name</Name>
 </Registry>
 </RegistryResponseType>
 </soap:Body>
</soap:Envelope>

Advertisements

About bebblebrox

I am an experienced software developer with over five year’s commercial experience with strong software design and development skills. I am searching for an ambitious start-up company with a shared passion for delivering quality software products.
This entry was posted in Uncategorized. Bookmark the permalink.

One Response to Contract first CXF

  1. asbestos says:

    Man, you are genius!
    10x for post

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s