001    // Copyright 2004, 2005 The Apache Software Foundation
002    //
003    // Licensed under the Apache License, Version 2.0 (the "License");
004    // you may not use this file except in compliance with the License.
005    // You may obtain a copy of the License at
006    //
007    //     http://www.apache.org/licenses/LICENSE-2.0
008    //
009    // Unless required by applicable law or agreed to in writing, software
010    // distributed under the License is distributed on an "AS IS" BASIS,
011    // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
012    // See the License for the specific language governing permissions and
013    // limitations under the License.
014    
015    package org.apache.tapestry.util;
016    
017    import org.apache.commons.pool.KeyedPoolableObjectFactory;
018    import org.apache.commons.pool.impl.GenericKeyedObjectPool;
019    import org.apache.hivemind.ApplicationRuntimeException;
020    import org.apache.oro.text.regex.Perl5Compiler;
021    
022    import java.util.ArrayList;
023    import java.util.HashMap;
024    import java.util.List;
025    import java.util.Map;
026    import java.util.regex.Matcher;
027    import java.util.regex.Pattern;
028    
029    /**
030     * Streamlines the interface to ORO by implicitly constructing the necessary compilers and matchers,
031     * and by caching compiled patterns.
032     * 
033     */
034    
035    public class RegexpMatcher
036    {    
037        private static final long SLEEP_TIME = 1000 * 60 * 4;
038    
039        private static final long EVICT_IDLE_TIME = 1000 * 60 * 60;
040        
041        private final KeyedPoolableObjectFactory _factory = new RegexpPoolObjectFactory();
042    
043        private final GenericKeyedObjectPool _pool;
044        
045        private Map _escapedPatternStrings = new HashMap();
046        
047        public RegexpMatcher()
048        {
049            _pool = new GenericKeyedObjectPool(_factory);
050            
051            _pool.setMinEvictableIdleTimeMillis(EVICT_IDLE_TIME);
052            _pool.setTimeBetweenEvictionRunsMillis(SLEEP_TIME);
053        }
054        
055        /**
056         * Clears any previously compiled patterns.
057         */
058        public void clear()
059        {
060            _pool.clear();
061        }
062        
063        public boolean matches(String pattern, String input)
064        {
065            Pattern compiled = null;
066            
067            try {
068                
069                compiled = (Pattern)_pool.borrowObject(pattern);
070                
071                return compiled.matcher(input).matches();
072                
073            } catch (Exception e) {
074                
075                throw new ApplicationRuntimeException(e);
076            } finally {
077                
078                try { _pool.returnObject(pattern, compiled); } catch (Throwable t) { }
079            }
080        }
081        
082        public boolean contains(String pattern, String input)
083        {
084            Pattern compiled = null;
085            
086            try {
087                
088                compiled = (Pattern)_pool.borrowObject(pattern);
089                
090                return compiled.matcher(input).find();
091                
092            } catch (Exception e) {
093                
094                throw new ApplicationRuntimeException(e);
095            } finally {
096                
097                try { _pool.returnObject(pattern, compiled); } catch (Throwable t) { }
098            }
099        }
100    
101        public String getEscapedPatternString(String pattern)
102        {
103            String result = (String) _escapedPatternStrings.get(pattern);
104            
105            if (result == null)
106            {
107                result = Perl5Compiler.quotemeta(pattern);
108    
109                _escapedPatternStrings.put(pattern, result);
110            }
111            
112            return result;
113        }
114        
115        /**
116         * Given an input string, finds all matches in an input string for the pattern.
117         * 
118         * @param pattern
119         *            the regexp pattern for matching
120         * @param input
121         *            the string to search for matches within
122         * @return array (possibly empty) of matches
123         * @since 4.0
124         */
125        public RegexpMatch[] getMatches(String pattern, String input)
126        {
127            Pattern compiled = null;
128            
129            try {
130                
131                compiled = (Pattern)_pool.borrowObject(pattern);
132    
133                Matcher matcher = compiled.matcher(input);
134                List matches = new ArrayList();
135                
136                while (matcher.find())
137                {
138                    int length = matcher.groupCount();
139                    String[] groups = new String[length + 1];
140                    groups[0] = matcher.group();
141                    
142                    for (int i=1; i <= length; i++) {
143                        groups[i] = matcher.group(i);
144                    }
145    
146                    matches.add(new RegexpMatch(length, groups));
147                }
148                
149                return (RegexpMatch[]) matches.toArray(new RegexpMatch[matches.size()]);
150                
151            } catch (Exception e) {
152                
153                throw new ApplicationRuntimeException(e);
154            } finally {
155                
156                try { _pool.returnObject(pattern, compiled); } catch (Throwable t) { }
157            }
158        }
159    
160        /**
161         * Given an input string, finds all matches in an input string for the pattern.
162         * 
163         * @param pattern
164         *            the regexp pattern for matching
165         * @param input
166         *            the string to search for matches within
167         * @param subgroup
168         *            the group (sub-expression) within the pattern to return as a match
169         * @return array (possibly empty) of matching strings
170         */
171        public String[] getMatches(String pattern, String input, int subgroup)
172        {
173            Pattern compiled = null;
174            
175            try {
176    
177                compiled = (Pattern)_pool.borrowObject(pattern);
178    
179                Matcher matcher = compiled.matcher(input);
180                List matches = new ArrayList();
181                
182                while (matcher.find())
183                {
184                    String matchedInput = matcher.group(subgroup);
185                    
186                    matches.add(matchedInput);
187                }
188    
189                return (String[]) matches.toArray(new String[matches.size()]);
190                
191            } catch (Exception e) {
192    
193                throw new ApplicationRuntimeException(e);
194            } finally {
195    
196                try { _pool.returnObject(pattern, compiled); } catch (Throwable t) { }
197            }
198        }
199    
200    }