CXF and Spring Tutorial
CXF and Spring Tutorial
In this blog we will look at how to develop a simple web service using CXF and Spring-based
configurations. We will take a use case of a Order Processing Application and than develop a
web service and client for this use case.
The objective of the Order Processing Application is to process a customer order. The order
process functionality will generate the customer order, thereby making the order valid and
approved. A typical scenario will be a customer making an order request to buy a particular item.
The purchase department will receive the order request from the customer and prepare a formal
purchase order. The purchase order will hold the details of the customer, the name of the item to
be purchased, the quantity, and the price. Once the order is prepared, it will be sent to the Order
Processing department for the necessary approval. If the order is valid and approved, then the
department will generate the unique order ID and send it back to the Purchase department. The
Purchase department will communicate the order ID back to the customer.
- Prepare an order
The client application will prepare an order and send it to the server application through a
business method call. The server application will contain a web service that will process the
order and generate a unique order ID. The generation of the unique order ID will signify order
approval.
In real world applications a unique order ID is always accompanied by the date the
order was approved. However, in this example we chose to keep it simple by only
generating order ID.
Developing a service
Let’s look specifically at how to create an Order Processing Web Service and then register it as a
Spring bean using a JAX-WS frontend.
Create a Service Endpoint Interface (SEI) and define a business method to be used with
the web service.
Create the implementation class and annotate it as a web service.
Create beans.xml and define the service class as a Spring bean using a JAX-WS frontend.
Let’s first create the SEI for our Order Processing Application. We will name our SEI
OrderProcess. The following code illustrates the OrderProcess SEI:
package demo.order;
import javax.jws.WebService;
@WebService
public interface OrderProcess {
@WebMethod
String processOrder(Order order);
}
As you can see from the preceding code, we created a Service Endpoint Interface named
OrderProcess. The SEI is 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.
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 using the JAXB Binding.
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.
Next we will look at how to publish the OrderProcess JAX-WS web service using Spring
configuration.
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.
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 coe 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 specifies 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
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 SEI class 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 SEI to invoke the web service. Again, CXF internally uses
JAX-WS frontend to define this client-side component.
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:
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.
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.
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. Following shows the code layout of the project
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 means compiling the source Java code. We will use the ANT tool to do this.
The ANT file is provided in Chapter2orderapp folder. The following code illustrates the sample
build.xml build script:
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 set CATALINA_HOME environment to point to tomcat installation
installation. 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.
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.
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
Summary
In this blog we provided an overview of a sample Order Processing Application and saw how to
develop a web service with Spring-based configuration. We also saw how to build, deploy, and
execute a web service using ANT and Tomcat.