Tutorial: How to log Axis2 request and response SOAP messages on service side?

Our task is to grab SOAP messages on service side. To do it we need to create logging module and connect it to our service.

Step 1. Create project
Create the Java Enterprise project without any libraries or frameworks that your IDE proposes. Import axis2 library like in this post.

1

Step 2. Write code
Create main class that implements Module (from org.apache.axis2.modules package). Implement all necessary methods. To do that you can just press “Alt”+”Enter” on line where you set class name.

2

That is it with this class:
public class Axis2GrabSOAPModule implements Module {
 @Override
 public void init(ConfigurationContext configurationContext, AxisModule axisModule) throws AxisFault {
 }
 @Override
 public void engageNotify(AxisDescription axisDescription) throws AxisFault {
 }
 @Override
 public boolean canSupportAssertion(Assertion assertion) {
  return false;
 }
 @Override
 public void applyPolicy(Policy policy, AxisDescription axisDescription) throws AxisFault {
 }
 @Override
 public void shutdown(ConfigurationContext configurationContext) throws AxisFault {
 }
}

Next create class that extends AbstractHandler and implements Handler. Implement required invoke method. In invoke method we will use log function. Also implement init method to set log filename. You can configure logger in TOMCAT_HOME/webapps/axis2/WEB-INF/classes, but I’d like to configure it in code. So class content:

public class CustomHandler extends AbstractHandler implements Handler {
 private Logger log = Logger.getLogger(LogHandler.class);
 @Override
 public void init(HandlerDescription handlerdesc) {
  super.init(handlerdesc);
  SimpleLayout layout = new SimpleLayout();
  FileAppender appender = null;
  try {
   appender = new FileAppender(layout, "DESIRED_LOGFILE_PATH/log.txt", false);
  } catch (IOException e) {
   e.printStackTrace();
  }
  log.addAppender(appender);
 }
 @Override
 public InvocationResponse invoke(MessageContext messageContext) throws AxisFault {
  log.info(messageContext.getEnvelope().toString());
  return InvocationResponse.CONTINUE;
 }
}

Replace DESIRED_LOGFILE_PATH with path, where log.txt should be located. You can write absolute path or path relatively to TOMCAT_HOME/bin.

Step 3. Create/edit configuration files.

Create directory “resources”. Then create directory “META-INF” in “resources”. Write to file resources/META-INF/module.xml this code:

<module name="MyLoggingModule" class="Axis2GrabSOAPModule">
 <InFlow>
  <handler name="InFlowLogHandler" class="CustomHandler">
   <order phase="loggingPhase" />
  </handler>
 </InFlow>
 <OutFlow>
  <handler name="OutFlowLogHandler" class="CustomHandler">
   <order phase="loggingPhase"/>
  </handler>
 </OutFlow>
 <OutFaultFlow>
  <handler name="FaultOutFlowLogHandler" class="CustomHandler">
   <order phase="loggingPhase"/>
  </handler>
 </OutFaultFlow>
 <InFaultFlow>
  <handler name="FaultInFlowLogHandler" class="CustomHandler">
   <order phase="loggingPhase"/>
  </handler>
 </InFaultFlow>
</module>

How you can see, we configured that our module will catch messages in and out directions including fault messages.

Then we need to configure axis2.xml which is located by default in TOMCAT_HOME/webapps/axis2/WEB-INF/conf. In this file you need to add “<phase name=”loggingPhase”/>” inside of “<phaseOrder type=”inflow”>…</phaseOrder>”, “<phaseOrder type=”outflow”>…</phaseOrder>”, “<phaseOrder type=”INfaultflow”>…</phaseOrder>” and “<phaseOrder type=”Outfaultflow”>…</phaseOrder>”. For example, in my axis2.xml phase orders defined like this:

 <phaseOrder type="InFlow">
  <!-- System predefined phases  -->
  <phase name="Transport">
   <handler name="RequestURIBasedDispatcher"
      class="org.apache.axis2.dispatchers.RequestURIBasedDispatcher">
    <order phase="Transport"/>
   </handler>
   <handler name="SOAPActionBasedDispatcher"
      class="org.apache.axis2.dispatchers.SOAPActionBasedDispatcher">
    <order phase="Transport"/>
   </handler>
  </phase>
  <phase name="Addressing">
   <handler name="AddressingBasedDispatcher"
      class="org.apache.axis2.dispatchers.AddressingBasedDispatcher">
    <order phase="Addressing"/>
   </handler>
  </phase>
  <phase name="Security"/>
  <phase name="PreDispatch"/>
  <phase name="Dispatch" class="org.apache.axis2.engine.DispatchPhase">
   <handler name="RequestURIBasedDispatcher"
      class="org.apache.axis2.dispatchers.RequestURIBasedDispatcher"/>
   <handler name="SOAPActionBasedDispatcher"
      class="org.apache.axis2.dispatchers.SOAPActionBasedDispatcher"/>
   <handler name="RequestURIOperationDispatcher"
      class="org.apache.axis2.dispatchers.RequestURIOperationDispatcher"/>
   <handler name="SOAPMessageBodyBasedDispatcher"
      class="org.apache.axis2.dispatchers.SOAPMessageBodyBasedDispatcher"/>
   <handler name="HTTPLocationBasedDispatcher"
      class="org.apache.axis2.dispatchers.HTTPLocationBasedDispatcher"/>
   <handler name="GenericProviderDispatcher"
      class="org.apache.axis2.jaxws.dispatchers.GenericProviderDispatcher"/>
   <handler name="MustUnderstandValidationDispatcher"
      class="org.apache.axis2.jaxws.dispatchers.MustUnderstandValidationDispatcher"/>
  </phase>
  <phase name="RMPhase"/>
  <!-- System predefined phases  -->
  <!-- After Postdispatch phase module author or service author can add any phase he want  -->
  <phase name="OperationInPhase">
   <handler name="MustUnderstandChecker"
      class="org.apache.axis2.jaxws.dispatchers.MustUnderstandChecker">
    <order phase="OperationInPhase"/>
   </handler>
  </phase>
  <phase name="soapmonitorPhase"/>
  <phase name="loggingPhase"/>
 </phaseOrder>
 <phaseOrder type="OutFlow">
  <!--  user can add his own phases to this area -->
  <phase name="soapmonitorPhase"/>
  <phase name="OperationOutPhase"/>
  <!--system predefined phase-->
  <!--these phase will run irrespective of the service-->
  <phase name="RMPhase"/>
  <phase name="PolicyDetermination"/>
  <phase name="MessageOut"/>
  <phase name="Security"/>
  <phase name="loggingPhase"/>
 </phaseOrder>
 <phaseOrder type="InFaultFlow">
  <phase name="Addressing">
   <handler name="AddressingBasedDispatcher"
      class="org.apache.axis2.dispatchers.AddressingBasedDispatcher">
    <order phase="Addressing"/>
   </handler>
  </phase>
  <phase name="Security"/>
  <phase name="PreDispatch"/>
  <phase name="Dispatch" class="org.apache.axis2.engine.DispatchPhase">
   <handler name="RequestURIBasedDispatcher"
      class="org.apache.axis2.dispatchers.RequestURIBasedDispatcher"/>
   <handler name="SOAPActionBasedDispatcher"
      class="org.apache.axis2.dispatchers.SOAPActionBasedDispatcher"/>
   <handler name="RequestURIOperationDispatcher"
      class="org.apache.axis2.dispatchers.RequestURIOperationDispatcher"/>
   <handler name="SOAPMessageBodyBasedDispatcher"
      class="org.apache.axis2.dispatchers.SOAPMessageBodyBasedDispatcher"/>
   <handler name="HTTPLocationBasedDispatcher"
      class="org.apache.axis2.dispatchers.HTTPLocationBasedDispatcher"/>
   <handler name="GenericProviderDispatcher"
      class="org.apache.axis2.jaxws.dispatchers.GenericProviderDispatcher"/>
   <handler name="MustUnderstandValidationDispatcher"
      class="org.apache.axis2.jaxws.dispatchers.MustUnderstandValidationDispatcher"/>
  </phase>
  <phase name="RMPhase"/>
  <!--  user can add his own phases to this area -->
  <phase name="OperationInFaultPhase"/>
  <phase name="soapmonitorPhase"/>
  <phase name="loggingPhase"/>
 </phaseOrder>
 <phaseOrder type="OutFaultFlow">
  <!--  user can add his own phases to this area -->
  <phase name="soapmonitorPhase"/>
  <phase name="OperationOutFaultPhase"/>
  <phase name="RMPhase"/>
  <phase name="PolicyDetermination"/>
  <phase name="MessageOut"/>
  <phase name="Security"/>
  <phase name="loggingPhase"/>
 </phaseOrder>

Now we need to edit services.xml of your service which messages you are going to handle. I will show you example on service, created in this post:

 <service name="CustomService" scope="application" targetNamespace="http://doszhan.com/">
  <description>
   My Custom Service
  </description>
  <module ref="MyLoggingModule"/>
  <messageReceivers>
   <messageReceiver mep="http://www.w3.org/2004/08/wsdl/in-only" class="org.apache.axis2.rpc.receivers.RPCInOnlyMessageReceiver" />
   <messageReceiver mep="http://www.w3.org/2004/08/wsdl/in-out" class="org.apache.axis2.rpc.receivers.RPCMessageReceiver" />
  </messageReceivers>
  <schema schemaNamespace="http://doszhan.com/xsd"/>
  <parameter name="ServiceClass">CustomService</parameter>
 </service>

Of course it is needed to rebuild service. You can read Step 4 and Step 5 in this post to see how to do it.

Step 4. Build

We need to export jar file. To do it go to “File”->”Project Structure…”->tab “Artifacts”. Click on green plus icon, select “JAR”->”Empty”. Set the name of JAR file you want. Click on “Create Manifest…” and select directory resources/META-INF. Click on green plus icon in “Output Layout” tab and select module.xml. Also double click on “‘YOUR_PROJECT_NAME’ compile output” to add generated classes into jar file. That’s it:

4

Click “OK” and build this artifact by “Build”->”Build Artifacts…”->THE_NAME_OF_JAR->”Build”. JAR file will be created in “out” folder. Just rename this file from THE_NAME_OF_JAR.jar to THE_NAME_OF_JAR.mar. So my project in the end looks like this:

4-2

Step 5. Run

Copy .aar service to TOMCAT_HOME/webapps/axis2/WEB-INF/services. Copy .mar module to TOMCAT_HOME/webapps/axis2/WEB-INF/modules. Axis2 supports hot deployment of services, but does not support hot deployment of modules. Therefore after copying files restart tomcat.

After restarting you may want to check whether everything is correct. In internet browser open “TOMCAT_SERVER_URL/manager/html”. You will be asked to enter login and password. These data configured in tomcat-users.xml. More detailed in post Step 1. Then click on “/axis2″->”Administration”. Default login and password pare for axis2 admin panel is “admin/axis2”. Check “Available Services” and “Available Modules” pages.

Run client of service and check path, what you set as directory of log file. Check log file. If everything is good, you will see request and response messages. In my case log file content is this:
INFO - <?xml version='1.0' encoding='utf-8'?> <soapenv:Envelope xmlns:soapenv="http://www.w3.org/2003/05/soap-envelope"> <soapenv:Body> <ns2:getWorkerWithChangedSalary xmlns:ns2="http://doszhan.com/xsd"> <ns2:worker> <ns1:name xmlns:ns1="http://models/xsd">Doszhan </ns1:name> <ns1:position xmlns:ns1="http://models/xsd">specialist </ns1:position> <ns1:salary xmlns:ns1="http://models/xsd">100 </ns1:salary> <ns1:surname xmlns:ns1="http://models/xsd">Kalibek </ns1:surname> </ns2:worker> </ns2:getWorkerWithChangedSalary> </soapenv:Body> </soapenv:Envelope>
INFO - <?xml version='1.0' encoding='utf-8'?> <soapenv:Envelope xmlns:soapenv="http://www.w3.org/2003/05/soap-envelope"> <soapenv:Body> <ns:getWorkerWithChangedSalaryResponse xmlns:ns="http://doszhan.com/xsd"> <ns:return xmlns:ax21="http://models/xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="ax21:Worker"> <ax21:name>Doszhan </ax21:name> <ax21:position>specialist </ax21:position> <ax21:salary>200 </ax21:salary> <ax21:surname>Kalibek </ax21:surname> </ns:return> </ns:getWorkerWithChangedSalaryResponse> </soapenv:Body> </soapenv:Envelope>

If you have found a spelling error, please, notify us by selecting that text and pressing Ctrl+Enter.

Profile photo of Doszhan Kalibek

Doszhan Kalibek