View Javadoc
1 /*
2 * Pointcut.java
3 * Created on September 12, 2003
4 *
5 * The Blues Framework - A lightweight application framework
6 * Copyright (C) 2003 Lonnie Pryor
7 * http://blues.lonniepryor.com
8 *
9 * This library is free software; you can redistribute it and/or modify it under the
10 * terms of the GNU Lesser General Public License as published by the Free Software
11 * Foundation; either version 2.1 of the License, or (at your option) any later
12 * version.
13 *
14 * This library is distributed in the hope that it will be useful, but WITHOUT ANY
15 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
16 * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public License along
19 * with this library; if not, write to:
20 *
21 * The Free Software Foundation, Inc.
22 * 59 Temple Place, Suite 330
23 * Boston, MA 02111-1307 USA
24 *
25 */
26 package com.lonniepryor.blues.aop;
27
28 import com.lonniepryor.blues.util.Expression;
29 import com.lonniepryor.blues.util.Methods;
30 import com.lonniepryor.blues.util.ParseException;
31 import com.lonniepryor.blues.util.Strings;
32 import com.lonniepryor.blues.util.TokenizedStrings;
33
34 /***
35 * Specification interface for identifying JoinPoints. Instances of this class may
36 * be logically combined using the AND, OR, and NOT operations. Many common
37 * use-cases are supplied via static accessor methods.
38 *
39 * @author Lonnie Pryor
40 * @version $Revision: 1.1 $
41 */
42 public abstract class Pointcut {
43 /***
44 * Creates a new Pointcut object.
45 */
46 protected Pointcut () {
47 }
48
49 /***
50 * Creates a new specification satisified by join points whose instance name
51 * satisfy the supplied specification.
52 *
53 * @param specification The specification to test instance names with.
54 *
55 * @return A new specification satisified by join points whose instance name
56 * satisfy the supplied specification.
57 */
58 public static Pointcut invokeInstance (final Strings specification) {
59 return new Pointcut() {
60 protected boolean evaluate (Aspect aspect, JoinPoint joinPoint) {
61 return specification.isSatisfiedBy(joinPoint.getInstanceName());
62 }
63 };
64 }
65
66 /***
67 * Creates a new specification satisified by join points whose target method
68 * satisfy the supplied specification.
69 *
70 * @param specification The specification to test target methods with.
71 *
72 * @return A new specification satisified by join points whose target method
73 * satisfy the supplied specification.
74 */
75 public static Pointcut invokeMethod (final Methods specification) {
76 return new Pointcut() {
77 protected boolean evaluate (Aspect aspect, JoinPoint joinPoint) {
78 return specification.isSatisfiedBy(joinPoint.getTargetMethod());
79 }
80 };
81 }
82
83 /***
84 * Creates a new specification satisified by join points that satisfy the named
85 * pointcut.
86 *
87 * @param poincutName The name of the pointcut to evaluate.
88 *
89 * @return A new specification satisified by join points that satisfy the named
90 * pointcut.
91 */
92 public static Pointcut refrence (final String poincutName) {
93 return new Pointcut() {
94 protected boolean evaluate (Aspect aspect, JoinPoint joinPoint) {
95 return aspect.callPointcut(poincutName, joinPoint);
96 }
97 };
98 }
99
100 /***
101 * Parses a pattern consisting of a pointcut declaration. Format:
102 * <pre>
103 * pointcut ::= invoke-pointcut | named-pointcut
104 * invoke-pointcut ::= "invoke" "(" invoke-params ")"
105 * invoke-params ::= [ "[" instance-pattern "]" ] method-pattern.
106 * instance-pattern ::= A '/'-delimeted {@link com.lonniepryor.blues.util.TokenizedStrings} pattern expression.
107 * method-pattern ::= A {@link com.lonniepryor.blues.util.Methods} pattern.
108 * named-pointcut ::= name "(" ")"
109 * name ::= Any valid Java name except "invoke".
110 * </pre>
111 * Example:
112 * <pre>
113 * invoke([aService || anotherService] void *(int, ..))
114 * </pre>
115 * The above creates a specification satisified by join points on instances named
116 * 'aService' or 'anotherService', with a target method that returns void and
117 * takes an int as its first parameter.
118 *
119 * @param pointcutPattern The pattern definition string.
120 *
121 * @return A specification matching the pattern.
122 *
123 * @throws ParseException if the pattern is invalid.
124 *
125 * @see com.lonniepryor.blues.util.Methods#parse(String)
126 * @see com.lonniepryor.blues.util.TokenizedStrings#parseExpression(String, char)
127 */
128 public static Pointcut parse (String pointcutPattern) {
129 int nameStart = Expression.ltrim(pointcutPattern, 0, pointcutPattern.length());
130 if (nameStart == pointcutPattern.length())
131 throw new ParseException("Illegal empty pointcut pattern");
132 int firstParen = pointcutPattern.indexOf('(', nameStart + 1);
133 if (firstParen < 0)
134 throw new ParseException(
135 "Opening parenthesis not found in '" + pointcutPattern + "'");
136 int nameEnd = Expression.rtrim(pointcutPattern, nameStart, firstParen);
137 if (nameEnd == nameStart)
138 throw new ParseException(
139 "No pointcut name found in '" + pointcutPattern + "'");
140 int lastParen = pointcutPattern.lastIndexOf(')');
141 if (lastParen < 0)
142 throw new ParseException(
143 "Unmatched parenthesis in '" + pointcutPattern + "'");
144 int paramsStart = Expression.ltrim(pointcutPattern, firstParen + 1, lastParen);
145 int paramsEnd = Expression.rtrim(pointcutPattern, paramsStart, lastParen);
146 if ("invoke".regionMatches(0, pointcutPattern, nameStart, nameEnd)) {
147 if (paramsStart == paramsEnd)
148 throw new ParseException(
149 "Illegal empty parameters for invoke() in '" + pointcutPattern + "'");
150 return readInvokeParams(pointcutPattern, paramsStart, paramsEnd);
151 }
152 if (paramsStart != paramsEnd)
153 throw new ParseException(
154 "Cannot pass parameters to refrenced pointcuts in '" + pointcutPattern
155 + "'");
156 return refrence(pointcutPattern.substring(nameStart, nameEnd));
157 }
158
159 /***
160 * Reads the parameters for an 'invoke' pointcut definition.
161 *
162 * @param pointcutPattern The pattern definition string.
163 * @param start The start of the parameters section.
164 * @param end The end of the parameters section.
165 *
166 * @return A specification matching the 'invoke' pointcut definition.
167 *
168 * @throws ParseException if the pattern is invalid.
169 */
170 private static Pointcut readInvokeParams (
171 String pointcutPattern, int start, int end) {
172 Pointcut spec = null;
173 if (pointcutPattern.charAt(start) == '[') {
174 int instanceNameEnd = pointcutPattern.indexOf(']', start);
175 if (instanceNameEnd < 0)
176 throw new ParseException(
177 "No closing instance name bracket found in '" + pointcutPattern + "'");
178 spec = invokeInstance(
179 TokenizedStrings.parseExpression(
180 pointcutPattern.substring(start + 1, instanceNameEnd), '/'));
181 start = Expression.ltrim(pointcutPattern, instanceNameEnd + 1, end);
182 }
183 if (start == end)
184 throw new ParseException(
185 "Method pattern not found in '" + pointcutPattern + "'");
186 Methods methodsSpec = Methods.parse(pointcutPattern.substring(start, end));
187 return (spec == null) ? invokeMethod(methodsSpec)
188 : invokeMethod(methodsSpec).and(spec);
189 }
190
191 /***
192 * Parses a logical expression as described in the Expression class, using this
193 * class's parse() method for creating values.
194 *
195 * @param pointcutPatternExpr The pattern expression definition string.
196 *
197 * @return A specification matching the pattern expression.
198 *
199 * @throws ParseException if the pattern expression is invalid.
200 *
201 * @see com.lonniepryor.blues.util.Expression
202 * @see Pointcut#parse(String)
203 */
204 public static Pointcut parseExpression (String pointcutPatternExpr) {
205 return (Pointcut)Expression.parse(
206 pointcutPatternExpr,
207 new Expression.Builder() {
208 public Object or (Object left, Object right) {
209 return ((Pointcut)left).or((Pointcut)right);
210 }
211
212 public Object and (Object left, Object right) {
213 return ((Pointcut)left).and((Pointcut)right);
214 }
215
216 public Object not (Object value) {
217 return ((Pointcut)value).not();
218 }
219
220 public Object create (String pointcutPattern) {
221 return parse(pointcutPattern);
222 }
223 });
224 }
225
226 /***
227 * Returns true if the parameters are not null and the supplied join point
228 * satisfies this pointcut.
229 *
230 * @param aspect The aspect to lookup refrenced pointcuts on.
231 * @param joinPoint The join point to evaluate.
232 *
233 * @return True if the parameters are not null and the supplied join point
234 * satisfies this pointcut.
235 */
236 public final boolean isSatisfiedBy (Aspect aspect, JoinPoint joinPoint) {
237 return (aspect != null) && (joinPoint != null) && evaluate(aspect, joinPoint);
238 }
239
240 /***
241 * Returns true if the supplied join point satisfies this pointcut.
242 *
243 * @param aspect The aspect to lookup refrenced pointcuts on.
244 * @param joinPoint The join point to evaluate.
245 *
246 * @return True if the supplied join point satisfies this pointcut.
247 */
248 protected abstract boolean evaluate (Aspect aspect, JoinPoint joinPoint);
249
250 /***
251 * Returns a specification representing a logical AND of this specification on
252 * the left and the supplied specification on the right.
253 *
254 * @param specification The specification to AND with.
255 *
256 * @return A specification representing a logical AND of this specification on
257 * the left and the supplied specification on the right.
258 */
259 public final Pointcut and (final Pointcut specification) {
260 return new Pointcut() {
261 public boolean evaluate (Aspect aspect, JoinPoint joinPoint) {
262 return Pointcut.this.evaluate(aspect, joinPoint)
263 && specification.evaluate(aspect, joinPoint);
264 }
265 };
266 }
267
268 /***
269 * Returns a specification representing a logical OR of this specification on the
270 * left and the supplied specification on the right.
271 *
272 * @param specification The specification to OR with.
273 *
274 * @return A specification representing a logical OR of this specification on the
275 * left and the supplied specification on the right.
276 */
277 public final Pointcut or (final Pointcut specification) {
278 return new Pointcut() {
279 public boolean evaluate (Aspect aspect, JoinPoint joinPoint) {
280 return Pointcut.this.evaluate(aspect, joinPoint)
281 || specification.evaluate(aspect, joinPoint);
282 }
283 };
284 }
285
286 /***
287 * Returns a specification representing a logical NOT of this specification.
288 *
289 * @return A specification representing a logical NOT of this specification.
290 */
291 public final Pointcut not () {
292 return new Pointcut() {
293 public boolean evaluate (Aspect aspect, JoinPoint joinPoint) {
294 return !Pointcut.this.evaluate(aspect, joinPoint);
295 }
296 };
297 }
298 }
This page was automatically generated by Maven