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.impl;
018    
019    import java.util.HashSet;
020    import java.util.Locale;
021    import java.util.Set;
022    import java.util.regex.Pattern;
023    
024    import org.apache.camel.Exchange;
025    import 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     */
042    public 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        
053        public boolean applyFilterToCamelHeaders(String headerName, Object headerValue, Exchange exchange) {
054            return doFiltering(Direction.OUT, headerName, headerValue, exchange);
055        }
056    
057        public boolean applyFilterToExternalHeaders(String headerName, Object headerValue, Exchange exchange) {
058            return doFiltering(Direction.IN, headerName, headerValue, exchange);
059        }
060    
061        /**
062         * Gets the "out" direction filter set.  The "out" direction is referred to 
063         * copying headers from a Camel message to an external message.
064         * 
065         * @return a set that contains header names that should be excluded.
066         */
067        public Set<String> getOutFilter() {
068            if (outFilter == null) {
069                outFilter = new HashSet<String>();
070            }
071            
072            return outFilter;
073        }
074    
075        /**
076         * Sets the "out" direction filter set.  The "out" direction is referred to 
077         * copying headers from a Camel message to an external message.
078         *
079         * @param value  the filter
080         */
081        public void setOutFilter(Set<String> value) {
082            outFilter = value;
083        }
084    
085        /**
086         * Gets the "out" direction filter regular expression {@link Pattern}.  The
087         * "out" direction is referred to copying headers from Camel message to
088         * an external message.  If the pattern matches a header, the header will 
089         * be filtered out. 
090         * 
091         * @return regular expression filter pattern
092         */
093        public String getOutFilterPattern() {
094            return outFilterPattern == null ? null : outFilterPattern.pattern();
095        }
096    
097        /**
098         * Sets the "out" direction filter regular expression {@link Pattern}.  The
099         * "out" direction is referred to copying headers from Camel message to
100         * an external message.  If the pattern matches a header, the header will 
101         * be filtered out. 
102         * 
103         * @param value regular expression filter pattern
104         */
105        public void setOutFilterPattern(String value) {
106            if (value == null) {
107                outFilterPattern = null;
108            } else {
109                outFilterPattern = Pattern.compile(value);
110            }
111        }
112        
113        /**
114         * Gets the "in" direction filter set.  The "in" direction is referred to 
115         * copying headers from an external message to a Camel message.
116         * 
117         * @return a set that contains header names that should be excluded.
118         */
119        public Set<String> getInFilter() {
120            if (inFilter == null) {
121                inFilter = new HashSet<String>();
122            }
123            return inFilter;
124        }
125    
126        /**
127         * Sets the "in" direction filter set.  The "in" direction is referred to 
128         * copying headers from an external message to a Camel message.
129         *
130         * @param value the filter
131         */
132        public void setInFilter(Set<String> value) {
133            inFilter = value;
134        }
135    
136        /**
137         * Gets the "in" direction filter regular expression {@link Pattern}.  The
138         * "in" direction is referred to copying headers from an external message
139         * to a Camel message.  If the pattern matches a header, the header will 
140         * be filtered out. 
141         * 
142         * @return regular expression filter pattern
143         */
144        public String getInFilterPattern() {
145            return inFilterPattern == null ? null : inFilterPattern.pattern();
146        }
147        
148        /**
149         * Sets the "in" direction filter regular expression {@link Pattern}.  The
150         * "in" direction is referred to copying headers from an external message
151         * to a Camel message.  If the pattern matches a header, the header will 
152         * be filtered out. 
153         * 
154         * @param value regular expression filter pattern
155         */
156        public void setInFilterPattern(String value) {
157            if (value == null) {
158                inFilterPattern = null;
159            } else {
160                inFilterPattern = Pattern.compile(value);
161            }
162        }
163    
164        /**
165         * Gets the isLowercase property which is a boolean to determine
166         * whether header names should be converted to lowercase before
167         * checking it the filter Set.  It does not affect filtering using
168         * regular expression pattern.
169         */
170        public boolean isLowerCase() {
171            return lowerCase;
172        }
173        
174        /**
175         * Sets the isLowercase property which is a boolean to determine
176         * whether header names should be converted to lowercase before
177         * checking it the filter Set.  It does not affect filtering using
178         * regular expression pattern.
179         */
180        public void setLowerCase(boolean value) {
181            lowerCase = value;
182        }
183        
184        public boolean isAllowNullValues() {
185            return allowNullValues;
186        }
187        
188        public void setAllowNullValues(boolean value) {
189            allowNullValues = value;
190        }   
191    
192        protected boolean extendedFilter(Direction direction, String key, Object value, Exchange exchange) {
193            return false;
194        }
195    
196        private boolean doFiltering(Direction direction, String headerName, Object headerValue, Exchange exchange) {
197            if (headerName == null) {
198                return true;
199            }
200            
201            if (headerValue == null && !allowNullValues) {
202                return true;
203            }
204            
205            Pattern pattern = null;
206            Set<String> filter = null;
207            
208            if (Direction.OUT == direction) {
209                pattern = outFilterPattern;
210                filter = outFilter;                
211            } else if (Direction.IN == direction) {
212                pattern = inFilterPattern;
213                filter = inFilter;
214            }
215       
216            if (pattern != null && pattern.matcher(headerName).matches()) {
217                return true;
218            }
219                
220            if (filter != null) {
221                if (isLowerCase()) {
222                    if (filter.contains(headerName.toLowerCase(Locale.ENGLISH))) {
223                        return true;
224                    }
225                } else {
226                    if (filter.contains(headerName)) {
227                        return true;
228                    }
229                }
230            }
231                
232            if (extendedFilter(direction, headerName, headerValue, exchange)) {
233                return true;
234            }
235                
236            return false;
237        }
238    
239    }