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    }