1 22 package org.jboss.aop.advice; 23 24 import java.lang.reflect.Method ; 25 import java.util.ArrayList ; 26 27 import javassist.NotFoundException; 28 29 import org.jboss.aop.JoinPointInfo; 30 import org.jboss.aop.joinpoint.Invocation; 31 import org.jboss.aop.util.ReflectUtils; 32 33 39 public class AdviceMethodFactory 40 { 41 private static final int IS_BEFORE = 1; 42 private static final int IS_AFTER = 2; 43 private static final int IS_THROWING = 3; 44 private static final int IS_AROUND = 4; 45 46 public static final AdviceMethodFactory BEFORE = new AdviceMethodFactory(IS_BEFORE, false, true, false, false); 47 public static final AdviceMethodFactory AFTER = new AdviceMethodFactory(IS_AFTER, false, true, true, false); 48 public static final AdviceMethodFactory THROWING = new AdviceMethodFactory(IS_THROWING, false, true, false, true); 49 public static final AdviceMethodFactory AROUND = new AdviceMethodFactory(IS_AROUND, true, false, false, false); 50 51 private static final Class INVOCATION = Invocation.class; 52 private static final Class THROWABLE = Throwable .class; 53 54 int type; 55 boolean canHaveJoinpoint; 56 boolean canHaveInvocation; 57 boolean mustHaveReturnType; 58 boolean mustHaveThrowable; 59 60 static final MatchData BEST_MATCH_START = new MatchData(); 61 62 private AdviceMethodFactory(int type, boolean canHaveInvocation, boolean canHaveJoinpoint, boolean canHaveReturnType, boolean canHaveThrowable) 63 { 64 this.type = type; 65 this.canHaveInvocation = canHaveInvocation; 66 this.canHaveJoinpoint = canHaveJoinpoint; 67 this.mustHaveReturnType = canHaveReturnType; 68 this.mustHaveThrowable = canHaveThrowable; 69 } 70 71 public AdviceMethodProperties findAdviceMethod(AdviceMethodProperties properties) 72 { 73 Method [] methods = ReflectUtils.getMethodsWithName(properties.getAspectClass(), properties.getAdviceName()); 74 75 if (methods.length == 0) return null; 76 if (methods.length == 1 && methods[0].getParameterTypes().length == 0) 77 { 78 if (mustHaveReturnType && !properties.getJoinpointReturnType().equals(Void.TYPE)) 79 { 80 return null; 81 } 82 if (mustHaveThrowable) 83 { 84 return null; 85 } 86 properties.setFoundProperties(methods[0], new ArrayList ()); 87 return properties; 88 } 89 90 MatchData bestMatch = BEST_MATCH_START; 91 for (int i = 0 ; i < methods.length ; i++) 92 { 93 MatchData matchData = matchParameters(properties, methods[i], bestMatch); 94 if (matchData != null) 95 { 96 bestMatch = matchData; 97 } 98 } 99 100 if (bestMatch.method != null) 101 { 102 return setupMethodAndArgsInProperties(properties, bestMatch); 103 } 104 105 106 return null; 107 } 108 109 private AdviceMethodProperties setupMethodAndArgsInProperties(AdviceMethodProperties properties, MatchData matchData) 110 { 111 ArrayList args = new ArrayList (); 112 if (matchData.invocationMatchDegree >= 0) 113 { 114 if (canHaveInvocation) args.add(AdviceMethodProperties.INVOCATION_ARG); 115 else if (canHaveJoinpoint) args.add(AdviceMethodProperties.JOINPOINT_ARG); 116 } 117 118 if (matchData.returnOrThrowingMatchDegree >= 0) 119 { 120 if (mustHaveReturnType) args.add(AdviceMethodProperties.RETURN_ARG); 121 else if (mustHaveThrowable) args.add(AdviceMethodProperties.THROWABLE_ARG); 122 } 123 124 if (matchData.argsIndices != null) 125 { 126 args.addAll(matchData.argsIndices); 127 } 128 129 properties.setFoundProperties(matchData.method, args); 130 131 return properties; 132 } 133 134 private MatchData matchParameters(AdviceMethodProperties properties, Method adviceMethod, MatchData bestMatch) 135 { 136 Class [] adviceParams = adviceMethod.getParameterTypes(); 137 if (adviceParams.length == 0 && bestMatch.method == null) return new MatchData(adviceMethod); 138 139 MatchData currentMatch = lookForJoinPointInfoOrInvocation(properties, adviceMethod, bestMatch); 140 if (currentMatch == null) 141 { 142 return null; 143 } 144 145 currentMatch = lookForThrowingOrReturn(properties, adviceMethod, currentMatch, bestMatch); 146 if (currentMatch == null) 147 { 148 return null; 149 } 150 151 currentMatch = matchActualArgs(properties, adviceMethod, currentMatch, bestMatch); 152 if (currentMatch == null) 153 { 154 return null; 155 } 156 157 if (currentMatch.currentParam == adviceMethod.getParameterTypes().length) return currentMatch; 158 159 return currentMatch; 160 } 161 162 163 164 168 private MatchData lookForJoinPointInfoOrInvocation(AdviceMethodProperties properties, Method method, MatchData bestMatch) 169 { 170 Class [] adviceParams = method.getParameterTypes(); 171 int index = 0; 172 int matchDegree = -1; 173 boolean firstIsSpecial = false; 174 175 if (canHaveInvocation) 176 { 177 if (isInvocation(adviceParams[index])) 179 { 180 firstIsSpecial = true; 181 matchDegree = matchClass(adviceParams[index], properties.getInvocationType()); 182 } 183 } 184 else if (canHaveJoinpoint) 185 { 186 if (isInfo(adviceParams[index])) 188 { 189 firstIsSpecial = true; 190 matchDegree = matchClass(adviceParams[index], properties.getInfoType()); 191 } 192 } 193 194 if (firstIsSpecial) 195 { 196 if (matchDegree < 0) 197 { 198 return null; 200 } 201 else 202 { 203 index++; 204 } 205 } 206 207 if (bestMatch.invocationMatchDegree >= 0 && (bestMatch.invocationMatchDegree < matchDegree || !firstIsSpecial)) 209 { 210 return null; 211 } 212 213 return new MatchData(method, index, matchDegree); 214 } 215 216 private MatchData lookForTargetObject(AdviceMethodProperties properties, Method adviceMethod, MatchData currentMatch, MatchData bestMatch) throws NotFoundException 217 { 218 return currentMatch; 219 } 220 221 private MatchData lookForThrowingOrReturn(AdviceMethodProperties properties, Method adviceMethod, MatchData currentMatch, MatchData bestMatch) 222 { 223 if (currentMatch.currentParam == adviceMethod.getParameterTypes().length) 224 { 225 return currentMatch; 226 } 227 228 if (mustHaveReturnType) 229 { 230 currentMatch = lookForReturn(properties, adviceMethod, currentMatch, bestMatch); 231 if (currentMatch == null) 232 { 233 return null; 234 } 235 } 236 else if (mustHaveThrowable) 237 { 238 currentMatch.returnOrThrowingMatchDegree = matchClass(adviceMethod.getParameterTypes()[currentMatch.currentParam], THROWABLE); 240 currentMatch.currentParam++; 241 } 242 243 if (bestMatch.returnOrThrowingMatchDegree >= 0 && bestMatch.returnOrThrowingMatchDegree < currentMatch.returnOrThrowingMatchDegree) 245 { 246 return null; 247 } 248 return currentMatch; 249 } 250 251 private MatchData lookForReturn(AdviceMethodProperties properties, Method adviceMethod, MatchData currentMatch, MatchData bestMatch) 252 { 253 Class returnType = properties.getJoinpointReturnType(); 255 if (returnType == null || returnType.equals(Void.TYPE)) 256 { 257 } 258 else 259 { 260 currentMatch.returnOrThrowingMatchDegree = subClassMatch(returnType, adviceMethod.getReturnType()); 263 264 265 266 if (currentMatch.returnOrThrowingMatchDegree < 0) 267 { 268 return null; 269 } 270 271 Class param = adviceMethod.getParameterTypes()[currentMatch.currentParam]; 273 274 if (!returnType.equals(param)) 275 { 276 int match2 = subClassMatch(returnType, param); 277 if (match2 < 0) 278 { 279 return null; 280 } 281 282 currentMatch.returnOrThrowingMatchDegree = (currentMatch.returnOrThrowingMatchDegree + match2)/2; 283 } 284 currentMatch.currentParam++; 285 } 286 287 return currentMatch; 288 } 289 290 private MatchData matchActualArgs(AdviceMethodProperties properties, Method adviceMethod, MatchData currentMatch, MatchData bestMatch) 291 { 292 int adviceParam = currentMatch.currentParam; 293 Class [] adviceParams = adviceMethod.getParameterTypes(); 294 295 Class [] targetParams = properties.getJoinpointParameters(); 296 297 if (adviceParams.length - currentMatch.currentParam > targetParams.length) 298 { 299 return null; 301 } 302 303 if (adviceParam == adviceParams.length) 304 { 305 return nullOrCurrentMatch(currentMatch, bestMatch); 307 } 308 309 currentMatch.argsIndices = new ArrayList (); 310 for (int i = 0; i < targetParams.length && adviceParam < adviceParams.length; i++) 311 { 312 int match = matchClass(adviceParams[adviceParam], targetParams[i]); 313 if (match < 0) 314 { 315 continue; 316 } 317 else 318 { 319 adviceParam++; 320 currentMatch.argsIndices.add(new Integer (i)); 321 currentMatch.argsDegreeSum += match; 322 } 323 } 324 325 if (currentMatch.argsIndices.size() != adviceParams.length - currentMatch.currentParam) 326 { 327 return null; 328 } 329 330 return nullOrCurrentMatch(currentMatch, bestMatch); 331 } 332 333 336 private MatchData nullOrCurrentMatch(MatchData currentMatch, MatchData bestMatch) 337 { 338 if (currentMatch.compare(bestMatch, true) < 0) 339 { 340 return currentMatch; 341 } 342 343 return null; 344 } 345 346 private boolean isInvocation(Class clazz) 347 { 348 return Invocation.class.isAssignableFrom(clazz); 349 } 350 351 private boolean isInfo(Class clazz) 352 { 353 return JoinPointInfo.class.isAssignableFrom(clazz); 354 } 355 356 360 private int matchClass(Class clazz, Class lookingFor) 361 { 362 return matchClass(clazz, lookingFor, 0); 363 } 364 365 private int subClassMatch(Class clazz, Class superClass) 366 { 367 return matchClass(superClass, clazz); 368 } 369 370 private int matchClass(Class wanted, Class candidate, int matchDegree) 371 { 372 if (candidate == null) return -1; 373 if (candidate.equals(wanted)) 374 { 375 return matchDegree; 376 } 377 378 matchDegree++; 379 380 Class [] interfaces = candidate.getInterfaces(); 381 for (int i = 0 ; i < interfaces.length ; i++) 382 { 383 if (matchClass(wanted, interfaces[i], matchDegree) > 0) return matchDegree; 384 } 385 386 if (matchClass(wanted, candidate.getSuperclass(), matchDegree) > 0) return matchDegree; 387 388 return -1; 389 } 390 391 } 392 393 class MatchData 394 { 395 Method method; 396 int invocationMatchDegree = -1; 397 int returnOrThrowingMatchDegree = -1; 398 ArrayList argsIndices = null; 399 int argsDegreeSum = 0; 400 401 int currentParam; 402 403 MatchData() 404 { 405 } 406 407 MatchData(Method method) 408 { 409 this.method = method; 410 } 411 412 MatchData(Method method, int currentParam, int firstParamMatchDegree) 413 { 414 this.method = method; 415 this.currentParam = currentParam; 416 this.invocationMatchDegree = firstParamMatchDegree; 417 } 418 419 public String toString() 420 { 421 return "MatchData[invMatch="+ invocationMatchDegree + "rtnMatch=" + returnOrThrowingMatchDegree + "args=" + ((argsIndices != null )? argsIndices.size() : 0) + "sum=" + argsDegreeSum + "]"; 422 } 423 424 427 int compare(MatchData other, boolean checkArgs) 428 { 429 int invMatch = compareMatchDegrees(this.invocationMatchDegree, other.invocationMatchDegree); 430 if (invMatch != 0) 431 { 432 return invMatch; 433 } 434 435 int retMatch = compareMatchDegrees(this.returnOrThrowingMatchDegree, other.returnOrThrowingMatchDegree); 436 if (retMatch != 0) 437 { 438 return retMatch; 439 } 440 441 if (checkArgs) 442 { 443 if (this.argsIndices == null && other.argsIndices == null) return 0; 444 else if (this.argsIndices != null && other.argsIndices == null) return -1; 445 else if (this.argsIndices == null && other.argsIndices != null) return 1; 446 else 447 { 448 if (this.argsIndices.size() > other.argsIndices.size()) return -1; 449 else if (this.argsIndices.size() < other.argsIndices.size()) return 1; 450 else 451 { 452 return this.argsDegreeSum < other.argsDegreeSum ? -1 : 1; 453 } 454 } 455 } 456 457 return 0; 458 } 459 460 463 int compareMatchDegrees(int mine, int other) 464 { 465 if (mine < 0 && other >= 0) 466 { 467 return 1; 468 } 469 else if (mine >= 0 && other < 0) 470 { 471 return -1; 472 } 473 else if (mine >= 0 && other >= 0 && mine != other) 474 { 475 return mine > other ? -1 : 1; 476 } 477 478 return 0; } 480 481 } 482 | Popular Tags |