001: /* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
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:
016: package org.acegisecurity.intercept.web;
017:
018: import org.acegisecurity.ConfigAttributeDefinition;
019:
020: import org.apache.commons.logging.Log;
021: import org.apache.commons.logging.LogFactory;
022:
023: import org.apache.oro.text.regex.MalformedPatternException;
024: import org.apache.oro.text.regex.Pattern;
025: import org.apache.oro.text.regex.PatternMatcher;
026: import org.apache.oro.text.regex.Perl5Compiler;
027: import org.apache.oro.text.regex.Perl5Matcher;
028:
029: import java.util.HashSet;
030: import java.util.Iterator;
031: import java.util.List;
032: import java.util.Set;
033: import java.util.Vector;
034:
035: /**
036: * Maintains a <code>List</code> of <code>ConfigAttributeDefinition</code>s associated with different HTTP request
037: * URL regular expression patterns.<p>Regular expressions are used to match a HTTP request URL against a
038: * <code>ConfigAttributeDefinition</code>.</p>
039: * <p>The order of registering the regular expressions using the {@link #addSecureUrl(String,
040: * ConfigAttributeDefinition)} is very important. The system will identify the <b>first</b> matching regular
041: * expression for a given HTTP URL. It will not proceed to evaluate later regular expressions if a match has already
042: * been found. Accordingly, the most specific regular expressions should be registered first, with the most general
043: * regular expressions registered last.</p>
044: * <p>If no registered regular expressions match the HTTP URL, <code>null</code> is returned.</p>
045: */
046: public class RegExpBasedFilterInvocationDefinitionMap extends
047: AbstractFilterInvocationDefinitionSource implements
048: FilterInvocationDefinition {
049: //~ Static fields/initializers =====================================================================================
050:
051: private static final Log logger = LogFactory
052: .getLog(RegExpBasedFilterInvocationDefinitionMap.class);
053:
054: //~ Instance fields ================================================================================================
055:
056: private List requestMap = new Vector();
057: private boolean convertUrlToLowercaseBeforeComparison = false;
058:
059: //~ Methods ========================================================================================================
060:
061: public void addSecureUrl(String perl5RegExp,
062: ConfigAttributeDefinition attr) {
063: Pattern compiledPattern;
064: Perl5Compiler compiler = new Perl5Compiler();
065:
066: try {
067: compiledPattern = compiler.compile(perl5RegExp,
068: Perl5Compiler.READ_ONLY_MASK);
069: } catch (MalformedPatternException mpe) {
070: throw new IllegalArgumentException(
071: "Malformed regular expression: " + perl5RegExp);
072: }
073:
074: requestMap.add(new EntryHolder(compiledPattern, attr));
075:
076: if (logger.isDebugEnabled()) {
077: logger.debug("Added regular expression: "
078: + compiledPattern.getPattern().toString()
079: + "; attributes: " + attr);
080: }
081: }
082:
083: public Iterator getConfigAttributeDefinitions() {
084: Set set = new HashSet();
085: Iterator iter = requestMap.iterator();
086:
087: while (iter.hasNext()) {
088: EntryHolder entryHolder = (EntryHolder) iter.next();
089: set.add(entryHolder.getConfigAttributeDefinition());
090: }
091:
092: return set.iterator();
093: }
094:
095: public int getMapSize() {
096: return this .requestMap.size();
097: }
098:
099: public boolean isConvertUrlToLowercaseBeforeComparison() {
100: return convertUrlToLowercaseBeforeComparison;
101: }
102:
103: public ConfigAttributeDefinition lookupAttributes(String url) {
104: PatternMatcher matcher = new Perl5Matcher();
105:
106: Iterator iter = requestMap.iterator();
107:
108: if (isConvertUrlToLowercaseBeforeComparison()) {
109: url = url.toLowerCase();
110:
111: if (logger.isDebugEnabled()) {
112: logger.debug("Converted URL to lowercase, from: '"
113: + url + "'; to: '" + url + "'");
114: }
115: }
116:
117: while (iter.hasNext()) {
118: EntryHolder entryHolder = (EntryHolder) iter.next();
119:
120: boolean matched = matcher.matches(url, entryHolder
121: .getCompiledPattern());
122:
123: if (logger.isDebugEnabled()) {
124: logger.debug("Candidate is: '" + url + "'; pattern is "
125: + entryHolder.getCompiledPattern().getPattern()
126: + "; matched=" + matched);
127: }
128:
129: if (matched) {
130: return entryHolder.getConfigAttributeDefinition();
131: }
132: }
133:
134: return null;
135: }
136:
137: public void setConvertUrlToLowercaseBeforeComparison(
138: boolean convertUrlToLowercaseBeforeComparison) {
139: this .convertUrlToLowercaseBeforeComparison = convertUrlToLowercaseBeforeComparison;
140: }
141:
142: //~ Inner Classes ==================================================================================================
143:
144: protected class EntryHolder {
145: private ConfigAttributeDefinition configAttributeDefinition;
146: private Pattern compiledPattern;
147:
148: public EntryHolder(Pattern compiledPattern,
149: ConfigAttributeDefinition attr) {
150: this .compiledPattern = compiledPattern;
151: this .configAttributeDefinition = attr;
152: }
153:
154: protected EntryHolder() {
155: throw new IllegalArgumentException(
156: "Cannot use default constructor");
157: }
158:
159: public Pattern getCompiledPattern() {
160: return compiledPattern;
161: }
162:
163: public ConfigAttributeDefinition getConfigAttributeDefinition() {
164: return configAttributeDefinition;
165: }
166: }
167: }
|