1

I have a situation where I have to write a client in Java against a very picky external web service (over https) and I can talk to the web service through the Web Services Explorer in Eclipse Java EE.

Unfortunately I cannot get the client to ask properly so I'd really like to see the SOAP messages going back and forth. Being new to web services this is a bit of a jungle. I am very familiar with Eclipse, and have spent some time with Netbeans and IntelliJ.

I'd really, really prefer using the Metro stack as it allows this to run on a stock Java 6, and deployment size matters. Is there a simple way to make Metro log what it does, or make it talk through the TCP/IP monitors in Eclipse and Netbeans? The Metro documentation seems to be primarily targeted at the web service author and not the client, so I might easily have missed it.

Any suggestions for a setup saying "Here is the WSDL - generate me a client where I can see the traffic"?

Arjan Tijms
  • 37,782
  • 12
  • 108
  • 140
Thorbjørn Ravn Andersen
  • 73,784
  • 33
  • 194
  • 347

3 Answers3

2

Just put a proxy or a tcp monitor "in the middle" and you will see the message.

I've been using tcpmon for a similar task.

Bozho
  • 588,226
  • 146
  • 1,060
  • 1,140
  • oops, missed the "over https" part. It won't work on https. but for development purposes can't you switch to http? Well, since you are one of the sides of the communication, you can decrypt the https message, but that might be too much headache. – Bozho Feb 08 '10 at 13:37
  • No. I do not have control over the remote web service :( – Thorbjørn Ravn Andersen Feb 09 '10 at 10:57
2

Here is another way to observe SOAP messages:

Supposing generated client classes looks like:

// generated service class
public class MyWebServiceClient extends javax.xml.ws.Service {
    // ...
    private final QName portName = "...";
    // ...
    public RetrieveMyObjects getRetrieveMyObjects() {
        return super.getPort(portName, RetrieveMyObject.class);
    }
    // ...
}

// generated port interface
// annotations here
public interface RetrieveMyObjects {

    // annotations here
    List<MyObject> getAll();

}

Now, upon executing following code:

MyWebServiceClient wsClient = new MyWebServiceClient("wsdl/location/url/here.wsdl");
RetrieveMyObjectsPort retrieveMyObjectsPort = wsClient.getRetrieveMyObjects();

wsClient should return instance which is both instance of RetrieveMyObjects & javax.xml.ws.BindingProvider interfaces. It is not stated anywhere on the surface of JAX-WS, but it seems that a lot of code is based on that fact. One can re-assure him\herself by executing something like:

if(!(retrieveMyObjectsPort instanceof javax.xml.ws.BindingProvider)) {
    throw new RuntimeException("retrieveMyObjectsPort is not instance of " + BindingProvider.class + ". Redirect following as well as authentication is not possible");
}

Now, when we are sure that retrieveMyObjectsPort is instance of javax.xml.ws.BindingProvider we can enable SOAPMessage logging by invoking following method on each desired web service port interface:

/**
 * Enables logging of send and received SOAP messages on the specified {@link BindingProvider}s
 */
private static void enableSoapMessageLogging(final Logger logger, final BindingProvider... bindingProviders) {
    for(final BindingProvider bindingProvider : bindingProviders) {
        final List<Handler> handlerChain = bindingProvider.getBinding().getHandlerChain();
        handlerChain.add(new SOAPHandler<SOAPMessageContext>() {
            @Override
            public boolean handleMessage(final SOAPMessageContext context) {
                try {
                    final ByteArrayOutputStream baos = new ByteArrayOutputStream();
                    context.getMessage().writeTo(baos);
                    logger.trace(new String(baos.toByteArray()));
                } catch(final Exception e) {
                    logger.error("", e);
                }
                return true;
            }

            @Override
            public boolean handleFault(final SOAPMessageContext context) {
                return true;
            }

            @Override
            public void close(final MessageContext context) {
            }

            @Override
            public Set<QName> getHeaders() {
                return null;
            }
        });
        bindingProvider.getBinding().setHandlerChain(handlerChain);
    }
}

// and somewhere at the beginning of application ...
enableSoapMessageLogging(logger, (BindingProvider) retrieveMyObjectsPort);

Hope this helps

Yuriy Nakonechnyy
  • 3,742
  • 4
  • 29
  • 41
1

It was helpful to turn on logging with

-Dcom.sun.xml.ws.assembler.client=true

in the Eclipse launch configuration.

Thorbjørn Ravn Andersen
  • 73,784
  • 33
  • 194
  • 347