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.List;
019
020 import org.apache.hivemind.ApplicationRuntimeException;
021 import org.apache.hivemind.util.StringUtils;
022
023 /**
024 * Parses a method pattern (consisting of a name pattern, followed by an optional parameters
025 * pattern) into a {@link org.apache.hivemind.methodmatch.MethodFilter}. In most cases, the
026 * patterns will require several checks (i.e., match against name, match against parameters) in
027 * which case a {@link org.apache.hivemind.methodmatch.CompositeFilter} is returned.
028 *
029 * @author Howard Lewis Ship
030 */
031
032 public class MethodPatternParser
033 {
034 private List _filters;
035
036 public MethodFilter parseMethodPattern(String pattern)
037 {
038 _filters = new ArrayList();
039
040 int parenx = pattern.indexOf('(');
041
042 String namePattern = parenx < 0 ? pattern : pattern.substring(0, parenx);
043
044 parseNamePattern(pattern, namePattern);
045
046 if (parenx >= 0)
047 parseParametersPattern(pattern, pattern.substring(parenx));
048
049 switch (_filters.size())
050 {
051 case 0:
052 return new MatchAllFilter();
053
054 case 1:
055
056 return (MethodFilter) _filters.get(0);
057
058 default:
059 return new CompositeFilter(_filters);
060 }
061 }
062
063 private void parseNamePattern(String methodPattern, String namePattern)
064 {
065 if (namePattern.equals("*"))
066 return;
067
068 if (namePattern.length() == 0)
069 throw new ApplicationRuntimeException(MethodMatchMessages
070 .missingNamePattern(methodPattern));
071
072 if (namePattern.startsWith("*") && namePattern.endsWith("*"))
073 {
074 String substring = namePattern.substring(1, namePattern.length() - 1);
075
076 validateNamePattern(methodPattern, substring);
077
078 _filters.add(new InfixNameFilter(substring));
079 return;
080 }
081
082 if (namePattern.startsWith("*"))
083 {
084 String suffix = namePattern.substring(1);
085
086 validateNamePattern(methodPattern, suffix);
087
088 _filters.add(new NameSuffixFilter(suffix));
089 return;
090 }
091
092 if (namePattern.endsWith("*"))
093 {
094 String prefix = namePattern.substring(0, namePattern.length() - 1);
095
096 validateNamePattern(methodPattern, prefix);
097
098 _filters.add(new NamePrefixFilter(prefix));
099 return;
100 }
101
102 validateNamePattern(methodPattern, namePattern);
103
104 _filters.add(new ExactNameFilter(namePattern));
105 }
106
107 private void parseParametersPattern(String methodPattern, String pattern)
108 {
109 if (pattern.equals("()"))
110 {
111 addParameterCountFilter(0);
112 return;
113 }
114
115 if (!pattern.endsWith(")"))
116 throw new ApplicationRuntimeException(MethodMatchMessages
117 .invalidParametersPattern(methodPattern));
118
119 // Trim off leading and trailing parens.
120
121 pattern = pattern.substring(1, pattern.length() - 1);
122
123 char ch = pattern.charAt(0);
124
125 if (Character.isDigit(ch))
126 {
127 addParameterCountFilter(methodPattern, pattern);
128 return;
129 }
130
131 String[] names = StringUtils.split(pattern);
132
133 // Would be nice to do some kind of validation here, to prove
134 // that the provided class names exist, and that
135 // primitive types names are valid.
136
137 addParameterCountFilter(names.length);
138 for (int i = 0; i < names.length; i++)
139 _filters.add(new ParameterFilter(i, names[i].trim()));
140
141 }
142
143 private void addParameterCountFilter(String methodPattern, String pattern)
144 {
145 try
146 {
147 int count = Integer.parseInt(pattern);
148 addParameterCountFilter(count);
149 }
150 catch (NumberFormatException ex)
151 {
152 throw new ApplicationRuntimeException(MethodMatchMessages
153 .invalidParametersPattern(methodPattern));
154 }
155 }
156
157 private void addParameterCountFilter(int count)
158 {
159 // Add the count filter first, since it is always the least expensive test.
160 _filters.add(0, new ParameterCountFilter(count));
161 }
162
163 private void validateNamePattern(String methodPattern, String nameSubstring)
164 {
165 if (nameSubstring.indexOf('*') >= 0)
166 throw new ApplicationRuntimeException(MethodMatchMessages
167 .invalidNamePattern(methodPattern));
168 }
169 }