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                if (partsContent.size() == 0) {
141                    break;
142                }
143                NodeList nl = partsContent.get(0);
144                if (header.getPart().getConcreteName().getNamespaceURI().equals(
145                        nl.item(0).getNamespaceURI())
146                        && header.getPart().getConcreteName().getLocalPart()
147                                .equals(nl.item(0).getLocalName())) {
148                    headerList.add(new Header(header.getPart().getConcreteName(),
149                            nl.item(0)));
150                    partsContent.remove(0);
151                }
152    
153            }
154    
155        }
156    
157        /**
158         * Copy NormalizedMessage attachments to SoapMessage attachments
159         */
160        private void fromNMSAttachments(Message message,
161                NormalizedMessage normalizedMessage) {
162            Set attachmentNames = normalizedMessage.getAttachmentNames();
163            Collection<Attachment> attachmentList = new ArrayList<Attachment>();
164            for (Iterator it = attachmentNames.iterator(); it.hasNext();) {
165                String id = (String) it.next();
166                DataHandler handler = normalizedMessage.getAttachment(id);
167                Attachment attachment = new AttachmentImpl(id, handler);
168                attachmentList.add(attachment);
169            }
170            message.setAttachments(attachmentList);
171            
172            if (message instanceof SoapMessage) {
173                SoapMessage soapMessage = (SoapMessage)message;
174                SoapVersion soapVersion = soapMessage.getVersion();
175                message.put(Message.CONTENT_TYPE, soapVersion.getContentType());
176            }
177            if (attachmentList.size() > 0) {
178                message.put(org.apache.cxf.message.Message.MTOM_ENABLED, true);
179                message.put("write.attachments", true);
180                message.getInterceptorChain().add(new AttachmentOutInterceptor());
181            }
182            
183        }
184    
185        /**
186         * Copy NormalizedMessage headers to SoapMessage headers
187         */
188        @SuppressWarnings("unchecked")
189        private void fromNMSHeaders(Message message,
190                NormalizedMessage normalizedMessage) {
191    
192            if (message instanceof SoapMessage) {
193    
194                Map<String, String> map = (Map<String, String>) normalizedMessage
195                        .getProperty(WSAUtils.WSA_HEADERS_OUTBOUND);
196    
197                if (map != null) {
198                    AddressingProperties addressingProperties = WSAUtils
199                            .getCXFAddressingPropertiesFromMap(map);
200                    ((SoapMessage) message).put(WSAUtils.WSA_HEADERS_OUTBOUND,
201                            addressingProperties);
202                }
203            }
204    
205            if (normalizedMessage.getProperty(JbiConstants.PROTOCOL_HEADERS) != null) {
206                Map<String, ?> headers = (Map<String, ?>) normalizedMessage
207                        .getProperty(JbiConstants.PROTOCOL_HEADERS);
208                for (Map.Entry<String, ?> entry : headers.entrySet()) {
209                    QName name = QNameUtil.parse(entry.getKey());
210                    if (name != null) {
211    
212                        Header header = new Header(name, entry.getValue());
213    
214                        if (message instanceof SoapMessage) {
215                            List<Header> headerList = ((SoapMessage) message)
216                                    .getHeaders();
217                            headerList.add(header);
218                        }
219    
220                    }
221                }
222            }
223            
224            
225        }
226    
227        private boolean isRequestor(org.apache.cxf.message.Message message) {
228            return Boolean.TRUE.equals(message
229                    .containsKey(org.apache.cxf.message.Message.REQUESTOR_ROLE));
230        }
231    
232    }