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 */
017package org.apache.camel.impl;
018
019import java.util.HashSet;
020import java.util.Locale;
021import java.util.Set;
022import java.util.regex.Pattern;
023
024import org.apache.camel.Exchange;
025import org.apache.camel.spi.HeaderFilterStrategy;
026
027/**
028 * The default header filtering strategy. Users can configure filter by
029 * setting filter set and/or setting a regular expression. Subclass can
030 * add extended filter logic in 
031 * {@link #extendedFilter(org.apache.camel.spi.HeaderFilterStrategy.Direction, String, Object, org.apache.camel.Exchange)}
032 * 
033 * Filters are associated with directions (in or out). "In" direction is
034 * referred to propagating headers "to" Camel message. The "out" direction
035 * is opposite which is referred to propagating headers from Camel message
036 * to a native message like JMS and CXF message. You can see example of
037 * DefaultHeaderFilterStrategy are being extended and invoked in camel-jms 
038 * and camel-cxf components.
039 *
040 * @version 
041 */
042public class DefaultHeaderFilterStrategy implements HeaderFilterStrategy {
043    
044    private Set<String> inFilter;
045    private Pattern inFilterPattern;
046
047    private Set<String> outFilter;
048    private Pattern outFilterPattern;
049
050    private boolean lowerCase;
051    private boolean allowNullValues;
052    private boolean caseInsensitive;
053    
054    public boolean applyFilterToCamelHeaders(String headerName, Object headerValue, Exchange exchange) {
055        return doFiltering(Direction.OUT, headerName, headerValue, exchange);
056    }
057
058    public boolean applyFilterToExternalHeaders(String headerName, Object headerValue, Exchange exchange) {
059        return doFiltering(Direction.IN, headerName, headerValue, exchange);
060    }
061
062    /**
063     * Gets the "out" direction filter set. The "out" direction is referred to
064     * copying headers from a Camel message to an external message.
065     * 
066     * @return a set that contains header names that should be excluded.
067     */
068    public Set<String> getOutFilter() {
069        if (outFilter == null) {
070            outFilter = new HashSet<String>();
071        }
072        
073        return outFilter;
074    }
075
076    /**
077     * Sets the "out" direction filter set. The "out" direction is referred to
078     * copying headers from a Camel message to an external message.
079     *
080     * @param value  the filter
081     */
082    public void setOutFilter(Set<String> value) {
083        outFilter = value;
084    }
085
086    /**
087     * Gets the "out" direction filter regular expression {@link Pattern}. The
088     * "out" direction is referred to copying headers from Camel message to
089     * an external message. If the pattern matches a header, the header will
090     * be filtered out. 
091     * 
092     * @return regular expression filter pattern
093     */
094    public String getOutFilterPattern() {
095        return outFilterPattern == null ? null : outFilterPattern.pattern();
096    }
097
098    /**
099     * Sets the "out" direction filter regular expression {@link Pattern}. The
100     * "out" direction is referred to copying headers from Camel message to
101     * an external message. If the pattern matches a header, the header will
102     * be filtered out. 
103     * 
104     * @param value regular expression filter pattern
105     */
106    public void setOutFilterPattern(String value) {
107        if (value == null) {
108            outFilterPattern = null;
109        } else {
110            outFilterPattern = Pattern.compile(value);
111        }
112    }
113    
114    /**
115     * Gets the "in" direction filter set. The "in" direction is referred to
116     * copying headers from an external message to a Camel message.
117     * 
118     * @return a set that contains header names that should be excluded.
119     */
120    public Set<String> getInFilter() {
121        if (inFilter == null) {
122            inFilter = new HashSet<String>();
123        }
124        return inFilter;
125    }
126
127    /**
128     * Sets the "in" direction filter set. The "in" direction is referred to
129     * copying headers from an external message to a Camel message.
130     *
131     * @param value the filter
132     */
133    public void setInFilter(Set<String> value) {
134        inFilter = value;
135    }
136
137    /**
138     * Gets the "in" direction filter regular expression {@link Pattern}. The
139     * "in" direction is referred to copying headers from an external message
140     * to a Camel message. If the pattern matches a header, the header will
141     * be filtered out. 
142     * 
143     * @return regular expression filter pattern
144     */
145    public String getInFilterPattern() {
146        return inFilterPattern == null ? null : inFilterPattern.pattern();
147    }
148    
149    /**
150     * Sets the "in" direction filter regular expression {@link Pattern}. The
151     * "in" direction is referred to copying headers from an external message
152     * to a Camel message. If the pattern matches a header, the header will
153     * be filtered out. 
154     * 
155     * @param value regular expression filter pattern
156     */
157    public void setInFilterPattern(String value) {
158        if (value == null) {
159            inFilterPattern = null;
160        } else {
161            inFilterPattern = Pattern.compile(value);
162        }
163    }
164
165    /**
166     * Gets the isLowercase property which is a boolean to determine
167     * whether header names should be converted to lower case before
168     * checking it with the filter Set. It does not affect filtering using
169     * regular expression pattern.
170     */
171    public boolean isLowerCase() {
172        return lowerCase;
173    }
174    
175    /**
176     * Sets the isLowercase property which is a boolean to determine
177     * whether header names should be converted to lower case before
178     * checking it with the filter Set. It does not affect filtering using
179     * regular expression pattern.
180     */
181    public void setLowerCase(boolean value) {
182        lowerCase = value;
183    }
184
185    /**
186     * Gets the caseInsensitive property which is a boolean to determine
187     * whether header names should be case insensitive when checking it 
188     * with the filter set.
189     * It does not affect filtering using regular expression pattern.
190     * 
191     * @return <tt>true</tt> if header names is case insensitive. 
192     */
193    public boolean isCaseInsensitive() {
194        return caseInsensitive;
195    }
196
197    /**
198     * Sets the caseInsensitive property which is a boolean to determine
199     * whether header names should be case insensitive when checking it 
200     * with the filter set.
201     * It does not affect filtering using regular expression pattern,
202     * 
203     * @param caseInsensitive <tt>true</tt> if header names is case insensitive.
204     */
205    public void setCaseInsensitive(boolean caseInsensitive) {
206        this.caseInsensitive = caseInsensitive;
207    }
208    
209    public boolean isAllowNullValues() {
210        return allowNullValues;
211    }
212    
213    public void setAllowNullValues(boolean value) {
214        allowNullValues = value;
215    }   
216
217    protected boolean extendedFilter(Direction direction, String key, Object value, Exchange exchange) {
218        return false;
219    }
220
221    private boolean doFiltering(Direction direction, String headerName, Object headerValue, Exchange exchange) {
222        if (headerName == null) {
223            return true;
224        }
225        
226        if (headerValue == null && !allowNullValues) {
227            return true;
228        }
229        
230        Pattern pattern = null;
231        Set<String> filter = null;
232        
233        if (Direction.OUT == direction) {
234            pattern = outFilterPattern;
235            filter = outFilter;                
236        } else if (Direction.IN == direction) {
237            pattern = inFilterPattern;
238            filter = inFilter;
239        }
240   
241        if (pattern != null && pattern.matcher(headerName).matches()) {
242            return true;
243        }
244            
245        if (filter != null) {
246            if (isCaseInsensitive()) {
247                for (String filterString : filter) {
248                    if (filterString.equalsIgnoreCase(headerName)) {
249                        return true;
250                    }
251                }
252            } else if (isLowerCase()) {
253                if (filter.contains(headerName.toLowerCase(Locale.ENGLISH))) {
254                    return true;
255                }
256            } else {
257                if (filter.contains(headerName)) {
258                    return true;
259                }
260            }
261        }
262
263        return extendedFilter(direction, headerName, headerValue, exchange);
264    }
265
266}