PageRenderTime 51ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 0ms

/components/camel-cxf-transport/src/main/java/org/apache/camel/component/cxf/common/header/CxfHeaderHelper.java

https://gitlab.com/matticala/apache-camel
Java | 312 lines | 201 code | 41 blank | 70 comment | 50 complexity | 45961420dc94955d096f9098e08fdf2b MD5 | raw file
  1. /**
  2. * Licensed to the Apache Software Foundation (ASF) under one or more
  3. * contributor license agreements. See the NOTICE file distributed with
  4. * this work for additional information regarding copyright ownership.
  5. * The ASF licenses this file to You under the Apache License, Version 2.0
  6. * (the "License"); you may not use this file except in compliance with
  7. * the License. You may obtain a copy of the License at
  8. *
  9. * http://www.apache.org/licenses/LICENSE-2.0
  10. *
  11. * Unless required by applicable law or agreed to in writing, software
  12. * distributed under the License is distributed on an "AS IS" BASIS,
  13. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. * See the License for the specific language governing permissions and
  15. * limitations under the License.
  16. */
  17. package org.apache.camel.component.cxf.common.header;
  18. import java.util.ArrayList;
  19. import java.util.Arrays;
  20. import java.util.Collections;
  21. import java.util.HashMap;
  22. import java.util.List;
  23. import java.util.Map;
  24. import java.util.TreeMap;
  25. import org.apache.camel.Exchange;
  26. import org.apache.camel.component.cxf.common.message.CxfConstants;
  27. import org.apache.camel.spi.HeaderFilterStrategy;
  28. import org.apache.cxf.endpoint.Client;
  29. import org.apache.cxf.helpers.CastUtils;
  30. import org.apache.cxf.message.Message;
  31. import org.slf4j.Logger;
  32. import org.slf4j.LoggerFactory;
  33. /**
  34. * Utility class to propagate headers to and from CXF message.
  35. *
  36. * @version
  37. */
  38. public final class CxfHeaderHelper {
  39. private static final Logger LOG = LoggerFactory.getLogger(CxfHeaderHelper.class);
  40. private static final Map<String, String> CAMEL_TO_CXF_HEADERS = new HashMap<>();
  41. private static final Map<String, String> CXF_TO_CAMEL_HEADERS = new HashMap<>();
  42. static {
  43. // initialize mappings between Camel and CXF header names
  44. defineMapping(Exchange.HTTP_URI, Message.REQUEST_URI);
  45. defineMapping(Exchange.HTTP_METHOD, Message.HTTP_REQUEST_METHOD);
  46. defineMapping(Exchange.HTTP_PATH, Message.PATH_INFO);
  47. defineMapping(Exchange.CONTENT_TYPE, Message.CONTENT_TYPE);
  48. defineMapping(Exchange.HTTP_CHARACTER_ENCODING, Message.ENCODING);
  49. defineMapping(Exchange.HTTP_QUERY, Message.QUERY_STRING);
  50. defineMapping(Exchange.ACCEPT_CONTENT_TYPE, Message.ACCEPT_CONTENT_TYPE);
  51. defineMapping(Exchange.HTTP_RESPONSE_CODE, Message.RESPONSE_CODE);
  52. }
  53. /**
  54. * Utility class does not have public constructor
  55. */
  56. private CxfHeaderHelper() {
  57. }
  58. private static void defineMapping(String camelHeader, String cxfHeader) {
  59. CAMEL_TO_CXF_HEADERS.put(camelHeader, cxfHeader);
  60. CXF_TO_CAMEL_HEADERS.put(cxfHeader, camelHeader);
  61. }
  62. /**
  63. * Propagates Camel headers to CXF headers.
  64. *
  65. * @param strategy header filter strategy
  66. * @param camelHeaders Camel headers
  67. * @param requestHeaders CXF request headers
  68. * @param camelExchange provides context for filtering
  69. */
  70. public static void propagateCamelHeadersToCxfHeaders(HeaderFilterStrategy strategy,
  71. Map<String, Object> camelHeaders, Map<String, List<String>> requestHeaders,
  72. Exchange camelExchange) throws Exception {
  73. if (strategy == null) {
  74. return;
  75. }
  76. camelHeaders.entrySet().forEach(entry -> {
  77. // Need to make sure the cxf needed header will not be filtered
  78. if (strategy.applyFilterToCamelHeaders(entry.getKey(), entry.getValue(), camelExchange)
  79. && CAMEL_TO_CXF_HEADERS.get(entry.getKey()) == null) {
  80. LOG.trace("Drop Camel header: {}={}", entry.getKey(), entry.getValue());
  81. return;
  82. }
  83. // we need to make sure the entry value is not null
  84. if (entry.getValue() == null) {
  85. LOG.trace("Drop Camel header: {}={}", entry.getKey(), entry.getValue());
  86. return;
  87. }
  88. String cxfHeaderName = CAMEL_TO_CXF_HEADERS.getOrDefault(entry.getKey(), entry.getKey());
  89. LOG.trace("Propagate Camel header: {}={} as {}", entry.getKey(), entry.getValue(), cxfHeaderName);
  90. requestHeaders.put(cxfHeaderName, Arrays.asList(entry.getValue().toString()));
  91. });
  92. }
  93. /**
  94. * Propagates Camel headers to CXF message.
  95. *
  96. * @param strategy header filter strategy
  97. * @param camelHeaders Camel header
  98. * @param cxfMessage CXF message
  99. * @param exchange provides context for filtering
  100. */
  101. public static void propagateCamelToCxf(HeaderFilterStrategy strategy,
  102. Map<String, Object> camelHeaders, Message cxfMessage, Exchange exchange) {
  103. // use copyProtocolHeadersFromCxfToCamel treemap to keep ordering and ignore key case
  104. cxfMessage.putIfAbsent(Message.PROTOCOL_HEADERS, new TreeMap<>(String.CASE_INSENSITIVE_ORDER));
  105. final Map<String, List<String>> cxfHeaders =
  106. CastUtils.cast((Map<?, ?>) cxfMessage.get(Message.PROTOCOL_HEADERS));
  107. if (strategy == null) {
  108. return;
  109. }
  110. camelHeaders.entrySet().forEach(entry -> {
  111. // Need to make sure the cxf needed header will not be filtered
  112. if (strategy.applyFilterToCamelHeaders(entry.getKey(), entry.getValue(), exchange)) {
  113. LOG.trace("Drop external header: {}={}", entry.getKey(), entry.getValue());
  114. return;
  115. }
  116. // we need to make sure the entry value is not null
  117. if (entry.getValue() == null) {
  118. LOG.trace("Drop Camel header: {}={}", entry.getKey(), entry.getValue());
  119. return;
  120. }
  121. String cxfHeaderName = CAMEL_TO_CXF_HEADERS.getOrDefault(entry.getKey(), entry.getKey());
  122. LOG.trace("Propagate Camel header: {}={} as {}", entry.getKey(), entry.getValue(), cxfHeaderName);
  123. if (Exchange.CONTENT_TYPE.equals(entry.getKey())) {
  124. cxfMessage.put(cxfHeaderName, entry.getValue());
  125. }
  126. if (Exchange.HTTP_RESPONSE_CODE.equals(entry.getKey())
  127. || Client.REQUEST_CONTEXT.equals(entry.getKey())
  128. || Client.RESPONSE_CONTEXT.equals(entry.getKey())) {
  129. cxfMessage.put(cxfHeaderName, entry.getValue());
  130. } else {
  131. Object values = entry.getValue();
  132. if (values instanceof List<?>) {
  133. cxfHeaders.put(cxfHeaderName, CastUtils.cast((List<?>) values, String.class));
  134. } else {
  135. List<String> listValue = new ArrayList<>();
  136. listValue.add(entry.getValue().toString());
  137. cxfHeaders.put(cxfHeaderName, listValue);
  138. }
  139. }
  140. });
  141. }
  142. /**
  143. * Propagates CXF headers to Camel headers.
  144. *
  145. * @param strategy header filter strategy
  146. * @param responseHeaders CXF response headers
  147. * @param camelHeaders Camel headers
  148. * @param camelExchange provides context for filtering
  149. */
  150. public static void propagateCxfHeadersToCamelHeaders(HeaderFilterStrategy strategy,
  151. Map<String, List<Object>> responseHeaders, Map<String, Object> camelHeaders,
  152. Exchange camelExchange) throws Exception {
  153. if (strategy == null) {
  154. return;
  155. }
  156. responseHeaders.entrySet().forEach(entry -> {
  157. if (strategy.applyFilterToExternalHeaders(entry.getKey(), entry.getValue(), camelExchange)) {
  158. LOG.trace("Drop external header: {}={}", entry.getKey(), entry.getValue());
  159. return;
  160. }
  161. String camelHeaderName = CXF_TO_CAMEL_HEADERS.getOrDefault(entry.getKey(), entry.getKey());
  162. LOG.trace("Populate external header: {}={} as {}", entry.getKey(), entry.getValue(), camelHeaderName);
  163. camelHeaders.put(camelHeaderName, entry.getValue().get(0));
  164. });
  165. }
  166. /**
  167. * Propagates CXF headers to Camel message.
  168. *
  169. * @param strategy header filter strategy
  170. * @param cxfMessage CXF message
  171. * @param camelMessage Camel message
  172. * @param exchange provides context for filtering
  173. */
  174. public static void propagateCxfToCamel(HeaderFilterStrategy strategy, Message cxfMessage,
  175. org.apache.camel.Message camelMessage, Exchange exchange) {
  176. if (strategy == null) {
  177. return;
  178. }
  179. // Copy the CXF protocol headers to the camel headers
  180. copyProtocolHeadersFromCxfToCamel(strategy, exchange, cxfMessage, camelMessage);
  181. // Copy the CXF HTTP headers to the camel headers
  182. copyHttpHeadersFromCxfToCamel(strategy, cxfMessage, camelMessage, exchange);
  183. // propagate request context
  184. copyCxfHeaderToCamel(strategy, exchange, cxfMessage, camelMessage, Client.REQUEST_CONTEXT);
  185. // propagate response context
  186. copyCxfHeaderToCamel(strategy, exchange, cxfMessage, camelMessage, Client.RESPONSE_CONTEXT);
  187. }
  188. private static void copyProtocolHeadersFromCxfToCamel(HeaderFilterStrategy strategy, Exchange exchange,
  189. Message cxfMessage, org.apache.camel.Message camelMessage) {
  190. Map<String, List<String>> cxfHeaders =
  191. CastUtils.cast((Map<?, ?>) cxfMessage.getOrDefault(Message.PROTOCOL_HEADERS, Collections.emptyMap()));
  192. cxfHeaders.entrySet().forEach(cxfHeader -> {
  193. String camelHeaderName = CXF_TO_CAMEL_HEADERS.getOrDefault(cxfHeader.getKey(), cxfHeader.getKey());
  194. Object value = convertCxfProtocolHeaderValues(cxfHeader.getValue(), exchange);
  195. copyCxfHeaderToCamel(strategy, exchange, cxfMessage, camelMessage, cxfHeader.getKey(), camelHeaderName, value);
  196. });
  197. }
  198. private static Object convertCxfProtocolHeaderValues(List<String> values, Exchange exchange) {
  199. if (values.size() == 1) {
  200. return values.get(0);
  201. }
  202. if (exchange.getProperty(CxfConstants.CAMEL_CXF_PROTOCOL_HEADERS_MERGED, Boolean.FALSE, Boolean.class)) {
  203. return String.join(", ", values);
  204. }
  205. return values;
  206. }
  207. public static void copyHttpHeadersFromCxfToCamel(HeaderFilterStrategy strategy, Message cxfMessage,
  208. org.apache.camel.Message camelMessage, Exchange exchange) {
  209. CXF_TO_CAMEL_HEADERS.entrySet().forEach(entry ->
  210. copyCxfHeaderToCamel(strategy, exchange, cxfMessage, camelMessage, entry.getKey(), entry.getValue()));
  211. }
  212. private static void copyCxfHeaderToCamel(HeaderFilterStrategy strategy, Exchange exchange,
  213. Message cxfMessage, org.apache.camel.Message camelMessage, String key) {
  214. copyCxfHeaderToCamel(strategy, exchange, cxfMessage, camelMessage, key, key);
  215. }
  216. private static void copyCxfHeaderToCamel(HeaderFilterStrategy strategy, Exchange exchange,
  217. Message cxfMessage, org.apache.camel.Message camelMessage, String cxfKey, String camelKey) {
  218. copyCxfHeaderToCamel(strategy, exchange, cxfMessage, camelMessage, cxfKey, camelKey, cxfMessage.get(cxfKey));
  219. }
  220. private static void copyCxfHeaderToCamel(HeaderFilterStrategy strategy, Exchange exchange,
  221. Message cxfMessage, org.apache.camel.Message camelMessage, String cxfKey, String camelKey,
  222. Object initialValue) {
  223. Object value = initialValue;
  224. if (Message.PATH_INFO.equals(cxfKey)) {
  225. // We need remove the BASE_PATH from the PATH_INFO
  226. value = convertPathInfo(cxfMessage);
  227. } else if (Message.CONTENT_TYPE.equals(cxfKey)) {
  228. // propagate content type with the encoding information
  229. // We need to do it as the CXF does this kind of thing in transport level
  230. value = determineContentType(cxfMessage);
  231. }
  232. if (value != null && !strategy.applyFilterToExternalHeaders(cxfKey, value, exchange)) {
  233. camelMessage.setHeader(camelKey, value);
  234. }
  235. }
  236. private static String convertPathInfo(Message message) {
  237. String pathInfo = findHeaderValue(message, Message.PATH_INFO);
  238. String basePath = findHeaderValue(message, Message.BASE_PATH);
  239. if (pathInfo != null && basePath != null && pathInfo.startsWith(basePath)) {
  240. return pathInfo.substring(basePath.length());
  241. }
  242. return pathInfo;
  243. }
  244. private static String determineContentType(Message message) {
  245. String ct = findHeaderValue(message, Message.CONTENT_TYPE);
  246. String enc = findHeaderValue(message, Message.ENCODING);
  247. if (null != ct) {
  248. if (enc != null
  249. && !ct.contains("charset=")
  250. && !ct.toLowerCase().contains("multipart/related")) {
  251. ct = ct + "; charset=" + enc;
  252. }
  253. } else if (enc != null) {
  254. ct = "text/xml; charset=" + enc;
  255. } else {
  256. ct = "text/xml";
  257. }
  258. // update the content_type value in the message
  259. message.put(Message.CONTENT_TYPE, ct);
  260. return ct;
  261. }
  262. private static String findHeaderValue(Message message, String key) {
  263. String value = (String) message.get(key);
  264. if (value != null) {
  265. return value;
  266. }
  267. Map<String, List<String>> protocolHeaders =
  268. CastUtils.cast((Map<?, ?>) message.getOrDefault(Message.PROTOCOL_HEADERS, Collections.emptyMap()));
  269. return protocolHeaders.getOrDefault(key, Collections.singletonList(null)).get(0);
  270. }
  271. }