Add HTTP Headers to JAX-WS service response
Asked Answered
B

1

11

I'm developing a Java Web Service. At this moment I can get Http header requests. But I want to add more header requests.

I'm currently doing this in a servlet filter.

@WebFilter(urlPatterns = {"/*"})
public class AddHeader implements Filter {

    @Resource
    private WebServiceContext context;

    public AddHeader() {
    }

    @Override
    public void init(FilterConfig fConfig) throws ServletException {
    }

    @Override
    public void destroy() {
    }

    @Override
    public void doFilter(
            ServletRequest request, ServletResponse response,
            FilterChain chain) throws IOException, ServletException {
        if (request.getContentLength() != -1 && context != null) {
            MessageContext mc = context.getMessageContext();
            ((HttpServletResponse) response).addHeader(
                    "Operation", "something"
            );
        }

        chain.doFilter(request, response);
    }
}

The problem with this strategy is that the added header is static.

With SoapHandler class I can obtain a SOAP message - dynamic:

public class SoapClass implements SOAPHandler<SOAPMessageContext> {


    @Override
    public boolean handleMessage(SOAPMessageContext messageContext) {
        log(messageContext);
        return true;
    }

    @Override
    public Set<QName> getHeaders() {
        Set<QName> qNames = Collections.EMPTY_SET;
        return qNames;
    }

    @Override
    public boolean handleFault(SOAPMessageContext messageContext) {
        log(messageContext);
        return true;
    }

    @Override
    public void close(MessageContext context) {
    }


    public static String getMsgAsString(SOAPMessage message) {
        String msg = null;
        try {
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            message.writeTo(baos);
            msg = baos.toString();
        } catch (SOAPException | IOException soape) {
        }
        return msg;
    }


    private String soapToString(SOAPMessage message, boolean indent) {
        final StringWriter sw = new StringWriter();

        try {
            TransformerFactory.newInstance().newTransformer().transform(
                    new DOMSource(message.getSOAPPart()),
                    new StreamResult(sw));
        } catch (TransformerException e) {
            throw new RuntimeException(e);
        }

        return (indent ? sw.toString() : sw.toString().replaceAll("[\\r\\n]", ""));
    }

So, what I really wanted was to join dynamic soap message with filter. How can I achieve this?

Baxy answered 8/5, 2015 at 17:46 Comment(3)
What do you mean by "the header is static"? What's a static header vs a dynamic header?Leavelle
"Operation", "something" is a value static that I defined. I want to be able different Soap Content for each requestBaxy
I still don't get it man: what's a "value static" vs a "soap content"? Are you looking to set an HTTP header based on a condition? Or are you looking to set a SOAP header? I want to be able different Soap Content for each request really doesn't translate very well. Can you post an illustration or something?Leavelle
L
11

While I'm still not entirely clear on what you really want, I will describe how to add HTTP headers in a SOAP web service response. The cleanest place to do this is in a JAX-WS handler, not unlike what you already have in the form of SoapClass.

To do this in your SOAPHandler, you must first obtain access to the list of headers in the underlying HttpServletResponse. This list is provided by the SOAPMessageContext:

    @Override
    public boolean handleMessage(SOAPMessageContext context) {
      //This property checks whether the handler is being invoked for a service response
      boolean response= ((Boolean) context.get(SOAPMessageContext.MESSAGE_OUTBOUND_PROPERTY)).booleanValue(); 

      if (response) {
          //this is a JAX-WS-provided map of HTTP headers
          Map<String, List<String>> headers = (Map<String, List<String>>) context.get(MessageContext.HTTP_RESPONSE_HEADERS);
          if (null == headers) {
              //create a new map of HTTP headers if there isn't already one
              headers = new HashMap<String, List<String>>();
          }
          //add your desired header
          headers.put("Operation",Collections.singletonList("something");
        }
      return true;
    }

An alternative approach is to access the HttpServletResponse that's underlying the web service response:

     @Override
    public boolean handleMessage(SOAPMessageContext context) {
      //This property checks whether the handler is being invoked for a service response
      boolean response= ((Boolean) context.get(SOAPMessageContext.MESSAGE_OUTBOUND_PROPERTY)).booleanValue(); 

      if (response) {
          //this is underlying http response object
          HttpServletResponse response = (HttpServletResponse) context.get(MessageContext.SERVLET_RESPONSE);

          //add your desired header
          response.addHeader("Operation", "something");
          }
      return true;
    }
Leavelle answered 13/5, 2015 at 5:38 Comment(6)
I tried that approach before. I receive an exception - request.headers is a read-only property.Baxy
My mistake @Goldbones; it should be HTTP_RESPONSE_HEADERS not HTTP_REQUEST_HEADERS. I've posted an alternative approach also. The approach you've already tried should always be part of your question: saves everyone time and makes for a better question.Leavelle
Perfect! That precisely what I wanted. I did that in another post, but no one could give an appropriate answer. In code that you provide, instead of static content("something" will be always the same answer in different requests) I have dynamic content (by Soap Message context), which is great because now I have different messages for different requests. Thanks!Baxy
@Leavelle I know this is an old post but thanks, you're latter variation got me over a hump, although response boolean always came back null. The HttpServ.. response was never null however, so I didn't need the boolean check. Thanks!Midsection
On //create a new map of HTTP headers if there isn't already one, should you not put the map on the context?Lessard
@Lessard yup you're rightLeavelle

© 2022 - 2024 — McMap. All rights reserved.