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.Collection;
021    import java.util.Iterator;
022    import java.util.List;
023    import java.util.Map;
024    import java.util.Set;
025    
026    import javax.activation.DataHandler;
027    import javax.jbi.messaging.MessageExchange;
028    import javax.jbi.messaging.NormalizedMessage;
029    import javax.xml.namespace.QName;
030    import javax.xml.transform.Source;
031    import javax.xml.transform.dom.DOMSource;
032    import org.w3c.dom.Element;
033    import org.w3c.dom.NodeList;
034    import org.apache.cxf.attachment.AttachmentImpl;
035    import org.apache.cxf.binding.soap.SoapMessage;
036    import org.apache.cxf.binding.soap.SoapVersion;
037    import org.apache.cxf.binding.soap.model.SoapBindingInfo;
038    import org.apache.cxf.binding.soap.model.SoapHeaderInfo;
039    import org.apache.cxf.endpoint.Endpoint;
040    import org.apache.cxf.headers.Header;
041    import org.apache.cxf.interceptor.AttachmentOutInterceptor;
042    import org.apache.cxf.interceptor.Fault;
043    import org.apache.cxf.message.Attachment;
044    import org.apache.cxf.message.Message;
045    import org.apache.cxf.phase.AbstractPhaseInterceptor;
046    import org.apache.cxf.phase.Phase;
047    import org.apache.cxf.service.model.BindingMessageInfo;
048    import org.apache.cxf.service.model.BindingOperationInfo;
049    import org.apache.cxf.ws.addressing.AddressingProperties;
050    import org.apache.servicemix.cxfbc.WSAUtils;
051    import org.apache.servicemix.jbi.jaxp.SourceTransformer;
052    import org.apache.servicemix.soap.interceptors.jbi.JbiConstants;
053    import org.apache.servicemix.soap.util.DomUtil;
054    import org.apache.servicemix.soap.util.QNameUtil;
055    
056    
057    public class JbiOutInterceptor extends AbstractPhaseInterceptor<Message> {
058    
059        public JbiOutInterceptor() {
060            super(Phase.PRE_STREAM);
061        }
062    
063        public void handleMessage(Message message) {
064            MessageExchange me = message.get(MessageExchange.class);
065            if (me == null) {
066                me = message.getContent(MessageExchange.class);
067            }
068            NormalizedMessage nm = me.getMessage("in");
069            fromNMSAttachments(message, nm);
070            fromNMSHeaders(message, nm);
071            extractHeaderFromMessagePart(message);
072        }
073    
074        private void extractHeaderFromMessagePart(Message message) {
075            Source source = message.getContent(Source.class);
076            if (source == null) {
077                return;
078            }
079    
080            Element element;
081            try {
082                element = new SourceTransformer().toDOMElement(source);
083            } catch (Exception e) {
084                throw new Fault(e);
085            }
086    
087            if (!JbiConstants.WSDL11_WRAPPER_NAMESPACE.equals(element
088                    .getNamespaceURI())
089                    || !JbiConstants.WSDL11_WRAPPER_MESSAGE_LOCALNAME
090                            .equals(element.getLocalName())) {
091                message.setContent(Source.class, new DOMSource(element));
092                return;
093            }
094    
095            BindingOperationInfo bop = message.getExchange().get(
096                    BindingOperationInfo.class);
097            if (bop == null) {
098                throw new Fault(
099                        new Exception("Operation not bound on this message"));
100            }
101            BindingMessageInfo msg = isRequestor(message) ? bop.getInput() : bop
102                    .getOutput();
103    
104            SoapBindingInfo binding = (SoapBindingInfo) message.getExchange().get(
105                    Endpoint.class).getEndpointInfo().getBinding();
106            String style = binding.getStyle(bop.getOperationInfo());
107            if (style == null) {
108                style = binding.getStyle();
109            }
110    
111            Element partWrapper = DomUtil.getFirstChildElement(element);
112            while (partWrapper != null) {
113                extractHeaderParts((SoapMessage) message, element, partWrapper, msg);
114                partWrapper = DomUtil.getNextSiblingElement(partWrapper);
115            }
116            message.setContent(Source.class, new DOMSource(element));
117        }
118    
119        private void extractHeaderParts(SoapMessage message,
120                Element element, Element partWrapper, BindingMessageInfo msg) {
121            List<NodeList> partsContent = new ArrayList<NodeList>();
122            if (partWrapper != null) {
123                if (!JbiConstants.WSDL11_WRAPPER_NAMESPACE.equals(element
124                        .getNamespaceURI())
125                        || !JbiConstants.WSDL11_WRAPPER_PART_LOCALNAME
126                                .equals(partWrapper.getLocalName())) {
127                    throw new Fault(new Exception(
128                            "Unexpected part wrapper element '"
129                                    + QNameUtil.toString(element) + "' expected '{"
130                                    + JbiConstants.WSDL11_WRAPPER_NAMESPACE
131                                    + "}part'"));
132                }
133                NodeList nodes = partWrapper.getChildNodes();
134                partsContent.add(nodes);
135            }
136    
137            List<Header> headerList = message.getHeaders();
138            List<SoapHeaderInfo> headers = msg.getExtensors(SoapHeaderInfo.class);
139            for (SoapHeaderInfo header : headers) {
140                NodeList nl = partsContent.get(0);
141                if (header.getPart().getConcreteName().getNamespaceURI().equals(
142                        nl.item(0).getNamespaceURI())
143                        && header.getPart().getConcreteName().getLocalPart()
144                                .equals(nl.item(0).getLocalName())) {
145                    headerList.add(new Header(header.getPart().getConcreteName(),
146                            nl.item(0)));
147                    partsContent.remove(0);
148                }
149    
150            }
151    
152        }
153    
154        /**
155         * Copy NormalizedMessage attachments to SoapMessage attachments
156         */
157        private void fromNMSAttachments(Message message,
158                NormalizedMessage normalizedMessage) {
159            Set attachmentNames = normalizedMessage.getAttachmentNames();
160            Collection<Attachment> attachmentList = new ArrayList<Attachment>();
161            for (Iterator it = attachmentNames.iterator(); it.hasNext();) {
162                String id = (String) it.next();
163                DataHandler handler = normalizedMessage.getAttachment(id);
164                Attachment attachment = new AttachmentImpl(id, handler);
165                attachmentList.add(attachment);
166            }
167            message.setAttachments(attachmentList);
168            
169            if (message instanceof SoapMessage) {
170                SoapMessage soapMessage = (SoapMessage)message;
171                SoapVersion soapVersion = soapMessage.getVersion();
172                message.put(Message.CONTENT_TYPE, soapVersion.getContentType());
173            }
174            if (attachmentList.size() > 0) {
175                message.put(org.apache.cxf.message.Message.MTOM_ENABLED, true);
176                message.put("write.attachments", true);
177                message.getInterceptorChain().add(new AttachmentOutInterceptor());
178            }
179            
180        }
181    
182        /**
183         * Copy NormalizedMessage headers to SoapMessage headers
184         */
185        @SuppressWarnings("unchecked")
186        private void fromNMSHeaders(Message message,
187                NormalizedMessage normalizedMessage) {
188    
189            if (message instanceof SoapMessage) {
190    
191                Map<String, String> map = (Map<String, String>) normalizedMessage
192                        .getProperty(WSAUtils.WSA_HEADERS_OUTBOUND);
193    
194                if (map != null) {
195                    AddressingProperties addressingProperties = WSAUtils
196                            .getCXFAddressingPropertiesFromMap(map);
197                    ((SoapMessage) message).put(WSAUtils.WSA_HEADERS_OUTBOUND,
198                            addressingProperties);
199                }
200            }
201    
202            if (normalizedMessage.getProperty(JbiConstants.PROTOCOL_HEADERS) != null) {
203                Map<String, ?> headers = (Map<String, ?>) normalizedMessage
204                        .getProperty(JbiConstants.PROTOCOL_HEADERS);
205                for (Map.Entry<String, ?> entry : headers.entrySet()) {
206                    QName name = QNameUtil.parse(entry.getKey());
207                    if (name != null) {
208    
209                        Header header = new Header(name, entry.getValue());
210    
211                        if (message instanceof SoapMessage) {
212                            List<Header> headerList = ((SoapMessage) message)
213                                    .getHeaders();
214                            headerList.add(header);
215                        }
216    
217                    }
218                }
219            }
220            
221            
222        }
223    
224        private boolean isRequestor(org.apache.cxf.message.Message message) {
225            return Boolean.TRUE.equals(message
226                    .containsKey(org.apache.cxf.message.Message.REQUESTOR_ROLE));
227        }
228    
229    }