2

Using JAX-WS 2, I see an issue that others have spoken about as well. The issue is that if a SOAP message is received inside a handler, and that SOAP message is large - whether due to inline SOAP body elements that happen to have lots of content, or due to MTOM attachments - then it is dangerously easy to get an OutOfMemoryError.

The reason is that the call to getMessage() seems to set off a chain of events that involve reading the entire SOAP message on the wire, and creating an object (or objects) representing what was on the wire.

For example:

...
public boolean handleMessage(SOAPMessageContext context)
{
    // for a large message, this will cause an OutOfMemoryError
    System.out.println( context.getMessage().countAttachments() );
...

My question is: is there a known mechanism/workaround for dealing with this? Specifically, it would be nice to access the SOAP part in a SOAP message without forcing the attachments (if MTOM for example) to also be vacuumed up.

Ahmed
  • 590
  • 8
  • 19
  • Please see http://stackoverflow.com/questions/15979580/jaxws-soap-handler-large-mtom-attachments/16016411#16016411 for the solution to this problem. – Kabron Jun 27 '13 at 01:09
  • That is an IBM-specific solution, but I appreciate the comment. I ended up solving this 3/4 of the way. The reason I say 3/4 is that there are four points where handlers are invoked: to/from the client, and to/from the server. I was able to write code that handles the raw data stream in 3 out of the 4 cases. Fortunately the three cases included the two we were mostly interested in: to/from the server. – Ahmed Jun 27 '13 at 05:29

4 Answers4

2

For those who run their app on JBoss 6 & 7 (with Apache CXF)... I was able to troubleshoot the problem by implementing my handler from the LogicalHandler interface instead of the SOAPHandler. In this case your handleMessage() method would get the LogicalMessageContext context (instead of SOAPMessageContext) in the arguments that has no issues with the context.getMessage() call

Vlad V
  • 21
  • 2
1

There's actually a JAX-WS RI (aka Metro) specific solution for this which is very effective.

See https://javaee.github.io/metro/doc/user-guide/ch02.html#efficient-handlers-in-jax-ws-ri. Unfortunately that link is now broken but you can find it on WayBack Machine. I'll give the highlights below:

The Metro folks back in 2007 introduced an additional handler type, MessageHandler<MessageHandlerContext>, which is proprietary to Metro. It is far more efficient than SOAPHandler<SOAPMessageContext> as it doesn't try to do in-memory DOM representation.

Here's the crucial text from the original blog article:

MessageHandler:

Utilizing the extensible Handler framework provided by JAX-WS Specification and the better Message abstraction in RI, we introduced a new handler called MessageHandler to extend your Web Service applications. MessageHandler is similar to SOAPHandler, except that implementations of it gets access to MessageHandlerContext (an extension of MessageContext). Through MessageHandlerContext one can access the Message and process it using the Message API. As I put in the title of the blog, this handler lets you work on Message, which provides efficient ways to access/process the message not just a DOM based message. The programming model of the handlers is same and the Message handlers can be mixed with standard Logical and SOAP handlers. I have added a sample in JAX-WS RI 2.1.3 showing the use of MessageHandler to log messages and here is a snippet from the sample:

public class LoggingHandler implements MessageHandler<MessageHandlerContext> {
    public boolean handleMessage(MessageHandlerContext mhc) {
        Message m = mhc.getMessage().copy();
        XMLStreamWriter writer = XMLStreamWriterFactory.create(System.out);
        try {
            m.writeTo(writer);
        } catch (XMLStreamException e) {
            e.printStackTrace();
            return false;
        }
        return true;
    }

    public boolean handleFault(MessageHandlerContext mhc) {
        ..... 
        return true;
    }

    public void close(MessageContext messageContext) {    }

    public Set getHeaders() {
        return null;
    }
}

(end quote from 2007 blog post)

You can find a full example in the Metro GitHub repo.

peterh
  • 18,404
  • 12
  • 87
  • 115
  • I am hitting `handler should not directly implement the javax.xml.ws.handler.Handler interface.`. Any ideas? – Panadol Chong Mar 28 '18 at 06:47
  • @PanadolChong. Ask a new question on SO and be sure to include your source. Are you actually using Metro ? (if you are using some other JAX-WS implementation then the above solution will not work) – peterh Mar 29 '18 at 12:23
0

What JAX-WS implementation runtime are you using? If there's a way to do this using the runtime built into WebSphere I'm certain there's a way to do this cleanly in other runtimes like Axis2 (proper), Apache CXF, and Metro/RI.

Kabron
  • 151
  • 1
  • 11
  • Using Metro. There wasn't a clean solution that I could come up with, and I found several other questioners on the net asking the same thing. As I said in my comment above however, I ended up solving it with a bit of effort. – Ahmed Sep 07 '13 at 02:05
0

I am using the other way to reduce the memory costing, which is Message Accessor.

Instead of using context.getMessage(), I changed it to this way:

Object accessor = context.get("jaxws.message.accessor");

if (accessor != null) {
                baosInString = accessor.toString();
                }

Base on advice from IBM website. http://www-01.ibm.com/support/docview.wss?uid=swg1PM21151

Panadol Chong
  • 1,793
  • 13
  • 54
  • 119
  • 1
    Not sure, but I think this solution is specific to Webshere's implementation of JAX-WS. If so, you should have noted that in your answer. – peterh Mar 29 '18 at 12:22
  • Hi @peterh, sorry I am still new. May I know the `metro` in your answer same with the IBM one? – Panadol Chong Mar 30 '18 at 02:32
  • 1
    JAX-WS is a *standard*, not an [implementation](https://en.wikipedia.org/wiki/Java_API_for_XML_Web_Services#Implementations). The best-known implementation is probably what is known as the Metro stack (also referred to as the Reference Implementation), largely because it is the one which comes bundled with the JDK itself. The JAX-WS implementation found in IBM WebSphere is a different one. – peterh Mar 30 '18 at 07:49