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