Saturday, January 11, 2014

Capturing SOAP packets in Apache Chainsaw


The logs from the handler mentioned in JAXWS Handler : Example for logging request / response SOAP packets can be forwarded over a socket to an external listener or a tool like Apache Chainsaw. In order to forward these logs over a socket, a SocketAppender needs to be used. The following modifications needs to be done to SOAPRequestResponseSpitter class. Add the imports
import org.apache.log4j.Logger;
import org.apache.log4j.net.SocketAppender;
Add the static block
private static Logger LOGGER = Logger.getLogger(SOAPRequestResponseSpitter.class);

 static {
  SocketAppender socketAppender = new SocketAppender("localhost", 4560);
  socketAppender.setReconnectionDelay(10000); // 10 seconds

  LOGGER.addAppender(socketAppender);
  socketAppender.activateOptions();
 }
In the log(..) method, write the soap packet to this logger.
 private void log(SOAPMessageContext smc) {
  Boolean outboundProperty = (Boolean) smc.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY);

  if (outboundProperty.booleanValue()) {
   System.out.println("\nOutbound message:");
  } else {
   System.out.println("\nInbound message:");
  }

  SOAPMessage message = smc.getMessage();
  ByteArrayOutputStream boas = new ByteArrayOutputStream();
  try {
   message.writeTo(boas);
   LOGGER.info(boas.toString());
   System.out.println(boas.toString());
   System.out.println("");
  } catch (Exception e) {
   System.out.println("Exception in handler: " + e);
  }
 }
Note: Above mentioned may be the worst way to configure an appender. A configuration file like log4j.xml or log4j.properties should be used instead. I don't want to go into details of how to configure log4j hence using the simple approach above to avoid distracting from the main focus. Launch Apache Chainsaw and choose the second option, i.e.
    Let me use a simple Receive: SocketReceiver on port 4560 (Default SocketAppender port)
Once this setting is used, all the SOAP packets being intercepted by the handler will be displayed on a tab in the Chainsaw application. Apache Chainsaw & the SocketAppender is being used here to log SOAP packets only. This combination can be used to remotely view any log4j logs transmitted by the SocketAppender.

Tuesday, October 22, 2013

Searching multiple words in multiple files in eclipse

There are times when we have to search for the occurrences of multiple words in multiple files. In eclipse you can perform this search using File Search with regex expressions.

  • Open Search > File dialog.
  • In the Containing text: field enter (?<!^\s*(//|\*).*)(jack|jim)
  • Select the Regular expression check box and hit the search button.
The above steps shall parse thru all the files selected in the File name patterns section and list all the files with either jack or jim or both.

To understand the expression above, you can refer to http://www.eclipse.org/tptp/home/downloads/installguide/gla_42/ref/rregexp.html

Tuesday, May 21, 2013

Temporary environment variables precedence in Windows

The user environment variables always have precedence over the system environment variables for the process run by the particular user.

In relation to the temporary folders, the TMP environment variable has a precedence over the TEMP environment variable (legacy reasons dating to DOS). So to sum up the temporary folders environment variable precedence (top to bottom) for the currently logged in user is:
  • User %TMP%  (Highest precedence)
  • System %TMP%
  • User %TEMP%
  • System %TEMP% (Lowest precedence)
You can verify the precedence using:
  • Command prompts echo %ENVIRONMENT VARIABLE%
  • Java's [System.getProperty("java.io.tmpdir")]
  • C# [Path.GetTempPath()]

Thursday, March 21, 2013

JAXWS Handler injection using Spring

I'll try to keep this post less verbose and let the code speak for itself.

In order inject the handler using Spring, we need the below mentioned default handler resolver class and the configuration.

DefaultHandlerResolver
package handler;

import java.util.List;

import javax.xml.ws.handler.Handler;
import javax.xml.ws.handler.HandlerResolver;
import javax.xml.ws.handler.PortInfo;

@SuppressWarnings("rawtypes")
public class DefaultHandlerResolver implements HandlerResolver {
 private List<Handler> handlerList;

 public List<Handler> getHandlerChain(PortInfo portInfo) {
  return handlerList;
 }

 public void setHandlerList(List<Handler> handlerList) {
  this.handlerList = handlerList;
 }
}


applicationContext.xml
<?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:util="http://www.springframework.org/schema/util"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
                           http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-2.5.xsd
                           http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd">

 <!-- Web Service custom properties (Timeouts in millis)  -->
 <util:map id="jaxwsCustomProperties">
  <entry key="com.sun.xml.ws.connect.timeout">
   <value type="java.lang.Integer">15000</value>
  </entry> 
  <entry key="com.sun.xml.ws.request.timeout">
   <value type="java.lang.Integer">15000</value>
  </entry>
 </util:map>

 <bean id="handlerResolver" class="handler.DefaultHandlerResolver">
  <property name="handlerList">
   <list>
    <bean class="handler.SOAPRequestResponseSpitter" />
   </list>
  </property>
 </bean>

 <bean id="calculatorServicePortType" class="org.springframework.remoting.jaxws.JaxWsPortProxyFactoryBean">
  <property name="serviceInterface" value="service.Calculator" />
  <property name="wsdlDocumentUrl" value="CalculatorService.wsdl" />
  <property name="namespaceUri" value="http://service/" />
  <property name="serviceName" value="CalculatorService" />
  <property name="endpointAddress" value="http://localhost:7001/CalculatorServiceWebApp/CalculatorService" />
  <property name="customProperties" ref="jaxwsCustomProperties" />
  <property name="handlerResolver" ref="handlerResolver"/>
 </bean>
</beans>


Once the above files are ready, then run the following in the main method of your test class or JUnit:
ApplicationContext context = new ClassPathXmlApplicationContext(new String[] { "applicationContext.xml" });
Calculator calculator = (Calculator) context.getBean("calculatorServicePortType");
System.out.println("Calculated result [" + calculator.add(2, 3) +"]");


The output should look like: Outbound message:
<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
  <S:Header/>
  <S:Body>
    <ns2:add xmlns:ns2="http://service/">
      <a>2</a>
      <b>3</b>
    </ns2:add>
  </S:Body>
</S:Envelope>
Inbound message:
<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
 <S:Header/>
 <S:Body>
  <ns2:addResponse xmlns:ns2="http://service/">
   <return>5</return>
  </ns2:addResponse>
 </S:Body>
</S:Envelope>
Calculated result [5]

JAXWS Handler : Example for logging request / response SOAP packets

There are times when we want to see the request / response SOAP packets in our system console or log files. Instead of going for TCP monitor or other similiar tools, I though of writing a handler. The code below is quite popular and can be found in many other posts too.

Adding this handler is simple. Just pass the binding object of your Web Service client port into the static addToPort(...) method in this class.
package handler;

import java.io.ByteArrayOutputStream;
import java.util.Collections;
import java.util.List;
import java.util.Set;

import javax.xml.namespace.QName;
import javax.xml.soap.SOAPMessage;
import javax.xml.ws.Binding;
import javax.xml.ws.handler.Handler;
import javax.xml.ws.handler.MessageContext;
import javax.xml.ws.handler.soap.SOAPHandler;
import javax.xml.ws.handler.soap.SOAPMessageContext;

public class SOAPRequestResponseSpitter implements SOAPHandler<SOAPMessageContext> {

 @Override
 public boolean handleMessage(SOAPMessageContext context) {
  logToSystemOut(context);
  return true;
 }

 @Override
 public boolean handleFault(SOAPMessageContext context) {
  logToSystemOut(context);
  return true;
 }

 private void logToSystemOut(SOAPMessageContext smc) {
  Boolean outboundProperty = (Boolean) smc.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY);

  if (outboundProperty.booleanValue()) {
   System.out.println("\nOutbound message:");
  } else {
   System.out.println("\nInbound message:");
  }

  SOAPMessage message = smc.getMessage();
  try {
       ByteArrayOutputStream baos = new ByteArrayOutputStream();
       message.writeTo(baos);
       System.out.println(baos.toString());
  } catch (Exception e) {
   System.out.println("Exception in handler: " + e);
  }
 }

 @Override
 public void close(MessageContext context) {
 }

 @Override
 public Set<QName> getHeaders() {
  return Collections.emptySet();
 }

 @SuppressWarnings("rawtypes")
 /**
  * This static method adds the handler to the provided port's binding object. 
  * 
  * @param binding - The binding object can be fetched by <code>((BindingProvider) port).getBinding()</code>
  */
 public static void addToPort(Binding binding) {
  List<Handler> handlerChain = binding.getHandlerChain();
  handlerChain.add(new SOAPRequestResponseSpitter());

  /*
   * Check List<Handler> javax.xml.ws.Binding.getHandlerChain() javadocs.
   * It states: Gets a copy of the handler chain for a protocol binding
   * instance. If the returned chain is modified a call to setHandlerChain
   * is required to configure the binding instance with the new chain.
   */
  binding.setHandlerChain(handlerChain);
 }
}


To inject this handler into the port using Spring, please refer to my other post JAXWS Handler injection using Spring

The handler gives you much control on how you want to log the packets. If you don't want to write a handler and just want to see the packets without making any changes to the application, you can use the below mentioned JVM argument in your server startup script and all the web service related tcp communication will be printed on the console.
  -Dcom.sun.xml.ws.transport.http.client.HttpTransportPipe.dump=true