| 1 18 19 package org.objectweb.jac.core; 20 21 import gnu.regexp.RE; 22 import gnu.regexp.REException; 23 import gnu.regexp.RESyntax; 24 import java.util.Arrays ; 25 import java.util.Collection ; 26 import java.util.HashSet ; 27 import java.util.Hashtable ; 28 import java.util.Iterator ; 29 import java.util.List ; 30 import java.util.StringTokenizer ; 31 import java.util.Vector ; 32 import org.apache.log4j.Logger; 33 import org.objectweb.jac.core.rtti.AbstractMethodItem; 34 import org.objectweb.jac.core.rtti.ClassItem; 35 import org.objectweb.jac.core.rtti.ClassRepository; 36 import org.objectweb.jac.core.rtti.CollectionItem; 37 import org.objectweb.jac.core.rtti.ConstructorItem; 38 import org.objectweb.jac.core.rtti.FieldItem; 39 import org.objectweb.jac.core.rtti.MethodItem; 40 import org.objectweb.jac.util.ExtArrays; 41 import org.objectweb.jac.util.Strings; 42 43 119 120 public class MethodPointcut extends Pointcut { 121 static Logger logger = Logger.getLogger("pointcut"); 122 static Logger loggerName = Logger.getLogger("pointcut.name"); 123 static Logger loggerHost = Logger.getLogger("pointcut.host"); 124 static Logger loggerPath = Logger.getLogger("pointcut.path"); 125 static Logger loggerKeywords = Logger.getLogger("pointcut.keywords"); 126 static Logger loggerCreate = Logger.getLogger("pointcut.create"); 127 static Logger loggerWrappers = Logger.getLogger("wappers"); 128 129 Vector wrappeeExprs = new Vector (); 130 Vector wrappeeRegexps = new Vector (); 131 Vector wrappeeClassExprs = new Vector (); 132 Vector wrappeeClassRegexps = new Vector (); 133 Vector wrappeeMethodExprs = new Vector (); 134 Vector wrappeeMethodRegexps = new Vector (); 135 Vector hostExprs = new Vector (); 136 Vector hostRegexps = new Vector (); 137 Vector iwrappeeExprs = new Vector (); 138 Vector iwrappeeClassExprs = new Vector (); 139 Vector iwrappeeMethodExprs = new Vector (); 140 Vector ihostExprs = new Vector (); 141 String wrappeeExpr; 142 String wrappeeClassExpr; 143 String wrappeeMethodExpr; 144 String hostExpr; 145 String wrappingClassName; 146 String methodName; 147 Object [] methodArgs; 148 String exceptionHandler; 149 boolean one2one = true; 150 boolean allInstances = false; 151 boolean allHosts = false; 152 boolean allClasses = false; 153 AspectComponent aspectComponent = null; 154 155 156 ClassItem wrapperClass; 157 158 160 static String [] wrappeeKeywords = new String [] { 161 "ALL" 162 }; 163 static String [] classKeywords = new String [] { 164 "ALL", 165 "COLLECTIONS" 166 }; 167 static String [] methodKeywords = new String [] { 168 "ALL", 169 "STATICS", 170 "CONSTRUCTORS", 171 "MODIFIERS", 172 "REFACCESSORS", 173 "COLACCESSORS", 174 "ACCESSORS", 175 "COLSETTERS", 176 "FIELDSETTERS", 177 "REFSETTERS", 178 "SETTERS", 179 "WRITERS", 180 "COLGETTERS", 181 "FIELDGETTERS", 182 "REFGETTERS", 183 "GETTERS", 184 "ADDERS", 185 "REMOVERS" 186 }; 187 static String [] hostKeywords = new String [] { 188 "ALL" 189 }; 190 191 193 194 public String toString() { 195 return "pointcut {"+wrappingClassName+","+ 196 methodName+ 197 "}->{"+wrappeeExpr+","+wrappeeClassExpr+","+ 198 wrappeeMethodExpr+","+hostExpr+"}"; 199 } 200 201 Wrapper commonWrapper = null; 202 Wrapper initWrapper = null; 203 204 231 public MethodPointcut(AspectComponent aspectComponent, 232 String wrappeeExpr, 233 String wrappeeClassExpr, 234 String wrappeeMethodExpr, 235 Wrapper initWrapper, 236 String wrappingClassName, 237 String methodName, 238 Object [] methodArgs, 239 String hostExpr, 240 String exceptionHandler, 241 boolean one2one) { 242 243 this.aspectComponent = aspectComponent; 244 this.wrappeeExpr = wrappeeExpr; 245 this.wrappeeClassExpr = wrappeeClassExpr; 246 this.wrappeeMethodExpr = wrappeeMethodExpr; 247 this.hostExpr = hostExpr; 248 this.initWrapper = initWrapper; 249 this.wrappingClassName = wrappingClassName; 250 this.methodName = methodName; 251 this.methodArgs = methodArgs; 252 this.exceptionHandler = exceptionHandler; 253 this.one2one = one2one; 254 255 parseExpr("wrappee class expression", null, null, 256 wrappeeClassExpr, classKeywords, 257 wrappeeClassExprs, iwrappeeClassExprs); 258 wrappeeClassRegexps = buildRegexps(wrappeeClassExprs); 259 260 parseExpr("host expression", null, null, 261 hostExpr, hostKeywords, 262 hostExprs, ihostExprs); 263 hostRegexps = buildRegexps(hostExprs); 264 265 if (wrappeeExpr.equals("ALL") || wrappeeExpr.equals(".*")) { 266 allInstances = true; 267 } 268 if (hostExpr.equals("ALL") || hostExpr.equals(".*")) { 269 allHosts = true; 270 } 271 if (wrappeeClassExpr.equals("ALL") || wrappeeClassExpr.equals(".*")) { 272 allClasses = true; 273 } 274 275 if (!allInstances) { 276 parseExpr("wrappee expression", null, null, 277 wrappeeExpr, wrappeeKeywords, 278 wrappeeExprs, iwrappeeExprs); 279 280 wrappeeRegexps = buildRegexps(wrappeeExprs); 281 } 282 283 loggerCreate.debug(aspectComponent+" new pointcut "+this); 284 } 285 286 291 Vector buildRegexps(Vector patterns) { 292 Vector result = new Vector (patterns.size()); 293 Iterator i = patterns.iterator(); 294 while (i.hasNext()) { 295 String pattern = (String )i.next(); 296 try { 297 result.add(buildRegexp(pattern)); 298 } catch(REException e) { 299 logger.error("invalid regexp \""+pattern+"\":"+e); 300 } 301 } 302 return result; 303 } 304 305 public static RE buildRegexp(String pattern) throws REException { 306 return new RE(Strings.replace(pattern,"$","\\$"),0, 307 RESyntax.RE_SYNTAX_EMACS); 308 } 309 310 314 Wrapper buildWrapper(Wrappee wrappee) { 315 try { 316 if (wrapperClass==null) { 317 wrapperClass = ClassRepository.get().getClass(wrappingClassName); 318 } 319 if (methodArgs!=null) { 320 if (wrapperClass.isInner()) 321 return (Wrapper)wrapperClass.newInstance( 322 ExtArrays.add(0,aspectComponent,methodArgs)); 323 else 324 return (Wrapper)wrapperClass.newInstance( 325 ExtArrays.add(0,aspectComponent,methodArgs)); 326 } else { 327 if (wrapperClass.isInner()) 328 return (Wrapper)wrapperClass.newInstance( 329 new Object [] {aspectComponent,aspectComponent}); 330 else 331 return (Wrapper)wrapperClass.newInstance( 332 new Object [] {aspectComponent}); 333 } 334 } catch(Exception e) { 335 logger.error("buildWrapper failed for "+wrappee,e); 336 } 337 return null; 338 } 339 340 351 352 public synchronized void applyTo(Wrappee wrappee, ClassItem cl) { 353 354 360 logger.info("apply "+this+" on "+wrappee+" - "+cl); 361 362 363 if (!isClassMatching(wrappee,cl)) { return; } 364 Logger classLogger = Logger.getLogger("pointcut."+cl); 365 if (classLogger.isDebugEnabled()) 366 classLogger.debug("class is matching"); 367 368 if (!isHostMatching(wrappee,cl)) { return; } 369 if (classLogger.isDebugEnabled()) 370 classLogger.debug("host is matching"); 371 372 if (!isNameMatching(wrappee,cl)) return; 373 if (classLogger.isDebugEnabled()) 374 classLogger.debug("name is matching"); 375 376 if (methodName!=null) { 378 try { 379 classLogger.debug( 380 "Upcalling "+aspectComponent.getClass().getName()+ 381 "."+methodName+"("+Arrays.asList(methodArgs)+")"); 382 Object [] args = ExtArrays.add(0,wrappee,methodArgs); 383 ClassRepository.get().getClass(aspectComponent.getClass()) 384 .invoke(aspectComponent, methodName, args); 385 } catch(Exception e) { 386 logger.error("Upcalling failed",e); 387 } 388 } 389 390 if (initWrapper==null 392 && wrappingClassName==null) 393 return; 394 Collection methodsToWrap = 395 wrappee!=null ? getMatchingMethodsFor(wrappee,cl) : getMatchingStaticMethodsFor(cl); 396 Wrapper wrapper = null; 397 if (initWrapper!=null) { 398 wrapper = commonWrapper = initWrapper; 399 wrapperClass = ClassRepository.get().getClass(wrapper); 400 } else { 401 if (one2one) { 402 wrapper = buildWrapper(wrappee); 403 } else { 404 if (commonWrapper==null) 405 commonWrapper = buildWrapper(wrappee); 406 wrapper = commonWrapper; 407 } 408 } 409 410 414 if (methodsToWrap!=null && methodsToWrap.size()>0) { 415 classLogger.debug( 416 "applying "+wrappingClassName+ 417 " on "+cl.getName()+" ("+ 418 NameRepository.get().getName(wrappee)+")"); 419 classLogger.debug("methods to wrap="+methodsToWrap); 420 } 421 422 loggerWrappers.debug("new pointcut: wrapper="+wrapper+" methods to wrap="+methodsToWrap); 423 424 Iterator it = methodsToWrap.iterator(); 427 boolean wrapped = false; 428 while (it.hasNext()) { 429 AbstractMethodItem method = (AbstractMethodItem)it.next(); 430 classLogger.debug( 431 "Wrapping "+method.getLongName()+" with "+wrappingClassName+ 432 " on "+wrappee+" - "+cl.getName()); 433 if (Wrapping.wrapMethod(wrappee,wrapper,method) && !wrapped) { 435 Wrapping.wrap(wrappee,cl,wrapper); 438 wrapped = true; 439 } 440 441 if (exceptionHandler!=null) { 443 Wrapping.addExceptionHandler(wrappee,wrapper, 444 exceptionHandler,method); 445 } 446 } 447 loggerWrappers.debug("wrapped = "+wrapped); 448 if (methodsToWrap.size()==0 && one2one) { 449 Wrapping.wrap(wrappee,cl,wrapper); 450 } 451 } 452 453 454 Hashtable cache = new Hashtable (); 455 456 457 Hashtable staticsCache = new Hashtable (); 458 459 467 protected Collection getMatchingMethodsFor(Wrappee wrappee, ClassItem cli) { 468 String name = null; 471 if (wrappee!=null) { 472 name = cli.getName(); 473 } 474 Collection result = (Collection )cache.get(name); 475 if (result==null) { 476 result = parseMethodExpr(wrappee,cli,wrappeeMethodExpr); 477 cache.put(name,result); 478 } else { 480 } 483 return result; 484 } 485 486 protected Collection getMatchingStaticMethodsFor(ClassItem cli) { 487 String name = cli.getName(); 490 Collection result = (Collection )staticsCache.get(name); 491 if (result==null) { 492 result = parseMethodExpr(null,cli,wrappeeMethodExpr); 494 staticsCache.put(name,result); 495 } else { 496 } 499 return result; 500 } 501 502 509 public Collection parseMethodExpr(Wrappee wrappee, ClassItem cli, String expr) { 510 String [] exprs = Strings.split(expr,"&&"); 512 Collection result = new HashSet (); 513 514 if (wrappee==null) { 515 result.addAll(cli.getAllStaticMethods()); 516 } else { 517 result.addAll(cli.getAllInstanceMethods()); 518 result.addAll(cli.getConstructors()); 519 } 520 for (int i=0; i<exprs.length; i++) { 521 String curExpr; 522 boolean inv = false; 523 exprs[i] = exprs[i].trim(); 524 if (exprs[i].charAt(0)=='!') { 525 inv = true; 526 curExpr = exprs[i].substring(1).trim(); 527 } else { 528 curExpr = exprs[i]; 529 } 530 531 String [] subExprs = Strings.split(curExpr,"||"); 532 HashSet subExprResult = new HashSet (); 533 for(int j=0; j<subExprs.length; j++) { 534 String curSubExpr = subExprs[j].trim(); 535 filterMethodKeywords(wrappee,cli,curSubExpr,inv,result,subExprResult); 536 } 537 result = subExprResult; 539 } 540 return result; 541 } 542 543 553 protected void filterMethodKeywords(Object wrappee, ClassItem cli, 554 String expr, boolean inv, 555 Collection source, Collection dest) { 556 557 String keyword = null; 559 for (int i=0; i<methodKeywords.length && keyword==null; i++) { 560 if (expr.startsWith(methodKeywords[i])) { 561 keyword = methodKeywords[i]; 562 List parameters = null; 564 565 Iterator it = source.iterator(); 566 boolean add = false; 567 while (it.hasNext()) { 568 AbstractMethodItem method = (AbstractMethodItem)it.next(); 569 add = false; 571 if (keyword.equals("ALL")) { 572 add = !inv; 573 } else if (keyword.equals("MODIFIERS")) { 574 if (parameters==null) 575 parameters = parseParameters(expr.substring(keyword.length()),cli); 576 add = (isWriter(method,parameters) || 577 isAdder(method,parameters) || 578 isRemover(method,parameters) || 579 isCollectionModifier(method,parameters)) 580 ^ inv; 581 } else if (keyword.equals("ACCESSORS")) { 582 add = method.isAccessor() ^ inv; 583 } else if (keyword.equals("REMOVERS")) { 584 if (parameters==null) 585 parameters = parseParameters(expr.substring(keyword.length()),cli); 586 add = isRemover(method,parameters) ^ inv; 587 } else if (keyword.equals("ADDERS")) { 588 if (parameters==null) 589 parameters = parseParameters(expr.substring(keyword.length()),cli); 590 add = isAdder(method,parameters) ^ inv; 591 } else if (keyword.equals("SETTERS")) { 592 if (parameters==null) 593 parameters = parseParameters(expr.substring(keyword.length()),cli); 594 add = isSetter(method,parameters) ^ inv; 595 } else if (keyword.equals("STATICS")) { 596 add = method.isStatic() ^ inv; 597 } else if (keyword.equals("CONSTRUCTORS")) { 598 add = (method instanceof ConstructorItem) ^ inv; 599 } else if (keyword.equals("COLGETTERS")) { 600 add = method.isCollectionGetter() ^ inv; 601 } else if (keyword.equals("COLACCESSORS")) { 602 if (parameters==null) 603 parameters = parseParameters(expr.substring(keyword.length()),cli); 604 add = isCollectionAccessor(method,parameters) ^ inv; 605 } else if (keyword.equals("FIELDGETTERS")) { 606 add = method.isFieldGetter() ^ inv; 607 } else if (keyword.equals("REFGETTERS")) { 608 add = method.isReferenceGetter() ^ inv; 609 } else if (keyword.equals("REFACCESSORS")) { 610 if (parameters==null) 611 parameters = parseParameters(expr.substring(keyword.length()),cli); 612 add = isReferenceAccessor(method,parameters) ^ inv; 613 } else if (keyword.equals("COLSETTERS")) { 614 add = method.isCollectionSetter() ^ inv; 615 } else if (keyword.equals("FIELDSETTERS")) { 616 add = method.isFieldSetter() ^ inv; 617 } else if (keyword.equals("REFSETTERS")) { 618 add = method.isReferenceSetter() ^ inv; 619 } else if (keyword.equals("WRITERS")) { 620 if (parameters==null) 621 parameters = parseParameters(expr.substring(keyword.length()),cli); 622 add = isWriter(method,parameters) ^ inv; 623 } else if (keyword.equals("GETTERS")) { 624 if (parameters==null) 625 parameters = parseParameters(expr.substring(keyword.length()),cli); 626 add = isGetter(method,parameters) ^ inv; 627 } 628 if (add) { 629 dest.add(method.getConcreteMethod()); 630 it.remove(); 631 } 632 } 633 } 634 } 635 636 if (keyword==null) { 638 try { 639 645 RE re = new RE(Strings.replace(expr,"$","\\$"),0, 646 RESyntax.RE_SYNTAX_EMACS); 647 Iterator it = source.iterator(); 648 while (it.hasNext()) { 649 AbstractMethodItem method = (AbstractMethodItem)it.next(); 650 if (re.isMatch(method.getFullName()) ^ inv) { 651 dest.add(method); 652 } 654 } 655 } catch (Exception e) { 657 logger.error("filterMethodKeywords"+e); 658 } 659 } 660 661 } 663 664 671 static boolean isAdder(AbstractMethodItem method, Collection collections) { 672 if (!method.isAdder()) { 673 return false; 674 } else { 675 if (collections==null) { 676 return true; 677 } else { 678 CollectionItem[] added = method.getAddedCollections(); 679 if (added!=null) { 680 for (int i=0; i<added.length; i++) { 681 if (collections.contains(added[i])) 682 return true; 683 } 684 } 685 return false; 686 } 687 } 688 } 689 690 697 static boolean isRemover(AbstractMethodItem method, Collection collections) { 698 if (!method.isRemover()) { 699 return false; 700 } else { 701 if (collections==null) { 702 return true; 703 } else { 704 CollectionItem[] removed = method.getRemovedCollections(); 705 if (removed!=null) { 706 for (int i=0; i<removed.length; i++) { 707 if (collections.contains(removed[i])) 708 return true; 709 } 710 } 711 return false; 712 } 713 } 714 } 715 716 717 |