Currently, I have two handlers, one for logging and one for signing the SOAP message (which inherently tampers with the SOAP message). Without the handler chain, MTOM works as expected, inserting a reference to the binary content, rather than inlining the base64 binary content.

As soon as I introduce a handler, the MTOM content is now included inline.

Is it possible to use handlers to sign a SOAP message or is there a more appropriate means of doing this?

Update 1 Unable to post the full source. Essentially though, custom SOAPHandler implementation. It performs some basic XMLDsig type operations on a timestamp (in header), custom header and SOAP body. The resultant digest values are then injected into a signature element in the header.

With respect to the logger, it is again a simple SOAPHandler. If either it or the signing handler are used exclusively, the result is the same, an MTOM message with the byte content inlined. The only progress I made was using a MessageHandler for logging. This allowed me to output the SOAP envelope (albeit with the byte content inlined) and still maintain the MTOM separation. So not really a solution but an indication that any modification of the SOAP message needs to occur at a lower level. This is leading me down the path of tubes.

Update 2

The following is an example of the MessageHandler approach. You can see that the raw HTTP dump will contain the multiple part message whereas the actually output inlines the base64. The only difference between this impementation and a SOAPHandler implementation is that the actual HTTP request changes to be a single part inlined MTOM message.

@Override
public boolean handleMessage(MessageHandlerContext context) {

  HttpTransportPipe.dump = true;

  Boolean isOutgoing = (Boolean) context.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY);

  if (isOutgoing) {
    System.out.println("\nOutbound message:");
    XMLStreamWriter writer = XMLStreamWriterFactory.create(System.out);
    try {
      context.getMessage().writeTo(writer);
    } catch (XMLStreamException e) {
      throw new IllegalStateException("Unable to write");
    }
  } else {
    System.out.println("\nInbound message:");
  }
  return true;
}
有帮助吗?

解决方案 2

Looks like I'm limited by the framework and the way in which the handlers work. I think at this stage, my only option is to go to a lower level. I did take a look at using tubes but the same behaviour exhibited itself so it looks as though any attempt to work with the XML of the request fails. As such, I'm going to have to abandon handlers for the time being and investigate at a lower level whether I can make use of codecs to do what I'm after. An MTOM implementation sounds like it may do what I'm after at the byte level:

http://jax-ws.java.net/nonav/jax-ws-20-fcs/arch/com/sun/xml/ws/encoding/MtomCodec.html

I imagined this would be a lot less complex to get working but will update with my progress on the codec front.

@David: Thanks for your help on the handler front but looks as though there is no solution at that level.

Update 1

Came up with an alternate solution that works for my purposes.

  1. I sign the necessary parts of the SOAP message using my SOAPHandler.
  2. Wrote a new SOAPHandler that then takes resultant message and manually extracts the incorrectly inlined binary content.
  3. I then create an AttachmentPart and inject the content from Step 2 into that. It takes Base64 encoded text too which is handy. That AttachmentPart then has a reference UUID assigned to it for Content-Id.
  4. I then create a new element in place of the Base64 content in the SOAP body that reference the UUID, along the lines of the following:

    <xop:Include xmlns:xop="http://www.w3.org/2004/08/xop/include" href="cid:UUID!!!"></xop:Include> 
    

Will probably write a blog post on this as it's been a bit of an epic journey to this point. It was not the best solution but it was certainly easier than going down the tubes/codec path.

其他提示

I tried to replicate your problem by putting together a simple service that accepts an image transferred by MTOM. I found that if I put the MTOM-enabling code before setting the handler, it encodes the message properly. If I set the handler first, it does not. Here is where I set up the properly functioning client code:

Service service = Service.create(url, qname);

Greeting greeting = service.getPort(Greeting.class);

BindingProvider bp = (BindingProvider) greeting;
SOAPBinding binding = (SOAPBinding) bp.getBinding();
binding.setMTOMEnabled(true);

service.setHandlerResolver(new HandlerResolver() {
    @SuppressWarnings("rawtypes")
    public List<Handler> getHandlerChain(PortInfo portInfo) {
        List<Handler> handlerList = new ArrayList<Handler>();
        handlerList.add(new RGBSOAPHandler());
        return handlerList;
    }
});

Where RGBSOAPHandler is just some example code I took from another SO answer.

EDIT: Also, if I try setting the handler on the binding and not the service then I get the same problem that you do. So if it looks like this:

Service service = Service.create(url, qname);

Greeting greeting = service.getPort(Greeting.class);

BindingProvider bp = (BindingProvider) greeting;
SOAPBinding binding = (SOAPBinding) bp.getBinding();
binding.setMTOMEnabled(true);

List<Handler> handlerList = new ArrayList<Handler>();
handlerList.add(new RGBSOAPHandler());
binding.setHandlerChain(handlerList);

Then my file is encoded in-line. I don't know why this is, but I suppose the answer is "don't do that". Set your handlers on the Service object.

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top