Search This Blog

Thursday 15 May 2014

The Phases in the Inbound chain - When does marshaling occur ?

In our last post we saw a simple Interceptor that read the request and modified it before sending it to our endpoint. The interceptor was executed in the PRE_INVOKE phase
public BodyInterceptor() {
   super(Phase.PRE_INVOKE);
   System.out.println("Creating Instance");
}
I decided to run the same interceptor in various phases. The request XML is as below:
<?xml version="1.0" encoding="UTF-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
  <soap:Header>
    <RandomHeader xmlns="http://ws.com/Service/xsd/random-schema">
      <hostName>Trial call</hostName>
    </RandomHeader>
  </soap:Header>
  <soap:Body>
    <GetRandomRequest xmlns="http://ws.com/Service/xsd/random-schema">
      <name>coolio</name>
    </GetRandomRequest>
  </soap:Body>
</soap:Envelope>
The code in the interceptor's handleMessage is very simple. It only logs the content:
public void handleMessage(Message message) throws Fault {
    System.out.println("Formats message is available in : " + message.getContentFormats());
    List contents = message.getContent(List.class);
    int i = 0;
    for (Object object : contents) {
      System.out.println("Object no " + i + " found is " + object);
      i++;
    }
  }
First is the RECEIVE phase. Its function is Transport level processing. On running the code:
Formats message is available in : 
[class org.apache.cxf.io.DelegatingInputStream, class java.io.InputStream]
java.lang.NullPointerException
    at com.ws.service.samplews_ns.interceptor.BodyInterceptor.handleMessage(BodyInterceptor.java:23)
The code fails to process the message as a list of objects. The null value for the list thus leads to a null pointer.
The code fails to process the message as a list of objects. The null value for the list thus leads to a null pointer.
Second is the PRE_STREAM phase. This involves Stream level processing/transformations. This gives the same output as above. The code also failed for USER_STREAM and POST_STREAM phases.
Third is the READ phase. This is where header reading typically occurs. The same exception occurs:
Formats message is available in : 
[class org.apache.cxf.io.DelegatingInputStream, class java.io.InputStream, 
interface javax.xml.stream.XMLStreamReader]
java.lang.NullPointerException
    at com.ws.service.samplews_ns.interceptor.BodyInterceptor.handleMessage(BodyInterceptor.java:23)
A new format has been added though.
Fourth is the PRE_PROTOCOL phase. The logs are as below:
Formats message is available in : 
[class org.apache.cxf.io.DelegatingInputStream, interface org.w3c.dom.Node, 
interface javax.xml.stream.XMLStreamReader, class java.io.InputStream]
java.lang.NullPointerException
    at com.ws.service.samplews_ns.interceptor.BodyInterceptor.handleMessage(BodyInterceptor.java:23)
While Node has been added as a format, the code still failed as I was trying to read it as a list. The output is same for USER_PROTOCOL and POST_PROTOCOL phase. In these phases, protocol processing functions, such as JAX-WS SOAP handlers are executed.
The fifth phase is UNMARSHAL phase. This is where the request is unmarshaled (using JAXB in my case). The code however failed again with the same error. I was kind of hoping that things would work here as the marshaling has been complete. On checking the interceptor chain:
unmarshal [BodyInterceptor, DocLiteralInInterceptor, SoapHeaderInterceptor]
The problem here is that my interceptor executes before the other marshaling interceptors for the phase. Accordingly I changed my code:
public BodyInterceptor() {
    super(Phase.UNMARSHAL);
    this.addAfter(DocLiteralInInterceptor.class.getName());
    this.addAfter(SoapHeaderInterceptor.class.getName());
    System.out.println("Creating Instance");
  }
The Interceptor is now required to run after the DocLiteralInInterceptor and SoapHeaderInterceptor. These interceptors are responsible for the marshalling. So when my interceptor runs, the marshalling should have been completed.
 If I now look at the interceptor chain logs:
unmarshal [DocLiteralInInterceptor, SoapHeaderInterceptor, BodyInterceptor]
The code now runs fine as the marshaling has been completed and the objects are available as a list.
 Formats message is available in : 
[interface org.w3c.dom.Node, interface java.util.List, class java.io.InputStream, 
class org.apache.cxf.io.DelegatingInputStream, interface javax.xml.stream.XMLStreamReader]
Object no 0 found is com.ws.service.xsd.random_schema.GetRandomRequest@15a3c12
The next phases are PRE_LOGICAL, USER_LOGICAL and POST_LOGICAL Here we have Processing of the umarshaled request. The code works fine here.
After this we havePRE_INVOKE (Pre invocation actions),INVOKE(Invocation of the service) and POST_INVOKE(Invocation of the outgoing chain if there is one). I ran the interceptor for all these phases. For all these phases the code works fine.
An interesting though is that as the POST_INVOKE phase run after the end point phase would I be able to access the Response object in my message content ?
 
Formats message is available in : 
[interface java.util.List, class org.apache.cxf.io.DelegatingInputStream, 
interface javax.xml.stream.XMLStreamReader, interface org.w3c.dom.Node]
Object no 0 found is com.ws.service.xsd.random_schema.GetRandomRequest@1dc6a3b
As seen above this is not the case. For the inbound chain only the request related data is visible.

NOTE: The explanation for the functions of each phase ( in in italics) was copied word for word from the CXF documentation

1 comment:

  1. Thank you for this idea how to check phases :) Was useful...
    DS

    ReplyDelete