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.cxfbc.interceptors;
018
019 import java.util.ArrayList;
020 import java.util.Iterator;
021 import java.util.List;
022
023 import javax.xml.stream.XMLStreamException;
024 import javax.xml.stream.XMLStreamWriter;
025 import javax.xml.transform.Source;
026
027 import org.w3c.dom.Attr;
028 import org.w3c.dom.Element;
029 import org.w3c.dom.NamedNodeMap;
030 import org.w3c.dom.Node;
031 import org.w3c.dom.NodeList;
032
033 import org.apache.cxf.binding.soap.SoapMessage;
034 import org.apache.cxf.binding.soap.SoapVersion;
035 import org.apache.cxf.binding.soap.interceptor.AbstractSoapInterceptor;
036 import org.apache.cxf.binding.soap.model.SoapBindingInfo;
037 import org.apache.cxf.binding.soap.model.SoapHeaderInfo;
038 import org.apache.cxf.endpoint.Endpoint;
039 import org.apache.cxf.headers.Header;
040 import org.apache.cxf.helpers.NSStack;
041 import org.apache.cxf.interceptor.Fault;
042 import org.apache.cxf.message.Message;
043 import org.apache.cxf.phase.Phase;
044 import org.apache.cxf.service.model.BindingMessageInfo;
045 import org.apache.cxf.service.model.BindingOperationInfo;
046 import org.apache.cxf.service.model.MessagePartInfo;
047 import org.apache.cxf.staxutils.StaxUtils;
048 import org.apache.servicemix.jbi.jaxp.SourceTransformer;
049 import org.apache.servicemix.jbi.util.QNameUtil;
050 import org.apache.servicemix.soap.interceptors.jbi.JbiConstants;
051 import org.apache.servicemix.soap.util.DomUtil;
052
053
054
055
056 /**
057 * @author <a href="mailto:gnodet [at] gmail.com">Guillaume Nodet</a>
058 */
059 public class JbiOutWsdl1Interceptor extends AbstractSoapInterceptor {
060
061 private boolean useJBIWrapper = true;
062 private boolean useSOAPWrapper = true;
063
064 public JbiOutWsdl1Interceptor(boolean useJBIWrapper, boolean useSOAPWrapper) {
065 super(Phase.MARSHAL);
066 this.useJBIWrapper = useJBIWrapper;
067 this.useSOAPWrapper = useSOAPWrapper;
068 }
069
070 public void handleMessage(SoapMessage message) {
071 try {
072 Source source = message.getContent(Source.class);
073 if (source == null) {
074 return;
075 }
076
077 Element element = new SourceTransformer().toDOMElement(source);
078 XMLStreamWriter xmlWriter = message
079 .getContent(XMLStreamWriter.class);
080
081 if (!useJBIWrapper) {
082 SoapVersion soapVersion = message.getVersion();
083 if (element != null) {
084 // if this message is coming from the CxfBCConsumer
085 Element bodyElement = null;
086 if (useSOAPWrapper) {
087 bodyElement = (Element) element.getElementsByTagNameNS(
088 element.getNamespaceURI(),
089 soapVersion.getBody().getLocalPart()).item(0);
090 }
091 if (bodyElement != null) {
092 StaxUtils.writeElement((Element)bodyElement.getFirstChild(), xmlWriter, false);
093 } else {
094 // if this message is coming from the CxfBCProvider
095 StaxUtils.writeElement(element, xmlWriter, false);
096 }
097 }
098 return;
099 }
100
101 if (!JbiConstants.WSDL11_WRAPPER_NAMESPACE.equals(element
102 .getNamespaceURI())
103 || !JbiConstants.WSDL11_WRAPPER_MESSAGE_LOCALNAME
104 .equals(element.getLocalName())) {
105 throw new Fault(new Exception("Message wrapper element is '"
106 + QNameUtil.toString(element) + "' but expected '{"
107 + JbiConstants.WSDL11_WRAPPER_NAMESPACE + "}message'"));
108 }
109
110 //save namespace which is potentially used by the soap message
111 List<Attr> nsList = saveLaterUsedNS(element);
112 //add the saved namespace to the soap body
113 for (Attr attr : nsList) {
114 xmlWriter.writeAttribute(attr.getName(), attr.getValue());
115 }
116
117 BindingOperationInfo bop = message.getExchange().get(
118 BindingOperationInfo.class);
119 if (bop == null) {
120 throw new Fault(
121 new Exception("Operation not bound on this message"));
122 }
123 BindingMessageInfo msg = isRequestor(message) ? bop.getInput()
124 : bop.getOutput();
125
126
127 SoapBindingInfo binding = (SoapBindingInfo) message.getExchange()
128 .get(Endpoint.class).getEndpointInfo().getBinding();
129 String style = binding.getStyle(bop.getOperationInfo());
130 if (style == null) {
131 style = binding.getStyle();
132 }
133
134 if ("rpc".equals(style)) {
135 addOperationNode(message, xmlWriter);
136 getRPCPartWrapper(msg, element, message, xmlWriter);
137 } else {
138 Element partWrapper = DomUtil.getFirstChildElement(element);
139 while (partWrapper != null) {
140 List<NodeList> partsContent = getPartsContent(message, element, partWrapper, msg);
141 for (NodeList nl : partsContent) {
142 for (int i = 0; i < nl.getLength(); i++) {
143 Node n = nl.item(i);
144 StaxUtils.writeNode(n, xmlWriter, false);
145 }
146 }
147 partWrapper = DomUtil.getNextSiblingElement(partWrapper);
148 }
149 }
150
151 if ("rpc".equals(style)) {
152 xmlWriter.writeEndElement();
153 }
154
155 } catch (Fault e) {
156 throw e;
157 } catch (Exception e) {
158 throw new Fault(e);
159 }
160 }
161
162 private List<Attr> saveLaterUsedNS(Element element) {
163 List<Attr> nsList = new ArrayList<Attr>();
164 NamedNodeMap attributes = element.getAttributes();
165 for (int i = 0; i < attributes.getLength(); i++) {
166 if (attributes.item(i) instanceof Attr) {
167 Attr attr = (Attr) attributes.item(i);
168 if (attr.getName().startsWith("xmlns:")
169 && !(attr.getName().startsWith("xmlns:" + JbiConstants.WSDL11_WRAPPER_MESSAGE_PREFIX)
170 || attr.getName().startsWith("xmlns:" + JbiConstants.WSDL11_WRAPPER_PREFIX))) {
171 nsList.add(attr);
172 }
173 }
174 }
175 return nsList;
176 }
177
178
179
180 private void getRPCPartWrapper(BindingMessageInfo msg,
181 Element element,
182 SoapMessage message,
183 XMLStreamWriter xmlWriter) {
184 try {
185 List<MessagePartInfo> parts = msg.getMessageParts();
186 Iterator iter = parts.iterator();
187 Element partWrapper = DomUtil.getFirstChildElement(element);
188 while (partWrapper != null) {
189 MessagePartInfo msgPart = (MessagePartInfo) iter.next();
190 String prefix = msgPart.getName().getPrefix();
191 String name = msgPart.getName().getLocalPart();
192 StaxUtils.writeStartElement(xmlWriter, prefix, name, "");
193 List<NodeList> partsContent = getPartsContent(message, element,
194 partWrapper, msg);
195 for (NodeList nl : partsContent) {
196 for (int i = 0; i < nl.getLength(); i++) {
197 Node n = nl.item(i);
198 StaxUtils.writeNode(n, xmlWriter, false);
199 }
200 }
201 xmlWriter.writeEndElement();
202 partWrapper = DomUtil.getNextSiblingElement(partWrapper);
203 }
204 } catch (Fault e) {
205 throw e;
206 } catch (Exception e) {
207 throw new Fault(e);
208 }
209 }
210
211 // Get each parts content
212 private List<NodeList> getPartsContent(SoapMessage message,
213 Element element,
214 Element partWrapper,
215 BindingMessageInfo msg) {
216 List<NodeList> partsContent = new ArrayList<NodeList>();
217 if (partWrapper != null) {
218 if (!JbiConstants.WSDL11_WRAPPER_NAMESPACE.equals(element.getNamespaceURI())
219 || !JbiConstants.WSDL11_WRAPPER_PART_LOCALNAME
220 .equals(partWrapper.getLocalName())) {
221 throw new Fault(new Exception(
222 "Unexpected part wrapper element '"
223 + QNameUtil.toString(element)
224 + "' expected '{"
225 + JbiConstants.WSDL11_WRAPPER_NAMESPACE
226 + "}part'"));
227 }
228 NodeList nodes = partWrapper.getChildNodes();
229 partsContent.add(nodes);
230 }
231
232 List<Header> headerList = message.getHeaders();
233 List<SoapHeaderInfo> headers = msg.getExtensors(SoapHeaderInfo.class);
234 for (SoapHeaderInfo header : headers) {
235 if (partsContent.size() == 0) {
236 break;
237 }
238 NodeList nl = partsContent.get(0);
239 if (header.getPart().getConcreteName().getNamespaceURI().equals(nl.item(0).getNamespaceURI())
240 && header.getPart().getConcreteName().getLocalPart().equals(nl.item(0).getLocalName())) {
241 headerList.add(new Header(header.getPart().getConcreteName(),
242 nl.item(0)));
243 partsContent.remove(0);
244 }
245
246 }
247
248 return partsContent;
249 }
250
251
252 protected String addOperationNode(Message message, XMLStreamWriter xmlWriter)
253 throws XMLStreamException {
254 String responseSuffix = !isRequestor(message) ? "Response" : "";
255 BindingOperationInfo boi = message.getExchange().get(
256 BindingOperationInfo.class);
257 String ns = boi.getName().getNamespaceURI();
258 NSStack nsStack = new NSStack();
259 nsStack.push();
260 nsStack.add(ns);
261 String prefix = nsStack.getPrefix(ns);
262 StaxUtils.writeStartElement(xmlWriter, prefix, boi.getName()
263 .getLocalPart()
264 + responseSuffix, ns);
265 return ns;
266 }
267
268 }