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 }