Web Services Using ColdFusion and Apache CXF

Since its emergence, Web Service technology has gone a long way towards perfecting itself and finding its right application in the real world. With the maturity of the specifications, Web Service technology, with its power of interoperability, is now the major enabling technology of SOA, which is being adopted by more and more enterprises to build their application integration infrastructure.

Developing Web Services involves a variety of technologies, XML processing, SOAP, and WSDL, to name a few. Luckily, there are frameworks that target handling theses kinds of middleware functions, freeing up developers to focus on the business logic.

Nowadays, many Web Service frameworks exist for all kinds of programming languages. Some of them are open source, others are commercially available. Some examples of such frameworks are Apache Axis and Axis2, WS02 Web Services Framework (WSF), Java Web Services Development Pack (GlassFish), JBossWS, and XINS.

Being one of the Web Service frameworks for Java, Apache CXF is an open source framework developed by the Apache Software Foundation. It's a continuation and merging of two open source projects, Codehaus' XFire project and ObjectWeb's Celtix project. When this was written, the stable version was 2.0.

CXF enables the creation of Web Services using Java technologies. It supports a variety of Web Service standards including WS-I Basic Profile 1.0, WS-Addressing, WS-Policy, WS-ReliableMessaging, and WS-Security.

CXF supports transport protocols like HTTP and JMS. The messaging formats supported include SOAP, XML, RESTFul HTTP, and CORBA. Besides JAXB data binding, it also supports Aegis binding.

CXF is JAX-WS (JSR 224)-compliant and version 2.0 has passed the TCK for JAX-WS 2.0. It makes intensive use of Java 5 annotations and so requires JDK/JRE 5.0 and above.

CXF leverages the Spring application framework for bean management. Endpoints and service clients can be managed as Spring beans.

In the first section of this article, a step-by-step Web Service example using CXF is presented. Some of CXF's basic features are revealed while going through the steps of creating the example. Then we'll touch on some of the unique features of CXF, including RESTful service support and Spring integration. At the end, a brief performance test will compare CXF with JBossWS and the JAX-WS Reference Implementation (RI).

An Example: Getting Movie Show Times
In this example, we'll build a Web Service that lets a client system query for movie show times using the ZIP code entered by a user. For demonstration purposes, most of the irrelevant details are ignored.

CXF supports both code-first development and contract-first development. While code-first development is a handy feature, and most developers find it more straightforward and easier to get start with, it has a vital weakness.

There are several reasons for this. First, a key aspect in successfully developing Web Services is to determine its granularity. Considering the fact that the major application of Web Services is to implement SOA solution at a really high level (e.g., at the enterprise level), the granularity couldn't be too small. In contrast are the Java classes and methods, which tend to be very fine-grained, and are often designed at the very low level (i.e. the class level). Secondly, Web Services bare the nature of language neutral. Building a service from a specific language (like Java) and transforming it into a language-neutral form through some tools would, in some cases, bring over language-specific features, which will degrade the language-neutral nature, thus hurt the interoperability, of the service. Lastly, from a design point of view, service-oriented principles are significantly different from object-oriented paradigms. Although an individual service might be realized using OO principles and techniques, the interaction between services rarely using any of them.

Due to the aforementioned reasons, code-first development will never let you get to the spirit of service-oriented development because developing in Java code and developing in WSDL requires different mindset. Developing with Java code-first and avoiding WSDL as much as possible will guarantee that you will build mediocre software at the best. This is especially true when it comes to designing and developing a SOA solution rather than just individual services.

With that said, let's start with contract-first development for our example, the first step of which is to create the contract - the WSDL document that describes the service.

WSDL Document
Listing 1 shows a segment of the WSDL document. In this document a service called MovieService is defined. This service has only one operation GetShowtimesForZip. The input of this operation is a message containing the ZIP code that the user entered, and the response is a list of theaters and movies along with show times.

The types are defined in a separated XML Schema document and are imported using <xsd:import> statement. The schema document isn't listed here to avoid lengthy text.

Nothing is really special about this WSDL document. Let's now generate the service interface and the service endpoint interface (SEI) from the WSDL document.

Service and Service Endpoint Interfaces
With the WSDL document ready, our next step is to generate server-side Java code from it. CXF provides a tool called wsdl2java that can be used to generate fully annotated Java code from a WSDL document. This tool operates according to the JAX-WS rules for WSDL <--> Java mapping, and its data binding mechanism conforms to JAXB (JSR 22). The tool comes with a set of optional arguments that allow control of the behavior of the tool.

The WSDL document used to generate the Java code has to have a valid portType element, but it doesn't require a binding element or a service element.

The simplest form of running the tool on the command line is listed in Listing 2.

You can specify the package of the generated code using the -p option as shown in Listing 3.

JAX-WS defines an XML-based binding language that can be used to customize the WSDL to Java bindings. The wsdl2java tool implements this feature using the -b option. Listing 4 shows how to specify a JAX-WS binding file for customization.

You can ask the tool to generate an Ant build file for use in your application. To do so, use the -ant option as shown in Listing 5:

Or you can define your own Ant macro. A sample of such a macro is included in the CXF distribution. Listing 6 shows a modified version of it.


The core part of this snippet is the java task with the classname attribute set to org.apache.cxf.tools.wsdlto.WSDLToJava. Include this macro in your build file and then you can call it as shown in Listing 7.

Successfully running the tool will generate all necessary software artifacts, which include a service interface, a service endpoint interface (SEI), Java classes that implement all types defined in the WSDL document, and APIs that are used to obtain instances of these types.

Service Implementation Class
Now it's time to provide an implementation for the service. We do so by creating a Java class called MovieServiceImpl. There are some requirements that this class has to fulfill to become a service implementation class. It must be annotated with the JAX-WS @WebService annotation, and the endpointInterface member attribute of the annotation must refer to the generated SEI, i.e., org.example.movieservice.MovieService in our example. The service implementation bean may implement the SEI, but it's not required to do so. The service implementation bean must implement all method signatures defined in the SEI.

Listing 8 shows a code snippet of the implementation class.

Server Development and Service Publishing
We now need to create a server that hosts our service. XML-based Java Web Services can be hosted either in a managed or in non-managed environment.

Non-Managed Environment
JAX-WS provides functionality for creating and publishing Web Service endpoints dynamically using javax.xml.ws.Endpoint API running in a non-managed environment. CXF is JAX-WS-compliant and so supports JAX-WS dynamic Web Service publishing. Listing 9 is a code snippet of dynamic publishing.

This code is not CXF-specific and is portable among all JAX-WS-compliant runtimes. The complete server code is straightforward and sp omitted here. Start the server and you can then test the server by pointing your browser to the location: http://localhost:8080/MyMovieService?wsdl.

Managed Environment
Implementing Enterprise Web Services (JSR 109) defines ways of implementing Web Services and publishing endpoints in a managed environment. The use of dynamic publishing is considered non-portable in a managed environment. So JSR 109 requires that both the servlet and EJB container disallow publishing the endpoint dynamically by not granting the publishEndpoint security permission.

There are two means of implementing Web Services that run in a managed Java EE environment. The first is a container-based extension of the JAX-RPC or JAX-WS programming model, which defines a Web Service as a Java class running in Web container. The second one defines the use of a stateless enterprise session bean to run in the EJB container.

Due to the fact that CXF doesn't come with any Java EE container, neither is it specifically designed to support a particular vendor's Java EE container, it's quite different to implement Web Services in a managed environment using CXF. First, CXF doesn't support deploying Web Services in an EJB container. Second, the way of deploying Web Services in a web container is different from the one defined by JSR 109. While JSR 109 requires the container runtime to embed each endpoint implementation class in one servlet, CXF provides a generic servlet for all endpoint implementation classes.

Let's see this in action by deploying our example service to a Web container. The whole process involves 1.) configuring the Spring runtime to be aware of the service implementation class, 2.) registering the CXF servlet with the Web container and lastly, 3.) providing a configuration file that glues the last two together.

Configuring Spring is ;ole configuring a Spring project. A Spring context loader listener is added to the Web container via web.xml. Also added is the Spring configuration file, cxf-bean.xml, which is passed to the container as a context parameter. We'll cover this file momentarily. Listing 10 is a fragment of the web.xml file.

Registering CXF servlet is also straightforward. See Listing 11. Note that only one servlet is needed, and it acts as the entry point of all service endpoints.

We now need to somehow let the servlet know how to dispatch requests to the corresponding service implementation beans. This is the exact purpose of cxf-bean.xml, which is listed in Listing 12.

Using this file, we guide the servlet to forward all requests at the address /MovieService to MovieServiceImpl bean. Note that you'd better make sure that the value of the address attribute matches the one you advertised in the WSDL document.

After packaging the application and deploying it to a Web container (say, Tomcat), we can test the service by pointing the browser to the address http://localhost:8080/MovieService/cxf/MovieService?wsdl.

This concludes the server development. Now we move on to client development.

Client Development
In general, JAX-WS defines the Web Service client programming model, while JSR 109 defines the Web Service client programming model in a Java EE environment.

As mentioned, CXF doesn't have any Java EE runtime, so the primary way of creating a client is through JAX-WS. Listing 13 shows a simple client that consumes the MovieService Web Service.

RESTful Web Services Support
CXF supports RESTful Web Services by annotations. It uses four annotations for specifying the HTTP verb that will be used for a method:

Listing 14 is a code snippet that shows how annotations are used to implement RESTful services. Four services are defined that let clients book tickets, get ticket information, modify the booking, and cancel the booking, respectively. The code itself is fairly self-explanatory.

Assuming that these services are deployed and running, a client system can modify booking information by sending an HTTP request to an URL similar to the following, with the METHOD attribute of the request set to PUT. Note the bold portion of the URL:

http://www.mymovieticket.com/ticketbooking/tickets/9182


Operating on the XML Level
XML-based Web Services use XML messages for communication between services and service clients. The high-level JAX-WS APIs are designed to hide the details of converting between Java method invocations and the corresponding XML message. But in some cases, operating at the XML message level is desirable.

JAX-WS defines two new APIs for the Web Services to operate at the XML level. They are javax.xml.ws.Provider and java.xml.ws.Dispatch. Provider is a server-side API while Dispatch is a client-side API. CXF supports this JAX-WS standard. Listing 15 is an example of server code operating at the XML message level. As you see, there's nothing specific to CXF in the code.

Spring Integration
CXF integrates with Spring application framework seamlessly. Service endpoints and service client beans can be created the Spring way. In Section 1.4.2, we've seen how a service endpoint bean can be created using Spring. What we're going to see here is how to create a client.

CXF includes a JaxWsProxyFactory class that creates a client for you from your service endpoint interface. You simply need to tell it what your SEI is (in this case MovieService interface) and the URL of your service. You can then create a client bean via the JaxWsProxyFactory bean by calling its create() method.

An XML configuration file is used to set this up. See Listing 16. This is just a regular Spring configuration file. In this file, two beans are declared, movieServiceClient, which is an SEI bean, and the clientFactory bean, which is a factory bean. The factory bean and factory method attributes specify the factory and the factory method used to create the SEI bean.

To access the SEI bean in the code, one can either get the client bean from the Spring context or inject it into the application using Spring's Injection of Control (IoC) feature. Listing 17 is an example of getting the bean from the context.

Performance
A brief performance test is done to compare the performance of three Web Service stacks - CXF, JBossWS, and JAX-WS RI. In the test, three servers are set up, one for each of the three stacks (the exact versions are CXF 2.0, JAX-WS RI 2.1.1, and JBossWS 2.0).

Apache JMeter test suite is chosen to be the testing software. A test plan is set up in JMeter to act as the client, which sends SOAP messages to the tested servers via HTTP. The servers simply echo the messages back. The sizes of the messages are 12KB.

For each server, five concurrent threads are set up to generate requests back to back. The test runs for 30 minutes and at the end the number of transactions finished is recorded.

The test machine is a Windows PC running XP Professional, with a 1.7GHz Intel Pentium processor and 1.5GB of RAM.

Table 1 summarizes the tests result. It shows the number of transactions during a 30-minute time period for each server.

At the first glance, one may conclude that JAX-WS RI is terribly slower than the other two because the number of transactions is so low. But further study of the testing results and logs indicates the opposite - JAX-WS RI might actually be the fastest of the three. Here's why.

The log shows that a total of 743,203 requests were made by the JAX-WS JMeter client during the time period. However, most of them (665,245) are returned as errors, all address-not-available errors. This is an error when all the ports in a machine are in use and there are no free ports. It can happen under very high loads. This could be an indication that the JAX-WS RI server started so many threads so quickly that the OS releasing ports can somehow not catch up, causing the system to run out of ports eventually.

To verify this hypothesis, the test was run again, only this time just one thread was run instead of five. Table 2 shows the result.

As one can see, the number of transactions is now comparable to the ones of CXF and JBossWS, and the number of errors dropped significantly. The error should be able to be eliminated if running on a server-class OS.

Conclusion
CXF is a robust Web Services framework that supports a variety of Web Service standards. It's easy to develop, configure, and deploy. Additional features such as integration with Spring make it an attractive choice when Inversion of Control (IoC) and Aspect Oriented Programming (AOP) features are important. With the existence of JSR 109, however, it's probably not a good choice when you're developing applications that run in Java EE containers because Java EE-compliant containers provide the same middleware functionalities, which, most likely, will work more seamlessly with the container.

References
•  Apache CXF Web site: http://incubator.apache.org/cxf/.
•  Codehaus XFire Web site: http://xfire.codehaus.org/.
•  Celtix Web site: http://celtix.objectweb.org/.
•  JAX-WS specification (JSR 224). Available at http://jcp.org/en/jsr/detail?id=224.
•  Implementing Enterprise Web Services (JSR 109). Available at http://jcp.org/en/jsr/detail?id=109.
•  Rob Harrop and Jan Machacek. Pro Spring. 2005.
•  Jeff Davies. The Definitive Guide to SOA: BEA AquaLogic Service Bus. 2007.
•  Richard Monson-Haefel. J2EE Web Services. 2003.
•  Meeraj Kinnumpurath. JBI - A Standard-based Approach for SOA in Java. 2005.

© 2008 SYS-CON Media