Tuesday, 30 September 2008

EasyMock replacement, JMockit rocks!

A while ago I was working on pure Java program which was written by one of my colleague. It is not a web application and it does not rely on any injection framework like Spring. The program itself is structured with a bit complicated design pattern. What I have to do is to add an extra feature with perform logging when a certain condition happen. Although it is not difficult to write that extra piece of work, the difficult part is actually how to test my extra piece of work properly without changing any existing code.

Here is the idea of the work:

  private static Log log = LogFactory.getLog(aClass.class);

  public void doImportantStuff()
  {
    if (important)
    {
      if (log.isInfoEnabled())
      {
        log.info("log some important information");
      }
    }
  }


To do a proper testing to see whether the code is actually calling log4j/commonlog, I have to mock the log object. However, since log object is created with as an static. I will not be able to mock it.

I search the net for a while, luckily I was able to find this tool called "JMockit". The cool feature it has is you don't need to rely on any injection framework, you can mock whatever you like. Since it used java.lang.instrument package, which can actually read and change the byte code at runtime, I can easily create a test which mock the log object and replace it at runtime.

To illustrate of what I mentioned, here is a sample test:

  public class AClassTest
  {
    public void testTheCodeDoesLogWhenItIsImportant()
    {
      Mockit.redefineMethods(Log.class, MockLog.class);

      // code that make it important

      new AClass().doImportantStuff();

      assertTrue(MockLog.infoMethodHasBeenCalled);
    }
  }

  public static class MockLog
  {
    public static boolean infoMethodHasBeenCalled = false;

    public void info(String value)
    {
      infoMethodHasBeenCalled = true;
    }
  }


As you can see the above, by using Mockit.redefineMethods(), Log object has been replaced with MyLog object which redefine the info() method. As a result, you can check whether the log.info() has been called properly without changing any of original code.

If you use EasyMock framework, you usually have to set the mock object in order to see the expectation. However, as because of runtime byte code modification feature, this mocking framework does not rely on that mock injection. It seems this mocking framework is unbeatable. However, one tricky thing is whenever you run your test, you have to provide jvm argument which point to JMockit jar file, which is "-javaagent:jmockit.jar". However, it does not harm to provide javagent argument. In fact, it is very easy to do so even if you use maven.

For further information on JMockit, please refer to JMockit official website.

Saturday, 16 August 2008

Create Apache CXF Interceptor (2)

To manipulate the header when a soap fault is returning, a org.apache.cxf.headers.Header object has to be created.

In the handleMessage method inside FaultHeaderInterceptor,

import javax.xml.namespace.QName;
import org.apache.cxf.headers.Header;
import org.w3c.dom.Element;
import com.sun.xml.messaging.saaj.soap.SOAPDocumentImpl;
import com.sun.xml.messaging.saaj.soap.impl.ElementImpl;
import com.sun.xml.messaging.saaj.soap.name.NameImpl;
import com.sun.xml.messaging.saaj.soap.ver1_1.SOAPPart1_1Impl;
import net.clockstudio.cxf.HeaderTransferObject;

public void handleMessage(SoapMessage message) throws Fault
{
  // previous code

  Header header = this.createHeader(headerTO);
  if (header != null)
  {
    message.getHeaders.add(header);
  }
}

private Header createHeader(HeaderTransferObject headerTO)
{
  if (headerTO != null)
  {
    QName qname = new QName("/some/qname");
    SOAPDocumentImpl doc = new SOAPDocmentImpl(new SOAPPart1_1Impl());
    doc.setErrorChecking(false);

    Element element = new ElementImpl(doc, NameImpl.createFromQualifiedName("MyHeader", "http://clockstudio.net/cxf/myheader"));

    Element subElement = new ElementImpl(doc, NameImpl.createFromQualifiedName("subHeader", "http://clockstudio.net/cxf/subheader"));
    subElement.setTextContent(headerTO.getInfo());

    // more headers can be added

    element.appendChild(subElement);
    return new Header(qname, element);
  }
  return null;
}

In the above code, HeaderTransferObject attributes hold the information for creating a header. To create a header, it takes a QName (Qualified Name) and Element objects. In this example, the Element objects are created using SOAPDocumentImpl as well as its qualified name.

As you can see, it's still fairly simple to create a header when a fault is returned. However, what if you want to capture the incoming platform specific header and return those information back? In an asynchronized environment, the client request comes along with it's session id, transaction info and those has to be returned when a fault is occured. So the client can then be able to trace back which thread made the request, what can you do with this case?

In this case, another Interceptor has to be created to capture the incoming header information. You may wonder that there is an Exchange object which hold all incoming, outgoing message in the whole process, however, from my experience, when a fault is occured, the incoming header information in the Exchange object will be erased, it is probably because of a fault routine is started. Or it maybe just a bug in CXF. A further investigation is needed. But now, the new SoapHeaderInterceptor will do the job which explicitly save the header information into the message.

Here is the code,

public SoapHeaderInterceptor()
{
  super(Phase.READ);
  addAfter(ReadHeadersInterceptor.class.getName());
}

public void handleMessage(SoapMessage message) throws Fault
{
  // retrieve the incoming header and saved it explicitly, if it's not saved, it will be lost when a fault is returned
  List list = (List) message.get("org.apache.cxf.headers.Header.list");
  if (list != null && !list.isEmpty() && list.get(0) instanceof SoapHeader)
  {
    SoapHeader header = (SoapHeader) list.get(0);
    message.put(SoapHeader.class, header);
  }
}

The above code capture the incoming SoapHeader and explicitly put into the message. So once a fault is occured, the FaultHeaderInterceptor can still find the SoapHeader message from the incoming request.

To retrieve the saved SoapHeader in FaultHeaderInterceptor,

public void handleMessage(SoapMessage message) throws Fault
{
  // code that create PlatFormException

  // retrieve the soapHeader saved in the inMessage in SoapHeaderInterceptor
  SoapHeader header = message.getExchange().getInMessage().get(SoapHeader.class);

  // code that manipulate the header with headerTO above, headerTO can now be replaced to this new header
}

In the configuration, this interceptor will be put under inInterceptors bucket,

<bean id="soapHeaderInterceptor"
class="com.telstra.sdfcore.csc.uup.interceptor.SoapHeaderInterceptor" />

<cxf:bus>
  <cxf:inInterceptors>
    <ref bean="soapHeaderInterceptor" />
  </cxf:inInterceptors>
  <cxf:outFaultInterceptors>
    <ref bean="faultHeaderInterceptor" />
  </cxf:outFaultInterceptors>

</cxf:bus>

Now, when a request comes in, it will save the header into the message by using SoapHeaderInterceptor. When a fault is occured, it will return a platform specific exception, as well as the platform specific header which comes from the request.

Friday, 15 August 2008

Create Apache CXF Interceptor (1)

Recently I am working on Apache CXF web service framework. There was an requirement from my project that any exception or fault has to be returned with a desired platform exception. Also, any returned soap fault message should include a platform specific soap header. So it means no matter whether it is a runtime exception thrown from the business logic, or it's just a schema validation exception, a specific platform exception with soap header has to be returned so that the client side could be able to interpret in it's specific way.

To fulfill this requirement, one of the option is to write an interceptor in CXF. I have been looking for a sample but since CXF is fairly new web service framework (up to this moment, the version 2.1 is still in Apache Incubator), I could not find any good one. The only document I can look for is the interceptor introduction page in CXF website. But it's actually a good document. So I would prefer you to have a look at the document to get the concept before you keep going on below.

In here (supposed you have read the interceptor concept), I will try to provide a solution that fulfill the requirements above.

First, I will create a FaultHeaderInterceptor which extends org.apache.cxf.binding.soap.interceptor.AbstractSoapInterceptor.

Before you write an interceptor, you should decide which phase that the interceptor should intercept the message. In the above case, since I have to manipulate the returned message, I put my interceptor into PREPARE_SEND phase. Also I put my interceptor to run after MessageSenderInterceptor to make sure CXF have done everything before I manipulate the message.

In the constructor,

public FaultHeaderInterceptor()
{
  super(Phase.PREPARE_SEND);
  addAfter(MessageSenderInterceptor.class.getName());
}

Since this interceptor is only responsible to change the soap message when a fault is returned, in CXF configuration, I put this interceptor in outFaultInterceptor tag, which means this interceptor only run when a fault happened.

In the configuration,


<bean id="faultHeaderInterceptor class="package.name.FaultHeaderInterceptor"/>

<cxf:bus>
  <cxf:outfaultinterceptors>
    <ref bean="faultHeaderInterceptor"/>
  </cxf:outfaultinterceptors>
</cxf:bus>


In the FaultHeaderInterceptor, I need to implement the method handleMessage(SoapMessage message), here is the logic,


public void handleMessage(SoapMessage message) throws Fault
{
  Exception exception = message.getContent(Exception.class);

  if (exception != null)
  {
    PlatformException platformException =
     new PlatformException(exception.getMessage());
    // overwrite Exception to PlatFormException
    Fault fault = new Fault(platformException);
    message.setContent(Exception.class, fault);
  }
}


**Note that the PlatformException is an annotated class with @WebFault, which means it represents the soapFault message.

Right now, whenever it is checked exception, or runtime exception that thrown by the CXF, it will return the PlatformException. That's easy! However, it only fulfill the first part of the requirement. To fulfill the second part, which I have to include the header.

To be continue...

Sunday, 3 August 2008

Using JPA with PostgreSql or MySql?

I found a pretty strange behaviour when I was trying to use JPA with Hibernate to connect to PostgreSql. Here is the scenario:

I create a JPA NamedQuery as follow:
SELECT J FROM Job J WHERE
( :id IS NULL OR J.id = :id )
It is fairly simple query. It takes "id" parameter if it passed in a non NULL value. The good thing on this query is you just need to create a single query and it can serve on 2 purposes. If a parameter "id" is provided, the result will be retricted to a single Job object, if it got a NULL value, the query will return a list of Job objects. Isn't it great?

So when I put this query to use on MySql enviornment, it works as I described. However, when I put this query to use on PostgreSql, it returns "org.hibernate.exception.SQLGrammarException: could not execute query". The PostgreSql log shows "could not determine data type of parameter". If the IS NULL checking is taken out, it runs perfectly. So I suspect there are problems in either JDBC driver or Postgresql, although I tends to believe it is a JDBC driver problem. After a day of research (googling and forum), there is still no exact answer. But there are some hints that when a NULL value is passing to PostgreSql, as Hibernate will serialize the Null to bytea type, which is not the same type as PostgreSql, so it cannot recognize the data type and cause the issue.

So a workaround solution suggested to use Hibernate query instead of JPA query. So when you use Hibernate query, you can specify the data type (e.g. org.hibernate.Hibernate.STRING) and let Hibernate to know what data type it is when a NULL is passed in.

Personally I love PostgreSql, however, so far, I face lots of trouble when I use PostgreSql as the database. This problem I mentioned above is only one of them. When I change to use MySql, it always work perfectly. Does it imply that there is something that is not mature when use PostgreSql? Further research is required.