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