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.cocoon.matching;
018:
019: import org.apache.avalon.framework.parameters.Parameters;
020: import org.apache.avalon.framework.thread.ThreadSafe;
021: import org.apache.cocoon.sitemap.PatternException;
022: import org.apache.cocoon.sitemap.SitemapParameters;
023: import org.apache.regexp.RE;
024: import org.apache.regexp.RECompiler;
025: import org.apache.regexp.REProgram;
026: import org.apache.regexp.RESyntaxException;
027:
028: import java.util.HashMap;
029: import java.util.Map;
030:
031: /**
032: * Base class for all matchers using a regular expression pattern.
033: *
034: * @author <a href="mailto:Giacomo.Pati@pwr.ch">Giacomo Pati</a>
035: * @author <a href="mailto:bloritsch@apache.org">Berin Loritsch</a>
036: * @author <a href="mailto:sylvain@apache.org">Sylvain Wallez</a>
037: * @version CVS $Id: AbstractRegexpMatcher.java 433543 2006-08-22 06:22:54Z crossley $
038: */
039:
040: public abstract class AbstractRegexpMatcher extends
041: AbstractPreparableMatcher implements ThreadSafe {
042:
043: /**
044: * Compile the pattern in a <code>org.apache.regexp.REProgram</code>.
045: */
046: public Object preparePattern(String pattern)
047: throws PatternException {
048: // if pattern is null, return null to allow throwing a located exception in preparedMatch()
049: if (pattern == null) {
050: return null;
051: }
052:
053: if (pattern.length() == 0) {
054: pattern = "^$";
055: if (getLogger().isWarnEnabled()) {
056: getLogger()
057: .warn(
058: "The empty pattern string was rewritten to '^$'"
059: + " to match for empty strings. If you intended"
060: + " to match all strings, please change your"
061: + " pattern to '.*'");
062: }
063: }
064:
065: try {
066: RECompiler compiler = new RECompiler();
067: REProgram program = compiler.compile(pattern);
068: return program;
069:
070: } catch (RESyntaxException rse) {
071: getLogger().debug(
072: "Failed to compile the pattern '" + pattern + "'",
073: rse);
074: throw new PatternException(rse.getMessage(), rse);
075: }
076: }
077:
078: /**
079: * Match the prepared pattern against the value returned by {@link #getMatchString(Map, Parameters)}.
080: */
081: public Map preparedMatch(Object preparedPattern, Map objectModel,
082: Parameters parameters) throws PatternException {
083:
084: if (preparedPattern == null) {
085: throw new PatternException("A pattern is needed at "
086: + SitemapParameters.getLocation(parameters));
087: }
088:
089: RE re = new RE((REProgram) preparedPattern);
090: String match = getMatchString(objectModel, parameters);
091:
092: if (match == null)
093: return null;
094:
095: if (re.match(match)) {
096: /* Handle parenthesised subexpressions. XXX: could be faster if we count
097: * parens *outside* the generated code.
098: * Note: *ONE* based, not zero, zero contains complete match
099: */
100: int parenCount = re.getParenCount();
101: Map map = new HashMap();
102: for (int paren = 0; paren <= parenCount; paren++) {
103: map.put(Integer.toString(paren), re.getParen(paren));
104: }
105:
106: return map;
107: }
108:
109: return null;
110: }
111:
112: /**
113: * Get the string to test against the regular expression. To be defined
114: * by concrete subclasses.
115: */
116: protected abstract String getMatchString(Map objectModel,
117: Parameters parameters);
118: }
|