View Javadoc

1   /*
2    * Jour - java profiler and monitoring library
3    *
4    * Copyright (C) 2004 Jour team
5    *
6    * This library is free software; you can redistribute it and/or
7    * modify it under the terms of the GNU Library General Public
8    * License as published by the Free Software Foundation; either
9    * version 2 of the License, or (at your option) any later version.
10   *
11   * This library is distributed in the hope that it will be useful,
12   * but WITHOUT ANY WARRANTY; without even the implied warranty of
13   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14   * Library General Public License for more details.
15   *
16   * You should have received a copy of the GNU Library General Public
17   * License along with this library; if not, write to the
18   * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19   * Boston, MA  02111-1307, USA.
20   */
21  package net.sf.jour.filter;
22  
23  import javassist.ClassPool;
24  import javassist.CtClass;
25  import javassist.CtConstructor;
26  import javassist.CtMethod;
27  import javassist.NotFoundException;
28  import net.sf.jour.log.Logger;
29  import net.sf.jour.util.RegExUtil;
30  
31  /**
32   * @author michaellif
33   */
34  public class Pointcut extends MatchStringFilter {
35  
36  	protected static final Logger log = Logger.getLogger();
37  
38  	private static String modifierKeywords = "((final)|(static)|(native)|(synchronized)|(private)|(public)|(protected))";
39  
40  	private static String modifierListPattern = "(" + modifierKeywords + "(([;,]!?)" + modifierKeywords + ")*)";
41  
42  	private static String interfaceMethodsPattern = "(\\S*)\\s*(\\S*)\\s*->\\s*(\\S*)\\s*\\((.*)\\)";
43  
44  	private static String classMethodsPattern = "(\\S*)\\s*(\\S*)\\s*=>\\s*(\\S*)\\s*\\((.*)\\)";
45  
46  	private static String methodPattern = "\\s*(\\S*)\\s*(\\S*)\\s*\\((.*)\\)";
47  
48  	private String retType = "";
49  
50  	private MatchStringListFilter retTypeFilter = new MatchStringListFilter();
51  
52  	private PointcutModifierListFiler modifierListFiler = new PointcutModifierListFiler();
53  
54  	private String classType = "*";
55  
56  	private String interfaceType;
57  
58  	private String classMethodsType;
59  
60  	private CtClass filterCtClass;
61  
62  	private String methodName = "";
63  
64  	PointcutParamsFilter paramsFilter = new PointcutParamsFilter();
65  
66  	/**
67       * Creates a new Pointcut object.
68       */
69  	public Pointcut(String expr) {
70  		String mod = RegExUtil.getParen(expr, modifierListPattern);
71  		if (mod != null) {
72  			if (debug) {
73  				log.debug("modexpr: " + expr);
74  				log.debug("mod: " + mod);
75  			}
76  			modifierListFiler.addPatterns(mod);
77  			expr = expr.substring(mod.length());
78  		}
79  		String[] interfaceResult = RegExUtil.match(expr, interfaceMethodsPattern);
80  		if ((debug) && (interfaceResult.length != 0)) {
81  			log.debug("interface expr: " + expr);
82  			for (int i = 0; i < interfaceResult.length; i++) {
83  				log.debug(i + " " + interfaceResult[i]);
84  			}
85  		}
86  		if (interfaceResult.length == 4) {
87  			log.debug("use interface expr: " + expr);
88  			interfaceType = interfaceResult[1];
89  		} else {
90  			interfaceResult = RegExUtil.match(expr, classMethodsPattern);
91  			if (interfaceResult.length == 4) {
92  				log.debug("use classMethods as filter expr: " + expr);
93  				classMethodsType = interfaceResult[1];
94  			}
95  		}
96  
97  		if (interfaceResult.length == 4) {
98  			retType = interfaceResult[0];
99  			retTypeFilter.addPatterns(retType);
100 
101 			methodName = interfaceResult[2];
102 			super.setPattern(methodName);
103 			paramsFilter.setParams(interfaceResult[3]);
104 
105 			modifierListFiler.initialized();
106 		} else {
107 			String[] result = RegExUtil.match(expr, methodPattern);
108 			if (debug) {
109 				log.debug("expr: " + expr);
110 				for (int i = 0; i < result.length; i++) {
111 					log.debug(i + " " + result[i]);
112 				}
113 			}
114 
115 			if (result.length == 3) {
116 				retType = result[0];
117 				retTypeFilter.addPatterns(retType);
118 				methodName = result[1];
119 				super.setPattern(methodName);
120 				paramsFilter.setParams(result[2]);
121 				modifierListFiler.initialized();
122 			} else {
123 				log.error("wrong pointcut expr \"" + expr + "\"");
124 			}
125 		}
126 	}
127 
128 	public int matchState(Object obj) {
129 		if (obj instanceof CtClass) {
130 			return b2Match(acceptClass((CtClass) obj));
131 		} else if (obj instanceof CtMethod) {
132 			return b2Match(acceptMethod((CtMethod) obj));
133 		} else {
134 			return super.matchState(obj);
135 		}
136 	}
137 
138 	private CtClass getclassAsMethodsFilter(ClassPool pool) {
139 		if (this.filterCtClass != null) {
140 			return this.filterCtClass;
141 		}
142 
143 		if (this.interfaceType != null) {
144 			return loadFilterClass(pool, this.interfaceType);
145 		} else if (this.classMethodsType != null) {
146 			return loadFilterClass(pool, this.classMethodsType);
147 		} else {
148 			return null;
149 		}
150 	}
151 
152 	private CtClass loadFilterClass(ClassPool pool, String className) {
153 		if (className == null) {
154 			return null;
155 		}
156 		try {
157 			this.filterCtClass = pool.get(className);
158 		} catch (NotFoundException nfe) {
159 			log.error("Error ", nfe);
160 			throw new Error(nfe.getMessage());
161 		}
162 		return this.filterCtClass;
163 	}
164 
165 	public boolean acceptClass(CtClass clazz) {
166 		return acceptClass(clazz.getName()) && acceptImplements(clazz);
167 	}
168 
169 	public boolean acceptImplements(CtClass clazz) {
170 		if (this.interfaceType == null) {
171 			return true;
172 		}
173 		CtClass ka[];
174 		try {
175 			ka = clazz.getInterfaces();
176 		} catch (NotFoundException e) {
177 			log.error("Error", e);
178 			throw new Error(e.getMessage());
179 		}
180 		for (int i = 0; i < ka.length; i++) {
181 			String name = ka[i].getName();
182 			if (name.equals(interfaceType)) {
183 				return true;
184 			}
185 		}
186 		return false;
187 	}
188 
189 	protected boolean acceptClass(String clazz) {
190 		return super.accept(getGlobPattern(classType), clazz);
191 	}
192 
193 	public boolean acceptMethod(CtMethod method) {
194 		try {
195 			String name = method.getName();
196 			CtClass[] paramTypes = method.getParameterTypes();
197 
198 			CtClass mFilterClass = getclassAsMethodsFilter(method.getDeclaringClass().getClassPool());
199 			if (mFilterClass != null) {
200 				CtMethod has = null;
201 				try {
202 					// this method does not search the superclasses
203 					has = mFilterClass.getDeclaredMethod(name, paramTypes);
204 				} catch (NotFoundException e) {
205 					return false;
206 				}
207 				if (has == null) {
208 					return false;
209 				}
210 			}
211 
212 			String[] params = new String[paramTypes.length];
213 			for (int i = 0; i < paramTypes.length; i++) {
214 				params[i] = paramTypes[i].getName();
215 			}
216 
217 			String retType = method.getReturnType().getName();
218 
219 			return super.match(name) && retTypeFilter.match(retType) && paramsFilter.match(params)
220 					&& modifierListFiler.match(method.getModifiers());
221 
222 		} catch (NotFoundException nfe) {
223 			log.error("Error", nfe);
224 			return false;
225 		}
226 	}
227 
228 	boolean acceptMethod(String method, String[] params, String retType) {
229 		// was TODO to add check for retType and params
230 		// return super.accept(getGlobPattern(methodName), method);
231 		return super.match(method) && retTypeFilter.match(retType) && paramsFilter.match(params);
232 	}
233 
234 	public boolean acceptConstr(CtConstructor constr) {
235 		try {
236 			CtClass[] paramTypes = constr.getParameterTypes();
237 			String[] params = new String[paramTypes.length];
238 			for (int i = 0; i < paramTypes.length; i++) {
239 				params[i] = paramTypes[i].getName();
240 			}
241 			return acceptConstr(params);
242 		} catch (NotFoundException nfe) {
243 			nfe.printStackTrace();
244 			return false;
245 		}
246 	}
247 
248 	protected boolean acceptConstr(String[] params) {
249 		// TODO to add check for params
250 		// return super.accept(getGlobPattern(methodName), "new");
251 		return super.match("new");
252 	}
253 
254 	public String getMethodName() {
255 		return methodName;
256 	}
257 
258 	public String getRetType() {
259 		return retType;
260 	}
261 
262 }