“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:
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:
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.