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