Total Pageviews

Showing posts with label Spring interceptors. Show all posts
Showing posts with label Spring interceptors. Show all posts

Wednesday, 23 October 2013

Spring : Logging SOAP Request and Response from a Apache – Cxf client using Slf4j



Let's start with the three step process of delegating cxf logging through Slf4j:

1. Enable inbound and outbound soap messages of Apache-CXF in Spring Context

For logging soap messages we need to configure this cxf bus for inbound and outbound messages as by default, it contributes no interceptors(implies no logging of SOAP messages) but can be easily configured/enabled as:

<?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:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:cache="http://www.springframework.org/schema/cache"
xmlns:cxf="http://cxf.apache.org/core"
xmlns:util="http://www.springframework.org/schema/util" xsi:schemaLocation="http://cxf.apache.org/core http://cxf.apache.org/schemas/core.xsd
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/cache http://www.springframework.org/schema/util
http://www.springframework.org/schema/cache/spring-cache.xsd
http://www.springframework.org/schema/util/spring-util-2.0.xsd "
>
<!-- Enabling Interceptors -->
<bean id="logInbound" class="org.apache.cxf.interceptor.LoggingInInterceptor"/>
<bean id="logOutbound" class="org.apache.cxf.interceptor.LoggingOutInterceptor"/>
 

<!-- Enabling message logging using custom CXF bean elements -->
<cxf:bus>
    <cxf:inInterceptors>
            <ref bean="logInbound"/>
    </cxf:inInterceptors>
    <cxf:outInterceptors>
            <ref bean="logOutbound"/>
     </cxf:outInterceptors>
     <cxf:outFaultInterceptors>
            <ref bean="logOutbound"/>
     </cxf:outFaultInterceptors>
     <cxf:inFaultInterceptors>
            <ref bean="logInbound"/>
     </cxf:inFaultInterceptors>
</cxf:bus>
</beans>

Note: The configurable properties of the bus are defined in the bus configuration schema http://cxf.apache.org/schemas/core.xsd. Be sure to include the namespace - URI pair for this schema in the schemaLocation attribute of the <beans> element.



2. Configure CXF for using Slf4j

CXF by default uses Java SE Logging API for both client- and server-side logging of SOAP requests and responses, which results in logging of SOAP messages in server logs (i.e.catalina.out for tomcat) but we can configure CXF to use Slf4j logging instead.

In the org.apache.cxf.common.logging package of the CXF api, there used to be a Slf4jLogger class that extends org.apache.cxf.common.logging.AbstractDelegatingLogger class, and can be used for delegating logging to a Slf4j API implementations i.e. log4j, logback etc.

This is achieved through the use of configuration files. There are two options to bootstrapping CXF logging and each is listed below:

Create a file, in the classpath, named META-INF/cxf/org.apache.cxf.Logger. This file should contain the fully-qualified name of the logging(Slf4jLogger in our case) class, with no comments, on a single line as: org.apache.cxf.common.logging.Slf4jLogger

Hint: To achieve it create the following directory structure, form its jar with any name you like and then put it in lib directory of your project with other jars: |-META-INF (directory)
   |-cxf (directory)
       |- org.apache.cxf.Logger (file: with name as specified, no extention at all)
         |-org.apache.cxf.common.logging.Slf4jLogger (content of org.apache.cxf.Logger file)

or
Supply a -Dorg.apache.cxf.Logger=org.apache.cxf.common.logging.Slf4jLogger system property to code, when executing.

3. Define Custom configuration location for logback.xml file

As Spring does not provide any convenience class that features simple methods for custom logback configuration as it provides for Log4j (org.springframework.util.Log4jConfigurer)  for defining the custom configuration location or a refresh interval. Hence, therefore, we need to explicitly define a logback configuration listener and  logbackConfigLocation as context parameter in our applications web.xml as:

<listener>
        <listener-class>ch.qos.logback.ext.spring.web.LogbackConfigListener</listener-class>
</listener>
<context-param>
       <param-name>logbackConfigLocation</param-name>
       <param-value>/WEB-INF/conf/logback.xml</param-value>
</context-param>

Now that we are done with all the prerequisites, Apache cxf will now be delegating all its logs to Slf4j rather than to default Java SE logging.

But as Slf4j is simply a logging facade API not really a logging implementation, instead it's an abstraction layer, and hence required to be plugged in with any of its implementation such as logback (log4j or java.util.logging are also possible) which natively implements the Slf4j API. And the same can be achieved for logback implementation by merely adding following jars in your applications class path:

slf4j-api-<version>.jar
logback-classic-<version> .jar
logback-core-<version>.jar
logback-ext-spring-<version>.jar

And more on regarding slf4j dependencies can be read from SLF4J Manual.

Spring : Logging SOAP Request and Response from a Apache – Cxf client using log4j 

Sunday, 9 December 2012

Spring : Logging SOAP Request and Response from a Apache – Cxf client using log4j


Before going in details of logging apache-cxf soap request and response using log4j, lets discuss the concept of Bus in apache-cxf.
Bus: It's a main component of entire cxf architecture and embodies Spring based configuration files(usually called cxf.xml). It acts as an interceptor provider, which will be added to the respective inbound and outbound message and fault interceptor chains for all client and server endpoints created on the bus (in its context). These configurations are loaded on servlet initialization through SpringBusFactory. And this files defines a common context for all the endpoints. The SpringBusFactory searches for all bean configuration files in the META-INF/cxf directories on classpath, and builds an application context from them. The bean configuration files included in the application context construction are:
  • META-INF/cxf/cxf.xml (e.g., in cxf-rt-core only)
  • META-INF/cxf/cxf-extension.xml (e.g. in cxf-rt-bindings-soap)
  • META-INF/cxf/cxf-property-editors.xml (e.g. in cxf-rt-transports-http)
Enabling inbound and outbound soap messages in Apache-CXF
For logging soap messages we need to configure this cxf bus for inbound and outbound messages as by default, it contributes no interceptors(implies no logging of SOAP messages) but could be easily configured/enabled as:
<!-- Enabling Interceptors -->
<bean id="logInbound" class="org.apache.cxf.interceptor.LoggingInInterceptor"/>
<bean id="logOutbound" class="org.apache.cxf.interceptor.LoggingOutInterceptor"/>
<!-- Begin: Enabling message logging using custom CXF bean elements -->
<cxf:bus>
<cxf:inInterceptors>
<ref bean="logInbound"/>
</cxf:inInterceptors>
<cxf:outInterceptors>
<ref bean="logOutbound"/>
</cxf:outInterceptors>
<cxf:outFaultInterceptors>
<ref bean="logOutbound"/>
</cxf:outFaultInterceptors>
<cxf:inFaultInterceptors>
<ref bean="logInbound"/>
</cxf:inFaultInterceptors>
</cxf:bus>
<!-- End: Enabling Interceptors -->
CXF by default uses Java SE Logging API for both client- and server-side logging of SOAP requests and responses, which results in logging of SOAP messages in server logs (i.e.catalina.out for tomcat) but we can configure CXF to use Log4J logging instead. In the org.apache.cxf.common.logging package of the CXF api, there used to be a Log4JLogger class, which extends org.apache.cxf.common.logging.AbstractDelegatingLogger class, and could be used for delegating logging to a Log4J implementation.

Configuring Log4J in CXF

In the same package as Log4JLogger, there exists a class LogUtils, which CXF uses to obtain logger instances from. This class contains a static final string KEY, which is set to the value org.apache.cxf.Logger. And CXF uses this value, to bootstrap which logging API to use.
So, what all we have to do is to over ride this key value. And this could be achieved in any of the following ways:
  1. Create a file, in the classpath, named META-INF/cxf/org.apache.cxf.Logger. This file should contain the fully-qualified name of the logging(Log4jLogger in our case) class, with no comments, on a single line as: org.apache.cxf.common.logging.Log4jLogger
(Hint: To achieve it create the following directory structure, form its jar with any name you like and then put it in lib directory of your project with other jars: |-META-INF (directory) |-cxf (directory) |- org.apache.cxf.Logger (file: with name as specified, no extention at all) |-org.apache.cxf.common.logging.Log4jLogger (content of org.apache.cxf.Logger) )
  1. Supply a -Dorg.apache.cxf.Logger=org.apache.cxf.common.logging.Log4jLogger system property to code, when executing.
Following Spring Web Context Configuration file(spring-servlet.xml) could be considered for reference:
<?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:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:cache="http://www.springframework.org/schema/cache"
xmlns:cxf="http://cxf.apache.org/core"
xmlns:util="http://www.springframework.org/schema/util" xsi:schemaLocation="http://cxf.apache.org/core http://cxf.apache.org/schemas/core.xsd
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/cache http://www.springframework.org/schema/util
http://www.springframework.org/schema/cache/spring-cache.xsd
http://www.springframework.org/schema/util/spring-util-2.0.xsd "
>
<!-- log 4j initialization -->
<bean id="log4jInitialization" class="org.springframework.beans.factory.config.MethodInvokingFactoryBean"
p:targetClass="org.springframework.util.Log4jConfigurer" p:targetMethod="initLogging"
p:arguments="${log4j.file.loc}"
/>
<!-- Enabling Interceptors -->
<bean id="logInbound" class="org.apache.cxf.interceptor.LoggingInInterceptor"/>
<bean id="logOutbound" class="org.apache.cxf.interceptor.LoggingOutInterceptor"/>
<!-- Enabling message logging using custom CXF bean elements -->
<cxf:bus>
<cxf:inInterceptors>
<ref bean="logInbound"/>
</cxf:inInterceptors>
<cxf:outInterceptors>
<ref bean="logOutbound"/>
</cxf:outInterceptors>
<cxf:outFaultInterceptors>
<ref bean="logOutbound"/>
</cxf:outFaultInterceptors>
<cxf:inFaultInterceptors>
<ref bean="logInbound"/>
</cxf:inFaultInterceptors>
</cxf:bus>
</beans>
Note: The configurable properties of the bus are defined in the bus configuration schema http://cxf.apache.org/schemas/core.xsd. Be sure to include the namespace - URI pair for this schema in the schemaLocation attribute of the <beans> element.

Logging SOAP Request and Response from a Apache – Cxf client using Slf4j