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