/** * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.camel.component.cxf.common.header; import java.util.HashMap; import java.util.List; import java.util.Map; import org.apache.camel.Exchange; import org.apache.camel.component.cxf.common.message.CxfConstants; import org.apache.camel.impl.DefaultHeaderFilterStrategy; import org.apache.cxf.endpoint.Client; import org.apache.cxf.headers.Header; import org.apache.cxf.message.Message; import org.apache.cxf.service.model.BindingInfo; import org.apache.cxf.service.model.BindingOperationInfo; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * The default CXF header filter strategy. * * @version */ public class CxfHeaderFilterStrategy extends DefaultHeaderFilterStrategy { private static final Logger LOG = LoggerFactory.getLogger(CxfHeaderFilterStrategy.class); private Map<String, MessageHeaderFilter> messageHeaderFiltersMap; private List<MessageHeaderFilter> messageHeaderFilters; private boolean relayHeaders = true; private boolean allowFilterNamespaceClash; private boolean relayAllMessageHeaders; public CxfHeaderFilterStrategy() { initialize(); } protected void initialize() { //filter the operationName and operationName getOutFilter().add(CxfConstants.OPERATION_NAME.toLowerCase()); getOutFilter().add(CxfConstants.OPERATION_NAMESPACE.toLowerCase()); // Request and response context Maps will be passed to CXF Client APIs getOutFilter().add(Client.REQUEST_CONTEXT.toLowerCase()); getOutFilter().add(Client.RESPONSE_CONTEXT.toLowerCase()); // protocol headers are stored as a Map. DefaultCxfBinding // read the Map and send each entry to the filter. Therefore, // we need to filter the header of this name. getOutFilter().add(Message.PROTOCOL_HEADERS.toLowerCase()); getInFilter().add(Message.PROTOCOL_HEADERS.toLowerCase()); // Add the filter for the Generic Message header // http://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.5 getOutFilter().add("cache-control"); getOutFilter().add("connection"); getOutFilter().add("date"); getOutFilter().add("pragma"); getOutFilter().add("trailer"); getOutFilter().add("transfer-encoding"); getOutFilter().add("upgrade"); getOutFilter().add("via"); getOutFilter().add("warning"); // Since CXF can take the content-type from the protocol header // we need to filter this header of this name. getOutFilter().add("Content-Type".toLowerCase()); // Filter out Content-Length since it can fool Jetty (HttpGenerator) to // close response output stream prematurely. (It occurs when the // message size (e.g. with attachment) is large and response content length // is bigger than request content length.) getOutFilter().add("Content-Length".toLowerCase()); // Filter Content-Length as it will cause some trouble when the message // is passed to the other endpoint getInFilter().add("content-length".toLowerCase()); setLowerCase(true); // initialize message header filter map with default SOAP filter messageHeaderFiltersMap = new HashMap<String, MessageHeaderFilter>(); addToMessageHeaderFilterMap(new SoapMessageHeaderFilter()); // filter headers begin with "Camel" or "org.apache.camel" setOutFilterPattern("(Camel|org\\.apache\\.camel)[\\.|a-z|A-z|0-9]*"); } @SuppressWarnings("unchecked") @Override protected boolean extendedFilter(Direction direction, String key, Object value, Exchange exchange) { // Currently only handles Header.HEADER_LIST message header relay/filter if (!Header.HEADER_LIST.equals(key) || value == null) { return false; } if (!relayHeaders) { // not propagating Header.HEADER_LIST at all return true; } if (relayAllMessageHeaders) { // all message headers will be relayed (no filtering) return false; } // get filter MessageHeaderFilter messageHeaderfilter = getMessageHeaderFilter(exchange); if (messageHeaderfilter == null) { LOG.debug("No CXF Binding namespace can be resolved. Message headers are intact."); return false; } LOG.trace("messageHeaderfilter = {}", messageHeaderfilter); try { messageHeaderfilter.filter(direction, (List<Header>)value); } catch (Throwable t) { if (LOG.isDebugEnabled()) { LOG.debug("Failed to cast value to Header<List> due to " + t.toString(), t); } } // return false since the header list (which has been filtered) should be propagated return false; } private void addToMessageHeaderFilterMap(MessageHeaderFilter filter) { for (String ns : filter.getActivationNamespaces()) { if (messageHeaderFiltersMap.containsKey(ns) && messageHeaderFiltersMap.get(ns) != messageHeaderFiltersMap && !allowFilterNamespaceClash) { throw new IllegalArgumentException("More then one MessageHeaderRelay activates " + "for the same namespace: " + ns); } messageHeaderFiltersMap.put(ns, filter); } } private MessageHeaderFilter getMessageHeaderFilter(Exchange exchange) { BindingOperationInfo boi = exchange.getProperty(BindingOperationInfo.class.getName(), BindingOperationInfo.class); String ns = null; if (boi != null) { BindingInfo b = boi.getBinding(); if (b != null) { ns = b.getBindingId(); } } MessageHeaderFilter answer = null; if (ns != null) { answer = messageHeaderFiltersMap.get(ns); } return answer; } /** * @param messageHeaderFilters the messageHeaderFilters to set */ public void setMessageHeaderFilters(List<MessageHeaderFilter> messageHeaderFilters) { this.messageHeaderFilters = messageHeaderFilters; // clear the amp to allow removal of default filter messageHeaderFiltersMap.clear(); for (MessageHeaderFilter filter : messageHeaderFilters) { addToMessageHeaderFilterMap(filter); } } /** * @return the messageHeaderFilters */ public List<MessageHeaderFilter> getMessageHeaderFilters() { return messageHeaderFilters; } /** * @return the allowFilterNamespaceClash */ public boolean isAllowFilterNamespaceClash() { return allowFilterNamespaceClash; } /** * @param allowFilterNamespaceClash the allowFilterNamespaceClash to set */ public void setAllowFilterNamespaceClash(boolean allowFilterNamespaceClash) { this.allowFilterNamespaceClash = allowFilterNamespaceClash; } /** * @return the messageHeaderFiltersMap */ public Map<String, MessageHeaderFilter> getMessageHeaderFiltersMap() { return messageHeaderFiltersMap; } /** * @param relayHeaders the relayHeaders to set */ public void setRelayHeaders(boolean relayHeaders) { this.relayHeaders = relayHeaders; } /** * @return the relayHeaders */ public boolean isRelayHeaders() { return relayHeaders; } /** * @return the relayAllMessageHeaders */ public boolean isRelayAllMessageHeaders() { return relayAllMessageHeaders; } /** * @param relayAllMessageHeaders the relayAllMessageHeaders to set */ public void setRelayAllMessageHeaders(boolean relayAllMessageHeaders) { this.relayAllMessageHeaders = relayAllMessageHeaders; } }