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