Saturday, 12 July 2008

How to debug async responses in Axis2

In a dual-channel web services scenario (using WS-Addressing), its often hard to debug the responses, because the client opens a random URL and tells the server to send messages there. So even if you are sending the requests via a TCP monitor, such as TCPMON, the responses end up going direct.

Charitha has posted a blog entry on how to debug the responses. Here is another approach.

The problem is quite hard to describe without a diagram, and since its still Saturday morning I'm not up to graphics. Here is my attempt to describe without a diagram.

In a normal HTTP flow, its fairly easy to capture the messages. There are two options:
  1. Set up a (forward) HTTP proxy, and configure your client to use that proxy. This means that any request the client sends will go via the HTTP proxy, and the request will contain the real full address of the target HTTP endpoint.
    So instead of the HTTP normal request:
    POST /axis2/services/blah HTTP/1.1

    you get:
    POST http://server.com/axis2/services/blah HTTP/1.1

    The result is that the proxy looks at the request and uses the full URL to pass the message on.
  2. Set up a Reverse HTTP Proxy, and redirect the request to this address. In this model the reverse proxy listens on one port and sends everything to another host/port. So for example, anything that comes into port 8081 is sent to localhost:8080.
The TCPMON utility supports both models, but for some reason the second (reverse proxy) model is more popular. This is the approach that Charitha has documented. I prefer the forward proxy approach, and I have two reasons.

Firstly, the reverse proxy doesn't work with .NET. In the reverse proxy model, you are fooling the client into thinking the service is really hosted at port 8081. With WS-Addressing the address is not just used at the HTTP transport level, but also encoded into the WS-A headers. Now Axis2 is a little bit looser about checking WS-A headers, and ignores the host/port. But .NET validates the complete URL and will reject messages with the wrong host or port.

Secondly, the proxy option I propose can be used with any client, because you simply tell the server to send all asynchronous responses through the proxy.

Ok, enough blather, what do you need to do?

How to debug the return half of an async interaction.
1. Basically you need to setup a proxy to capture the responses.
2. Choose a port you aren’t already using (e.g. 999) and start tcpmon in Proxy mode
on that port
a. You can do this with the command line: tcpmon 999
b. Or through the TCPMON admin screen
3. Now edit the SERVER’s axis2.xml
4. You can read about this here: http://ws.apache.org/axis2/1_4/http-transport.html
5. Edit the Axis2.xml config to add the PROXY parameter:
<!-- ======================================= -->
<!-- Parameters -->
<!-- ======================================= -->
<parameter name="Proxy">
<Configuration>
<proxyhost>localhost</proxyhost>
<proxyport>999</proxyport>
</configuration>
</parameter>

6. Now all the responses (which are initiated by the server) will go through the
proxy

I suggest you try both my approach and Charitha's. I think there are going to be situations where each are more useful. I also want to thank Charitha for prompting me to blog my approach.

4 comments:

  1. Hi Paul,
    Very helpful post! thanks!
    The XML elements of axis2.xml (Step 5)are not shown in the post. You may need to use HTML tags for < and > to show them in the post.
    Thanks
    Charitha

    ReplyDelete
  2. Your approach, Paul, assumes that the server is a) Axis2, and b) under your control. In many cases, one or the other isn't true, so I have to say I tend to prefer Charitha's technique - rewriting the wsa:ReplyTo address works regardless of the server.

    ReplyDelete
  3. Glen

    Good point. I think you can say that if the server is in your control, then my approach works, and if the client is in your control Charitha's approach works. So that way you have both options covered.

    However, in either case its worth noting that the "reverse proxy" model will never work with .NET (except with extra configuration), so if you have the client in your control and talking to a .NET server, you want to make sure outgoing requests go through a forward proxy.

    ReplyDelete
  4. Good point backatcha, Paul! :)

    If you own the server but not the client, then you can use your technique to set the outgoing proxy, and if you want the incoming requests you'll need to move your server to a new port and put a TCPMON on the old one. If you own the client, then you can use Charitha's technique to rewrite the ReplyTo, and optionally use an outgoing proxy TCPMON to catch the requests too.

    One last quick note - this stuff can also be accomplished with Synapse / ESB, by sitting the mediator in front of the service and having it rewrite the ReplyTos to go back to itself.

    ReplyDelete