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: 45301 $
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         * @return a set that contains headers names that should be excluded.
102         */
103        public void setOutFilter(Set<String> value) {
104            outFilter = value;
105        }
106    
107        /**
108         * Gets the "out" direction filter regular expression {@link Pattern}.  The
109         * "out" direction is referred to copying headers from Camel message to
110         * an external message.  If the pattern matches a header, the header will 
111         * be filtered out. 
112         * 
113         * @return regular expression filter pattern
114         */
115        public String getOutFilterPattern() {
116            return outFilterPattern == null ? null : outFilterPattern.pattern();
117        }
118        
119    
120        /**
121         * Sets the "out" direction filter regular expression {@link Pattern}.  The
122         * "out" direction is referred to copying headers from Camel message to
123         * an external message.  If the pattern matches a header, the header will 
124         * be filtered out. 
125         * 
126         * @param value regular expression filter pattern
127         */
128        public void setOutFilterPattern(String value) {
129            if (value == null) {
130                outFilterPattern = null;
131            } else {
132                outFilterPattern = Pattern.compile(value);
133            }
134        }
135        
136        /**
137         * Gets the "in" direction filter set.  The "in" direction is referred to 
138         * copying headers from an external message to a Camel message.
139         * 
140         * @return a set that contains header names that should be excluded.
141         */
142        public Set<String> getInFilter() {
143            if (inFilter == null) {
144                inFilter = new HashSet<String>();
145            }
146            return inFilter;
147        }
148    
149        /**
150         * Sets the "in" direction filter set.  The "in" direction is referred to 
151         * copying headers from an external message to a Camel message.
152         * 
153         * @return a set that contains headers names that should be excluded.
154         */
155        public void setInFilter(Set<String> value) {
156            inFilter = value;
157        }
158    
159        /**
160         * Gets the "in" direction filter regular expression {@link Pattern}.  The
161         * "in" direction is referred to copying headers from an external message
162         * to a Camel message.  If the pattern matches a header, the header will 
163         * be filtered out. 
164         * 
165         * @return regular expression filter pattern
166         */
167        public String getInFilterPattern() {
168            return inFilterPattern == null ? null : inFilterPattern.pattern();
169        }
170        
171        /**
172         * Sets the "in" direction filter regular expression {@link Pattern}.  The
173         * "in" direction is referred to copying headers from an external message
174         * to a Camel message.  If the pattern matches a header, the header will 
175         * be filtered out. 
176         * 
177         * @param value regular expression filter pattern
178         */
179        public void setInFilterPattern(String value) {
180            if (value == null) {
181                inFilterPattern = null;
182            } else {
183                inFilterPattern = Pattern.compile(value);
184            }
185        }
186    
187        /**
188         * Gets the isLowercase property which is a boolean to determinte
189         * whether header names should be converted to lowercase before
190         * checking it the filter Set.  It does not affect filtering using
191         * regular expression pattern.
192         */
193        public boolean getIsLowercase() {
194            return isLowercase;
195        }
196        
197        /**
198         * Sets the isLowercase property which is a boolean to determinte
199         * whether header names should be converted to lowercase before
200         * checking it the filter Set.  It does not affect filtering using
201         * regular expression pattern.
202         */
203        public void setIsLowercase(boolean value) {
204            isLowercase = value;
205        }
206        
207        public boolean getAllowNullValues() {
208            return allowNullValues;
209        }
210        
211        public void setAllowNullValues(boolean value) {
212            allowNullValues = value;
213        }   
214    
215        protected boolean extendedFilter(Direction direction, String key, Object value) {
216            return false;
217        }
218    
219        private boolean doFiltering(Direction direction, String headerName, Object headerValue) {
220            
221            if (headerName == null) {
222                return true;
223            }
224            
225            if (headerValue == null && !allowNullValues) {
226                return true;
227            }
228            
229            Pattern pattern = null;
230            Set<String> filter = null;
231            
232            if (Direction.OUT == direction) {
233                pattern = outFilterPattern;
234                filter = outFilter;                
235            } else if (Direction.IN == direction) {
236                pattern = inFilterPattern;
237                filter = inFilter;
238            }
239       
240            if (pattern != null && pattern.matcher(headerName).matches()) {
241                return true;
242            }
243                
244            if (filter != null) {
245                if (isLowercase) {
246                    if (filter.contains(headerName.toLowerCase())) {
247                        return true;
248                    }
249                } else {
250                    if (filter.contains(headerName)) {
251                        return true;
252                    }
253                }
254            }
255                
256            if (extendedFilter(direction, headerName, headerValue)) {
257                return true;
258            }
259                
260            return false;
261        }
262    }