Friday, June 11, 2010

How to change the endpoint defined in the WSDL

Why should one do that? There might be several different reasons, I'll write about the one that moved me. We are developing a new integrated enterprise application for a customer that is located in another city: the core of the system is developed in RPG-LE and uses a cool UI that greatly extends the classic "green screen". The system is deployed on an iSeries and exposes Axis2 Web Services through an IBM Websphere Application Server; these services are accessed by a web application hosted in a protected network that is used by local offices all over Italy.

We periodically update their core system in a direct way, but for security reasons we do not have administrative access to their application server, so whenever we release an update we have to contact them and wait for them to republish the Web Services. As, despite of all my efforts to persuade the decisors, this still happens manually (nemo propheta in patria), every now and then we experience strange behaviours in remote clients.

As I still haven't managed to obtain dedicated services instances and databases for tests (see above) I must revert to plain old manual testing. More or less, as I definitely don't want to jump on the bandwagon of keyboard monkeys that seems so in fashion. Lazy as every good programmer should be (if nothing else I still got something of a good programmer) at least I have partly automated the process with a combination of Selenium, wsmonitor and Poster.

What I still missed was the possibility to easily override the endpoint defined in the WSDL I used when I generated the client in NetBeans for a scenario like this: we develop the core, expose the services, generate a client, use it in the remote application, run it and check that everything is working fine, deploy to the customer, ask them to republish the services, generate a client, use it in the remote application, run it and check that everything is working fine and it is not. And if you're wondering, yes there is some echo in this room.

As a matter of fact, every now and then we got as an answer a SOAP fault with a crystal clear message like

java.lang.NumberFormatException: High-order nibble of the byte at array offset 11 is not valid.  Byte value: 40

WTF??? At this point we normally check that the customer properly deployed the services diffing the WSDLs, then eventually contact them, but that's not always as easy as we'd wish. To get further informations (and to speedup the test process) I would like to use Poster to test that the service is working as expected, but for that I need the content to post. That's where wsmonitor would come useful, but it turns out that I cannot update the client through it:

Please enable REST support in WEB-INF/conf/axis2.xml

Before you ask, they wouldn't allow it. So I had to directly generate a client from their anthracite coal grey box (don't call it black, they'd be resented about it) but have it point to my local wsmonitor instead (I'm afraid either NetBeans still has to catch up a little with this or I have to find out how to sort it out) to see the outgoing and incoming messages.

Now the real magic you've been waiting for (well maybe you haven't, but I sure did): the client code generated by NetBeans looks like this snippet:

MyService service = new MyService();
MyServicePortType port =
service.getMyServiceSOAP11PortHttp();

At this point the port refers to the endpoint defined in the remote WSDL. To override it all you need to do is add this line:

((BindingProvider) port).getRequestContext().put(
BindingProvider.ENDPOINT_ADDRESS_PROPERTY,
"http://localhost:12345/path/to/MyService");

So what? as awkward as it might seem, the fastest solutions (obviously as far as I know, which is not much) turned out to generate the client from the original WSDL, debug the client application, start the wsmonitor, change the endpoint on the fly and apply the code changes class as needed, and... ta-daaah! here are the SOAP messages!

From this point on I can happily close everything else and switch to Poster: until a click on the POST button returns me a valid message I don't even waste a second on my IDE or on the client application.

Why did I choose 12345 for the port? Because

...that's the stupidest combination I've ever heard of in my life! That's the kinda thing an idiot would have on his luggage!

Now, if you're yelling

1, 2, 3, 4, 5? That's amazing! I've got the same combination on my luggage!

console yourself, you're not alone :-)

2 comments:

24BOB42 said...

How about just

System.setProperty("http.proxyHost", "127.0.0.1");
System.setProperty("http.proxyPort", "4040");

For SOAP monitoring, that should suffice.

.MOz said...

You caught me off guard :-)