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