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 }