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.net.URI;
020 import java.util.HashMap;
021 import java.util.Map;
022
023 import javax.jbi.JBIException;
024 import javax.jbi.component.ComponentContext;
025 import javax.jbi.messaging.DeliveryChannel;
026 import javax.jbi.messaging.MessageExchange;
027 import javax.jbi.messaging.MessageExchangeFactory;
028 import javax.jbi.messaging.MessagingException;
029 import javax.jbi.messaging.NormalizedMessage;
030 import javax.security.auth.Subject;
031 import javax.xml.namespace.QName;
032 import javax.xml.transform.Source;
033
034 import org.apache.cxf.binding.soap.SoapMessage;
035 import org.apache.cxf.headers.Header;
036 import org.apache.cxf.interceptor.Fault;
037 import org.apache.cxf.message.Attachment;
038 import org.apache.cxf.message.Message;
039 import org.apache.cxf.phase.AbstractPhaseInterceptor;
040 import org.apache.cxf.phase.Phase;
041 import org.apache.cxf.service.model.BindingOperationInfo;
042 import org.apache.cxf.ws.addressing.AddressingProperties;
043 import org.apache.servicemix.cxfbc.WSAUtils;
044 import org.apache.servicemix.soap.util.QNameUtil;
045
046 /**
047 * @author <a href="mailto:gnodet [at] gmail.com">Guillaume Nodet</a>
048 */
049 public class JbiInInterceptor extends AbstractPhaseInterceptor<Message> {
050
051 public static final String OPERATION_MEP = "MEP";
052
053 public JbiInInterceptor() {
054 super(Phase.PRE_INVOKE);
055 }
056
057 public void handleMessage(Message message) {
058 try {
059 MessageExchange exchange;
060 NormalizedMessage nm;
061 // Create message
062 if (!isRequestor(message)) {
063 exchange = createExchange(message);
064 nm = exchange.createMessage();
065 exchange.setMessage(nm, "in");
066 message.setContent(MessageExchange.class, exchange);
067 } else {
068 exchange = message.getContent(MessageExchange.class);
069 if (exchange == null) {
070 throw new IllegalStateException("Content of type "
071 + MessageExchange.class + " not found on message");
072 }
073 if (message.getContent(Exception.class) == null) {
074 nm = exchange.createMessage();
075 exchange.setMessage(nm, "out");
076 } else {
077 exchange.setFault(exchange.createFault());
078 nm = exchange.getFault();
079 }
080 }
081 // Put headers
082 toNMSHeaders(nm, message);
083
084 // copy wsa headers if present
085 toNMSWSAHeaders(nm, message);
086
087 // Put attachments
088 toNMSAttachments(nm, message);
089 // Put subject
090 nm.setSecuritySubject(message.get(Subject.class));
091 // Put main source
092 getContent(nm, message);
093 // Register new content
094 message.setContent(NormalizedMessage.class, nm);
095 } catch (JBIException e) {
096 throw new Fault(e);
097 }
098 }
099
100 /**
101 * Create the JBI exchange
102 */
103 private MessageExchange createExchange(Message message) throws JBIException {
104 URI mep;
105 BindingOperationInfo operation = message.getExchange().get(
106 BindingOperationInfo.class);
107 if (operation != null) {
108 if (operation.getOutput() == null) {
109 mep = CxfJbiConstants.IN_ONLY;
110 } else {
111 mep = CxfJbiConstants.IN_OUT;
112 }
113 } else {
114 mep = (URI) message.get(OPERATION_MEP);
115 }
116 if (mep == null) {
117 throw new NullPointerException("MEP not found");
118 }
119 MessageExchangeFactory mef = message.getExchange().get(
120 MessageExchangeFactory.class);
121 if (mef == null) {
122 DeliveryChannel dv = message.getExchange().get(
123 DeliveryChannel.class);
124 if (dv == null) {
125 ComponentContext cc = message.getExchange().get(
126 ComponentContext.class);
127 if (cc == null) {
128 throw new NullPointerException(
129 "MessageExchangeFactory or DeliveryChannel or ComponentContext not found");
130 }
131 dv = cc.getDeliveryChannel();
132 }
133 mef = dv.createExchangeFactory();
134 }
135 MessageExchange me = mef.createExchange(mep);
136 me.setOperation(operation.getName());
137 return me;
138 }
139
140 private void toNMSWSAHeaders(NormalizedMessage normalizedMessage,
141 Message soapMessage) {
142 SoapMessage message = null;
143 if (!(soapMessage instanceof SoapMessage)) {
144 return;
145 } else {
146 message = (SoapMessage) soapMessage;
147 }
148
149 if (message.get(WSAUtils.WSA_HEADERS_INBOUND) != null) {
150 normalizedMessage.setProperty(WSAUtils.WSA_HEADERS_INBOUND,
151 WSAUtils.getAsMap((AddressingProperties) message
152 .get(WSAUtils.WSA_HEADERS_INBOUND)));
153 }
154
155 }
156
157 /**
158 * Convert SoapMessage headers to NormalizedMessage headers
159 */
160 private void toNMSHeaders(NormalizedMessage normalizedMessage,
161 Message soapMessage) {
162 SoapMessage message = null;
163 if (!(soapMessage instanceof SoapMessage)) {
164 return;
165 } else {
166 message = (SoapMessage) soapMessage;
167 }
168 Map<String, Object> headers = new HashMap<String, Object>();
169 QName excludeName = new QName(
170 "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd",
171 "Security");
172 for (Header header : message.getHeaders()) {
173 if (!header.getName().equals(excludeName)) {
174 // We must exclude this security header since in Sun's SAAJ impl, the ElementImpl
175 // has a field which doesn't implement Serializable interface, which will cause
176 //java.io.NotSerializableException when we try to serialize the JBI message.
177 // And this security header isn't necessary inside jbi container since we have already
178 // delegate the AA to JAAS at this stage.
179 // SM-1696 track this issue
180 headers.put(QNameUtil.toString(header.getName()), header
181 .getObject());
182 }
183 }
184
185 normalizedMessage.setProperty(CxfJbiConstants.PROTOCOL_HEADERS, headers);
186
187 }
188
189 /**
190 * Convert SoapMessage attachments to NormalizedMessage attachments
191 */
192 private void toNMSAttachments(NormalizedMessage normalizedMessage,
193 Message soapMessage) throws MessagingException {
194 if (soapMessage.getAttachments() != null) {
195 for (Attachment att : soapMessage.getAttachments()) {
196 normalizedMessage.addAttachment(att.getId(), att
197 .getDataHandler());
198 }
199 }
200 }
201
202 /**
203 * Extract the content as a jaxp Source
204 */
205 private void getContent(NormalizedMessage nm, Message message)
206 throws MessagingException {
207 Exception e = message.getContent(Exception.class);
208 if (e == null) {
209 nm.setContent(message.getContent(Source.class));
210 /*
211 * } else if (e instanceof SoapFault) { SoapFault fault =
212 * (SoapFault) e; nm.setContent(fault.getDetails());
213 * nm.setProperty(JbiConstants.SOAP_FAULT_CODE, fault.getCode());
214 * nm.setProperty(JbiConstants.SOAP_FAULT_NODE, fault.getNode());
215 * nm.setProperty(JbiConstants.SOAP_FAULT_REASON,
216 * fault.getReason()); nm.setProperty(JbiConstants.SOAP_FAULT_ROLE,
217 * fault.getRole()); nm.setProperty(JbiConstants.SOAP_FAULT_SUBCODE,
218 * fault.getSubcode());
219 */
220 }
221 }
222
223 protected boolean isRequestor(Message message) {
224 return Boolean.TRUE.equals(message.get(Message.REQUESTOR_ROLE));
225 }
226
227 }