001 /*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements. See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License. You may obtain a copy of the License at
008 *
009 * http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017 package org.apache.servicemix.soap.bindings.soap.interceptors;
018
019 import java.net.URI;
020
021 import javax.xml.namespace.QName;
022 import javax.xml.stream.XMLStreamConstants;
023 import javax.xml.stream.XMLStreamReader;
024 import javax.xml.transform.Source;
025 import javax.xml.transform.dom.DOMSource;
026
027 import org.apache.servicemix.soap.api.Message;
028 import org.apache.servicemix.soap.bindings.soap.SoapConstants;
029 import org.apache.servicemix.soap.bindings.soap.SoapFault;
030 import org.apache.servicemix.soap.bindings.soap.SoapVersion;
031 import org.apache.servicemix.soap.core.AbstractInterceptor;
032 import org.apache.servicemix.soap.util.DomUtil;
033 import org.apache.servicemix.soap.util.stax.StaxUtil;
034 import org.w3c.dom.Element;
035
036 /**
037 * @author <a href="mailto:gnodet [at] gmail.com">Guillaume Nodet</a>
038 */
039 public class SoapFaultInInterceptor extends AbstractInterceptor {
040
041 public void handleMessage(Message message) {
042 XMLStreamReader xmlReader = message.getContent(XMLStreamReader.class);
043 if (xmlReader == null || xmlReader.getEventType() != XMLStreamConstants.START_ELEMENT) {
044 return;
045 }
046 SoapVersion soapVersion = message.get(SoapVersion.class);
047 if (!soapVersion.getFault().equals(xmlReader.getName())) {
048 return;
049 }
050 // Read fault as DOM
051 Element el = StaxUtil.createElement(xmlReader);
052 SoapFault fault = readFault(el);
053 message.setContent(Exception.class, fault);
054 }
055
056 private SoapFault readFault(Element element) throws SoapFault {
057 QName code = null;
058 QName subcode = null;
059 String reason = null;
060 URI node = null;
061 URI role = null;
062 Source details = null;
063 // Parse soap 1.1 faults
064 if (SoapConstants.SOAP_11_URI.equals(element.getNamespaceURI())) {
065 // Fault code
066 Element child = DomUtil.getFirstChildElement(element);
067 checkElementName(child, SoapConstants.SOAP_11_FAULTCODE);
068 code = DomUtil.createQName(child, DomUtil.getElementText(child));
069 // Fault string
070 child = DomUtil.getNextSiblingElement(child);
071 checkElementName(child, SoapConstants.SOAP_11_FAULTSTRING);
072 reason = DomUtil.getElementText(child);
073 child = DomUtil.getNextSiblingElement(child);
074 QName childname = DomUtil.getQName(child);
075 // Fault actor
076 if (SoapConstants.SOAP_11_FAULTACTOR.equals(childname)) {
077 node = URI.create(DomUtil.getElementText(child));
078 child = DomUtil.getNextSiblingElement(child);
079 childname = DomUtil.getQName(child);
080 }
081 // Fault details
082 if (SoapConstants.SOAP_11_FAULTDETAIL.equals(childname)) {
083 Element subchild = DomUtil.getFirstChildElement(child);
084 if (subchild != null) {
085 details = new DOMSource(subchild);
086 subchild = DomUtil.getNextSiblingElement(subchild);
087 if (subchild != null) {
088 throw new SoapFault(SoapFault.RECEIVER, "Multiple elements are not supported in Detail");
089 }
090 }
091 child = DomUtil.getNextSiblingElement(child);
092 childname = DomUtil.getQName(child);
093 }
094 // Nothing should be left
095 if (childname != null) {
096 throw new SoapFault(SoapFault.SENDER, "Unexpected element: " + childname);
097 }
098 // Parse soap 1.2 faults
099 } else {
100 // Fault code
101 Element child = DomUtil.getFirstChildElement(element);
102 checkElementName(child, SoapConstants.SOAP_12_FAULTCODE);
103 Element subchild = DomUtil.getFirstChildElement(child);
104 checkElementName(subchild, SoapConstants.SOAP_12_FAULTVALUE);
105 code = DomUtil.createQName(subchild, DomUtil.getElementText(subchild));
106 if (!SoapConstants.SOAP_12_CODE_DATAENCODINGUNKNOWN.equals(code) &&
107 !SoapConstants.SOAP_12_CODE_MUSTUNDERSTAND.equals(code) &&
108 !SoapConstants.SOAP_12_CODE_RECEIVER.equals(code) &&
109 !SoapConstants.SOAP_12_CODE_SENDER.equals(code) &&
110 !SoapConstants.SOAP_12_CODE_VERSIONMISMATCH.equals(code)) {
111 throw new SoapFault(SoapFault.SENDER, "Unexpected fault code: " + code);
112 }
113 subchild = DomUtil.getNextSiblingElement(subchild);
114 if (subchild != null) {
115 checkElementName(subchild, SoapConstants.SOAP_12_FAULTSUBCODE);
116 Element subsubchild = DomUtil.getFirstChildElement(subchild);
117 checkElementName(subsubchild, SoapConstants.SOAP_12_FAULTVALUE);
118 subcode = DomUtil.createQName(subsubchild, DomUtil.getElementText(subsubchild));
119 subsubchild = DomUtil.getNextSiblingElement(subsubchild);
120 if (subsubchild != null) {
121 checkElementName(subsubchild, SoapConstants.SOAP_12_FAULTSUBCODE);
122 throw new SoapFault(SoapFault.RECEIVER, "Unsupported nested subcodes");
123 }
124 }
125 // Fault reason
126 child = DomUtil.getNextSiblingElement(child);
127 checkElementName(child, SoapConstants.SOAP_12_FAULTREASON);
128 subchild = DomUtil.getFirstChildElement(child);
129 checkElementName(subchild, SoapConstants.SOAP_12_FAULTTEXT);
130 reason = DomUtil.getElementText(subchild);
131 subchild = DomUtil.getNextSiblingElement(subchild);
132 if (subchild != null) {
133 throw new SoapFault(SoapFault.RECEIVER, "Unsupported multiple reasons");
134 }
135 // Fault node
136 child = DomUtil.getNextSiblingElement(child);
137 QName childname = DomUtil.getQName(child);
138 if (SoapConstants.SOAP_12_FAULTNODE.equals(childname)) {
139 node = URI.create(DomUtil.getElementText(child));
140 child = DomUtil.getNextSiblingElement(child);
141 childname = DomUtil.getQName(child);
142 }
143 // Fault role
144 if (SoapConstants.SOAP_12_FAULTROLE.equals(childname)) {
145 role = URI.create(DomUtil.getElementText(child));
146 child = DomUtil.getNextSiblingElement(child);
147 childname = DomUtil.getQName(child);
148 }
149 // Fault details
150 if (SoapConstants.SOAP_12_FAULTDETAIL.equals(childname)) {
151 subchild = DomUtil.getFirstChildElement(child);
152 if (subchild != null) {
153 details = new DOMSource(subchild);
154 subchild = DomUtil.getNextSiblingElement(subchild);
155 if (subchild != null) {
156 throw new SoapFault(SoapFault.RECEIVER, "Multiple elements are not supported in Detail");
157 }
158 }
159 child = DomUtil.getNextSiblingElement(child);
160 childname = DomUtil.getQName(child);
161 }
162 // Nothing should be left
163 if (childname != null) {
164 throw new SoapFault(SoapFault.SENDER, "Unexpected element: " + childname);
165 }
166 }
167 return new SoapFault(code, subcode, reason, node, role, details);
168 }
169
170 private void checkElementName(Element element, QName expected) throws SoapFault {
171 QName name= DomUtil.getQName(element);
172 if (!expected.equals(name)) {
173 throw new SoapFault(SoapFault.SENDER, "Expected element: " + expected + " but found " + name);
174 }
175 }
176
177 }