Copied: cxf/trunk/rt/ws/rm/src/main/java/org/apache/cxf/ws/rm/soap/RMSoapInInterceptor.java (from r1566482, cxf/trunk/rt/ws/rm/src/main/java/org/apache/cxf/ws/rm/soap/RMSoapInterceptor.java) URL: http://svn.apache.org/viewvc/cxf/trunk/rt/ws/rm/src/main/java/org/apache/cxf/ws/rm/soap/RMSoapInInterceptor.java?p2=cxf/trunk/rt/ws/rm/src/main/java/org/apache/cxf/ws/rm/soap/RMSoapInInterceptor.java&p1=cxf/trunk/rt/ws/rm/src/main/java/org/apache/cxf/ws/rm/soap/RMSoapInterceptor.java&r1=1566482&r2=1566555&rev=1566555&view=diff ============================================================================== --- cxf/trunk/rt/ws/rm/src/main/java/org/apache/cxf/ws/rm/soap/RMSoapInterceptor.java (original) +++ cxf/trunk/rt/ws/rm/src/main/java/org/apache/cxf/ws/rm/soap/RMSoapInInterceptor.java Mon Feb 10 10:08:34 2014 @@ -19,7 +19,6 @@ package org.apache.cxf.ws.rm.soap; -import java.net.HttpURLConnection; import java.util.ArrayList; import java.util.Collection; import java.util.HashSet; @@ -34,14 +33,11 @@ import javax.xml.bind.JAXBContext; import javax.xml.bind.JAXBException; import javax.xml.namespace.QName; -import org.w3c.dom.Attr; import org.w3c.dom.Element; import org.w3c.dom.Node; import org.apache.cxf.binding.Binding; -import org.apache.cxf.binding.soap.Soap11; import org.apache.cxf.binding.soap.SoapFault; -import org.apache.cxf.binding.soap.SoapHeader; import org.apache.cxf.binding.soap.SoapMessage; import org.apache.cxf.binding.soap.interceptor.AbstractSoapInterceptor; import org.apache.cxf.common.logging.LogUtils; @@ -52,7 +48,6 @@ import org.apache.cxf.interceptor.Interc import org.apache.cxf.interceptor.InterceptorChain; import org.apache.cxf.message.Exchange; import org.apache.cxf.message.Message; -import org.apache.cxf.message.MessageUtils; import org.apache.cxf.phase.Phase; import org.apache.cxf.phase.PhaseInterceptor; import org.apache.cxf.service.Service; @@ -76,7 +71,6 @@ import org.apache.cxf.ws.rm.RMException; import org.apache.cxf.ws.rm.RMManager; import org.apache.cxf.ws.rm.RMMessageConstants; import org.apache.cxf.ws.rm.RMProperties; -import org.apache.cxf.ws.rm.SequenceFault; import org.apache.cxf.ws.rm.v200702.AckRequestedType; import org.apache.cxf.ws.rm.v200702.SequenceAcknowledgement; import org.apache.cxf.wsdl.interceptors.BareInInterceptor; @@ -85,7 +79,7 @@ import org.apache.cxf.wsdl.interceptors. * Protocol Handler responsible for {en|de}coding the RM * Properties for {outgo|incom}ing messages. */ -public class RMSoapInterceptor extends AbstractSoapInterceptor { +public class RMSoapInInterceptor extends AbstractSoapInterceptor { protected static JAXBContext jaxbContext; @@ -97,12 +91,12 @@ public class RMSoapInterceptor extends A HEADERS = set; } - private static final Logger LOG = LogUtils.getL7dLogger(RMSoapInterceptor.class); + private static final Logger LOG = LogUtils.getL7dLogger(RMSoapInInterceptor.class); /** * Constructor. */ - public RMSoapInterceptor() { + public RMSoapInInterceptor() { super(Phase.PRE_PROTOCOL); addAfter(MAPCodec.class.getName()); @@ -123,113 +117,8 @@ public class RMSoapInterceptor extends A * @see org.apache.cxf.interceptor.Interceptor#handleMessage(org.apache.cxf.message.Message) */ public void handleMessage(SoapMessage message) throws Fault { - mediate(message); - } - - /** - * Mediate message flow, peforming RMProperties {en|de}coding. - * - * @param message the messsage - */ - void mediate(SoapMessage message) { - if (MessageUtils.isOutbound(message)) { - encode(message); - } else { - decode(message); - updateServiceModelInfo(message); - } - } - - /** - * Encode the current RM properties in protocol-specific headers. - * - * @param message the SOAP message - */ - void encode(SoapMessage message) { - RMProperties rmps = RMContextUtils.retrieveRMProperties(message, true); - if (null != rmps) { - encode(message, rmps); - } else if (MessageUtils.isFault(message)) { - Exception ex = message.getContent(Exception.class); - if (ex instanceof SoapFault && ex.getCause() instanceof SequenceFault) { - encodeFault(message, (SequenceFault)ex.getCause()); - } - } - - } - - /** - * Encode the current RM properties in protocol-specific headers. - * - * @param message the SOAP message. - * @param rmps the current RM properties. - */ - public static void encode(SoapMessage message, RMProperties rmps) { - if (null == rmps) { - return; - } - LOG.log(Level.FINE, "encoding RMPs in SOAP headers"); - - try { - - List<Header> headers = message.getHeaders(); - discardRMHeaders(headers); - - AddressingProperties maps = RMContextUtils.retrieveMAPs(message, false, true); - ProtocolVariation protocol = ProtocolVariation.findVariant(rmps.getNamespaceURI(), - maps.getNamespaceURI()); - Element header = protocol.getCodec().buildHeaders(rmps, Soap11.getInstance().getHeader()); - Node node = header.getFirstChild(); - if (node != null && MessageUtils.isPartialResponse(message)) { - // make sure the response is returned as HTTP 200 and not 202 - message.put(Message.RESPONSE_CODE, HttpURLConnection.HTTP_OK); - } - while (node != null) { - Header holder = null; - if (node.getLocalName().equals("Sequence")) { - holder = new SoapHeader(new QName(node.getNamespaceURI(), node.getLocalName()), node); - ((SoapHeader)holder).setMustUnderstand(true); - } else { - holder = new Header(new QName(node.getNamespaceURI(), node.getLocalName()), node); - } - headers.add(holder); - node = node.getNextSibling(); - } - - } catch (JAXBException je) { - LOG.log(Level.WARNING, "SOAP_HEADER_ENCODE_FAILURE_MSG", je); - } - } - - /** - * Encode the SequenceFault in protocol-specific header. - * - * @param message the SOAP message. - * @param sf the SequenceFault. - */ - public static void encodeFault(SoapMessage message, SequenceFault sf) { - LOG.log(Level.FINE, "Encoding SequenceFault in SOAP header"); - try { - List<Header> headers = message.getHeaders(); - discardRMHeaders(headers); - Message inmsg = message.getExchange().getInMessage(); - RMProperties rmps = RMContextUtils.retrieveRMProperties(inmsg, false); - AddressingProperties maps = RMContextUtils.retrieveMAPs(inmsg, false, false); - ProtocolVariation protocol = ProtocolVariation.findVariant(rmps.getNamespaceURI(), - maps.getNamespaceURI()); - Element header = protocol.getCodec().buildHeaderFault(sf, Soap11.getInstance().getHeader()); - Node node = header.getFirstChild(); - if (node instanceof Element) { - Attr attr = header.getOwnerDocument().createAttributeNS("http://www.w3.org/2000/xmlns/", - "xmlns:" + RMConstants.NAMESPACE_PREFIX); - attr.setValue(rmps.getNamespaceURI()); - ((Element)node).setAttributeNodeNS(attr); - } - - headers.add(new Header(new QName(node.getNamespaceURI(), node.getLocalName()), node)); - } catch (JAXBException je) { - LOG.log(Level.WARNING, "SOAP_HEADER_ENCODE_FAILURE_MSG", je); - } + decode(message); + updateServiceModelInfo(message); } /** @@ -321,24 +210,6 @@ public class RMSoapInterceptor extends A LOG.log(Level.WARNING, "SOAP_HEADER_DECODE_FAILURE_MSG", ex); } } - - /** - * Discard any pre-existing RM headers - this may occur if the runtime - * re-uses a SOAP message. - * - * @param header the SOAP header element - */ - private static void discardRMHeaders(List<Header> header) { - Iterator<Header> iter = header.iterator(); - while (iter.hasNext()) { - Header hdr = iter.next(); - String uri = hdr.getName().getNamespaceURI(); - if (RM10Constants.NAMESPACE_URI.equals(uri) - || RM11Constants.NAMESPACE_URI.equals(uri)) { - iter.remove(); - } - } - } /** * When invoked inbound, check if the action indicates that this is one of the @@ -434,7 +305,7 @@ public class RMSoapInterceptor extends A // In the logical RM interceptor set it back to what it was so that the logical // addressing interceptor does not try to send a partial response to // server originated oneway RM protocol messages. - // The actions that can appear in the response to the requestor should be excluded. + // if (!consts.getCreateSequenceResponseAction().equals(action) && !consts.getSequenceAckAction().equals(action)
Added: cxf/trunk/rt/ws/rm/src/main/java/org/apache/cxf/ws/rm/soap/RMSoapOutInterceptor.java URL: http://svn.apache.org/viewvc/cxf/trunk/rt/ws/rm/src/main/java/org/apache/cxf/ws/rm/soap/RMSoapOutInterceptor.java?rev=1566555&view=auto ============================================================================== --- cxf/trunk/rt/ws/rm/src/main/java/org/apache/cxf/ws/rm/soap/RMSoapOutInterceptor.java (added) +++ cxf/trunk/rt/ws/rm/src/main/java/org/apache/cxf/ws/rm/soap/RMSoapOutInterceptor.java Mon Feb 10 10:08:34 2014 @@ -0,0 +1,195 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.cxf.ws.rm.soap; + +import java.net.HttpURLConnection; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.logging.Level; +import java.util.logging.Logger; + +import javax.xml.bind.JAXBContext; +import javax.xml.bind.JAXBException; +import javax.xml.namespace.QName; +import javax.xml.soap.SOAPException; +import javax.xml.soap.SOAPMessage; + +import org.w3c.dom.Attr; +import org.w3c.dom.Element; +import org.w3c.dom.Node; + +import org.apache.cxf.binding.soap.Soap11; +import org.apache.cxf.binding.soap.SoapFault; +import org.apache.cxf.binding.soap.SoapMessage; +import org.apache.cxf.binding.soap.interceptor.AbstractSoapInterceptor; +import org.apache.cxf.common.logging.LogUtils; +import org.apache.cxf.headers.Header; +import org.apache.cxf.interceptor.Fault; +import org.apache.cxf.message.Message; +import org.apache.cxf.message.MessageUtils; +import org.apache.cxf.phase.Phase; +import org.apache.cxf.ws.addressing.AddressingProperties; +import org.apache.cxf.ws.rm.ProtocolVariation; +import org.apache.cxf.ws.rm.RM10Constants; +import org.apache.cxf.ws.rm.RM11Constants; +import org.apache.cxf.ws.rm.RMConstants; +import org.apache.cxf.ws.rm.RMContextUtils; +import org.apache.cxf.ws.rm.RMOutInterceptor; +import org.apache.cxf.ws.rm.RMProperties; +import org.apache.cxf.ws.rm.SequenceFault; + +/** + * Protocol Handler responsible for {en|de}coding the RM + * Properties for {outgo|incom}ing messages. + */ +public class RMSoapOutInterceptor extends AbstractSoapInterceptor { + + protected static JAXBContext jaxbContext; + + private static final Set<QName> HEADERS; + static { + Set<QName> set = new HashSet<QName>(); + set.addAll(RM10Constants.HEADERS); + set.addAll(RM11Constants.HEADERS); + HEADERS = set; + } + + private static final Logger LOG = LogUtils.getL7dLogger(RMSoapOutInterceptor.class); + + /** + * Constructor. + */ + public RMSoapOutInterceptor() { + super(Phase.POST_PROTOCOL); + + addAfter(RMOutInterceptor.class.getName()); + } + + // AbstractSoapInterceptor interface + + /** + * @return the set of SOAP headers understood by this handler + */ + public Set<QName> getUnderstoodHeaders() { + return HEADERS; + } + + // Interceptor interface + + /* (non-Javadoc) + * @see org.apache.cxf.interceptor.Interceptor#handleMessage(org.apache.cxf.message.Message) + */ + public void handleMessage(SoapMessage message) throws Fault { + encode(message); + } + + /** + * Encode the current RM properties in protocol-specific headers. + * + * @param message the SOAP message + */ + void encode(SoapMessage message) { + RMProperties rmps = RMContextUtils.retrieveRMProperties(message, true); + if (null != rmps) { + encode(message, rmps); + } else if (MessageUtils.isFault(message)) { + Exception ex = message.getContent(Exception.class); + if (ex instanceof SoapFault && ex.getCause() instanceof SequenceFault) { + encodeFault(message, (SequenceFault)ex.getCause()); + } + } + + } + + /** + * Encode the current RM properties in protocol-specific headers. + * + * @param message the SOAP message. + * @param rmps the current RM properties. + */ + public static void encode(SoapMessage message, RMProperties rmps) { + if (null == rmps) { + return; + } + LOG.log(Level.FINE, "encoding RMPs in SOAP headers"); + try { + + AddressingProperties maps = RMContextUtils.retrieveMAPs(message, false, true); + ProtocolVariation protocol = ProtocolVariation.findVariant(rmps.getNamespaceURI(), + maps.getNamespaceURI()); + SOAPMessage content = message.getContent(SOAPMessage.class); + boolean added = protocol.getCodec().insertHeaders(rmps, content.getSOAPPart()); + if (added && MessageUtils.isPartialResponse(message)) { + // make sure the response is returned as HTTP 200 and not 202 + message.put(Message.RESPONSE_CODE, HttpURLConnection.HTTP_OK); + } + if (added) { + try { + content.saveChanges(); +// ByteArrayOutputStream bos = new ByteArrayOutputStream(); +// content.writeTo(bos); +// bos.close(); +// LOG.info("Message after headers added: " + bos.toString("UTF-8")); + } catch (SOAPException e) { + // TODO Auto-generated catch block + e.printStackTrace(); +// } catch (IOException e) { +// // TODO Auto-generated catch block +// e.printStackTrace(); + } + + } + + } catch (JAXBException je) { + LOG.log(Level.WARNING, "SOAP_HEADER_ENCODE_FAILURE_MSG", je); + } + } + + /** + * Encode the SequenceFault in protocol-specific header. + * + * @param message the SOAP message. + * @param sf the SequenceFault. + */ + public static void encodeFault(SoapMessage message, SequenceFault sf) { + LOG.log(Level.FINE, "Encoding SequenceFault in SOAP header"); + try { + List<Header> headers = message.getHeaders(); + Message inmsg = message.getExchange().getInMessage(); + RMProperties rmps = RMContextUtils.retrieveRMProperties(inmsg, false); + AddressingProperties maps = RMContextUtils.retrieveMAPs(inmsg, false, false); + ProtocolVariation protocol = ProtocolVariation.findVariant(rmps.getNamespaceURI(), + maps.getNamespaceURI()); + Element header = protocol.getCodec().buildHeaderFault(sf, Soap11.getInstance().getHeader()); + Node node = header.getFirstChild(); + if (node instanceof Element) { + Attr attr = header.getOwnerDocument().createAttributeNS("http://www.w3.org/2000/xmlns/", + "xmlns:" + RMConstants.NAMESPACE_PREFIX); + attr.setValue(rmps.getNamespaceURI()); + ((Element)node).setAttributeNodeNS(attr); + } + + headers.add(new Header(new QName(node.getNamespaceURI(), node.getLocalName()), node)); + } catch (JAXBException je) { + LOG.log(Level.WARNING, "SOAP_HEADER_ENCODE_FAILURE_MSG", je); + } + } +} \ No newline at end of file Added: cxf/trunk/rt/ws/rm/src/test/java/org/apache/cxf/ws/rm/soap/RMSoapOutInterceptorTest.java URL: http://svn.apache.org/viewvc/cxf/trunk/rt/ws/rm/src/test/java/org/apache/cxf/ws/rm/soap/RMSoapOutInterceptorTest.java?rev=1566555&view=auto ============================================================================== --- cxf/trunk/rt/ws/rm/src/test/java/org/apache/cxf/ws/rm/soap/RMSoapOutInterceptorTest.java (added) +++ cxf/trunk/rt/ws/rm/src/test/java/org/apache/cxf/ws/rm/soap/RMSoapOutInterceptorTest.java Mon Feb 10 10:08:34 2014 @@ -0,0 +1,475 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.cxf.ws.rm.soap; + +import java.io.InputStream; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Iterator; +import java.util.List; +import java.util.Set; + +import javax.xml.namespace.QName; +import javax.xml.stream.XMLInputFactory; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; + +import org.w3c.dom.Element; + +import org.apache.cxf.BusFactory; +import org.apache.cxf.binding.soap.SoapFault; +import org.apache.cxf.binding.soap.SoapMessage; +import org.apache.cxf.binding.soap.interceptor.ReadHeadersInterceptor; +import org.apache.cxf.binding.soap.interceptor.StartBodyInterceptor; +import org.apache.cxf.headers.Header; +import org.apache.cxf.message.Exchange; +import org.apache.cxf.message.ExchangeImpl; +import org.apache.cxf.message.Message; +import org.apache.cxf.message.MessageImpl; +import org.apache.cxf.message.MessageUtils; +import org.apache.cxf.ws.addressing.AddressingProperties; +import org.apache.cxf.ws.addressing.Names; +import org.apache.cxf.ws.rm.RM10Constants; +import org.apache.cxf.ws.rm.RMConstants; +import org.apache.cxf.ws.rm.RMContextUtils; +import org.apache.cxf.ws.rm.RMProperties; +import org.apache.cxf.ws.rm.SequenceFault; +import org.apache.cxf.ws.rm.v200702.AckRequestedType; +import org.apache.cxf.ws.rm.v200702.Identifier; +import org.apache.cxf.ws.rm.v200702.ObjectFactory; +import org.apache.cxf.ws.rm.v200702.SequenceAcknowledgement; +import org.apache.cxf.ws.rm.v200702.SequenceAcknowledgement.AcknowledgementRange; +import org.apache.cxf.ws.rm.v200702.SequenceType; +import org.easymock.EasyMock; +import org.easymock.IMocksControl; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +public class RMSoapOutInterceptorTest extends Assert { + + private static final String SEQ_IDENTIFIER = "http://Business456.com/RM/ABC"; + private static final Long ONE = new Long(1); + private static final Long TEN = new Long(10); + private static final Long MSG1_MESSAGE_NUMBER = ONE; + private static final Long MSG2_MESSAGE_NUMBER = new Long(2); + + private IMocksControl control; + + private SequenceType s1; + private SequenceType s2; + private SequenceAcknowledgement ack1; + private SequenceAcknowledgement ack2; + private AckRequestedType ar1; + private AckRequestedType ar2; + + @Before + public void setUp() { + control = EasyMock.createNiceControl(); + } + + @Test + public void testGetUnderstoodHeaders() throws Exception { + RMSoapOutInterceptor codec = new RMSoapOutInterceptor(); + Set<QName> headers = codec.getUnderstoodHeaders(); + assertTrue("expected Sequence header", headers.contains(RM10Constants.SEQUENCE_QNAME)); + assertTrue("expected SequenceAcknowledgment header", + headers.contains(RM10Constants.SEQUENCE_ACK_QNAME)); + assertTrue("expected AckRequested header", + headers.contains(RM10Constants.ACK_REQUESTED_QNAME)); + } + + @Test + public void testHandleMessage() throws NoSuchMethodException { + Method m = RMSoapOutInterceptor.class.getDeclaredMethod("mediate", + new Class[] {SoapMessage.class}); + RMSoapOutInterceptor codec = + EasyMock.createMockBuilder(RMSoapOutInterceptor.class) + .addMockedMethod(m).createMock(control); + SoapMessage msg = control.createMock(SoapMessage.class); + codec.mediate(msg); + EasyMock.expectLastCall(); + + control.replay(); + codec.handleMessage(msg); + control.verify(); + } + + @Test + public void testMediate() throws NoSuchMethodException, XMLStreamException { + Method m1 = RMSoapOutInterceptor.class.getDeclaredMethod("encode", + new Class[] {SoapMessage.class}); + Method m2 = RMSoapOutInterceptor.class.getDeclaredMethod("decode", + new Class[] {SoapMessage.class}); + RMSoapOutInterceptor codec = + EasyMock.createMockBuilder(RMSoapOutInterceptor.class) + .addMockedMethods(m1, m2).createMock(control); + + SoapMessage msg = control.createMock(SoapMessage.class); + Exchange exchange = control.createMock(Exchange.class); + EasyMock.expect(msg.getExchange()).andReturn(exchange); + EasyMock.expect(exchange.getOutMessage()).andReturn(msg); + codec.encode(msg); + EasyMock.expectLastCall(); + + control.replay(); + codec.mediate(msg); + control.verify(); + + control.reset(); + EasyMock.expect(msg.getExchange()).andReturn(null); + codec.decode(msg); + EasyMock.expectLastCall(); + + control.replay(); + codec.mediate(msg); + control.verify(); + + } + + @Test + public void testEncode() throws Exception { + RMSoapOutInterceptor codec = new RMSoapOutInterceptor(); + setUpOutbound(); + SoapMessage message = setupOutboundMessage(); + + // no RM headers + + codec.handleMessage(message); + verifyHeaders(message, new String[] {}); + + // one sequence header + + message = setupOutboundMessage(); + RMProperties rmps = RMContextUtils.retrieveRMProperties(message, true); + rmps.setSequence(s1); + codec.encode(message); + verifyHeaders(message, new String[] {RMConstants.SEQUENCE_NAME}); + + // one acknowledgment header + + message = setupOutboundMessage(); + rmps = RMContextUtils.retrieveRMProperties(message, true); + Collection<SequenceAcknowledgement> acks = new ArrayList<SequenceAcknowledgement>(); + acks.add(ack1); + rmps.setAcks(acks); + codec.encode(message); + verifyHeaders(message, new String[] {RMConstants.SEQUENCE_ACK_NAME}); + + // two acknowledgment headers + + message = setupOutboundMessage(); + rmps = RMContextUtils.retrieveRMProperties(message, true); + acks.add(ack2); + rmps.setAcks(acks); + codec.encode(message); + verifyHeaders(message, new String[] {RMConstants.SEQUENCE_ACK_NAME, + RMConstants.SEQUENCE_ACK_NAME}); + + // one ack requested header + + message = setupOutboundMessage(); + rmps = RMContextUtils.retrieveRMProperties(message, true); + Collection<AckRequestedType> requested = new ArrayList<AckRequestedType>(); + requested.add(ar1); + rmps.setAcksRequested(requested); + codec.encode(message); + verifyHeaders(message, new String[] {RMConstants.ACK_REQUESTED_NAME}); + + // two ack requested headers + + message = setupOutboundMessage(); + rmps = RMContextUtils.retrieveRMProperties(message, true); + requested.add(ar2); + rmps.setAcksRequested(requested); + codec.encode(message); + verifyHeaders(message, new String[] {RMConstants.ACK_REQUESTED_NAME, + RMConstants.ACK_REQUESTED_NAME}); + } + + @Test + public void testEncodeFault() throws Exception { + RMSoapOutInterceptor codec = new RMSoapOutInterceptor(); + setUpOutbound(); + SoapMessage message = setupOutboundFaultMessage(); + + // no RM headers and no fault + + codec.encode(message); + verifyHeaders(message, new String[] {}); + + // fault is not a SoapFault + + message = setupOutboundFaultMessage(); + assertTrue(MessageUtils.isFault(message)); + Exception ex = new RuntimeException(""); + message.setContent(Exception.class, ex); + codec.encode(message); + verifyHeaders(message, new String[] {}); + + // fault is a SoapFault but does not have a SequenceFault cause + + message = setupOutboundFaultMessage(); + SoapFault f = new SoapFault("REASON", RM10Constants.UNKNOWN_SEQUENCE_FAULT_QNAME); + message.setContent(Exception.class, f); + codec.encode(message); + verifyHeaders(message, new String[] {}); + + // fault is a SoapFault and has a SequenceFault cause + + message = setupOutboundFaultMessage(); + SequenceFault sf = new SequenceFault("REASON"); + sf.setFaultCode(RM10Constants.UNKNOWN_SEQUENCE_FAULT_QNAME); + Identifier sid = new Identifier(); + sid.setValue("SID"); + sf.setSender(true); + f.initCause(sf); + message.setContent(Exception.class, f); + codec.encode(message); + verifyHeaders(message, new String[] {RMConstants.SEQUENCE_FAULT_NAME}); + + } + + @Test + public void testDecodeSequence() throws XMLStreamException { + SoapMessage message = setUpInboundMessage("resources/Message1.xml"); + RMSoapOutInterceptor codec = new RMSoapOutInterceptor(); + codec.handleMessage(message); + RMProperties rmps = RMContextUtils.retrieveRMProperties(message, false); + SequenceType st = rmps.getSequence(); + assertNotNull(st); + assertEquals(st.getIdentifier().getValue(), SEQ_IDENTIFIER); + assertEquals(st.getMessageNumber(), MSG1_MESSAGE_NUMBER); + + assertNull(rmps.getAcks()); + assertNull(rmps.getAcksRequested()); + + } + + @Test + public void testDecodeAcknowledgements() throws XMLStreamException { + SoapMessage message = setUpInboundMessage("resources/Acknowledgment.xml"); + RMSoapOutInterceptor codec = new RMSoapOutInterceptor(); + codec.handleMessage(message); + RMProperties rmps = RMContextUtils.retrieveRMProperties(message, false); + Collection<SequenceAcknowledgement> acks = rmps.getAcks(); + assertNotNull(acks); + assertEquals(1, acks.size()); + SequenceAcknowledgement ack = acks.iterator().next(); + assertNotNull(ack); + assertEquals(ack.getIdentifier().getValue(), SEQ_IDENTIFIER); + assertEquals(2, ack.getAcknowledgementRange().size()); + AcknowledgementRange r1 = ack.getAcknowledgementRange().get(0); + AcknowledgementRange r2 = ack.getAcknowledgementRange().get(1); + verifyRange(r1, 1, 1); + verifyRange(r2, 3, 3); + assertNull(rmps.getSequence()); + assertNull(rmps.getAcksRequested()); + } + + @Test + public void testDecodeAcknowledgements2() throws XMLStreamException { + SoapMessage message = setUpInboundMessage("resources/Acknowledgment2.xml"); + RMSoapOutInterceptor codec = new RMSoapOutInterceptor(); + codec.handleMessage(message); + RMProperties rmps = RMContextUtils.retrieveRMProperties(message, false); + Collection<SequenceAcknowledgement> acks = rmps.getAcks(); + assertNotNull(acks); + assertEquals(1, acks.size()); + SequenceAcknowledgement ack = acks.iterator().next(); + assertNotNull(ack); + assertEquals(1, ack.getAcknowledgementRange().size()); + AcknowledgementRange r1 = ack.getAcknowledgementRange().get(0); + verifyRange(r1, 1, 3); + assertNull(rmps.getSequence()); + assertNull(rmps.getAcksRequested()); + } + + private void verifyRange(AcknowledgementRange r, int i, int j) { + assertNotNull(r); + if (i > 0) { + assertNotNull(r.getLower()); + assertEquals(i, r.getLower().longValue()); + } + if (j > 0) { + assertNotNull(r.getUpper()); + assertEquals(j, r.getUpper().longValue()); + } + } + + @Test + public void testDecodeAcksRequested() throws XMLStreamException { + SoapMessage message = setUpInboundMessage("resources/Retransmission.xml"); + RMSoapOutInterceptor codec = new RMSoapOutInterceptor(); + codec.handleMessage(message); + RMProperties rmps = RMContextUtils.retrieveRMProperties(message, false); + Collection<AckRequestedType> requested = rmps.getAcksRequested(); + assertNotNull(requested); + assertEquals(1, requested.size()); + AckRequestedType ar = requested.iterator().next(); + assertNotNull(ar); + assertEquals(ar.getIdentifier().getValue(), SEQ_IDENTIFIER); + + SequenceType s = rmps.getSequence(); + assertNotNull(s); + assertEquals(s.getIdentifier().getValue(), SEQ_IDENTIFIER); + assertEquals(s.getMessageNumber(), MSG2_MESSAGE_NUMBER); + + assertNull(rmps.getAcks()); + } + + private void setUpOutbound() { + ObjectFactory factory = new ObjectFactory(); + s1 = factory.createSequenceType(); + Identifier sid = factory.createIdentifier(); + sid.setValue("sequence1"); + s1.setIdentifier(sid); + s1.setMessageNumber(ONE); + s2 = factory.createSequenceType(); + sid = factory.createIdentifier(); + sid.setValue("sequence2"); + s2.setIdentifier(sid); + s2.setMessageNumber(TEN); + + ack1 = factory.createSequenceAcknowledgement(); + SequenceAcknowledgement.AcknowledgementRange r = + factory.createSequenceAcknowledgementAcknowledgementRange(); + r.setLower(ONE); + r.setUpper(ONE); + ack1.getAcknowledgementRange().add(r); + ack1.setIdentifier(s1.getIdentifier()); + + ack2 = factory.createSequenceAcknowledgement(); + r = factory.createSequenceAcknowledgementAcknowledgementRange(); + r.setLower(ONE); + r.setUpper(TEN); + ack2.getAcknowledgementRange().add(r); + ack2.setIdentifier(s2.getIdentifier()); + + ar1 = factory.createAckRequestedType(); + ar1.setIdentifier(s1.getIdentifier()); + + ar2 = factory.createAckRequestedType(); + ar2.setIdentifier(s2.getIdentifier()); + } + + private SoapMessage setupOutboundMessage() throws Exception { + Exchange ex = new ExchangeImpl(); + Message message = new MessageImpl(); + SoapMessage soapMessage = new SoapMessage(message); + RMProperties rmps = new RMProperties(); + rmps.exposeAs(RM10Constants.NAMESPACE_URI); + RMContextUtils.storeRMProperties(soapMessage, rmps, true); + AddressingProperties maps = new AddressingProperties(); + RMContextUtils.storeMAPs(maps, soapMessage, true, false); + ex.setOutMessage(soapMessage); + soapMessage.setExchange(ex); + return soapMessage; + } + + private SoapMessage setupOutboundFaultMessage() throws Exception { + Exchange ex = new ExchangeImpl(); + Message message = new MessageImpl(); + RMProperties rmps = new RMProperties(); + rmps.exposeAs(RM10Constants.NAMESPACE_URI); + RMContextUtils.storeRMProperties(message, rmps, false); + AddressingProperties maps = new AddressingProperties(); + RMContextUtils.storeMAPs(maps, message, false, false); + ex.setInMessage(message); + message = new MessageImpl(); + SoapMessage soapMessage = new SoapMessage(message); + ex.setOutFaultMessage(soapMessage); + soapMessage.setExchange(ex); + return soapMessage; + } + + private void verifyHeaders(SoapMessage message, String... names) { + List<Header> header = message.getHeaders(); + + // check all expected headers are present + + for (String name : names) { + boolean found = false; + Iterator<Header> iter = header.iterator(); + while (iter.hasNext()) { + Object obj = iter.next().getObject(); + if (obj instanceof Element) { + Element elem = (Element) obj; + String namespace = elem.getNamespaceURI(); + String localName = elem.getLocalName(); + if (RM10Constants.NAMESPACE_URI.equals(namespace) + && localName.equals(name)) { + found = true; + break; + } else if (Names.WSA_NAMESPACE_NAME.equals(namespace) + && localName.equals(name)) { + found = true; + break; + } + } + } + assertTrue("Could not find header element " + name, found); + } + + // no other headers should be present + + Iterator<Header> iter1 = header.iterator(); + while (iter1.hasNext()) { + Object obj = iter1.next().getObject(); + if (obj instanceof Element) { + Element elem = (Element) obj; + String namespace = elem.getNamespaceURI(); + String localName = elem.getLocalName(); + assertTrue(RM10Constants.NAMESPACE_URI.equals(namespace) + || Names.WSA_NAMESPACE_NAME.equals(namespace)); + boolean found = false; + for (String name : names) { + if (localName.equals(name)) { + found = true; + break; + } + } + assertTrue("Unexpected header element " + localName, found); + } + } + } + + private SoapMessage setUpInboundMessage(String resource) throws XMLStreamException { + Message message = new MessageImpl(); + SoapMessage soapMessage = new SoapMessage(message); + RMProperties rmps = new RMProperties(); + rmps.exposeAs(RM10Constants.NAMESPACE_URI); + RMContextUtils.storeRMProperties(soapMessage, rmps, false); + AddressingProperties maps = new AddressingProperties(); + RMContextUtils.storeMAPs(maps, soapMessage, false, false); + message.put(MessaRMSoapOutInterceptorTestENABLED, false); + InputStream is = RMSoapInterceptorTest.class.getResourceAsStream(resource); + assertNotNull(is); + XMLStreamReader reader = XMLInputFactory.newInstance().createXMLStreamReader(is); + soapMessage.setContent(XMLStreamReader.class, reader); + ReadHeadersInterceptor rji = new ReadHeadersInterceptor(BusFactory.getDefaultBus()); + rji.handleMessage(soapMessage); + StartBodyInterceptor sbi = new StartBodyInterceptor(); + sbi.handleMessage(soapMessage); + return soapMessage; + } +}
