Thursday, 20 December 2012

Demystifying Apache CXF: A RESTful Hello World App

The first post of this how-to series showed you what it takes to expose a Hello World application as a SOAP over HTTP Web Service using CXF. For this post, I'll show you how to expose the same app as a RESTful service.

In the Java world, we use JAX-RS for mapping a class to a RESTful service. Giving a RESTful interface to our Hello World app is just a matter of adding JAX-RS annotations to HelloWorldImpl:

In the class, I tell the JAX-RS provider (i.e., CXF):
  • HelloWorldImpl is a resource available on the URL relative path "/helloWorld" (@Path("/helloWorld")).
  • the HTTP reply sent back to the client should have the Content-Type set to "text/hml" (@Produces).
  • sayHi is to be called when the HTTP request is a GET and the relative path is "/helloWorld/sayHi/" + [variable] (@Path("sayHi/{text}")).
  • to bind the URL parameter with the method argument text (@PathParam).

As in the previous how-to, I'm going to deploy the app onto an embedded Jetty server instead of deploying it onto a standalone web container:

RuntimeDelegate.getInstance().createEndpoint(...) is a JAX-RS method that returns an unpublished endpoint. It takes in:
  • a class responsible for configuring and launching the web server. This class differs across JAX-RS providers. CXF expects this class to be JAXRSServerFactoryBean.
  • an object that extends Application. This user-defined class must return JAX-RS annotated classes responsible for processing client requests. For us, this means returning HelloWorldImpl:

Back to our file, I tell the endpoint to bind the server to the URL http://localhost:9000. Then, from the endpoint, I create a org.apache.cxf.endpoint.Server object and invoke start(...) to publish the service. Note that, underneath, org.apache.cxf.endpoint.Server is a configured Jetty. 

Before testing the service, I add the required CXF libraries to the Java classpath by declaring them as dependencies in project's POM :

If you compare this POM with the POM of the first how-to, you'll note that now I've swapped the JAX-WS frontend with the JAX-RS one.

All that is left is to run the server with the following Maven commands:

Once the server is up, accessing via your browser the URL http://localhost:9000/helloWorld/sayHi/Ricston should give you "Hello Ricston".

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.