Another entry to my regularly updated wtf?!-list: First of all, it’s kind of a big deal to get things working once you are trying to debug output communicated through webservices. No matter if you use XFire, axis or anything else, you always need to access the handler chain to get a hold of the actual message in the first place.
So, if you want to have pretty XML, you need to add a LoggingHandler to the handlerchain at first, and after that, you need to create a dummy OutputStream to capture the message, get a ByteArrayInputStream to work with and isolate the String, which we are going to write back to the console or whichever other OutputStream you like.
This is expensive shit. And the worst part: I am not coming up with any smart solution. I just have to advise everybody to use this for debugging only, and don’t even think about building this logging mechanism into a production environment with hundreds of requests per second.
So, either you just download the LoggingHandler.java or you include these snippets and make things work for you:
private void setLoggingHandler(BindingProvider bp) { javax.xml.ws.Binding binding = bp.getBinding(); List handlerList = binding.getHandlerChain(); if (handlerList == null) handlerList = new ArrayList(); LoggingHandler loggingHandler = new LoggingHandler(); handlerList.add(loggingHandler); binding.setHandlerChain(handlerList); }
Include the above somewhere in your code and run
WSBindingProvider bp = (WSBindingProvider)yourJaxWsClient; setAuthenticationCredentials(bp, auth); setLoggingHandler(bp);
After doing that, you added your own logging handler to the chain. In jax-ws, this handler needs to implement the SOAPHandler interface. After you’ve done that, you need to access the message and (if you want pretty printing) do some ByteArray stream hocuspocus. You need to do this:
SOAPMessage lMessage = pContext.getMessage(); ByteArrayOutputStream lByteArrayOS = new ByteArrayOutputStream(); try { lMessage.writeTo(lByteArrayOS); ByteArrayInputStream bis = new ByteArrayInputStream(lByteArrayOS.toByteArray()); prettyPrint(bis); } } catch (Exception e) {}
We wrote the message to our dummy OutputStream and turned it into an InputStream right away. This type of String operation is really expensive. But we needed to do it this way because we only have access to writeTo(OutputStream os) on the SOAPMessage object. That’s why it should be for debugging only. I would recommend a debugging flag in your application that only adds the logging handler to your clients handler chain if the application is in debug mode.
The prettyPrint method looks like this (I used dom4j for formatting):
private void prettyPrint(ByteArrayInputStream pByteArrayIS) {
try {
BufferedReader lBufferedReader = new BufferedReader(new InputStreamReader(pByteArrayIS));
StringBuffer lStringBuffer = new StringBuffer();
while (lBufferedReader.ready()) {
lStringBuffer.append(lBufferedReader.readLine());
}
lBufferedReader.close();
String lXml = lStringBuffer.toString();
Document lDocument = DocumentHelper.parseText(lXml);
OutputFormat lPrettyFormat = OutputFormat.createPrettyPrint();
//you can of course use any other OutputStream now
XMLWriter xw = new XMLWriter(System.out, lPrettyFormat);
xw.write(lDocument);
} catch (IOException ex) {
ex.printStackTrace();
} catch (DocumentException ex) {
ex.printStackTrace();
}
}
And that’s it. You can easily just use the LoggingHandler I wrote and add it to the handler chain, but most people want to understand what they’re doing first.
This one is ready to go, so have fun. I’ve been busting my balls trying to find away around this, but this is an easy way to add pretty-print-xml-logging to you jax-ws client.