You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cxf.apache.org by ay...@apache.org on 2013/05/17 10:54:44 UTC

svn commit: r1483696 - in /cxf/trunk/rt: bindings/soap/src/main/java/org/apache/cxf/binding/soap/ bindings/soap/src/main/java/org/apache/cxf/binding/soap/interceptor/ bindings/soap/src/test/java/org/apache/cxf/binding/soap/interceptor/ frontend/jaxws/s...

Author: ay
Date: Fri May 17 08:54:44 2013
New Revision: 1483696

URL: http://svn.apache.org/r1483696
Log:
[CXF-5009] Allow multiple subcodes in a SOAP 1.2 fault

Modified:
    cxf/trunk/rt/bindings/soap/src/main/java/org/apache/cxf/binding/soap/SoapFault.java
    cxf/trunk/rt/bindings/soap/src/main/java/org/apache/cxf/binding/soap/interceptor/Soap12FaultInInterceptor.java
    cxf/trunk/rt/bindings/soap/src/main/java/org/apache/cxf/binding/soap/interceptor/Soap12FaultOutInterceptor.java
    cxf/trunk/rt/bindings/soap/src/test/java/org/apache/cxf/binding/soap/interceptor/SoapFaultSerializerTest.java
    cxf/trunk/rt/frontend/jaxws/src/main/java/org/apache/cxf/jaxws/JaxWsClientProxy.java

Modified: cxf/trunk/rt/bindings/soap/src/main/java/org/apache/cxf/binding/soap/SoapFault.java
URL: http://svn.apache.org/viewvc/cxf/trunk/rt/bindings/soap/src/main/java/org/apache/cxf/binding/soap/SoapFault.java?rev=1483696&r1=1483695&r2=1483696&view=diff
==============================================================================
--- cxf/trunk/rt/bindings/soap/src/main/java/org/apache/cxf/binding/soap/SoapFault.java (original)
+++ cxf/trunk/rt/bindings/soap/src/main/java/org/apache/cxf/binding/soap/SoapFault.java Fri May 17 08:54:44 2013
@@ -20,6 +20,8 @@
 package org.apache.cxf.binding.soap;
 
 import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
 import java.util.Map;
 import java.util.ResourceBundle;
 
@@ -48,7 +50,7 @@ public class SoapFault extends Fault {
      * FaultHandler) be mapped to "Sender" instead.
      */ 
 
-    private QName subCode;
+    private List<QName> subCodes;
     private String role;
     private String node;
     private Map<String, String> namespaces = new HashMap<String, String>();
@@ -84,7 +86,7 @@ public class SoapFault extends Fault {
     }
     
     public String getSubCodeString(String prefix, String defaultPrefix) {
-        return getFaultCodeString(prefix, defaultPrefix, subCode);
+        return getFaultCodeString(prefix, defaultPrefix, getRootSubCode());
     }
     
     private String getFaultCodeString(String prefix, String defaultPrefix, QName fCode) {
@@ -100,6 +102,19 @@ public class SoapFault extends Fault {
         
         return codePrefix + ":" + fCode.getLocalPart();        
     }
+    
+    private QName getRootSubCode() {
+        return subCodes != null && subCodes.size() > 0 ? subCodes.get(0) : null;
+    }
+
+    private void setRootSubCode(QName subCode) {
+        if (subCodes == null) {
+            subCodes = new LinkedList<QName>();
+        } else {
+            subCodes.clear();
+        }
+        subCodes.add(subCode);
+    }
 
     public String getReason() {
         return getMessage();
@@ -132,21 +147,53 @@ public class SoapFault extends Fault {
     }    
 
     /**
-     * Returns the SubCode for the Fault Code.
+     * Returns the SubCode for the Fault Code. If there are more than one Subcode entries 
+     * in this fault, the first Subcode is returned.
      * 
      * @return The SubCode element as detailed by the SOAP 1.2 spec.
      */
     public QName getSubCode() {
-        return subCode;
+        return getRootSubCode();
+    }
+
+    /**
+     * Returns the SubCode list for the Fault Code.
+     * 
+     * @return The SubCode element list as detailed by the SOAP 1.2 spec.
+     */
+    public List<QName> getSubCodes() {
+        return subCodes;
     }
 
     /**
-     * Sets the SubCode for the Fault Code.
+     * Sets the SubCode for the Fault Code. If there are more than one Subcode entries 
+     * in this fault, the first Subcode is set while the other entries are removed.
      * 
      * @param subCode The SubCode element as detailed by the SOAP 1.2 spec.
      */
     public void setSubCode(QName subCode) {
-        this.subCode = subCode;
+        setRootSubCode(subCode);
+    }
+
+    /**
+     * Sets the SubCode list for the Fault Code.
+     * 
+     * @param subCode The SubCode element list as detailed by the SOAP 1.2 spec.
+     */
+    public void setSubCodes(List<QName> subCodes) {
+        this.subCodes = subCodes;
+    }
+
+    /**
+     * Appends the SubCode to the SubCode list.
+     * 
+     * @param subCode The SubCode element as detailed by the SOAP 1.2 spec. 
+     */
+    public void appendSubCode(QName subCode) {
+        if (subCodes == null) {
+            subCodes = new LinkedList<QName>();
+        }
+        subCodes.add(subCode);
     }
 
     public Map<String, String> getNamespaces() {

Modified: cxf/trunk/rt/bindings/soap/src/main/java/org/apache/cxf/binding/soap/interceptor/Soap12FaultInInterceptor.java
URL: http://svn.apache.org/viewvc/cxf/trunk/rt/bindings/soap/src/main/java/org/apache/cxf/binding/soap/interceptor/Soap12FaultInInterceptor.java?rev=1483696&r1=1483695&r2=1483696&view=diff
==============================================================================
--- cxf/trunk/rt/bindings/soap/src/main/java/org/apache/cxf/binding/soap/interceptor/Soap12FaultInInterceptor.java (original)
+++ cxf/trunk/rt/bindings/soap/src/main/java/org/apache/cxf/binding/soap/interceptor/Soap12FaultInInterceptor.java Fri May 17 08:54:44 2013
@@ -20,6 +20,8 @@
 package org.apache.cxf.binding.soap.interceptor;
 
 import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
 import java.util.Map;
 import java.util.logging.Logger;
 
@@ -30,6 +32,7 @@ import javax.xml.xpath.XPathConstants;
 
 import org.w3c.dom.Element;
 import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
 
 import org.apache.cxf.binding.soap.Soap11;
 import org.apache.cxf.binding.soap.Soap12;
@@ -67,7 +70,7 @@ public class Soap12FaultInInterceptor ex
                                            XMLStreamReader reader) {
         String exMessage = null;
         QName faultCode = null;
-        QName subCode = null;
+        List<QName> subCodes = null;
         String role = null;
         String node = null;
         Element detail = null;
@@ -103,11 +106,16 @@ public class Soap12FaultInInterceptor ex
                 faultCode = XMLUtils.getQName(el.getTextContent(), el);
             }
             
-            el = (Element)xu.getValue("//s:Fault/s:Code/s:Subcode/s:Value", 
+            el = (Element)xu.getValue("//s:Fault/s:Code/s:Subcode", 
                                       fault, 
                                       XPathConstants.NODE);
             if (el != null) {
-                subCode = XMLUtils.getQName(el.getTextContent(), el);
+                subCodes = new LinkedList<QName>();
+                NodeList vlist = el.getElementsByTagNameNS(Soap12.SOAP_NAMESPACE, "Value");
+                for (int i = 0; i < vlist.getLength(); i++) {
+                    Node v = vlist.item(i);
+                    subCodes.add(XMLUtils.getQName(v.getTextContent(), v));
+                }
             }
             
             exMessage = (String) xu.getValue("//s:Fault/s:Reason/s:Text/text()", 
@@ -140,7 +148,7 @@ public class Soap12FaultInInterceptor ex
         }
         
         SoapFault fault = new SoapFault(exMessage, faultCode);
-        fault.setSubCode(subCode);
+        fault.setSubCodes(subCodes);
         fault.setDetail(detail);
         fault.setRole(role);
         fault.setNode(node);

Modified: cxf/trunk/rt/bindings/soap/src/main/java/org/apache/cxf/binding/soap/interceptor/Soap12FaultOutInterceptor.java
URL: http://svn.apache.org/viewvc/cxf/trunk/rt/bindings/soap/src/main/java/org/apache/cxf/binding/soap/interceptor/Soap12FaultOutInterceptor.java?rev=1483696&r1=1483695&r2=1483696&view=diff
==============================================================================
--- cxf/trunk/rt/bindings/soap/src/main/java/org/apache/cxf/binding/soap/interceptor/Soap12FaultOutInterceptor.java (original)
+++ cxf/trunk/rt/bindings/soap/src/main/java/org/apache/cxf/binding/soap/interceptor/Soap12FaultOutInterceptor.java Fri May 17 08:54:44 2013
@@ -23,6 +23,7 @@ import java.util.Map;
 import java.util.logging.Level;
 import java.util.logging.Logger;
 
+import javax.xml.namespace.QName;
 import javax.xml.stream.XMLStreamWriter;
 
 import org.w3c.dom.Element;
@@ -92,14 +93,19 @@ public class Soap12FaultOutInterceptor e
                                                            defaultPrefix));
                 writer.writeEndElement();
 
-                if (fault.getSubCode() != null) {
-                    writer.writeStartElement(defaultPrefix, "Subcode", ns);
-                    writer.writeStartElement(defaultPrefix, "Value", ns);
-                    writer.writeCharacters(fault.getSubCodeString(getFaultCodePrefix(writer, 
-                                                                                     fault.getSubCode()), 
-                                                                  defaultPrefix));                
-                    writer.writeEndElement();
-                    writer.writeEndElement();
+                if (fault.getSubCodes() != null) {
+                    int fscCount = 0;
+                    for (QName fsc : fault.getSubCodes()) {
+                        writer.writeStartElement(defaultPrefix, "Subcode", ns);
+                        writer.writeStartElement(defaultPrefix, "Value", ns);
+                        writer.writeCharacters(getCodeString(getFaultCodePrefix(writer, fsc), 
+                                                             defaultPrefix, fsc));
+                        writer.writeEndElement();
+                        fscCount++;
+                    }
+                    while (fscCount-- > 0) {
+                        writer.writeEndElement();
+                    }
                 }
                 writer.writeEndElement();
 
@@ -151,5 +157,20 @@ public class Soap12FaultOutInterceptor e
             }
             return code;
         }
+
+        //REVISIT either make SoapFault's this method public or put this method into a soap fault utility class
+        private static String getCodeString(String prefix, String defaultPrefix, QName code) {
+            String codePrefix = null;
+            if (StringUtils.isEmpty(prefix)) {
+                codePrefix = code.getPrefix();
+                if (StringUtils.isEmpty(codePrefix)) {
+                    codePrefix = defaultPrefix;
+                }
+            } else {
+                codePrefix = prefix;
+            }
+            
+            return codePrefix + ":" + code.getLocalPart();        
+        }
     }
 }

Modified: cxf/trunk/rt/bindings/soap/src/test/java/org/apache/cxf/binding/soap/interceptor/SoapFaultSerializerTest.java
URL: http://svn.apache.org/viewvc/cxf/trunk/rt/bindings/soap/src/test/java/org/apache/cxf/binding/soap/interceptor/SoapFaultSerializerTest.java?rev=1483696&r1=1483695&r2=1483696&view=diff
==============================================================================
--- cxf/trunk/rt/bindings/soap/src/test/java/org/apache/cxf/binding/soap/interceptor/SoapFaultSerializerTest.java (original)
+++ cxf/trunk/rt/bindings/soap/src/test/java/org/apache/cxf/binding/soap/interceptor/SoapFaultSerializerTest.java Fri May 17 08:54:44 2013
@@ -142,9 +142,66 @@ public class SoapFaultSerializerTest ext
         assertNotNull(fault2);
         assertEquals(Soap12.getInstance().getSender(), fault2.getFaultCode());
         assertEquals(fault.getMessage(), fault2.getMessage());        
+        assertEquals(fault.getSubCode(), fault2.getSubCode());
     }
     
     @Test
+    public void testSoap12WithMultipleSubCodesOut() throws Exception {
+        String faultString = "Hadrian caused this Fault!";
+        SoapFault fault = new SoapFault(faultString, Soap12.getInstance().getSender());
+        
+        fault.appendSubCode(new QName("http://cxf.apache.org/soap/fault", "invalidsoap", "cxffaultcode"));
+        fault.appendSubCode(new QName("http://cxf.apache.org/soap/fault2", "invalidsoap2", "cxffaultcode2"));
+
+        SoapMessage m = new SoapMessage(new MessageImpl());
+        m.setVersion(Soap12.getInstance());
+        
+        m.setContent(Exception.class, fault);
+
+        ByteArrayOutputStream out = new ByteArrayOutputStream();
+        XMLStreamWriter writer = StaxUtils.createXMLStreamWriter(out);
+        writer.writeStartDocument();
+        writer.writeStartElement("Body");
+
+        m.setContent(XMLStreamWriter.class, writer);
+
+        Soap12FaultOutInterceptorInternal.INSTANCE.handleMessage(m);
+
+        writer.writeEndElement();
+        writer.writeEndDocument();
+        writer.close();
+
+        Document faultDoc = DOMUtils.readXml(new ByteArrayInputStream(out.toByteArray()));
+        
+        assertValid("//soap12env:Fault/soap12env:Code/soap12env:Value[text()='ns1:Sender']", 
+                    faultDoc);
+        assertValid("//soap12env:Fault/soap12env:Code/soap12env:Subcode/"
+                    + "soap12env:Value[text()='ns2:invalidsoap']", 
+                    faultDoc);
+        assertValid("//soap12env:Fault/soap12env:Code/soap12env:Subcode/soap12env:Subcode/"
+                    + "soap12env:Value[text()='ns2:invalidsoap2']", 
+                    faultDoc);
+        assertValid("//soap12env:Fault/soap12env:Reason/soap12env:Text[@xml:lang='en']", 
+                    faultDoc);
+        assertValid("//soap12env:Fault/soap12env:Reason/soap12env:Text[text()='" + faultString + "']", 
+                    faultDoc);
+
+        XMLStreamReader reader = StaxUtils.createXMLStreamReader(new ByteArrayInputStream(out.toByteArray()));
+        m.setContent(XMLStreamReader.class, reader);
+
+        reader.nextTag();
+
+        Soap12FaultInInterceptor inInterceptor = new Soap12FaultInInterceptor();
+        inInterceptor.handleMessage(m);
+
+        SoapFault fault2 = (SoapFault)m.getContent(Exception.class);
+        assertNotNull(fault2);
+        assertEquals(Soap12.getInstance().getSender(), fault2.getFaultCode());
+        assertEquals(fault.getMessage(), fault2.getMessage());        
+        assertEquals(fault.getSubCodes(), fault2.getSubCodes());
+    }
+
+    @Test
     public void testFaultToSoapFault() throws Exception {
         Exception ex = new Exception();
         Fault fault = new Fault(ex, Fault.FAULT_CODE_CLIENT);

Modified: cxf/trunk/rt/frontend/jaxws/src/main/java/org/apache/cxf/jaxws/JaxWsClientProxy.java
URL: http://svn.apache.org/viewvc/cxf/trunk/rt/frontend/jaxws/src/main/java/org/apache/cxf/jaxws/JaxWsClientProxy.java?rev=1483696&r1=1483695&r2=1483696&view=diff
==============================================================================
--- cxf/trunk/rt/frontend/jaxws/src/main/java/org/apache/cxf/jaxws/JaxWsClientProxy.java (original)
+++ cxf/trunk/rt/frontend/jaxws/src/main/java/org/apache/cxf/jaxws/JaxWsClientProxy.java Fri May 17 08:54:44 2013
@@ -28,6 +28,7 @@ import java.util.Map;
 import java.util.concurrent.Future;
 import java.util.logging.Logger;
 
+import javax.xml.namespace.QName;
 import javax.xml.soap.SOAPConstants;
 import javax.xml.soap.SOAPException;
 import javax.xml.soap.SOAPFault;
@@ -218,10 +219,12 @@ public class JaxWsClientProxy extends or
             if (role != null) {
                 soapFault.setFaultActor(role);
             }
-            if (((SoapFault)ex).getSubCode() != null 
+            if (((SoapFault)ex).getSubCodes() != null 
                 && !SOAPConstants.URI_NS_SOAP_1_1_ENVELOPE.equals(soapFault.getNamespaceURI())) {
                 // set the subcode only if it is supported (e.g, 1.2)
-                soapFault.appendFaultSubcode(((SoapFault)ex).getSubCode());
+                for (QName fsc : ((SoapFault)ex).getSubCodes()) {
+                    soapFault.appendFaultSubcode(fsc);    
+                }
             }
 
             if (((SoapFault)ex).hasDetails()) {