Search This Blog

Monday, 3 March 2014

handleMessage method of Handler being called twice ?

In our previous post we saw how a handler is invoked with CXF. We also saw that our handler was invoked twice - once as a part of the inbound flow and once as a part of the outbound flow. There is a slight problem here. The same handleMessage method of the same Handler instance is used in both cases - which means the same code executes twice!
This is quite a problem. How to ensure that for a single request response combination, the handleMessage runs only once.
Or can we ensure that separate parts of the same method are execute for both request and response processing.
While option one may not be possible as Handlers are not CXF specific but a part of the wider JAX-WS framework, option two can definitely be done. Consider the modified method from our previous example:
public boolean handleMessage(final LogicalMessageContext context) {

    final Boolean outboundProperty = (Boolean) context.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY);
    if (Boolean.FALSE.equals(outboundProperty)) {
      LOG.info("handleMessage - dealing with inbound flow");
    } else if (Boolean.TRUE.equals(outboundProperty)) {
      LOG.info("handleMessage - dealing with outbound flow");
    }
    return true;
  }
The code now checks for the value of the MESSAGE_OUTBOUND_PROPERTY variable (javax.xml.ws.handler.message.outbound) in the context. For an inbound flow it is false indicating that is is an incoming request. Similarly when the same method is invoked as a part of the outbound flow the value will be true indicating that is to handle the outgoing response.
There are several more such predefined properties associated with the Context. I decided to look at some associated fields here:
public boolean handleMessage(final LogicalMessageContext context) {

    final Boolean outboundProperty = (Boolean) context.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY);

    if (Boolean.FALSE.equals(outboundProperty)) {
      System.out.println("handleMessage - dealing with inbound flow");
      System.out.println("Request Method - " + context.get(MessageContext.HTTP_REQUEST_METHOD));
      System.out.println("Request Path Info - " + context.get(MessageContext.PATH_INFO));
      System.out.println("Request query String - " + context.get(MessageContext.QUERY_STRING));
      final Map<String, List<String>> headers = (Map<String, List<String>>) context
          .get(MessageContext.HTTP_REQUEST_HEADERS);
      for (final String headerName : headers.keySet()) {
        System.out.println("Request Header - " + headerName + ", header value " + headers.get(headerName));
      }

      final Map<String, DataHandler> inMsgAttachments = (Map<String, DataHandler>) context
          .get(MessageContext.INBOUND_MESSAGE_ATTACHMENTS);
      System.out.println("Any incoming attachments ? " + !inMsgAttachments.isEmpty());

    } else if (Boolean.TRUE.equals(outboundProperty)) {
      LOG.info("handleMessage - dealing with outbound flow");
      System.out.println("Response code " + context.get(MessageContext.HTTP_RESPONSE_CODE));

      final Map<String, List<String>> headers = (Map<String, List<String>>) context
          .get(MessageContext.HTTP_RESPONSE_HEADERS);
      if (null == headers) {
        System.out.println("No response Headers");
      } else {
        for (final String headerName : headers.keySet()) {
          System.out.println("Response Header - " + headerName + ", header value " + headers.get(headerName));
        }

      }

      final Map<String, DataHandler> outMsgAttachments = (Map<String, DataHandler>) context
          .get(MessageContext.OUTBOUND_MESSAGE_ATTACHMENTS);

      System.out.println("Any incoming attachments ? " + !outMsgAttachments.isEmpty());
    }
    return true;
  }
I tested the above using a JAXWS client (pure CXF client API) just like in the previous example. The output for the above code is as below:
9900 [http-bio-8080-exec-3] DEBUG org.apache.cxf.jaxws.handler.HandlerChainInvoker  
- invoking handler of type com.ws.service.samplews_ns.handler.CrazyHandler
handleMessage - dealing with inbound flow
Request Method - POST
Request Path Info - /Handler/services/randomService
Request query String - null
Request Header - Accept, header value [*/*]
Request Header - cache-control, header value [no-cache]
Request Header - connection, header value [keep-alive]
Request Header - Content-Length, header value [213]
Request Header - content-type, header value [text/xml; charset=UTF-8]
Request Header - host, header value [localhost:8080]
Request Header - pragma, header value [no-cache]
Request Header - SOAPAction, header value ["/Service/random"]
Request Header - user-agent, header value [Apache CXF 2.7.4]
Any incoming attachments ? false
...
9992 [http-bio-8080-exec-3] INFO  com.ws.service.samplews_ns.handler.CrazyHandler  
- handleMessage - dealing with outbound flow
Response code null
No response Headers
Any incoming attachments ? false
There are also keys that allow us access to the HttpServletRequest, HttpServletResponse, ServletContext. We can also acquire the qualified names of our WSDL service and port from here among others.

No comments:

Post a Comment