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 {
059 private class StoredPattern
060 {
061 String _methodPattern;
062
063 MethodFilter _filter;
064
065 Object _patternValue;
066
067 StoredPattern(String pattern, Object value)
068 {
069 _methodPattern = pattern;
070 _patternValue = value;
071 }
072
073 boolean match(MethodSignature sig)
074 {
075 if (_filter == null)
076 {
077
078 try
079 {
080 _filter = parseMethodPattern(_methodPattern);
081 }
082 catch (RuntimeException ex)
083 {
084 Location l = HiveMind.findLocation(new Object[]
085 { _patternValue, ex });
086
087 if (l == null)
088 throw ex;
089
090 throw new ApplicationRuntimeException(MethodMatchMessages.exceptionAtLocation(
091 l,
092 ex), ex);
093 }
094 }
095
096 return _filter.matchMethod(sig);
097 }
098 }
099
100 private MethodPatternParser _parser = new MethodPatternParser();
101
102 private List _methodInfos;
103
104 private Object _defaultValue;
105
106 /**
107 * Constructor that takes a default value returned when no stored method pattern matches the
108 * input to {@link #get(MethodSignature)}.
109 *
110 * @since 1.1
111 */
112 public MethodMatcher(Object defaultValue)
113 {
114 _defaultValue = defaultValue;
115 }
116
117 public MethodMatcher()
118 {
119 this(null);
120 }
121
122 private MethodFilter parseMethodPattern(String pattern)
123 {
124 return _parser.parseMethodPattern(pattern);
125 }
126
127 /**
128 * Stores a pattern and an associated value. Values can later be accessed via
129 * {@link #get(MethodSignature)}.
130 *
131 * @param methodPattern
132 * a pattern that is used to recognize methods
133 * @param patternValue
134 * a value associated with the pattern
135 */
136 public synchronized void put(String methodPattern, Object patternValue)
137 {
138 if (_methodInfos == null)
139 _methodInfos = new ArrayList();
140
141 StoredPattern sp = new StoredPattern(methodPattern, patternValue);
142
143 _methodInfos.add(sp);
144 }
145
146 /**
147 * Returns a pattern value prevoiusly stored via {@link #put(String, Object)}. Iterates over
148 * the patterns stored, in the order in which they were stored, until a match is found.
149 *
150 * @param sig
151 * the MethodSignature to find a matching pattern for
152 * @return the pattern value for the matching pattern, or the default value if not found (the
153 * default value may be set in the constructor)
154 */
155 public synchronized Object get(MethodSignature sig)
156 {
157 if (_methodInfos == null)
158 return _defaultValue;
159
160 Iterator i = _methodInfos.iterator();
161 while (i.hasNext())
162 {
163 StoredPattern sp = (StoredPattern) i.next();
164
165 if (sp.match(sig))
166 return sp._patternValue;
167 }
168
169 // Not found.
170
171 return _defaultValue;
172 }
173 }