Total Pageviews

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 

Wednesday, 14 August 2013

Configuring Tomcat for gzip compression

Before going in details of configuring Tomcat for gzip compression, let us have a brief over gzip compression:

When a user hits a url in the browser, a http call is made to the server for the requested page or file. The bigger the size of requested content the longer it would take to get to the browser. This cost not only in terms of time a user spent while waiting for the response but in terms of network bandwidth as well.

Here, gzip compression could be used. The requested webpages/style sheets/java scripts/ image files etc. could be compressed before sending them over to the browser, which exceptionally reduces transfer time as the files are much smaller now.

It begins from the application server which either returns a compressed resource if it supports the zip compression else an unzipped resource.

Gzip locates similar strings within the files and replaces those strings temporarily to make the overall file size smaller. Usually CSS files, java script files and HTML files use a lot of repeated text and have loads of whitespace, which could be highly compressed using gzip and can reduce load time of files drastically.

The exchange of compressed content between browser and server could be verified through exchange of headers between them:
1. The browser sends a header telling the server that it accepts compressed content (gzip / deflate are two compression schemes): Accept-Encoding: gzip, deflate
2. The server sends a response if the content is actually compressed: Content-Encoding: gzip

If the server doesn't send the content-encoding response header, it means the file is not compressed. The "Accept-encoding" header is just a request by the browser, not a constraint for the server. If the server doesn't returns the compressed content, the browser has to render the heavy response.

Configuring Tomcat for gzip compression:
For configuring the tomcat for gzip, it is only required to update the ‘connector’ element inside /conf/server.xml for the following attributes as:

compression="on"
noCompressionUserAgents="gozilla, traviata"
compressableMimeType="text/html, text/xml, text/css, application/xml, application/xhtml+xml, application/rss+xml, application/javascript, application/x-javascript"


The explanation for the used connector attributes is as follows:

1. compression: The Connector may use HTTP/1.1 GZIP compression in an attempt to save server bandwidth. The acceptable values for the parameter is "off" (disable compression), "on" (allow compression), "force" (forces compression in all cases), or a numerical integer value (which is equivalent to "on", but specifies the minimum amount of data before the output is compressed). If not specified, this attribute is set to "off" by default.

2. noCompressionUserAgents: The value is a comma separated list of regular expressions matching user-agents of HTTP clients for which compression should not be used, because these clients, although they do advertise support for the feature, have a broken implementation. The default value is an empty String (regexp matching disabled).

3. compressableMimeType: The value is a comma separated list of MIME types for which HTTP compression may be used. The default value is text/html,text/xml,text/plain if nothing is specified.

Steps to verify the compression:
1. Update the configuration as said above and restart the server.
2. Check if the you are getting ‘Content-Encoding: gzip’ header in HttpResponse.( could be checked though firebug add-on available for Mozilla firefox).

Following are some screenshots taken from firebug showing the difference in load time and in response size with and without gzip compression:

1. Without gzip compression: Size: 628.7 Kb, Load Time: 1.07 seconds

2. With gzip Compression: Size: 187.5 Kb, Load Time: 925 milliseconds


Tuesday, 15 January 2013

Servers : Apache Web-Server Vs Apache Tomcat

Apache web-server (also known as Apache Hyper Text Transfer Protocol server) and Apache Tomcat both are SERVERS( servers are software that works on network or on internet) and are both developed by APACHE.

Apache is a server designed to serve HTTP, or we can also call it as a web-server, which serves the requests from browsers for web-pages. But an Apache server is not limited to this only. It can effectively serve the HTTP requests for the static contents but can be also configured to handle requests for dynamic contents generated through a wide range of languages and technologies like PHP, J2EE or whatever.

Next comes is Apache Tomcat, which itself is a server and compliments Apache web-server. It is also developed by Apache and usually CONFUSES us with the Apache web-server developed by Apache itself. Although they are both servers that are meant for use in the Internet, but they have separate and distinct roles to play.

Apache Tomcat is a server specifically meant to run applications that were written in Java and JSP (Java Server Pages). It is open source software just like Apache web-server created by Apache, and is free to use. It's primary purpose is to implement the Java Servlet API and execute Java servlets for dynamic websites. Tomcat can also be used as a regular HTTP web-server that serves static pages, but that is not its primary purpose.

If we are putting up a Apache web-server and we want to have Java or JSP support, then we should go for offering that Apache Tomcat has as both are made by Apache. And, hence reduces the chances of encountering problem while configuring them to work together.

In short we can say "Apache Tomcat server is a SPECIALIZED web server called a "servlet container." And it features a BASIC web server CUSTOMIZED to execute Java servlets and JSP pages. BUT at the same time it can also be configured to serve other technologies as well."

Now, as the individuality of Apache web-server and Apache Tomcat is quite clear to us, we can say that "Apache web-server is usually configured to use the Tomcat server as a back-end handler for servlets and JSPs".

Friday, 4 January 2013

Spring : Configuring failover in Spring


WebClients can be configured in Spring to handle the failover in case any of the webservice connection fails to respond due to network or server failure or due to any other reason. In order to handle such issues Apache CXF provides Sequential and Random strategies, which are supported and implementers can develop more sophisticated failover features by retrieving alternate addresses.

The above could be achieved by doing the following configurations in spring-servlet.xml (Spring Web Context Configuration file) or whatever else you call it.

Spring-servlet.xml( failover configurations only)
____________________________________________________________________________

<?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/cache/spring-cache.xsd
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util-2.0.xsd
"
>

<!-- begin: Fail over configurations -->
<util:list id="alternateSerAddresses" list-class="java.util.concurrent.CopyOnWriteArrayList">
    <value>http://hostname:port/servie-location-1</value>
    <value>http://hostname:port/servie-location-2</value>
    <value>http://hostname:port/servie-location-3</value>
</util:list>

<bean id="serviceClientFactory" class="org.apache.cxf.jaxws.JaxWsProxyFactoryBean">
   <property name="serviceClass" value="com.soaptopupsuite.EndPointInterface"/>
   <property name="address" value="http://hostname:port/service-default-loc"/>
   <property name="username" value="service-username"/>
   <property name="password" value="service-password"/>
   <property name="features">
    <util:list>
      <bean class="org.apache.cxf.clustering.FailoverFeature">
             <property name="strategy">
                  <bean class="org.apache.cxf.clustering.SequentialStrategy">
                <property name="alternateAddresses" ref="alternateSerAddresses"/>
             </bean>
             </property>
         </bean>
     </util:list>
</property>
</bean>

<bean id="serviceClient" class="com.soaptopupsuite.EndPointInterface" factory-   bean="serviceClientFactory" factory-method="create"/>
<bean id="servicePort" class="com.swaraj.client.WsClient">
   <property name="port" ref="serviceClient" />
</bean>
<!-- end: Fail over configurations -->
</beans>

Here, the client factory does not itself defines the address attribute. It uses that alternateSerAddresses list exclusively throughout all the invocations and primary address exists as default location. SequentialStrategy will use one endpoint after another providing nice round robin implementation (RandomStrategy is available as well, where an end point is picked up randomly). Also in this configuration we will get failoverif any endpoint fails, all endpoints starting from the default one will be examined (except the one that has just failed).


Reference Java Code (Spring 3.1) :

package com.swaraj.client;


@Service
public class WsClient {
/* list of instance variable*/
// web service location
private EndPointInterface port;
// setter injection for EndPointInterface
   public void setPort(EndPointInterface port) {
       this.port = port;
   }
// Invoking web service method on EndPointInterface port.
   public String webSerMethodCall(){
       return port.testCall();
   }
}

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