Tutorial to develop Contract First webservice using CXF



In this short tutorial let us discuss how to develop a contract first webservice using Apache CXF. 

 Let us consider the scenario where the webservice accepts employee id and the year as input and returns the employee name and the number of hours the employee has worked in the year[which is as input] . So we come up with the empworkhours.wsdl  below.

 <?xml version="1.0" encoding="UTF-8"?>
<wsdl:definitions name="EmpWorkHours" targetNamespace="http://ts.com/empwork"
    xmlns:tns="http://ts.com/empwork"
    xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
    xmlns="http://schemas.xmlsoap.org/wsdl/"
    xmlns:emp="http://ts.com/empwork/types"
    xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
    xmlns:xsd="http://www.w3.org/2001/XMLSchema">
    <wsdl:types>
        <schema targetNamespace="http://ts.com/empwork/types"
            xmlns="http://www.w3.org/2001/XMLSchema"
        xmlns:tns="http://ts.com/empwork/types"
            elementFormDefault="qualified">
            <xsd:element name="EmpWorkHoursRequest" type="emp:EmpWorkHoursRequestType"/>
            <xsd:element name="EmpWorkHoursResponse" type="emp:EmpWorkHoursResultType"/>
            <xsd:complexType name="EmpWorkHoursRequestType">
                <xsd:sequence>
                    <xsd:element name="empid" type="xsd:string"/>
                    <xsd:element name="year" type="xsd:integer"/>
                </xsd:sequence>
            </xsd:complexType>
            <xsd:complexType name="EmpWorkHoursResultType">
                <xsd:sequence>
                    <xsd:element name="empid" type="xsd:string"/>
                    <xsd:element name="year" type="xsd:integer"/>
                    <xsd:element name="name" type="xsd:string"/>
                    <xsd:element name="workhours" type="xsd:integer"/>
                </xsd:sequence>
            </xsd:complexType>
        </schema>
    </wsdl:types>
    <wsdl:message name="request">
        <wsdl:part element="emp:EmpWorkHoursRequest" name="in"/>
    </wsdl:message>
    <wsdl:message name="response">
        <wsdl:part element="emp:EmpWorkHoursResponse" name="out"/>
    </wsdl:message>
    <wsdl:portType name="EmpWorkHours">
        <wsdl:operation name="getWorkHours">
            <wsdl:input message="tns:request" name="workHoursRequest"/>
            <wsdl:output message="tns:response" name="workHoursResponse"/>
        </wsdl:operation>
    </wsdl:portType>
    <wsdl:binding name="EmpWorkHours_SOAPBinding" type="tns:EmpWorkHours">
        <soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/>
        <wsdl:operation name="getWorkHours">
            <soap:operation soapAction="" style="document"/>
            <wsdl:input name="workHoursRequest">
                <soap:body use="literal"/>
            </wsdl:input>
            <wsdl:output name="workHoursResponse">
                <soap:body use="literal"/>
            </wsdl:output>
        </wsdl:operation>
    </wsdl:binding>
    <wsdl:service name="SOAPService">
        <wsdl:port binding="tns:EmpWorkHours_SOAPBinding" name="EmpWorkHoursWS">
            <soap:address location="http://localhost:8090/cxfcontractfirstwebapp/services/EmpWorkHoursWS"/>
        </wsdl:port>
    </wsdl:service>
</wsdl:definitions>

 

Now let us create a Maven web application with the pom.xml given below.


<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.thea</groupId>
    <artifactId>cxfcontractfirstwebapp</artifactId>
    <packaging>war</packaging>
    <version>0.1</version>
    <name>cxfcontractfirstwebapp Maven Webapp</name>
    <url>http://maven.apache.org</url>
    <dependencies>
        <dependency>
            <groupId>org.apache.cxf</groupId>
            <artifactId>cxf-rt-frontend-jaxws</artifactId>
            <version>2.1.2</version>
        </dependency>
        <dependency>
            <groupId>org.apache.cxf</groupId>
            <artifactId>cxf-rt-transports-http</artifactId>
            <version>2.1.2</version>
        </dependency>
        <!-- Jetty is needed if you're are not using the CXFServlet -->
        <dependency>
            <groupId>org.apache.cxf</groupId>
            <artifactId>cxf-rt-transports-http-jetty</artifactId>
            <version>2.1.2</version>
        </dependency>
    </dependencies>
    <build>
        <finalName>cxfcontractfirstwebapp</finalName>
        <plugins>
            <plugin>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>2.0.2</version>
                <configuration>
                    <source>1.5</source>
                    <target>1.5</target>
                </configuration>
            </plugin>
            <!-- wsdl generator plugin-->
            <plugin>
                <groupId>org.apache.cxf</groupId>
                <artifactId>cxf-codegen-plugin</artifactId>
                <version>2.1.2</version>
                <executions>
                    <execution>
                        <id>generate-sources</id>
                        <phase>generate-sources</phase>
                        <configuration>
                            <sourceRoot>./src/main/java</sourceRoot>
                            <wsdlOptions>
                                <wsdlOption>
                                    <wsdl>E:\javacode\nbcodepart2\cxfcontractfirstwebapp\src\main\wsdl\empworkhours.wsdl</wsdl>
                                    <extraargs>
                                        <extraarg>-server</extraarg>
                                        <extraarg>-impl</extraarg>
                                    </extraargs>
                                </wsdlOption>
                            </wsdlOptions>
                        </configuration>
                        <goals>
                            <goal>wsdl2java</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
</project>
 

Now let us generate the server and implementation Java files from the wsdl using the command mvn generate-sources.

Now edit EmpWorkHoursImpl.java to remove name in the WebService annotation. Also include the desired logic to fetch the hours worked by the employee in the given year from a datasource. After modification the file should look as below.

 package com.ts.empwork;

import java.math.BigInteger;
import java.util.logging.Logger;

@javax.jws.WebService(serviceName = "SOAPService",
portName = "EmpWorkHoursWS",
targetNamespace = "http://ts.com/empwork",
wsdlLocation = "file:/E:/javacode/nbcodepart2/cxfcontractfirstwebapp/src/main/wsdl/empworkhours.wsdl",
endpointInterface = "com.ts.empwork.EmpWorkHours")
public class EmpWorkHoursImpl implements EmpWorkHours {

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

    /* (non-Javadoc)
     * @see com.ts.empwork.EmpWorkHours#getWorkHours(com.ts.empwork.types.EmpWorkHoursRequestType  in )*
     */
    public com.ts.empwork.types.EmpWorkHoursResultType getWorkHours(com.ts.empwork.types.EmpWorkHoursRequestType in) {
        LOG.info("Executing operation getWorkHours");
        System.out.println(in);
        try {
            com.ts.empwork.types.EmpWorkHoursResultType _return = new com.ts.empwork.types.EmpWorkHoursResultType();

            //The below data will be fetched from a datasource. To keep the example simple
            //we set hard coded values here

            _return.setEmpid(in.getEmpid());
            _return.setYear(in.getYear());
            _return.setName("Karthik");
            _return.setWorkhours(new BigInteger("1800"));


            return _return;
        } catch (Exception ex) {
            ex.printStackTrace();
            throw new RuntimeException(ex);
        }
    }
}

 So far we have generated the server and implementation files. Now let us generate the client Java files [which are required to consume the webservice] into yet another simple Java project  by introducing <extraarg>-client</extraarg> in the pom.xml. [You may comment server and impl extraargs as they are not needed in a client].

Now as we have generated both the client and server side Java files form wsdl, comment the wsdl generator plugin in the pom.xml of both the server and client projects. [It is not required until we need to regenerate files for any change in wsdl]. This is as a precaution so that we do not accidentally override the implementation files.

Now edit the web.xml of the Maven web application. The content of the final web.xml is as below.

 <?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
    <display-name>cxfcontractfirstwebapp</display-name>
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:cxf.xml</param-value>
    </context-param>
    <listener>
        <listener-class>
      org.springframework.web.context.ContextLoaderListener
        </listener-class>
    </listener>
    <servlet>
        <servlet-name>CXFServlet</servlet-name>
        <servlet-class>
        org.apache.cxf.transport.servlet.CXFServlet
        </servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>CXFServlet</servlet-name>
        <url-pattern>/services/*</url-pattern>
    </servlet-mapping>
</web-app>

 Then let us create a file called cxf.xml under resources folder of Maven structure [that is under projectroot/src/main/resources]. The content of cxf.xml is as below.

<beans xmlns="http://www.springframework.org/schema/beans"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      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://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" />
    <jaxws:endpoint id="EmpWorkHours"
                  implementor="com.ts.empwork.EmpWorkHoursImpl"
                  address="/EmpWorkHoursWS">
        <jaxws:properties>
        </jaxws:properties>
    </jaxws:endpoint>
</beans>

 Package the web application using Maven and deploy it on the desired server like Tomcat or GlassFish.

For the given example you may verify the successful installation by checking that the service is listed as an available service when you type http://localhost:8090/cxfcontractfirstwebapp/services in the browser. [Note: Please change the port number and the server as required]

Now let us concentrate on the client side which will consume the deployed web service. Find EmpWorkHours_EmpWorkHoursWS_Client.java [a generated file and modify the content as below].

package com.ts.empwork;

import java.io.File;
import java.math.BigInteger;
import java.net.MalformedURLException;
import java.net.URL;
import javax.xml.namespace.QName;

public final class EmpWorkHours_EmpWorkHoursWS_Client {

    private static final QName SERVICE_NAME = new QName("http://ts.com/empwork", "SOAPService");

    private EmpWorkHours_EmpWorkHoursWS_Client() {
    }

    public static void main(String args[]) throws Exception {
        URL wsdlURL = SOAPService.WSDL_LOCATION;
        if (args.length > 0) {
            File wsdlFile = new File(args[0]);
            try {
                if (wsdlFile.exists()) {
                    wsdlURL = wsdlFile.toURI().toURL();
                } else {
                    wsdlURL = new URL(args[0]);
                }
            } catch (MalformedURLException e) {
                e.printStackTrace();
            }
        }

        SOAPService ss = new SOAPService(wsdlURL, SERVICE_NAME);
        EmpWorkHours port = ss.getEmpWorkHoursWS();

        {
            System.out.println("Invoking getWorkHours...");
            com.ts.empwork.types.EmpWorkHoursRequestType _getWorkHours_in = new com.ts.empwork.types.EmpWorkHoursRequestType();
            _getWorkHours_in.setEmpid("1001");
            _getWorkHours_in.setYear(new BigInteger("2008"));
            com.ts.empwork.types.EmpWorkHoursResultType _getWorkHours__return = port.getWorkHours(_getWorkHours_in);
            System.out.println("getWorkHours.result=" + _getWorkHours__return.getWorkhours());

        }

        System.exit(0);
    }
}
 

Then run it to verify that it prints the work hours as 1800 [which was set in the server]. I used Netbeans to run and the output is as in the screenshot. [I had the client Java application that consumes the web service built by Maven ]


For beginners in web services, there are two approaches to develop a
webservice. Approach 1 is contract first - we start with a wsdl file
and Approach 2 - code first - we start with  Java class(es) [assuming
the programming language is Java] and expose them as webservice [for
which XFire and CXF are famous for].


 
 
 
 
Comments:

Hello, Thank's for this intresting work. i've problem when i try mvn eclipe:eclipse the message generated is : Unable to download the artifact from any repositiry : org.apache.cxf : cxf-codegen-plugin : pom:2.1.2 from the specified remote repositories and that even if i have apache-plugin-snapshots Apache Maven Plugin Snapshots http://people.apache.org/repo/m2-snapshot-repository false true apache-plugin-incubating Apache Plugin Incubating Repository http://people.apache.org/repo/m2-incubating-repository/ Thank's

Posted by kakach on October 07, 2008 at 07:57 AM CDT #

Hi kakach, Can you please send me your pom.xml? The tutorial uses NetBeans but I will try topost one with eclipse.

Posted by karthikeyan c on October 09, 2008 at 11:45 PM CDT #

Post a Comment:
  • HTML Syntax: Allowed
 

« January 2009
SunMonTueWedThuFriSat
    
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
       
Today

Valid XHTML or CSS?

[This is a Roller site]
 
© Karthik