6

I need to log the full http request and response in a JAX-WS WebService call. For the request I need the request headers and the body and for the response, response headers and body.

After some researching, I've found that I can get this information with the property:

-Dcom.sun.xml.ws.transport.http.client.HttpTransportPipe.dump=true

and show the information that I need but it dumps it to the console and I need to store it in the database with an internal request id.

I've tried to implement a handler:

public class LoggingHandler implements SOAPHandler<SOAPMessageContext> {

    @Override
    public boolean handleMessage(SOAPMessageContext context) {
        Boolean outbound = (Boolean) context.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY);
        if (outbound) {
            System.out.println("SOAP outbound!!!!!");
            Map<String, List<String>> responseHeaders = (Map<String, List<String>>) context
                    .get(SOAPMessageContext.HTTP_RESPONSE_HEADERS);
            try {
                String headers = getHeaders(responseHeaders);
                System.out.println(headers);
                String body = getBody(context.getMessage());
                System.out.println(body);
            } catch (Exception ex) {
                // TODO: What do I have to do in this case?
            }
        } else {
            System.out.println("SOAP inbound!!!!!");
            Map<String, List<String>> requestHeaders = (Map<String, List<String>>) context
                    .get(SOAPMessageContext.HTTP_REQUEST_HEADERS);
            try {
                String headers = getHeaders(requestHeaders);
                System.out.println(headers);
                String body = getBody(context.getMessage());
                System.out.println(body);
            } catch (Exception ex) {
                // TODO: What do I have to do in this case?
            }
        }
        return true;
    }

    private String getBody(SOAPMessage message) throws SOAPException, IOException {
        OutputStream stream = new ByteArrayOutputStream();
        message.writeTo(stream);
        return stream.toString();
    }

    public String getFullHttpRequest(HttpServletRequest request) throws IOException {
        InputStream in = request.getInputStream();
        String encoding = request.getCharacterEncoding();
        encoding = encoding == null ? "UTF-8" : encoding;
        String body = IOUtils.toString(in, encoding);
        return body;
    }

    private String getHeaders(Map<String, List<String>> headers) throws IOException {
        StringBuffer result = new StringBuffer();
        if (headers != null) {
            for (Entry<String, List<String>> header : headers.entrySet()) {
                if (header.getValue().isEmpty()) {
                    // I don't think this is legal, but let's just dump it,
                    // as the point of the dump is to uncover problems.
                    result.append(header.getValue());
                } else {
                    for (String value : header.getValue()) {
                        result.append(header.getKey() + ": " + value);
                    }
                }
                result.append("\n");
            }
        }
        return result.toString();
    }

}

but in this case, I can get the http request headers and body but in the response, I only get the body, http response headers are always empty.

Any idea on how to archieve this? The objective is to be able to store the full http request and response in a database.

Thanks!!

Jonathan
  • 20,053
  • 6
  • 63
  • 70
drublik
  • 456
  • 2
  • 5
  • 19

1 Answers1

3

You could also try

    -Dcom.sun.xml.ws.transport.http.HttpAdapter.dump=true

I'm assuming you're providing your web service from within a Java EE application server of some sort (and not from a standalone client). You cannot have access to Java EE infrastructure like HttpServletRequest and HttpServletResponse outside of the context of a web/Java EE container.

You could try to get your hands on the actual servlet response object (within a web context) with

    HttpServletResponse response = (HttpServletResponse) messageContext.get(SOAPMessageContext.SERVLET_RESPONSE); //messageContext is the SOAPMessageContext
    List<String> responseHeaderNames = (List<String>)response.getHeaderNames();
        for(String headerName : responseHeaderNames){
             //Do whatever you want with it.
              }

I seriously doubt that you'll be able to get your hands on the full response headers within a handler though. Your question really intrigued me and I've spent quite some time researching that part. In all the code samples I've seen, Not even the example on the metro site attempt to implement this functionality and I think the reason is simple. As at the point where a handler is invoked, the container may not have enough definitive information to stamp an http header on the outbound message. You might be able to add stuff but that's doubtful as well.

Arjan Tijms
  • 37,782
  • 12
  • 108
  • 140
kolossus
  • 20,559
  • 3
  • 52
  • 104
  • Thanks for your reply. I'm providing the webservice using Spring 3 in a Tomcat application server. Your first proposal, will just dump it to the console, right? I need to be able to store it in a database and regarding the second option, I'll give it a try. Thanks! – drublik Nov 09 '12 at 08:35
  • @drublik sure, let us know how it works out. I'm curious for one – kolossus Nov 14 '12 at 05:06
  • thanks for your reply but HttpServletResponse doesn't have a "getHeaderNames()" method. In fact, it seems that it doesn't have any method to get headers, only to set. This function is in HttpServletRequest only. – drublik Nov 28 '12 at 09:30
  • @drublik, what servlet version are you using? I can guarantee that it's available in 3.0 – kolossus Nov 28 '12 at 11:23
  • ok! I was using servlet-api 2.5 as the target server is Tomcat 6.0.24 (I think that servlet-api 3.0 is only available in Tomcat 7 or newer) – drublik Nov 28 '12 at 11:29
  • Any change on how to achieve this with with servlet-api 2.5? – drublik Dec 12 '12 at 09:16
  • @drublik, I'm afraid I can't help with that. Doesn't seem to be provided for in 2.5. You could attempt to read the response output stream from the beginning until the first blank space (which demarcates the header from the body of the response), pretty verbose but it should work. – kolossus Dec 12 '12 at 17:37