Developing a Web Service with CXF

July 23, 2010

Webservices

«»

Creating a Service Endpoint Interface (SEI)


Let’s first create the SEifor our Order Processing Application. We will name our
SEiOrderProcess. The following code illustrates the OrderProcess SEI:



package demo.order;
import javax.jws.WebService;
@WebService
public interface OrderProcess {
@WebMethod
}


As you can see from the preceding code, we created a Service Endpoint Interface
named OrderProcess. The SEiis just like any other Java interface. It defines an
abstract business method processOrder. The method takes an Order bean as a
parameter and returns an order ID String value. The goal of the processOrder method
is to process the order placed by the customer and return the unique order ID.


One significant thing to observe is the @WebService annotation. The annotation is
placed right above the interface definition. It signifies that this interface is not an
ordinary interface but a web service interface. This interface is known as Service
Endpoint Interface
and will have a business method exposed as a service method to
be invoked by the client.


The @WebService annotation is part of the JAX-WS annotation library. JAX-WS
provides a library of annotations to turn Plain Old Java classes into web services and
specifies detailed mapping from a service defined in WSDL to the Java classes that
will implement that service. The javax.jws.WebService annotation also comes with
attributes that completely define a web service. For the moment we will ignore these
attributes and proceed with our development.


The javax.jws.@WebMethod annotation is optional and is used for customizing the
web service operation. The @WebMethod annotation provides the operation name and
the action elements which are used to customize the name attribute of the operation
and the SOAP action element in the WSDL document.


The following code shows the Order class:



package demo.order;
import javax.xml.bind.annotation.XmlRootElement;
@XmlRootElement(name = “Order”)
public class Order {
private String customerID;
private String itemID;
private int qty;
private double price;
// Contructor
public Order() {
}
public String getCustomerID() {
return customerID;
}
public void setCustomerID(String customerID) {
this.customerID = customerID;
}
public String getItemID() {
return itemID;
}
public void setItemID(String itemID) {
this.itemID = itemID;
}
public int getQty() {
return qty;
}
public void setQty(int qty) {
this.qty = qty;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
}


As you can see, we have added an @XmlRootElement annotation to the Order
class. The @XmlRootElement is part of the Java Architecture for XML Binding
(JAXB)
annotation library. JAXB provides data binding capabilities by providing
a convenient way to map XML schema to a representation in Java code. The JAXB
shields the conversion of XML schema messages in SOAP messages to Java code
without having the developers know about XML and SOAP parsing. CXF uses JAXB
as the default data binding component.


The @XmlRootElement annotations associated with Order class map the Order class to
the XML root element. The attributes contained within the Order object by default are
mapped to @XmlElement. The @XmlElement annotations are used to define elements
within the XML. The @XmlRootElement and @XmlElement annotations allow you to
customize the namespace and name of the XML element. If no customizations are
provided, then the JAXB runtime by default would use the same name of attribute for
the XML element. CXF handles this mapping of Java objects to XML.


Developing a service implementation class


We will now develop the implementation class that will realize our OrderProcess
SEI. We will name this implementation class OrderProcessImpl. The following code
illustrates the service implementation class OrderProcessImpl:



@WebService
public class OrderProcessImpl implements OrderProcess {
public String processOrder(Order order) {
String orderID = validate(order);
return orderID;
}
/**
* Validates the order and returns the order ID
**/
private String validate(Order order) {
String custID = order.getCustomerID();
String itemID = order.getItemID();
int qty = order.getQty();
double price = order.getPrice();
if (custID != null && itemID != null && !custID.equals(“”)
&& !itemID.equals(“”) && qty > 0
&& price > 0.0) {
return “ORD1234″;
}
return null;
}
}


As we can see from the preceding code, our implementation class
OrderProcessImpl is pretty straightforward. It also has @WebService annotation
defined above the class declaration. The class OrderProcessImpl implements
OrderProcess SEI. The class implements the processOrder method. The
processOrder method checks for the validity of the order by invoking the validate
method. The validate method checks whether the Order bean has all the relevant
properties valid and not null.



It is recommended that developers explicitly implement OrderProcess
SEI, though it may not be necessary. This can minimize coding errors
by ensuring that the methods are implemented as defined.


Next we will look at how to publish the OrderProcess JAX-WS web service using
Sping configuration.


Spring-based server bean


What makes CXF the obvious choice as a web service framework is its use of
Spring-based configuration files to publish web service endpoints. It is the use
of such configuration files that makes the development of web service convenient
and easy with CXF.



Please refer to the Getting Started with Spring framework appendix chapter
to understand the concept of Inversion of Control, AOP (Aspect oriented
program)
, and features provided by the Spring framework using a sample
use case.


Spring provides a lightweight container which works on the concept of Inversion
of Control (IoC)
or Dependency Injection (DI) architecture; it does so through the
implementation of a configuration file that defines Java beans and its dependencies.
By using Spring you can abstract and wire all the class dependencies in a single
configuration file. The configuration file is often referred to as an Application
Context or Bean Context file.


We will create a server side Spring-based configuration file and name it as
beans.xml. The following code illustrates the beans.xml configuration file:



<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=”orderProcess”
implementor=”demo.order.OrderProcessImpl”
address=”/OrderProcess” />
</beans>


Let’s examine the previous code and understand what it really means. It first defines
the necessary namespaces. It then defines a series of <import> statements. It imports
cxf.xml, cxf-extension-soap.xml, and cxf-servlet.xml. These files are Springbased
configuration files that define core components of CXF. They are used to
kick start CXF runtime and load the necessary infrastructure objects such as WSDL
manager, conduit manager, destination factory manager, and so on


The <jaxws:endpoint> element in the beans.xml file specifies the OrderProcess
web service as a JAX-WS endpoint. The element is defined with the following
three attributes:



  • id—s pecifies a unique identifier for a bean. In this case, jaxws:endpoint is
    a bean, and the id name is orderProcess.

  • implementor— specifies the actual web service implementation class. In this
    case, our implementor class is OrderProcessImpl.

  • address— specifies the URL address where the endpoint is to be published.
    The URL address must to be relative to the web context. For our example,
    the endpoint will be published using the relative path /OrderProcess.


The <jaxws:endpoint> element signifies that the CXF internally uses JAX-WS
frontend to publish the web service. This element definition provides a short and
convenient way to publish a web service. A developer need not have to write any
Java class to publish a web service.


Developing a client


In the previous section we discussed and illustrated how to develop and publish a
web service. We now have the server-side code that publishes our OrderProcess
web service. The next set of tasks will be to create the client-side code that will
consume or invoke our OrderProcess web service. To achieve this, we will perform
the following steps:



  • Develop the client-beans.xml to define the client factory class as a Spring
    bean using JAX-WS frontend

  • Develop a client Java application to invoke the web service


Developing a Spring-based client bean


We will create a client-side Spring-based configuration file and name it as
client-beans.xml. The following code illustrates the client-beans.xml
configuration file:



<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”>
<jaxws:client id=”orderClient” serviceClass=
“demo.order.OrderProcess” address=
“http://localhost:8080/orderapp/OrderProcess” />
</beans>


The <jaxws:client> element in the client-beans.xml file specifies the client bean
using JAX-WS frontend. The element is defined with the following three attributes:



  • id—specifies a unique identifier for a bean. In this case, jaxws:client is a
    bean and the id name is orderClient. The bean will represent an SEI.

  • serviceClass—specifies the web service SEI. In this case our SEiclass is
    OrderProcess

  • address—specifies the URL address where the endpoint is
    published. In this case the endpoint is published at the URL address:

    http://localhost:8080/orderapp/OrderProcess


<jaxws:client> signifies the client bean that represents an OrderProcess SEI. The
client application will make use of this SEito invoke the web service. Again, CXF
internally uses JAX-WS frontend to define this client-side component.


Developing web service client code


We will now create a standalone Java class to invoke our OrderProcess web service.
The following code illustrates the client invocation of a web service method:



public final class Client {
public Client() {
}
public static void main(String args[]) throws Exception {
// START SNIPPET: client
ClassPathXmlApplicationContext context
= new ClassPathXmlApplicationContext(new String[]
{“demo/order/client/client-beans.xml”});
OrderProcess client = (OrderProcess) context.
getBean(“orderClient”);
// Populate the Order bean
Order order = new Order();
order.setCustomerID(“C001″);
order.setItemID(“I001″);
order.setQty(100);
order.setPrice(200.00);
String orderID = client.processOrder(order);
String message = (orderID == null) ?
“Order not approved” : “Order approved;
order ID is ” + orderID;
System.out.println(message);
System.exit(0);


As you can see from the above code, we have the main method that first loads
the client-beans.xml configuration file. It uses the Spring application context
component ClassPathXmlApplicationContext to load the configuration file. The
context component’s getBean method is passed the bean ID orderClient. This
method will return the OrderProcess SEicomponent. Using the SEI, we then invoke
the web service method processOrder. One thing to observe here is that the client
always uses the interface to invoke a web service method. The processOrder method
takes the Order bean as a parameter. The following code depicts the Order bean:



public class Order {
private String customerID;
private String itemID;
private int qty;
private double price;
// Contructor
public Order() {
}
// Getter and setter methods for the above declared properties
}


The above Order bean is populated with the valid values and passed to the
processOrder method. The method will then process the order and return the
unique order ID.


We have now finished developing server and client side components. To summarize,
we created the OrderProcess service endpoint interface and the implementation
class. We then created server and client-side Spring-based configuration files and
finally we created the client application. The relevant components are developed
and we are all set to run or execute our code. But before we do that, you will have
to create one final component that will integrate Spring and CXF.


We need to wire Spring and CXF through web.xml. The following code illustrates
the web.xml file:



<web-app>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>WEB-INF/beans.xml</param-value>
</context-param>
<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
<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>/*</url-pattern>
</servlet-mapping>
</web-app>


Let’s go through the above piece of code. The web.xml, as we know, is the web
application configuration file that defines a servlet and its properties. The file
defines CXFServlet, which acts as a front runner component that initiates the
CXF environment. It defines the listener class ContextLoaderListener, which
is responsible for loading the server-side configuration file beans.xml. So upon
the web server startup, the order process web service endpoint will be registered
and published.


Running the program



The source code and build file for the chapter is available in the
Chapter2/orderapp folder of the downloaded source code.


Before running the program, we will organize the code so far developed in the
appropriate folder structure. You can create the folder structure, as shown in the
following screenshot, and put the components in the respective sub folders



The developed code will go into the following:



  • The Java code will go into the respective package folders

  • The beans.xml and web.xml will go into the webapp\WEB-INF folder

  • The client-beans.xml file will go into the demo\order\client folder


Once the code is organized, we will go about building and deploying it in the
Tomcat server. It will typically involve three steps:



  • Building the code

  • Deploying the code

  • Executing the code


Building the code


Building the code means compiling the source Java code. We will use the
ANT tool to do this. The ANT file is provided in Chapter2\orderapp folder.
The following code illustrates the sample build.xml build script:



<?xml version=”1.0″ encoding=”UTF-8″?>
<project name=”CXF Chapter2 example” default=”build” basedir=”.”>
<import file=”common_build.xml”/>
<target name=”client” description=
“run demo client” depends=”build”>
<property name=”param” value=”"/>
<cxfrun classname=”demo.order.client.Client” />
</target>
<target name=”server” description=
“run demo server” depends=”build”>
<cxfrun classname=”demo.spring.servlet.Server”/>
</target>
<property name=”cxf.war.file.name” value=”orderapp”/>
<target name=”war” depends=”build”>
<cxfwar filename=”${cxf.war.file.name}.war” webxml=
“webapp/WEB-INF/web.xml” />
</target>
</project>


Alongside build.xml, you will also find common_build.xml in the same folder.
The common_buid.xml refers to CATALINA_HOME environment variable to
find location of tomcat installation. Please make sure that you have set up the
environment variables as mentioned in Appendix A. Open the command prompt
window, go to C:\orderapp folder and run the ant command. It will build the code
and put the class files under the newly created build folder. The following figure
shows the output generated upon running the ant command.



Deploying the code


Having built the code, we will deploy it. Deployment effectively means building and
moving the code archive to the server deploy path. We will be using the Tomcat web
container to deploy and run the application. To deploy our built code, navigate to
project root folder, and enter the following command:



ant deploy


This will build the WAR file and put it under the Tomcat server webapp path. For
example, if you have installed the Tomcat under the root folder, then the WAR
will be deployed to /Tomcat/webapp folder.


Executing the code


Following code deployment, we are all set to run the Order Process Application.
You will execute the Java client program Client.java to invoke the Order Process
web service. The program will invoke the processOrder method that will generate
the order ID if the specified order is approved. Before running the client program,
we need to start the Tomcat web server. There are several ways of starting the
Tomcat server depending on the Tomcat version that is installed. Once the server is
started, you need to run the client program by giving the following command at the
command prompt window:



ant client


As you can see above, we are using Ant to run the client program. Upon executing
this command, it will generate the following output:



Thus we have successfully executed the order processing web service.

email

«»

Comments

comments