Web service message logging with Apache CXF

Learn to perform web service message logging using Apache CXF

Logging can be used as a tool to monitor and debug the application. In this article, you will learn how to perform Web service message logging with Apache CXF. The article will demonstrate various ways in which you can implement message logging. It will illustrate the use of significant CXF features like Interceptors and Features to perform message logging. The article will also demonstrate message logging using Spring based bean configuration.

Share:

Rajeev Hathi, Java Architect, Writer

Rajeev Hathi works as a Software Consultant for the J2EE platform. His professional interests are architecting, designing and developing J2EE-based applications.  He has attained SUN certifications in Java and J2EE technologies (Core Java, Web, EJB, Architect). He has contributed several technical papers for IBM developerWorks portal. He is also the co-author of the book Apache CXF Web Service Development. His pastime hobbies are listening to music and watching sports. The author's official web site is http://www.rajeevhathi.com which is a technical blog site and he can be reached at rajeevhathi@gmail.com.



01 September 2011

Also available in Japanese

Overview

Apache CXF is a web service framework used to develop, build and deploy web services. CXF supports many features that can be used by the developers to develop and deploy Web service based application. One such feature is logging. Logging here effective means logging Web service messages. CXF makes use of standard Java logging API to log the messages. It allows you to log both incoming and outgoing messages. The messages can be logged both at the client and the server side. Logging is important as one can see the actual SOAP payload being passed to the server and back. It can be useful as a debugging tool. Logging can be implemented in CXF through the concept of Interceptors and Features. The article will demonstrate a simple Web service message logging using the said concepts. You will also look at using Spring based bean configuration to configure the message logging.

You will develop a simple Web service using JAX-WS frontend or API of CXF. Let's consider an online Learning Management System (LMS) where typical functionalities would include user management, course creation, discussion forum, gradebook maintanence, content management etc. As part of this article, we will take the 'Course Creation' use case and develop a simple Web service class called CourseBuilder. The article indirectly will show how one can develop a simple Web service and publish it as a JAX-WS endpoint. The primary objective though will be to show the logging mechanisms. The article focuses only on server side logging. You can easily emulate client side logging once you understand the server side logging.

Our Web service class will look like the following

Listing 1. CourseBuilderImpl Web service class
@WebService
public class CourseBuilderImpl implements CourseBuilder {

    public String createCourse(Course course) {
        System.out.println("Course code is " + course.getCode());
        System.out.println("Course title is " + course.getTitle());
		
		return "Course created successfully";
    }
}

The above Web service class CourseBuilderImpl is pretty simple. The createCourse method takes a Course bean as a paramater and returns the status string indicating successful creation of course. You will now log the service messages on the console. The service messages effectively means the SOAP payload or the actual data that takes the form of method parameters and return types. You will display this payload on the console by turning on the logging feature.

Logging using Interceptors

Interceptors in CXF are components that intercepts SOAP messages. It can intercept incoming messages as well as outgoing messages. And therefore one can configure these interceptors either at the client application or on the server side or both. CXF provides number of built-in interceptors. Two such interceptors perform logging of messages and they are LoggingInInterceptor and LoggingOutInterceptor interceptors. You will use these interceptors to perform server side logging. The below code shows the way:

Listing 2. Server code
public final class Server {

    public static void main(String args[]) throws Exception {
		CourseBuilderImpl implementor = new CourseBuilderImpl();
		JaxWsServerFactoryBean svrFactory = new JaxWsServerFactoryBean();
		svrFactory.setAddress("http://localhost:9000/CourseBuilder");
		svrFactory.setServiceBean(implementor);
		svrFactory.getInInterceptors().add(new LoggingInInterceptor());
		svrFactory.getOutInterceptors().add(new LoggingOutInterceptor());
		svrFactory.create();
    }
}

The above code uses JaxWsServerFactoryBean server factory class to publish CourseBuilder service as JAX-WS endpoint. As you can see it sets the implementation class and the endpoint address. The create method starts the embedded standalone Jetty server. The significant part of the code is highlighted in the bold. It uses the two interceptors viz. LoggingInInterceptor and LoggingOutInterceptor. These are added to the factory class before the call to create method is made. This highlighted code enables the logging feature on the server side for both incoming and outgoing message. Once you run the client application, it will log the following output on the server console:

Figure 1. Server console
Server console

The above server console output shows the inbound and outbound SOAP payload. You can also control the size of the logging content by specifying it in the constructor. The size indicates number of bytes. For example, new LoggingInInterceptor(1024). So as you see logging interceptors makes it so easy to log your service messages. You can also make use of annotations to implement logging. The following code makes use of annotations to implement logging through interceptors.

Listing 3. Logging using interceptor annotations
@WebService
@InInterceptors(interceptors = "org.apache.cxf.interceptor.LoggingInInterceptor")
@OutInterceptors(interceptors = "org.apache.cxf.interceptor.LoggingOutInterceptor")
public class CourseBuilderImpl implements CourseBuilder {
...

The @InInterceptors and @OutInterceptors annotations can be used to define inbound and outbound interceptors respectively. The annotations can be declared in the service class or service endpoint interface (SEI). If the said annotations are placed in the SEI then the logging is enabled both on the client and server application. In the above code, the annotation is declared in the CourseBuilderImpl service implementation class and therefore the messages will be logged only on the server side.

Logging using Features

Features in CXF works more like decorators. It is applied to client, server and bus components. It basically extends the functionality of the client, server or the bus. CXF provides some of the built-in Feature implementations and one of them is LoggingFeature feature class. The LoggingFeature class performs logging of SOAP messages. We will revist the server code shown earlier. You will now use LoggingFeature feature class instead of interceptors:

Listing 4. Logging feature
public final class Server {

    public static void main(String args[]) throws Exception {
		CourseBuilderImpl implementor = new CourseBuilderImpl();
		JaxWsServerFactoryBean svrFactory = new JaxWsServerFactoryBean();
		svrFactory.setAddress("http://localhost:9000/CourseBuilder");
		svrFactory.setServiceBean(implementor);
		svrFactory.getFeatures().add(new LoggingFeature());
		svrFactory.create();
    }
}

What is CXF Bus?

A CXF bus can be thought of as a global or application level component that manages the core or infrastructure components (also called as extensions) of the framework and also acts as a interceptor provider. If you implement logging at the bus level, then the said logging feature will be common to all the service endpoints configured in the server or client runtime.

The highlighted code says it all. It will log both inbound and outbound messages i.e. messages received by the server and the response returned by the server. The LoggingFeature feature class in turn uses logging interceptors. Direct use of interceptors though can give you better control. For example, if you only want to log only incoming message and not the outgoing, in that case one can use only LoggingInInterceptor interceptor class and need not use LoggingFeature class. Just as with logging interceptors, LoggingFeature class allows you to set the limit size for logging content in number of bytes. The limit size can be specified in the constructor like below:

Listing 5. Logging feature with size limit
public final class Server {

    public static void main(String args[]) throws Exception {
		JaxWsServerFactoryBean svrFactory = new JaxWsServerFactoryBean();
		...
		// This will only log upto 1K or 1024 characters
		svrFactory.getFeatures().add(new LoggingFeature(1024)); 
		...
	}
}

LoggingFeature feature class also allows you to set the output destination of the messages to be logged. One can configure to log the message to stdout (Console), stderr (Error console) or to a file. You can set the output destination for both incoming and outgoing messages. The below code shows the use of output destination with LoggingFeature class.

Listing 6. Logging feature with output destination
public final class Server {

    public static void main(String args[]) throws Exception {
		JaxWsServerFactoryBean svrFactory = new JaxWsServerFactoryBean();
		...
		svrFactory.getFeatures().add(
			new LoggingFeature("<stdout>", "file://home/myLog.txt")); 
		...
	}
}

A different LoggingFeature constructor above takes two String parameters. These parameters indicate the output log destination for the incoming and outgoing messages respectively. From the above code, the inbound message will be logged to the console and the outbound message will be logged to the file.

With Features, you can also use annotations. The @Features annotation is used to specify features. The below code illustrates the use of @Features annotation.

Listing 7. Logging feature using annotation
@WebService
@Features(features = "org.apache.cxf.feature.LoggingFeature")
public class CourseBuilderImpl implements CourseBuilder {
...

In the above code, the @Features annotation is used to specify the LoggingFeature feature class to perform logging on the server side.

If you do not wish to use interceptor or feature annotation then you can simply use @Logging annotation to log the messages. The following code makes the logging even simpler:

Listing 8. @Logging annotation
@WebService
@Logging
public class CourseBuilderImpl implements CourseBuilder {
...

Logging using Spring based bean configuration

With CXF, you can also publish your Web service using Spring based bean configuration file. The obvious advantage of using the Spring configuration file is you can dynamically add features and interceptors to your service bean without the need of re-compiling your code. Readers are encouraged to read one of my earlier article on Web service development with Apache CXF and Spring. It walks you through developing and eventually publishing Web service using Spring configuration file.

The below code shows the configuration file that defines CourseBuilderImpl bean as JAX-WS endpoint.

Listing 9. Configuring CourseBuilderImpl service bean as JAX-WS endpoint
<?xml version="1.0" encoding="UTF-8"?>
<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:endpoint 
	  id="courseBuilder" 
	  implementor="demo.cxf.logging.CourseBuilderImpl" 
	  address="/CourseBuilder" />
</beans>

The <jaxws:endpoint> element is used to define the CourseBuilderImpl service bean as a JAX-WS endpoint. The endpoint URL is relative to the web context (This is ofcourse if you are using CXFServlet as a http transport). Now to use the logging interceptors, you need to change the above code to look like the following:

Listing 10. Configuring logging interceptors
<beans>
...
	<bean id="logIn" class="org.apache.cxf.interceptor.LoggingInInterceptor"/>
	<bean id="logOut" class="org.apache.cxf.interceptor.LoggingOutInterceptor"/>

	<jaxws:endpoint 
	  id="courseBuilder" 
	  implementor="demo.cxf.logging.CourseBuilderImpl" 
	  address="/CourseBuilder" >
	  
		<jaxws:inInterceptors>
			<ref bean="logIn"/>
		</jaxws:inInterceptors>
		<jaxws:outInterceptors>
			<ref bean="logOut"/>
		</jaxws:outInterceptors>
		
	</jaxws:endpoint>
</beans>

The above revised code now has two interceptor beans added viz. LoggingInInterceptor and LoggingOutInterceptor. The reference of these beans is passed to the CourseBuilderImpl service bean through the use of <jaxws-inInterceptors> and <jaxws-outInterceptors> elements respectively. This will ensure that both inbound and outbound service messages are logged.

Similarly, you can also configure logging feature through Spring. The below code illustrates logging feature.

Listing 11. Configuring logging feature
<beans>
...
	<jaxws:endpoint 
	  id="courseBuilder" 
	  implementor="demo.cxf.logging.CourseBuilderImpl" 
	  address="/CourseBuilder" >
	  
		<jaxws:features>
			<bean class="org.apache.cxf.feature.LoggingFeature"/>
        </jaxws:features>
		
	</jaxws:endpoint>
</beans>

As you can see from the above code, <jaxws:features> element is used to specify the logging feature.

To summarize, we explored the CXF native features like Interceptors and Features to perform service message logging. You can achieve the message logging programmatically, through annotations and using Spring based bean configuration. Apache CXF framework also allows you to integrate logging frameworks like Log4j and SLF4J. It also provides support for various debugging tools for you Web service runtime. For more details on the logging and debugging with CXF, you can visit the following link: CXF Debugging and Logging

Resources

Comments

developerWorks: Sign in

Required fields are indicated with an asterisk (*).


Need an IBM ID?
Forgot your IBM ID?


Forgot your password?
Change your password

By clicking Submit, you agree to the developerWorks terms of use.

 


The first time you sign into developerWorks, a profile is created for you. Information in your profile (your name, country/region, and company name) is displayed to the public and will accompany any content you post, unless you opt to hide your company name. You may update your IBM account at any time.

All information submitted is secure.

Choose your display name



The first time you sign in to developerWorks, a profile is created for you, so you need to choose a display name. Your display name accompanies the content you post on developerWorks.

Please choose a display name between 3-31 characters. Your display name must be unique in the developerWorks community and should not be your email address for privacy reasons.

Required fields are indicated with an asterisk (*).

(Must be between 3 – 31 characters.)

By clicking Submit, you agree to the developerWorks terms of use.

 


All information submitted is secure.

Dig deeper into SOA and web services on developerWorks


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=SOA and web services
ArticleID=755062
ArticleTitle=Web service message logging with Apache CXF
publish-date=09012011