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.hivemind.methodmatch;
016:
017: import java.util.ArrayList;
018: import java.util.Iterator;
019: import java.util.List;
020:
021: import org.apache.hivemind.ApplicationRuntimeException;
022: import org.apache.hivemind.HiveMind;
023: import org.apache.hivemind.Location;
024: import org.apache.hivemind.service.MethodSignature;
025:
026: /**
027: * A utility class used for matching a {@link org.apache.hivemind.service.MethodSignature} against a
028: * method pattern (this is primarily used by {@link org.apache.hivemind.ServiceInterceptorFactory
029: * interceptor factories}). A method pattern consists of a <em>name pattern</em> and an optional
030: * <em>parameters pattern</em>.
031: * <p>
032: * The name pattern matches against the method name, and can be one of the following:
033: * <ul>
034: * <li>A single name - which requires an exact match. Example: <code>perform</code>
035: * <li>A name suffix, indicated with a leading '*'. Example: <code>*form</code>
036: * <li>A name prefix, indicated with a trailing '*'. Example: <code>per*</code>
037: * <li>A name substring, indicated with leading and trailing '*'s. Example: <code>*erfo*</code>.
038: * <li>A match any, indicated with a single '*'. Example: <code>*</code>
039: * </ul>
040: * <p>
041: * The parameters pattern follows the name pattern and is optional. It is used to check the number
042: * of parameters, or their types. When the parameters pattern is omitted, then the number and types
043: * of parameters are not considred when matching methods.
044: * <p>
045: * The parameters pattern, when present, is contained within open and closed parenthis after the
046: * method pattern. Inside the parenthesis may be a number, indicating the exact number of method
047: * parameters to match against. Alternately, a comma-seperated list of Java types is used, which
048: * matches against a method that takes the exact set of parameters. Examples:
049: * <ul>
050: * <li><code>perform()</code>-- method with no parameters
051: * <li><code>perform(2)</code>-- method with two parameters
052: * <li><code>perform(java.util.List, int)</code>- method taking a List and an int parameter
053: * </ul>
054: *
055: * @author Howard Lewis Ship
056: */
057: public class MethodMatcher {
058: private class StoredPattern {
059: String _methodPattern;
060:
061: MethodFilter _filter;
062:
063: Object _patternValue;
064:
065: StoredPattern(String pattern, Object value) {
066: _methodPattern = pattern;
067: _patternValue = value;
068: }
069:
070: boolean match(MethodSignature sig) {
071: if (_filter == null) {
072:
073: try {
074: _filter = parseMethodPattern(_methodPattern);
075: } catch (RuntimeException ex) {
076: Location l = HiveMind.findLocation(new Object[] {
077: _patternValue, ex });
078:
079: if (l == null)
080: throw ex;
081:
082: throw new ApplicationRuntimeException(
083: MethodMatchMessages.exceptionAtLocation(l,
084: ex), ex);
085: }
086: }
087:
088: return _filter.matchMethod(sig);
089: }
090: }
091:
092: private MethodPatternParser _parser = new MethodPatternParser();
093:
094: private List _methodInfos;
095:
096: private Object _defaultValue;
097:
098: /**
099: * Constructor that takes a default value returned when no stored method pattern matches the
100: * input to {@link #get(MethodSignature)}.
101: *
102: * @since 1.1
103: */
104: public MethodMatcher(Object defaultValue) {
105: _defaultValue = defaultValue;
106: }
107:
108: public MethodMatcher() {
109: this (null);
110: }
111:
112: private MethodFilter parseMethodPattern(String pattern) {
113: return _parser.parseMethodPattern(pattern);
114: }
115:
116: /**
117: * Stores a pattern and an associated value. Values can later be accessed via
118: * {@link #get(MethodSignature)}.
119: *
120: * @param methodPattern
121: * a pattern that is used to recognize methods
122: * @param patternValue
123: * a value associated with the pattern
124: */
125: public synchronized void put(String methodPattern,
126: Object patternValue) {
127: if (_methodInfos == null)
128: _methodInfos = new ArrayList();
129:
130: StoredPattern sp = new StoredPattern(methodPattern,
131: patternValue);
132:
133: _methodInfos.add(sp);
134: }
135:
136: /**
137: * Returns a pattern value prevoiusly stored via {@link #put(String, Object)}. Iterates over
138: * the patterns stored, in the order in which they were stored, until a match is found.
139: *
140: * @param sig
141: * the MethodSignature to find a matching pattern for
142: * @return the pattern value for the matching pattern, or the default value if not found (the
143: * default value may be set in the constructor)
144: */
145: public synchronized Object get(MethodSignature sig) {
146: if (_methodInfos == null)
147: return _defaultValue;
148:
149: Iterator i = _methodInfos.iterator();
150: while (i.hasNext()) {
151: StoredPattern sp = (StoredPattern) i.next();
152:
153: if (sp.match(sig))
154: return sp._patternValue;
155: }
156:
157: // Not found.
158:
159: return _defaultValue;
160: }
161: }
|