Hi,

JBoss AS7 uses the JBossWS-CXF as default webservice provider which provides most of the features coming with Apache CXF (including WS-Security, WS-Policy, WS-Addressing, WS-ReliableMessaging, basic WS-Trust, MTOM) as well as common JBossWS stack features like endpoint metrics, record management, endpoint address rewrite, etc.

In this example we will see how we can enable the client side Logging for the incoming and outgoing SOAP Request/Responses, which are most desired for trouble shooting and debugging purpose.

In this example we will mainly focus on following points

Point-1). How to use the JBoss Specific Tools to build the WebServices. The details of these tools like “wsconsume” and “wsprovide” are mentioned in the following link: https://docs.jboss.org/author/display/JBWS/JAX-WS+Tools

Point-2). Where we need to place the “log4j.properties fileat the client side in order to generate a separate Log file containing the SOAP request/response.

Point-3). How to use “org.apache.cxf.interceptor.LoggingInInterceptor” and “org.apache.cxf.interceptor.LoggingOutInterceptor” at client side.

Point-4). Here we are using JBoss AS7.1.0 CR1b which can be downloaded from the following link: http://www.jboss.org/jbossas/downloads. I am using “jboss-as-7.1.0.CR1b” in this demo.

Point-5). Source Code of this Demo is available at https://github.com/jaysensharma/MiddlewareMagicDemos

Developing Simple WebService

Step-1). Create a directory somewhere in your file system as “/home/userone/CXFClientSide_Logging_Demo” then create another directory “src” inside the “/home/userone/CXFClientSide_Logging_Demo”.

Step-2). Write a simple webservice implementation pojo class “DemoCXF.java” as following inside the directory “/home/userone/CXFClientSide_Logging_Demo/src”:


package ws;
import javax.jws.WebMethod;
import javax.jws.WebService;
import javax.annotation.Resource;
import javax.xml.ws.WebServiceContext;
import java.util.Collection;

@WebService(name = "DemoCXF", serviceName ="DemoCXFService", portName ="DemoCXFPort", targetNamespace="http://test.org")

public class DemoCXF
{
  @Resource
  WebServiceContext ctx;

  @WebMethod()
  public String sayHello(String name)
  {
    System.out.println("nnt Method Invoked....String sayHello("+name+")");
    return "Hello JBossAS7 User: "+name;
  }

  @WebMethod()
  public String getProperty(String propertyName)
  {
    System.out.println("nnt Method Invoked....String getProperty(String propertyName)");
    return "RETURNED: "+(Collection) ctx.getMessageContext().values();
  }
}

Step-3). Write the “web.xml” file to define the WebService as following inside the directory “/home/userone/CXFClientSide_Logging_Demo/src”:

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5"
         xmlns="http://java.sun.com/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
  <servlet> 
    <servlet-name>DemoCXF</servlet-name>  
    <servlet-class>ws.DemoCXF</servlet-class>  
  </servlet>  

  <servlet-mapping> 
    <servlet-name>DemoCXF</servlet-name>  
    <url-pattern>/*</url-pattern> 
  </servlet-mapping>  
</web-app>

Step-4). Write the WebService client code “Test_CXF_Client.java” as following inside the directory “/home/userone/CXFClientSide_Logging_Demo/src”:


package client;
import java.net.URL;
import javax.xml.namespace.QName;

// Client side Logging related CXF APIs 
import org.apache.cxf.endpoint.Client;
import org.apache.cxf.frontend.ClientProxy;
import org.apache.cxf.interceptor.LoggingInInterceptor;
import org.apache.cxf.interceptor.LoggingOutInterceptor;

public class Test_CXF_Client
  {
     public static void main(String ar[]) throws Exception
      {
        String WSDL_URL=ar[0]+"?wsdl";
        DemoCXFService service=new DemoCXFService(new URL(WSDL_URL));
        DemoCXF port=service.getDemoCXFPort();

        /* Following part of code is needed for client side Logging of Soap request/response */
        /* We need to make sure that we place the "log4j.properties" file inside clients classpath */
        Client client = ClientProxy.getClient(port);
        client.getInInterceptors().add(new LoggingInInterceptor());
        client.getOutInterceptors().add(new LoggingOutInterceptor()); 

         
        System.out.println("nt port.sayHello("MiddlewareMagic") = "+port.sayHello("MiddlewareMagic"));
      }
  }

Step-5). As we are going to generate the client side logging in a separate log file at client side using CXF APIs so we will need to write a “log4j.properties” file as following inside the directory “/home/userone/CXFClientSide_Logging_Demo/src”:

# Direct log messages to a log file
log4j.rootLogger=INFO, WSClientAppender


log4j.appender.WSClientAppender=org.apache.log4j.RollingFileAppender
log4j.appender.WSClientAppender.File=/NotBackedUp/Downloads/CXFClientDemo/clientStuff/webserviceClient.log
log4j.appender.WSClientAppender.MaxFileSize=10MB
log4j.appender.WSClientAppender.MaxBackupIndex=3
log4j.appender.WSClientAppender.layout=org.apache.log4j.PatternLayout
log4j.appender.WSClientAppender.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n

NOTE: Make sure that you have defined the right Location for the Log File and the Directory must exist, which is defined in the above file property “log4j.appender.WSClientAppender.File”.

Step-6). Now we will write simple ANT build script “build.xml” which will build / deploy and run the webservice & client as following inside the directory “/home/userone/CXFClientSide_Logging_Demo”:

<project name="JBoss_Service" default="deploy">
<property name="jboss.home" value="/home/userone/jboss-as-7.1.0.CR1b" />
<property name="jboss.module.dir" value="${jboss.home}/modules" />

<property name="basedir" value="." />
<property name="war.dir" value="CXFClientLoggingDemoWAR" />
<property name="war.name" value="CXFClientLoggingDemo.war" />
<property name="src.dir" value="src" />
<property name="client.src.dir" value="${basedir}/clientSrc" />
<property name="output.dir" value="build" />
<property name="client.dir" value="${basedir}/clientStuff" />
<property name="client.jar.name" value="DemoCXFClient.jar" />
 
   <path id="jboss.classpath">
     <fileset dir="${jboss.module.dir}">
        <include name="**/*.jar"/>
     </fileset>  
   </path>

   <path id="client.classpath">
     <fileset dir="${jboss.module.dir}">
        <include name="**/*.jar"/>
     </fileset>  
     <fileset dir="${client.dir}">
        <include name="*.jar"/>
     </fileset>  
   </path>

   <taskdef name="wsprovide" classname="org.jboss.ws.tools.ant.WSProvideTask">
       <classpath refid="jboss.classpath"/>
   </taskdef>

   <taskdef name="wsconsume" classname="org.jboss.ws.tools.ant.WSConsumeTask">
       <classpath refid="jboss.classpath"/>
   </taskdef>

        <target name="init">
           <delete dir="${output.dir}" />
           <mkdir dir="${output.dir}" />
           <mkdir dir="${output.dir}/${war.dir}"/>
           <mkdir dir="${output.dir}/${war.dir}/META-INF"/>
           <mkdir dir="${output.dir}/${war.dir}/WEB-INF"/>
           <mkdir dir="${output.dir}/${war.dir}/WEB-INF/classes"/>
           <delete dir="${client.dir}" />
           <mkdir dir="${client.dir}/META-INF"/>
        </target>
	 
    <target name="build" depends="init">
       <javac srcdir="${src.dir}" destdir="${output.dir}/${war.dir}/WEB-INF/classes"  includes="*.java" excludes="Test_CXF_Client.java" classpathref="jboss.classpath"/>
        <copy todir="${output.dir}/${war.dir}/WEB-INF">
	  <fileset dir="${basedir}/src">
	      <include name="web.xml"/>
	  </fileset>
	</copy>   
       <wsprovide
        	fork="false"
        	keep="true"
        	destdir="${output.dir}"
        	resourcedestdir="${output.dir}/${war.dir}/WEB-INF/wsdl"
        	sourcedestdir="${output.dir}"
        	genwsdl="true" 
        	verbose="true"
        	sei="ws.DemoCXF">
            	<classpath>
                	  <pathelement path="${output.dir}/${war.dir}/WEB-INF/classes"/>
            	</classpath>
      </wsprovide>

      <jar jarfile="${output.dir}/${war.name}" basedir="${output.dir}/${war.dir}" compress="true" /> 
      
    </target>

        <target name="deploy" depends="build">
            <echo message="*******************  Deploying   *********************" />  
            <echo message="********** ${war.name} to ${jboss.home}/standalone/deployments **********" />  
            <copy file="${output.dir}/${war.name}" todir="${jboss.home}/standalone/deployments/"/>

            <echo message="*******************  Deployed Successfully   *********************" />  
        </target>
  
        <target name="post-deploy" >
            <echo message="*******************  NOTE  *********************" />
            <echo message="***** You should be able to access your WSDL using Browser now *****" />
            <echo message="                http://localhost:8080/CXFClientLoggingDemo?wsdl          " />
        </target>  

        <target name="client" depends="post-deploy">
           <delete dir="${client.dir}" />
           <mkdir dir="${client.dir}"/>             
             <wsconsume
                      fork="true"
                      keep="true"
                      destdir="${client.dir}"
                      sourcedestdir="${client.dir}"
                      package="client"
                      wsdlLocation="service.wsdl"
                      wsdl="http://localhost:8080/CXFClientLoggingDemo?wsdl">
            </wsconsume>


            <!-- We need to make sure that log4j.properties is present inside client's classpath-->
            <copy file="${src.dir}/log4j.properties" todir="${client.dir}" />

            <javac srcdir="${src.dir}" destdir="${client.dir}"  includes="Test_CXF_Client.java" classpathref="client.classpath">
	        <classpath>
	            <pathelement location="${client.dir}"/>
	            <path refid="client.classpath"/>
	        </classpath>
            </javac>

            <jar jarfile="${client.dir}/${client.jar.name}" basedir="${client.dir}" compress="true" /> 


            <!-- Cleaning Client Stuff Directory --> 
            <delete dir="${client.dir}/client"/> 
            <delete file="${client.dir}/log4j.properties"/> 
       </target>

        <target name="run" depends="client">
            <java classname="client.Test_CXF_Client" fork="true" >
	        <classpath>
	            <pathelement location="${client.dir}/DemoCXFClient.jar"/>
	            <path refid="client.classpath"/>
	        </classpath>
                <jvmarg value="-Dorg.apache.cxf.Logger=org.apache.cxf.common.logging.Log4jLogger" />
                <arg value="http://localhost:8080/CXFClientLoggingDemo"/>
            </java>
        </target>  

</project>

NOTE: The only change in the above file you need to do is to change the “jboss.home” directory path in the second line of the above script to point to your own JBoss AS7 directory.

Step-7). Now Start your JBoss Profile as following from inside the directory “/home/userone/jboss-as-7.1.0.CR1/bin”:

.
 ./standalone.sh -c standalone-full.xml
.

Step-8). Now before running your ANT script to build and deploy the above webapplication you should have the ANT as well as JAVA set in the $PATH variable of the Shell / command prompt as following:

For Unix Based OS:
export PATH=/home/userone/jdk1.6.0_21/bin:/home/userone/org.apache.ant_1.6.5/bin:$PATH

For Windows Based OS:
set PATH=C:/jdk1.6.0_21/bin;C:/org.apache.ant_1.6.5/bin;%PATH%

Step-9). Now once the PATH is set In the command/Shell prompt you can move inside the directory “/home/userone/CXFClientSide_Logging_Demo” and then run the ant to build and deploy the WebService application on your JBoss Standalone full profile, by running the command “ant deploy”

[userone@localhost CXFClientSide_Logging_Demo]$ ant deploy
Buildfile: build.xml

init:
   [delete] Deleting directory /home/userone/CXFClientSide_Logging_Demo/build
    [mkdir] Created dir: /home/userone/CXFClientSide_Logging_Demo/build
    [mkdir] Created dir: /home/userone/CXFClientSide_Logging_Demo/build/CXFClientLoggingDemoWAR
    [mkdir] Created dir: /home/userone/CXFClientSide_Logging_Demo/build/CXFClientLoggingDemoWAR/META-INF
    [mkdir] Created dir: /home/userone/CXFClientSide_Logging_Demo/build/CXFClientLoggingDemoWAR/WEB-INF
    [mkdir] Created dir: /home/userone/CXFClientSide_Logging_Demo/build/CXFClientLoggingDemoWAR/WEB-INF/classes
   [delete] Deleting directory /home/userone/CXFClientSide_Logging_Demo/clientStuff
    [mkdir] Created dir: /home/userone/CXFClientSide_Logging_Demo/clientStuff/META-INF

build:
    [javac] Compiling 1 source file to /home/userone/CXFClientSide_Logging_Demo/build/CXFClientLoggingDemoWAR/WEB-INF/classes
     [copy] Copying 1 file to /home/userone/CXFClientSide_Logging_Demo/build/CXFClientLoggingDemoWAR/WEB-INF
[wsprovide] Generating from endpoint: ws.DemoCXF
[wsprovide] log4j:WARN No appenders could be found for logger (org.apache.cxf.common.logging.LogUtils).
[wsprovide] log4j:WARN Please initialize the log4j system properly.
[wsprovide] log4j:WARN See http://logging.apache.org/log4j/1.2/faq.html#noconfig for more info.
[wsprovide] java2ws -s /home/userone/CXFClientSide_Logging_Demo/build -classdir /home/userone/CXFClientSide_Logging_Demo/build -d /home/userone/CXFClientSide_Logging_Demo/build/CXFClientLoggingDemoWAR/WEB-INF/wsdl -verbose -wsdl -cp ::::::::: -wrapperbean -createxsdimports ws.DemoCXF
[wsprovide] java2ws - Apache CXF 2.4.4
[wsprovide] 
      [jar] Building jar: /home/userone/CXFClientSide_Logging_Demo/build/CXFClientLoggingDemo.war

deploy:
     [echo] *******************  Deploying   *********************
     [echo] ********** CXFClientLoggingDemo.war to /home/userone/jboss-as-7.1.0.CR1b/standalone/deployments **********
     [copy] Copying 1 file to /home/userone/jboss-as-7.1.0.CR1b/standalone/deployments
     [echo] *******************  Deployed Successfully   *********************

BUILD SUCCESSFUL
Total time: 6 seconds

As soon as the WebService will be deployed on the JBoss AS7 you will see the following kind of output on your JBoss Console (STDOUT):

12:55:32,698 INFO  [org.jboss.as.server.deployment] (MSC service thread 1-7) Starting deployment of "CXFClientLoggingDemo.war"
12:55:32,953 INFO  [org.jboss.wsf.stack.cxf.metadata.MetadataBuilder] (MSC service thread 1-2) Add Service
 id=DemoCXF
 address=http://localhost:8080/CXFClientLoggingDemo
 implementor=ws.DemoCXF
 invoker=org.jboss.wsf.stack.cxf.JBossWSInvoker
 serviceName={http://test.org}DemoCXFService
 portName={http://test.org}DemoCXFPort
 wsdlLocation=null
 mtomEnabled=false
12:55:32,954 INFO  [org.jboss.ws.common.management.DefaultEndpointRegistry] (MSC service thread 1-2) register: jboss.ws:context=CXFClientLoggingDemo,endpoint=DemoCXF
12:55:33,174 INFO  [org.apache.cxf.service.factory.ReflectionServiceFactoryBean] (MSC service thread 1-2) Creating Service {http://test.org}DemoCXFService from class ws.DemoCXF
12:55:33,482 INFO  [org.apache.cxf.endpoint.ServerImpl] (MSC service thread 1-2) Setting the server's publish address to be http://localhost:8080/CXFClientLoggingDemo
12:55:33,605 INFO  [org.jboss.wsf.stack.cxf.deployment.WSDLFilePublisher] (MSC service thread 1-2) WSDL published to: file:/home/userone/jboss-as-7.1.0.CR1b/standalone/data/wsdl/CXFClientLoggingDemo.war/DemoCXFService.wsdl
12:55:33,613 INFO  [org.jboss.as.webservices] (MSC service thread 1-8) JBAS015539: Starting service jboss.ws.port-component-link
12:55:33,622 INFO  [org.jboss.as.webservices] (MSC service thread 1-3) JBAS015539: Starting service jboss.ws.endpoint."CXFClientLoggingDemo.war".DemoCXF
12:55:33,647 INFO  [org.jboss.web] (MSC service thread 1-7) registering web context: /CXFClientLoggingDemo
12:55:33,667 INFO  [org.jboss.as.server] (DeploymentScanner-threads - 2) JBAS018559: Deployed "CXFClientLoggingDemo.war"

Step-10). Now we will try to compile and run the WebService Client application by running the command “ant run”

[userone@localhost CXFClientSide_Logging_Demo]$ ant run
Buildfile: build.xml

post-deploy:
     [echo] *******************  NOTE  *********************
     [echo] ***** You should be able to access your WSDL using Browser now *****
     [echo]                 http://localhost:8080/CXFClientLoggingDemo?wsdl          

client:
   [delete] Deleting directory /home/userone/CXFClientSide_Logging_Demo/clientStuff
    [mkdir] Created dir: /home/userone/CXFClientSide_Logging_Demo/clientStuff
[wsconsume] Consuming wsdl: http://localhost:8080/CXFClientLoggingDemo?wsdl
[wsconsume] log4j:WARN No appenders could be found for logger (org.apache.cxf.common.logging.LogUtils).
[wsconsume] log4j:WARN Please initialize the log4j system properly.
[wsconsume] log4j:WARN See http://logging.apache.org/log4j/1.2/faq.html#noconfig for more info.
     [copy] Copying 1 file to /home/userone/CXFClientSide_Logging_Demo/clientStuff
    [javac] Compiling 1 source file to /home/userone/CXFClientSide_Logging_Demo/clientStuff
      [jar] Building jar: /home/userone/CXFClientSide_Logging_Demo/clientStuff/DemoCXFClient.jar
   [delete] Deleting directory /home/userone/CXFClientSide_Logging_Demo/clientStuff/client
   [delete] Deleting: /home/userone/CXFClientSide_Logging_Demo/clientStuff/log4j.properties

run:
      Feb 4, 2012 12:55:45 PM client.DemoCXFService <clinit>
      INFO: Can not initialize the default wsdl from service.wsdl
      
      	 port.sayHello("MiddlewareMagic") = Hello JBossAS7 User: MiddlewareMagic

BUILD SUCCESSFUL
Total time: 9 seconds

Step-11). Once the webservice is invoked successfully then you will be able to see the Client Side log file is generated in the location which is mentioned in the “log4j.properties” file…something like following:

12:55:46,418  INFO ReflectionServiceFactoryBean:366 - Creating Service {http://test.org}DemoCXFService from WSDL: http://localhost:8080/CXFClientLoggingDemo?wsdl
12:55:46,930  INFO LoggingOutInterceptor:151 - Outbound Message
---------------------------
ID: 1
Address: http://localhost:8080/CXFClientLoggingDemo
Encoding: UTF-8
Content-Type: text/xml
Headers: {Accept=[*/*], SOAPAction=[""]}
Payload: <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"><soap:Body><ns2:sayHello xmlns:ns2="http://test.org"><arg0>MiddlewareMagic</arg0></ns2:sayHello></soap:Body></soap:Envelope>
--------------------------------------
12:55:47,061  INFO LoggingInInterceptor:151 - Inbound Message
----------------------------
ID: 1
Response-Code: 200
Encoding: UTF-8
Content-Type: text/xml;charset=UTF-8
Headers: {Content-Length=[235], content-type=, Date=[Sat, 04 Feb 2012 07:25:46 GMT], Server=[Apache-Coyote/1.1]}
Payload: <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"><soap:Body><ns2:sayHelloResponse xmlns:ns2="http://test.org"><return>Hello JBossAS7 User: MiddlewareMagic</return></ns2:sayHelloResponse></soap:Body></soap:Envelope>
--------------------------------------

Enabling Logging On JBoss Server Side

You can add the following System Property (-Dorg.apache.cxf.logging.enabled=true) on JBoss Configuration like “standalone-full.xml” as following:

<server xmlns="urn:jboss:domain:1.3">

    <extensions>
        <extension module="org.jboss.as.clustering.infinispan"/>
        <extension module="org.jboss.as.cmp"/>
       .
       .
       .
        <extension module="org.jboss.as.webservices"/>
        <extension module="org.jboss.as.weld"/>
    </extensions>

    <system-properties>
        <property name="org.apache.cxf.logging.enabled" value="true"/>
    </system-properties>


    <management>
        <security-realms>
       .
       .
        </security-realms>
   </management>

.
.
Thanks 🙂
Middleware Magic Team

If you enjoyed this post, please consider leaving a comment or subscribing to the RSS feed to have future articles delivered to your feed reader.