Wednesday 19 December 2012

Demystifying Apache CXF: A Hello World App

"CXF scares the sh**t out of me!". This was a client's comment during our discussion on Apache CXF and I think it's a feeling shared by many. This feeling usually arises from a complaint I hear on CXF: the lack of documentation. However, I suspect that CXF's flexibility confuses numerous newbies and therefore contributes to the negative feelings towards it. The bad news is that, for some, it's hard to live without CXF. Popular open source software such as Apache Camel, Mule, and JBoss AS rely on CXF for their out-of-the-box web service support.

With the hope of increasing the understanding of Apache CXF, I've decided to publish the first of a series of how-tos. Each how-to demonstrates how to accomplish a particular task in CXF. For example, in this one I'll show how to publish a SOAP over HTTP Web Service. Throughout the how-tos, I will assume you have knowledge of basic Java and web services (e.g., SOAP, WSDL, REST). I will also assume you have knowledge of Maven. Maven is the tool I use for setting up dependencies, build and run the apps described by the how-tos. Don't worry, I'll make the apps available on GitHub :-).

Before getting our hands dirty with this how-to, I'll give a 10,000 foot view of Apache CXF for those who are new to the framework. The following is its definition taken from CXF's official website:

"Apache CXF is an open source services [Java] framework. CXF helps you build and develop services using frontend programming APIs, like JAX-WS and JAX-RS. These services can speak a variety of protocols such as SOAP, XML/HTTP, RESTful HTTP, or CORBA and work over a variety of transports such as HTTP, JMS or JBI."

In other words, with CXF, we can mix and match frontend APIs [1], protocols and transports to implement a service. For instance, we can instruct CXF to expose a Java application's interface as a WSDL and have the app talk with clients using CORBA over IIOP. But CXF is not just used to "build and develop services". We can also use CXF to build and develop service clients such as a SOAP consumer [2].

Now that we have an idea of what CXF is, let's follow the first how-to: Publish a SOAP over HTTP Web Service that takes in a string and returns "Hello" with the input string appended to it.

I have the following class:

I want the class to be exposed to the outside world as a Web Service. That is, I want to have:
  • a WSDL that reflects the class interface and is accessible to clients
  • SOAP requests translated into object method invocations and method results translated into SOAP replies.

With CXF, different approaches exist for doing the above. In this post, I'll cover the standard approach and leverage CXF's support for JAX-WS. In the Java world, JAX-WS is a spec for mapping a class to a SOAP Web Service. I map HelloWorldImpl by adding annotations to it:

The JAX-WS annotations in the class instruct the JAX-WS provider (i.e., CXF) to:
  • Expose HelloWorldImpl as a Web Service (@WebService)
  • Set the parameter name in the WSDL to "text" (@WebParam(name = "text")) [3].

The next step is to launch the Web Service so I can process SOAP requests. One strategy for launching the Web Service is to deploy the app onto a web container such as Tomcat. But this requires quite a bit of setup. I'd like to keep things simple for this first how-to. JAX-WS provides an easy way for launching the Web Service from within your application [4]:

Endpoint.publish(...) tells the JAX-WS provider to start an embedded web server (Jetty for CXF) on a different thread. I give the method a URL from where the Web Service will be operating on and the class to be published as a Web Service.

What happens if I try to run the app without including the CXF libraries in the Java classpath? It will actually run without a hitch, that is, the Web Service will start up. The problem is I won't be using CXF as the JAX-WS provider. If you're using the Oracle JDK, JAX-WS RI is the default JAX-WS provider since it comes bundled with the JDK. Changing from JAX-WS RI to CXF is just a matter of declaring two CXF dependencies in the POM file:

To test the Web Service, from your console, goto the project's root directory and type:

Accessing http://localhost:9000/helloWorld?wsdl from your browser should bring up the Web Service's WSDL.

1: A frontend programming API is an API for mapping your application interface (e.g., Java interface) to a different interface (e.g., RESTful).
2: Funnily enough, this isn't mentioned in the definition.
3: @WebParam is required because a JAX-WS provider cannot deduce the parameter name from the compiled code in some situations.
4: Note that I'm not saying this is the suggested approach for a production environment. Even though it takes more time to setup, a web container offers several advantages over an embedded approach.

No comments:

Post a Comment