Author: scheu Date: Sun Nov 7 14:26:52 2010 New Revision: 1032284 URL: http://svn.apache.org/viewvc?rev=1032284&view=rev Log: AXIS2-4862 Contributor:Rich Scheuerle Summary: Ensure that if a handler changes the attachments or SOAPPart, that the JAX-WS runtime's message is updated.
Modified: axis/axis2/java/core/trunk/modules/jaxws-integration/test/org/apache/axis2/jaxws/sample/AddNumbersHandlerTests.java axis/axis2/java/core/trunk/modules/jaxws-integration/test/org/apache/axis2/jaxws/sample/addnumbershandler/AddNumbersClientProtocolHandler.java axis/axis2/java/core/trunk/modules/jaxws/src/org/apache/axis2/jaxws/handler/HandlerChainProcessor.java axis/axis2/java/core/trunk/modules/jaxws/src/org/apache/axis2/jaxws/handler/HandlerResolverImpl.java axis/axis2/java/core/trunk/modules/jaxws/src/org/apache/axis2/jaxws/handler/SoapMessageContext.java Modified: axis/axis2/java/core/trunk/modules/jaxws-integration/test/org/apache/axis2/jaxws/sample/AddNumbersHandlerTests.java URL: http://svn.apache.org/viewvc/axis/axis2/java/core/trunk/modules/jaxws-integration/test/org/apache/axis2/jaxws/sample/AddNumbersHandlerTests.java?rev=1032284&r1=1032283&r2=1032284&view=diff ============================================================================== --- axis/axis2/java/core/trunk/modules/jaxws-integration/test/org/apache/axis2/jaxws/sample/AddNumbersHandlerTests.java (original) +++ axis/axis2/java/core/trunk/modules/jaxws-integration/test/org/apache/axis2/jaxws/sample/AddNumbersHandlerTests.java Sun Nov 7 14:26:52 2010 @@ -841,6 +841,53 @@ public class AddNumbersHandlerTests exte TestLogger.logger.debug("----------------------------------"); } + public void testAddNumbersClientHandlerWithFalse() throws Exception { + AddNumbersClientLogicalHandler2 clh = new AddNumbersClientLogicalHandler2(); + AddNumbersClientProtocolHandler cph = new AddNumbersClientProtocolHandler(); + cph.setPivot(true); + try{ + TestLogger.logger.debug("----------------------------------"); + TestLogger.logger.debug("test: " + getName()); + + AddNumbersHandlerService service = new AddNumbersHandlerService(); + AddNumbersHandlerPortType proxy = service.getAddNumbersHandlerPort(); + + BindingProvider p = (BindingProvider)proxy; + + p.getRequestContext().put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, + axisEndpoint); + + List<Handler> handlers = p.getBinding().getHandlerChain(); + if (handlers == null) { + handlers = new ArrayList<Handler>(); + } + handlers.add(clh); + handlers.add(cph); + + p.getBinding().setHandlerChain(handlers); + + int total = proxy.addNumbersHandler(99,10); + + // Note that a return of 0 indicates that the new message that was added to + // in the client protocol handler was lost during handler processing. + assertTrue("Expected a pivot and -99 to be returned. But it was "+ total, total == -99); + } catch(Exception e) { + throw e; + } finally { + cph.setPivot(false); + } + + String log = readLogFile(); + String expected_calls = + "AddNumbersClientLogicalHandler2 HANDLE_MESSAGE_OUTBOUND\n" + + "AddNumbersClientProtocolHandler HANDLE_MESSAGE_OUTBOUND\n" + + "AddNumbersClientLogicalHandler2 HANDLE_MESSAGE_INBOUND\n" + + "AddNumbersClientProtocolHandler CLOSE\n" + + "AddNumbersClientLogicalHandler2 CLOSE\n"; + assertEquals(expected_calls, log); + + TestLogger.logger.debug("----------------------------------"); + } /** * test results should be the same as testAddNumbersClientHandler, except that * AddNumbersClientLogicalHandler2 doubles the first param on outbound. Async, of course. Modified: axis/axis2/java/core/trunk/modules/jaxws-integration/test/org/apache/axis2/jaxws/sample/addnumbershandler/AddNumbersClientProtocolHandler.java URL: http://svn.apache.org/viewvc/axis/axis2/java/core/trunk/modules/jaxws-integration/test/org/apache/axis2/jaxws/sample/addnumbershandler/AddNumbersClientProtocolHandler.java?rev=1032284&r1=1032283&r2=1032284&view=diff ============================================================================== --- axis/axis2/java/core/trunk/modules/jaxws-integration/test/org/apache/axis2/jaxws/sample/addnumbershandler/AddNumbersClientProtocolHandler.java (original) +++ axis/axis2/java/core/trunk/modules/jaxws-integration/test/org/apache/axis2/jaxws/sample/addnumbershandler/AddNumbersClientProtocolHandler.java Sun Nov 7 14:26:52 2010 @@ -19,9 +19,17 @@ package org.apache.axis2.jaxws.sample.addnumbershandler; +import javax.xml.soap.SOAPException; +import javax.xml.soap.SOAPMessage; +import javax.xml.soap.SOAPPart; +import javax.xml.transform.Source; +import javax.xml.transform.stream.StreamSource; import javax.xml.ws.handler.MessageContext; import javax.xml.ws.handler.MessageContext.Scope; import javax.xml.ws.handler.soap.SOAPMessageContext; + +import java.io.ByteArrayInputStream; +import java.io.InputStream; import java.util.Set; /* @@ -33,6 +41,16 @@ import java.util.Set; public class AddNumbersClientProtocolHandler implements javax.xml.ws.handler.soap.SOAPHandler<SOAPMessageContext> { HandlerTracker tracker = new HandlerTracker(AddNumbersClientProtocolHandler.class.getSimpleName()); + boolean forcePivot = false; + + private final String PIVOT_MESSAGE = + "<SOAP-ENV:Envelope xmlns:SOAP-ENV=\"http://schemas.xmlsoap.org/soap/envelope/\"><SOAP-ENV:Body>"+ + "<p:addNumbersHandlerResponse xmlns:p=\"http://org/test/addnumbershandler\">" + + "<p:return>-99</p:return>" + + "</p:addNumbersHandlerResponse>" + + "</SOAP-ENV:Body></SOAP-ENV:Envelope>"; + + public void close(MessageContext messagecontext) { tracker.close(); @@ -52,24 +70,43 @@ public class AddNumbersClientProtocolHan public boolean handleMessage(SOAPMessageContext messagecontext) { Boolean outbound = (Boolean) messagecontext.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY); tracker.handleMessage(outbound); - if (outbound) { - + if (outbound && !forcePivot) { String appProp1 = "AddNumbersClientProtocolHandlerOutboundAppScopedProperty"; messagecontext.put(appProp1, "myVal"); messagecontext.setScope(appProp1, Scope.APPLICATION); String appProp2 = "AddNumbersClientProtocolHandlerOutboundHandlerScopedProperty"; messagecontext.put(appProp2, "client apps can't see this"); + return true; } - else { // client inbound response + else if (!forcePivot) { // client inbound response String appProp1 = "AddNumbersClientProtocolHandlerInboundAppScopedProperty"; messagecontext.put(appProp1, "myVal"); messagecontext.setScope(appProp1, Scope.APPLICATION); String appProp2 = "AddNumbersClientProtocolHandlerInboundHandlerScopedProperty"; messagecontext.put(appProp2, "client apps can't see this"); + return true; + } else { + // Change the message and reverse the chain + // I am changing the message at the SOAPPart level to make sure the new message "sticks" + InputStream is = new ByteArrayInputStream(PIVOT_MESSAGE.getBytes()); + Source source = new StreamSource(is); + + SOAPMessage message = messagecontext.getMessage(); + message.removeAllAttachments(); + SOAPPart soapPart = message.getSOAPPart(); + try { + soapPart.setContent(source); + } catch (SOAPException e) { + throw new RuntimeException(e); + } + return false; } - return true; + } + public void setPivot(boolean value) { + forcePivot = value; + } } Modified: axis/axis2/java/core/trunk/modules/jaxws/src/org/apache/axis2/jaxws/handler/HandlerChainProcessor.java URL: http://svn.apache.org/viewvc/axis/axis2/java/core/trunk/modules/jaxws/src/org/apache/axis2/jaxws/handler/HandlerChainProcessor.java?rev=1032284&r1=1032283&r2=1032284&view=diff ============================================================================== --- axis/axis2/java/core/trunk/modules/jaxws/src/org/apache/axis2/jaxws/handler/HandlerChainProcessor.java (original) +++ axis/axis2/java/core/trunk/modules/jaxws/src/org/apache/axis2/jaxws/handler/HandlerChainProcessor.java Sun Nov 7 14:26:52 2010 @@ -837,6 +837,12 @@ public class HandlerChainProcessor { saaj_called = false; soap_headers_adapter_called = false; + // If the handler changed the SOAPPart or Attachments, then we need + // that the Message gets updated + if (currentMC instanceof SoapMessageContext){ + ((SoapMessageContext)currentMC).checkAndUpdate(); + } + if (savedEx != null) { throw savedEx; } @@ -860,6 +866,12 @@ public class HandlerChainProcessor { saaj_called = false; soap_headers_adapter_called = false; + // If the handler changed the SOAPPart or Attachments, then we need + // that the Message gets updated + if (currentMC instanceof SoapMessageContext){ + ((SoapMessageContext)currentMC).checkAndUpdate(); + } + if (savedEx != null) { throw savedEx; } Modified: axis/axis2/java/core/trunk/modules/jaxws/src/org/apache/axis2/jaxws/handler/HandlerResolverImpl.java URL: http://svn.apache.org/viewvc/axis/axis2/java/core/trunk/modules/jaxws/src/org/apache/axis2/jaxws/handler/HandlerResolverImpl.java?rev=1032284&r1=1032283&r2=1032284&view=diff ============================================================================== --- axis/axis2/java/core/trunk/modules/jaxws/src/org/apache/axis2/jaxws/handler/HandlerResolverImpl.java (original) +++ axis/axis2/java/core/trunk/modules/jaxws/src/org/apache/axis2/jaxws/handler/HandlerResolverImpl.java Sun Nov 7 14:26:52 2010 @@ -38,6 +38,7 @@ import org.apache.axis2.util.LoggingCont import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import javax.xml.namespace.QName; import javax.xml.ws.WebServiceException; import javax.xml.ws.handler.Handler; import javax.xml.ws.handler.LogicalHandler; @@ -325,8 +326,9 @@ public class HandlerResolverImpl extends // There is no EndpointDescription that matches the portInfo specified so // return the empty list of handlers since there are no ports that match if (log.isDebugEnabled()) { + QName qName = (portinfo == null) ? null : portinfo.getPortName(); log.debug("The PortInfo object did not match any ports; returning an empty list of handlers." - + " PortInfo QName: " + portinfo.getPortName()); + + " PortInfo QName: " + qName); } return handlers; } Modified: axis/axis2/java/core/trunk/modules/jaxws/src/org/apache/axis2/jaxws/handler/SoapMessageContext.java URL: http://svn.apache.org/viewvc/axis/axis2/java/core/trunk/modules/jaxws/src/org/apache/axis2/jaxws/handler/SoapMessageContext.java?rev=1032284&r1=1032283&r2=1032284&view=diff ============================================================================== --- axis/axis2/java/core/trunk/modules/jaxws/src/org/apache/axis2/jaxws/handler/SoapMessageContext.java (original) +++ axis/axis2/java/core/trunk/modules/jaxws/src/org/apache/axis2/jaxws/handler/SoapMessageContext.java Sun Nov 7 14:26:52 2010 @@ -30,13 +30,17 @@ import org.apache.axis2.jaxws.message.fa import org.apache.axis2.jaxws.message.factory.JAXBBlockFactory; import org.apache.axis2.jaxws.message.factory.MessageFactory; import org.apache.axis2.jaxws.registry.FactoryRegistry; +import org.apache.axis2.util.JavaUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import javax.xml.bind.JAXBContext; import javax.xml.namespace.QName; +import javax.xml.soap.AttachmentPart; import javax.xml.soap.SOAPConstants; +import javax.xml.soap.SOAPEnvelope; import javax.xml.soap.SOAPMessage; +import javax.xml.soap.SOAPPart; import javax.xml.stream.XMLStreamException; import java.util.ArrayList; import java.util.HashSet; @@ -53,10 +57,17 @@ public class SoapMessageContext extends javax.xml.ws.handler.soap.SOAPMessageContext { private static final Log log = LogFactory.getLog(SoapMessageContext.class); - // cache the message object after transformation --- see getMessage and setMessage methods + // Cache the message object and SOAPMessage after transformation Message cachedMessage = null; SOAPMessage cachedSoapMessage = null; + // Cache information about the SOAPMessage so that we can tell if it has changed + SOAPPart cachedSoapPart = null; + SOAPEnvelope cachedSoapEnvelope = null; + List<AttachmentPart> cachedAttachmentParts = new ArrayList<AttachmentPart>(); + + + public SoapMessageContext(MessageContext messageCtx) { super(messageCtx); } @@ -137,9 +148,142 @@ public class SoapMessageContext extends if (msg != cachedMessage) { cachedMessage = msg; cachedSoapMessage = msg.getAsSOAPMessage(); + cacheSOAPMessageInfo(cachedSoapMessage); } return cachedSoapMessage; } + + /** + * Check the current (cached) SOAPMessage and make sure + * its internals are consistent with when it was created. + * If not, the Message is recreated. + */ + public void checkAndUpdate() { + if (log.isDebugEnabled()) { + log.debug("Start:checkAndUpdate"); + } + if (cachedSoapMessage != null) { + + boolean match = checkSOAPMessageInfo(cachedSoapMessage); + + if (!match) { + if (log.isDebugEnabled()) { + log.debug("checkAndUpdate detected a mismatch.."); + } + setMessage(cachedSoapMessage); + } + } + if (log.isDebugEnabled()) { + log.debug("End:checkAndUpdate"); + } + } + + /** + * Updates information about the SOAPMessage so that + * we can determine later if it has changed + * @param sm SOAPMessage + */ + private void cacheSOAPMessageInfo(SOAPMessage sm) { + cachedSoapPart = null; + cachedSoapEnvelope = null; + cachedAttachmentParts.clear(); + try { + cachedSoapPart = sm.getSOAPPart(); + if (cachedSoapPart != null) { + cachedSoapEnvelope = cachedSoapPart.getEnvelope(); + } + if (sm.countAttachments() > 0) { + Iterator it = sm.getAttachments(); + while (it != null && it.hasNext()) { + AttachmentPart ap = (AttachmentPart) it.next(); + cachedAttachmentParts.add(ap); + } + } + } catch (Throwable t) { + if (log.isDebugEnabled()) { + log.debug("Ignoring ", t); + } + } + } + + /** + * Checks the information in SOAPMessage sm against + * the information previously cached. If an exception occurs + * @param sm SOAPMessage + * @return true if match , (exceptions are interpeted as false) + */ + private boolean checkSOAPMessageInfo(SOAPMessage sm) { + if (log.isDebugEnabled()) { + log.debug("checkSOAPMessageInfo with " + JavaUtils.getObjectIdentity(sm)); + } + // Check SOAPPart and SOAPEnvelope identity + SOAPPart currentSoapPart = null; + SOAPEnvelope currentSoapEnvelope = null; + + try { + currentSoapPart = sm.getSOAPPart(); + if (currentSoapPart != null) { + currentSoapEnvelope = cachedSoapPart.getEnvelope(); + } + // Check object identity + if (cachedSoapPart != currentSoapPart) { + if (log.isDebugEnabled()) { + log.debug("checkSOAPMessageInfo returns false due to: mismatched SOAPParts"); + } + return false; + } + if (cachedSoapEnvelope != currentSoapEnvelope) { + if (log.isDebugEnabled()) { + log.debug("checkSOAPMessageInfo returns false due to: mismatched SOAPEnvelopes"); + } + return false; + } + } catch(Throwable t) { + if (log.isDebugEnabled()) { + log.debug("checkSOAPMessageInfo returns false due to: ", t); + } + } + + // Check AttachmentParts + try { + int currentNumAttachmentParts = sm.countAttachments(); + if (currentNumAttachmentParts != cachedAttachmentParts.size()) { + if (log.isDebugEnabled()) { + log.debug("checkSOAPMessageInfo returns false due to: " + + "current number of AttachmentParts is " + currentNumAttachmentParts + + " versus cached number is " + cachedAttachmentParts.size()); + } + return false; + } + if (currentNumAttachmentParts > 0) { + if (log.isDebugEnabled()) { + log.debug("checkSOAPMessageInfo detected " + currentNumAttachmentParts + "AttachmentParts"); + } + Iterator cachedIT = cachedAttachmentParts.iterator(); + Iterator currentIT = sm.getAttachments(); + while (currentIT.hasNext() && cachedIT.hasNext()) { + AttachmentPart currentAP = (AttachmentPart) currentIT.next(); + AttachmentPart cachedAP = (AttachmentPart) cachedIT.next(); + if (currentAP != cachedAP) { + if (log.isDebugEnabled()) { + log.debug("checkSOAPMessageInfo returns false due to: " + + "current AttachmentParts is " + JavaUtils.getObjectIdentity(currentAP) + + " and cached is " + JavaUtils.getObjectIdentity(cachedAP)); + } + return false; + } + } + } + } catch(Throwable t) { + if (log.isDebugEnabled()) { + log.debug("checkSOAPMessageInfo returns false due to: ", t); + } + } + if (log.isDebugEnabled()) { + log.debug("checkSOAPMessageInfo returns true"); + } + return true; + } public Set<String> getRoles() { // TODO implement better. We should be doing smarter checking of the header, @@ -167,16 +311,22 @@ public class SoapMessageContext extends return roles; } - public void setMessage(SOAPMessage soapmessage) { - // TODO I don't like this at all. + public void setMessage(SOAPMessage soapMessage) { + if(log.isDebugEnabled()){ + log.debug("setMessage new=" + JavaUtils.getObjectIdentity(soapMessage) + + " existing=" + JavaUtils.getObjectIdentity(cachedSoapMessage)); + } try { Message msg = - ((MessageFactory) FactoryRegistry.getFactory(MessageFactory.class)).createFrom(soapmessage); + ((MessageFactory) FactoryRegistry.getFactory(MessageFactory.class)).createFrom(soapMessage); messageCtx.getMEPContext().setMessage(msg); cachedMessage = msg; - cachedSoapMessage = soapmessage; + cachedSoapMessage = soapMessage; + cacheSOAPMessageInfo(cachedSoapMessage); } catch (XMLStreamException e) { - // TODO log it, and throw something? + if(log.isDebugEnabled()){ + log.debug("Ignoring exception " + e); + } } }