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    }