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 }