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.camel.component.cxf.common.header;
018    
019    import java.util.ArrayList;
020    import java.util.List;
021    import java.util.Map;
022    import java.util.TreeMap;
023    
024    import org.apache.camel.Exchange;
025    import org.apache.camel.spi.HeaderFilterStrategy;
026    import org.apache.cxf.endpoint.Client;
027    import org.apache.cxf.helpers.CastUtils;
028    import org.apache.cxf.message.Message;
029    
030    /**
031     * Utility class to propagate headers to and from CXF message.
032     *
033     * @version 
034     */
035    public final class CxfHeaderHelper {
036    
037        /**
038         * Utility class does not have public constructor
039         */
040        private CxfHeaderHelper() {
041        }
042    
043        /**
044         * Propagates Camel headers to CXF message.
045         *
046         * @param strategy header filter strategy
047         * @param headers Camel header
048         * @param message CXF message
049         * @param exchange provides context for filtering
050         */
051        public static void propagateCamelToCxf(HeaderFilterStrategy strategy,
052                Map<String, Object> headers, Message message, Exchange exchange) {
053    
054            Map<String, List<String>> cxfHeaders =
055                CastUtils.cast((Map<?, ?>)message.get(Message.PROTOCOL_HEADERS));
056    
057            if (cxfHeaders == null) {
058                // use a treemap to keep ordering and ignore key case
059                cxfHeaders = new TreeMap<String, List<String>>(String.CASE_INSENSITIVE_ORDER);
060                message.put(Message.PROTOCOL_HEADERS, cxfHeaders);
061            }
062    
063            for (Map.Entry<String, Object> entry : headers.entrySet()) {
064                if (strategy != null
065                        && !strategy.applyFilterToCamelHeaders(entry.getKey(), entry.getValue(), exchange)) {
066    
067                    if (Exchange.CONTENT_TYPE.equals(entry.getKey())) {
068                        message.put(Message.CONTENT_TYPE, entry.getValue());
069                    } else if (Client.REQUEST_CONTEXT.equals(entry.getKey())
070                                || Client.RESPONSE_CONTEXT.equals(entry.getKey())
071                                || Message.RESPONSE_CODE.equals(entry.getKey())) {
072                        message.put(entry.getKey(), entry.getValue());
073                    } else {
074                        List<String> listValue = new ArrayList<String>();
075                        listValue.add(entry.getValue().toString());
076                        cxfHeaders.put(entry.getKey(), listValue);
077                    }
078                }
079            }
080        }
081    
082        public static void propagateCxfToCamel(HeaderFilterStrategy strategy,
083                Message message, Map<String, Object> headers, Exchange exchange) {
084    
085            if (strategy == null) {
086                return;
087            }
088    
089            // Copy the CXF protocol headers to the camel headers
090            Map<String, List<String>> cxfHeaders =
091                CastUtils.cast((Map<?, ?>)message.get(Message.PROTOCOL_HEADERS));
092            if (cxfHeaders != null) {
093                for (Map.Entry<String, List<String>> entry : cxfHeaders.entrySet()) {
094                    if (!strategy.applyFilterToExternalHeaders(entry.getKey(), entry.getValue(), exchange)) {
095                        headers.put(entry.getKey(), entry.getValue().get(0));
096                    }
097                }
098            }
099    
100            // propagate content type with the encoding information
101            // We need to do it as the CXF does this kind of thing in transport level
102            String key = Message.CONTENT_TYPE;
103            Object value = determineContentType(message);
104            
105            if (value != null && !strategy.applyFilterToExternalHeaders(key, value, exchange)) {
106                headers.put(Exchange.CONTENT_TYPE, value);
107            }
108    
109            // propagate request context
110            key = Client.REQUEST_CONTEXT;
111            value = message.get(key);
112            if (value != null && !strategy.applyFilterToExternalHeaders(key, value, exchange)) {
113                headers.put(key, value);
114            }
115    
116            // propagate response context
117            key = Client.RESPONSE_CONTEXT;
118            value = message.get(key);
119            if (value != null && !strategy.applyFilterToExternalHeaders(key, value, exchange)) {
120                headers.put(key, value);
121            }
122            
123            // propagate response code
124            key = Message.RESPONSE_CODE;
125            value = message.get(key);
126            if (value != null && !strategy.applyFilterToExternalHeaders(key, value, exchange)) {
127                headers.put(Exchange.HTTP_RESPONSE_CODE, value);
128            }
129        }
130        
131        private static String determineContentType(Message message) {
132            String ct  = (String)message.get(Message.CONTENT_TYPE);
133            String enc = (String)message.get(Message.ENCODING);
134    
135            if (null != ct) {
136                if (enc != null 
137                    && ct.indexOf("charset=") == -1
138                    && !ct.toLowerCase().contains("multipart/related")) {
139                    ct = ct + "; charset=" + enc;
140                }
141            } else if (enc != null) {
142                ct = "text/xml; charset=" + enc;
143            } else {
144                ct = "text/xml";
145            }
146            // update the content_type value in the message
147            message.put(Message.CONTENT_TYPE, ct);
148            return ct;
149        }
150    
151    }