summaryrefslogtreecommitdiffstats
path: root/loadtime
diff options
context:
space:
mode:
authoraclement <aclement>2009-12-10 20:03:37 +0000
committeraclement <aclement>2009-12-10 20:03:37 +0000
commit1d471f7cfaf166d4321c56b52fe47859e9974441 (patch)
tree4214e926f363914f4e8475bc9e2ca652bee8d10f /loadtime
parent95ae07b5aa70a702bac463a7775ec36487936bb9 (diff)
downloadaspectj-1d471f7cfaf166d4321c56b52fe47859e9974441.tar.gz
aspectj-1d471f7cfaf166d4321c56b52fe47859e9974441.zip
296734: various optimizations for LTW and aop.xml include/exclude processing
Diffstat (limited to 'loadtime')
-rw-r--r--loadtime/.classpath1
-rw-r--r--loadtime/src/org/aspectj/weaver/loadtime/ClassLoaderWeavingAdaptor.java271
-rw-r--r--loadtime/src/org/aspectj/weaver/loadtime/ConcreteAspectCodeGen.java11
-rw-r--r--loadtime/testsrc/org/aspectj/weaver/loadtime/ClassLoaderWeavingAdaptorTest.java456
4 files changed, 666 insertions, 73 deletions
diff --git a/loadtime/.classpath b/loadtime/.classpath
index 2d821b9df..c4d795a66 100644
--- a/loadtime/.classpath
+++ b/loadtime/.classpath
@@ -14,5 +14,6 @@
<classpathentry kind="lib" path="/lib/bcel/bcel.jar" sourcepath="/lib/bcel/bcel-src.zip"/>
<classpathentry kind="lib" path="/lib/ext/jrockit/jrockit.jar"/>
<classpathentry combineaccessrules="false" kind="src" path="/org.aspectj.matcher"/>
+ <classpathentry kind="lib" path="/lib/aspectj/lib/aspectjrt.jar"/>
<classpathentry kind="output" path="bin"/>
</classpath>
diff --git a/loadtime/src/org/aspectj/weaver/loadtime/ClassLoaderWeavingAdaptor.java b/loadtime/src/org/aspectj/weaver/loadtime/ClassLoaderWeavingAdaptor.java
index b8dc0ff1d..694e7afb5 100644
--- a/loadtime/src/org/aspectj/weaver/loadtime/ClassLoaderWeavingAdaptor.java
+++ b/loadtime/src/org/aspectj/weaver/loadtime/ClassLoaderWeavingAdaptor.java
@@ -63,10 +63,21 @@ public class ClassLoaderWeavingAdaptor extends WeavingAdaptor {
private List m_dumpTypePattern = new ArrayList();
private boolean m_dumpBefore = false;
private boolean dumpDirPerClassloader = false;
- private List m_includeTypePattern = new ArrayList();
- private List m_excludeTypePattern = new ArrayList();
- private List m_includeStartsWith = new ArrayList();
- private List m_excludeStartsWith = new ArrayList();
+
+ private boolean hasExcludes = false;
+ private List<TypePattern> excludeTypePattern = new ArrayList<TypePattern>(); // anything
+ private List<String> excludeStartsWith = new ArrayList<String>(); // com.foo..*
+ private List<String> excludeStarDotDotStar = new ArrayList<String>(); // *..*CGLIB*
+ private List<String> excludeExactName = new ArrayList<String>(); // com.foo.Bar
+ private List<String> excludeEndsWith = new ArrayList<String>(); // com.foo.Bar
+ private List<String[]> excludeSpecial = new ArrayList<String[]>();
+
+ private boolean hasIncludes = false;
+ private List<TypePattern> includeTypePattern = new ArrayList<TypePattern>();
+ private List<String> m_includeStartsWith = new ArrayList<String>();
+ private List<String> includeExactName = new ArrayList<String>();
+ private boolean includeStar = false;
+
private List m_aspectExcludeTypePattern = new ArrayList();
private List m_aspectExcludeStartsWith = new ArrayList();
private List m_aspectIncludeTypePattern = new ArrayList();
@@ -135,7 +146,6 @@ public class ClassLoaderWeavingAdaptor extends WeavingAdaptor {
}
boolean success = true;
- // if (trace.isTraceEnabled()) trace.enter("initialize",this,new Object[] { classLoader, context });
this.weavingContext = context;
if (weavingContext == null) {
@@ -155,9 +165,8 @@ public class ClassLoaderWeavingAdaptor extends WeavingAdaptor {
return;
}
- bcelWorld = new LTWWorld(classLoader, weavingContext, // TODO when the world works in terms of the context, we can remove
- // the loader...
- getMessageHandler(), null);
+ // TODO when the world works in terms of the context, we can remove the loader
+ bcelWorld = new LTWWorld(classLoader, weavingContext, getMessageHandler(), null);
weaver = new BcelWeaver(bcelWorld);
@@ -371,6 +380,9 @@ public class ClassLoaderWeavingAdaptor extends WeavingAdaptor {
bcelWorld.getLint().loadDefaultProperties();
} else {
bcelWorld.getLint().setAll(weaverOption.lint);
+ if (weaverOption.lint.equals("ignore")) {
+ bcelWorld.setAllLintIgnored();
+ }
}
}
// TODO proceedOnError option
@@ -474,7 +486,8 @@ public class ClassLoaderWeavingAdaptor extends WeavingAdaptor {
break;
}
- ((BcelWorld) weaver.getWorld()).addSourceObjectType(Utility.makeJavaClass(concreteAspect.name, gen.getBytes()));
+ ((BcelWorld) weaver.getWorld()).addSourceObjectType(Utility.makeJavaClass(concreteAspect.name, gen.getBytes()),
+ true);
concreteAspects.add(gen);
@@ -534,7 +547,7 @@ public class ClassLoaderWeavingAdaptor extends WeavingAdaptor {
}
/**
- * Register the include / exclude filters We duplicate simple patterns in startWith filters that will allow faster matching
+ * Register the include / exclude filters. We duplicate simple patterns in startWith filters that will allow faster matching
* without ResolvedType
*
* @param weaver
@@ -546,38 +559,120 @@ public class ClassLoaderWeavingAdaptor extends WeavingAdaptor {
for (Iterator iterator = definitions.iterator(); iterator.hasNext();) {
Definition definition = (Definition) iterator.next();
for (Iterator iterator1 = definition.getIncludePatterns().iterator(); iterator1.hasNext();) {
+ hasIncludes = true;
String include = (String) iterator1.next();
- TypePattern includePattern = new PatternParser(include).parseTypePattern();
- m_includeTypePattern.add(includePattern);
fastMatchInfo = looksLikeStartsWith(include);
if (fastMatchInfo != null) {
m_includeStartsWith.add(fastMatchInfo);
+ } else if (include.equals("*")) {
+ includeStar = true;
+ } else if ((fastMatchInfo = looksLikeExactName(include)) != null) {
+ includeExactName.add(fastMatchInfo);
+ } else {
+ TypePattern includePattern = new PatternParser(include).parseTypePattern();
+ includeTypePattern.add(includePattern);
}
}
for (Iterator iterator1 = definition.getExcludePatterns().iterator(); iterator1.hasNext();) {
+ hasExcludes = true;
String exclude = (String) iterator1.next();
- TypePattern excludePattern = new PatternParser(exclude).parseTypePattern();
- m_excludeTypePattern.add(excludePattern);
fastMatchInfo = looksLikeStartsWith(exclude);
if (fastMatchInfo != null) {
- m_excludeStartsWith.add(fastMatchInfo);
+ excludeStartsWith.add(fastMatchInfo);
+ } else if ((fastMatchInfo = looksLikeStarDotDotStarExclude(exclude)) != null) {
+ excludeStarDotDotStar.add(fastMatchInfo);
+ } else if ((fastMatchInfo = looksLikeExactName(exclude)) != null) {
+ excludeExactName.add(exclude);
+ } else if ((fastMatchInfo = looksLikeEndsWith(exclude)) != null) {
+ excludeEndsWith.add(fastMatchInfo);
+ } else if (exclude
+ .equals("org.codehaus.groovy..* && !org.codehaus.groovy.grails.web.servlet.mvc.SimpleGrailsController*")) {
+ // TODO need a more sophisticated analysis here, to allow for similar situations
+ excludeSpecial.add(new String[] { "org.codehaus.groovy.",
+ "org.codehaus.groovy.grails.web.servlet.mvc.SimpleGrailsController" });
+ // for the related test:
+ // } else if (exclude.equals("testdata..* && !testdata.sub.Oran*")) {
+ // excludeSpecial.add(new String[] { "testdata.", "testdata.sub.Oran" });
+ } else {
+ TypePattern excludePattern = new PatternParser(exclude).parseTypePattern();
+ excludeTypePattern.add(excludePattern);
}
}
}
}
/**
- * Checks if the type pattern can be handled as a startswith check
- *
- * TODO AV - enhance to support "char.sss" ie FQN direclty (match iff equals) we could also add support for "*..*charss"
- * endsWith style?
+ * Checks if the pattern looks like "*..*XXXX*" and if so returns XXXX. This will enable fast name matching of CGLIB exclusion
*
- * @param typePattern
- * @return null if not possible, or the startWith sequence to test against
+ */
+ private String looksLikeStarDotDotStarExclude(String typePattern) {
+ if (!typePattern.startsWith("*..*")) {
+ return null;
+ }
+ if (!typePattern.endsWith("*")) {
+ return null;
+ }
+ String subPattern = typePattern.substring(4, typePattern.length() - 1);
+ if (hasStarDot(subPattern, 0)) {
+ return null;
+ }
+ return subPattern.replace('$', '.');
+ }
+
+ /**
+ * Checks if the pattern looks like "com.foo.Bar" - an exact name
+ */
+ private String looksLikeExactName(String typePattern) {
+ if (hasSpaceAnnotationPlus(typePattern, 0) || typePattern.indexOf("*") != -1) {
+ return null;
+ }
+ return typePattern.replace('$', '.');
+ }
+
+ /**
+ * Checks if the pattern looks like "*Exception"
+ */
+ private String looksLikeEndsWith(String typePattern) {
+ if (typePattern.charAt(0) != '*') {
+ return null;
+ }
+ if (hasSpaceAnnotationPlus(typePattern, 1) || hasStarDot(typePattern, 1)) {
+ return null;
+ }
+ return typePattern.substring(1).replace('$', '.');
+ }
+
+ /**
+ * Determine if something in the string is going to affect our ability to optimize. Checks for: ' ' '@' '+'
+ */
+ private boolean hasSpaceAnnotationPlus(String string, int pos) {
+ for (int i = pos, max = string.length(); i < max; i++) {
+ char ch = string.charAt(i);
+ if (ch == ' ' || ch == '@' || ch == '+') {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Determine if something in the string is going to affect our ability to optimize. Checks for: '*' '.'
+ */
+ private boolean hasStarDot(String string, int pos) {
+ for (int i = pos, max = string.length(); i < max; i++) {
+ char ch = string.charAt(i);
+ if (ch == '*' || ch == '.') {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Checks if the type pattern looks like "com.foo..*"
*/
private String looksLikeStartsWith(String typePattern) {
- if (typePattern.indexOf('@') >= 0 || typePattern.indexOf('+') >= 0 || typePattern.indexOf(' ') >= 0
- || typePattern.charAt(typePattern.length() - 1) != '*') {
+ if (hasSpaceAnnotationPlus(typePattern, 0) || typePattern.charAt(typePattern.length() - 1) != '*') {
return null;
}
// now must looks like with "charsss..*" or "cha.rss..*" etc
@@ -586,9 +681,8 @@ public class ClassLoaderWeavingAdaptor extends WeavingAdaptor {
int length = typePattern.length();
if (typePattern.endsWith("..*") && length > 3) {
if (typePattern.indexOf("..") == length - 3 // no ".." before last sequence
- && typePattern.indexOf('*') == length - 1) { // no "*" before last sequence
- return typePattern.substring(0, length - 2).replace('$', '.');
- // ie "charsss." or "char.rss." etc
+ && typePattern.indexOf('*') == length - 1) { // no earlier '*'
+ return typePattern.substring(0, length - 2).replace('$', '.'); // "charsss." or "char.rss." etc
}
}
return null;
@@ -618,67 +712,120 @@ public class ClassLoaderWeavingAdaptor extends WeavingAdaptor {
}
}
+ /**
+ * Determine whether a type should be accepted for weaving, by checking it against any includes/excludes.
+ *
+ * @param className the name of the type to possibly accept
+ * @param bytes the bytecode for the type (in case we need to look inside, eg. annotations)
+ * @return true if it should be accepted for weaving
+ */
@Override
protected boolean accept(String className, byte[] bytes) {
- // avoid ResolvedType if not needed
- if (m_excludeTypePattern.isEmpty() && m_includeTypePattern.isEmpty()) {
+
+ if (!hasExcludes && !hasIncludes) {
return true;
}
// still try to avoid ResolvedType if we have simple patterns
String fastClassName = className.replace('/', '.').replace('$', '.');
- for (int i = 0; i < m_excludeStartsWith.size(); i++) {
- if (fastClassName.startsWith((String) m_excludeStartsWith.get(i))) {
+ for (String excludeStartsWithString : excludeStartsWith) {
+ if (fastClassName.startsWith(excludeStartsWithString)) {
return false;
}
}
+ // Fast exclusion of patterns like: "*..*CGLIB*"
+ if (!excludeStarDotDotStar.isEmpty()) {
+ for (String namePiece : excludeStarDotDotStar) {
+ int index = fastClassName.lastIndexOf('.');
+ if (fastClassName.indexOf(namePiece, index + 1) != -1) {
+ return false;
+ }
+ }
+ }
+
+ if (!excludeEndsWith.isEmpty()) {
+ for (String lastPiece : excludeEndsWith) {
+ if (fastClassName.endsWith(lastPiece)) {
+ return false;
+ }
+ }
+ }
+
+ // Fast exclusion of exact names
+ if (!excludeExactName.isEmpty()) {
+ for (String name : excludeExactName) {
+ if (fastClassName.equals(name)) {
+ return false;
+ }
+ }
+ }
+
+ if (!excludeSpecial.isEmpty()) {
+ for (String[] entry : excludeSpecial) {
+ String excludeThese = entry[0];
+ String exceptThese = entry[1];
+ if (fastClassName.startsWith(excludeThese) && !fastClassName.startsWith(exceptThese)) {
+ return false;
+ }
+ }
+ }
+
/*
* Bug 120363 If we have an exclude pattern that cannot be matched using "starts with" then we cannot fast accept
*/
- if (m_excludeTypePattern.isEmpty()) {
+ boolean didSomeIncludeMatching = false;
+ if (excludeTypePattern.isEmpty()) {
+ if (includeStar) {
+ return true;
+ }
+ if (!includeExactName.isEmpty()) {
+ didSomeIncludeMatching = true;
+ for (String exactname : includeExactName) {
+ if (fastClassName.equals(exactname)) {
+ return true;
+ }
+ }
+ }
boolean fastAccept = false;// defaults to false if no fast include
for (int i = 0; i < m_includeStartsWith.size(); i++) {
- fastAccept = fastClassName.startsWith((String) m_includeStartsWith.get(i));
+ didSomeIncludeMatching = true;
+ fastAccept = fastClassName.startsWith(m_includeStartsWith.get(i));
if (fastAccept) {
- break;
+ return true;
}
}
+ // We may have processed all patterns now... check that and return
+ if (includeTypePattern.isEmpty()) {
+ return !didSomeIncludeMatching;
+ }
}
- // needs further analysis
- // TODO AV - needs refactoring
- // during LTW this calling resolve at that stage is BAD as we do have the bytecode from the classloader hook
- // but still go thru resolve that will do a getResourcesAsStream on disk
- // this is also problematic for jit stub which are not on disk - as often underlying infra
- // does returns null or some other info for getResourceAsStream (f.e. WLS 9 CR248491)
- // Instead I parse the given bytecode. But this also means it will be parsed again in
- // new WeavingClassFileProvider() from WeavingAdaptor.getWovenBytes()...
-
- ensureDelegateInitialized(className, bytes);
- ResolvedType classInfo = delegateForCurrentClass.getResolvedTypeX();// BAD:
- // weaver.getWorld().resolve(UnresolvedType.forName(
- // className), true);
+ boolean accept;
+ try {
+ ensureDelegateInitialized(className, bytes);
- // exclude are "AND"ed
- for (Iterator iterator = m_excludeTypePattern.iterator(); iterator.hasNext();) {
- TypePattern typePattern = (TypePattern) iterator.next();
- if (typePattern.matchesStatically(classInfo)) {
- // exclude match - skip
- return false;
+ ResolvedType classInfo = delegateForCurrentClass.getResolvedTypeX();
+
+ // exclude are "AND"ed
+ for (TypePattern typePattern : excludeTypePattern) {
+ if (typePattern.matchesStatically(classInfo)) {
+ // exclude match - skip
+ return false;
+ }
}
- }
- // include are "OR"ed
- boolean accept = true;// defaults to true if no include
- for (Iterator iterator = m_includeTypePattern.iterator(); iterator.hasNext();) {
- TypePattern typePattern = (TypePattern) iterator.next();
- accept = typePattern.matchesStatically(classInfo);
- if (accept) {
- break;
+ // include are "OR"ed
+ accept = !didSomeIncludeMatching; // only true if no includes at all
+ for (TypePattern typePattern : includeTypePattern) {
+ accept = typePattern.matchesStatically(classInfo);
+ if (accept) {
+ break;
+ }
+ // goes on if this include did not match ("OR"ed)
}
- // goes on if this include did not match ("OR"ed)
+ } finally {
+ this.bcelWorld.demote();
}
- this.bcelWorld.demote();
return accept;
}
diff --git a/loadtime/src/org/aspectj/weaver/loadtime/ConcreteAspectCodeGen.java b/loadtime/src/org/aspectj/weaver/loadtime/ConcreteAspectCodeGen.java
index 18176f0e2..41b9b4ca3 100644
--- a/loadtime/src/org/aspectj/weaver/loadtime/ConcreteAspectCodeGen.java
+++ b/loadtime/src/org/aspectj/weaver/loadtime/ConcreteAspectCodeGen.java
@@ -270,12 +270,14 @@ public class ConcreteAspectCodeGen {
// hierarchy that have not been
// concretized.
private void getOutstandingAbstractMethodsHelper(ResolvedType type, Map collector) {
- if (type == null)
+ if (type == null) {
return;
+ }
// Get to the top
if (!type.equals(ResolvedType.OBJECT)) {
- if (type.getSuperclass() != null)
+ if (type.getSuperclass() != null) {
getOutstandingAbstractMethodsHelper(type.getSuperclass(), collector);
+ }
}
ResolvedMember[] rms = type.getDeclaredMethods();
if (rms != null) {
@@ -309,8 +311,9 @@ public class ConcreteAspectCodeGen {
private boolean hasPointcutAnnotation(ResolvedMember member) {
AnnotationAJ[] as = member.getAnnotations();
- if (as == null || as.length == 0)
+ if (as == null || as.length == 0) {
return false;
+ }
for (int i = 0; i < as.length; i++) {
if (as[i].getTypeSignature().equals("Lorg/aspectj/lang/annotation/Pointcut;")) {
return true;
@@ -440,7 +443,7 @@ public class ConcreteAspectCodeGen {
// register the fresh new class into the world repository as it does not
// exist on the classpath anywhere
JavaClass jc = cg.getJavaClass((BcelWorld) world);
- ((BcelWorld) world).addSourceObjectType(jc);
+ ((BcelWorld) world).addSourceObjectType(jc, true);
return jc.getBytes();
}
diff --git a/loadtime/testsrc/org/aspectj/weaver/loadtime/ClassLoaderWeavingAdaptorTest.java b/loadtime/testsrc/org/aspectj/weaver/loadtime/ClassLoaderWeavingAdaptorTest.java
index 805b989a6..58166e20c 100644
--- a/loadtime/testsrc/org/aspectj/weaver/loadtime/ClassLoaderWeavingAdaptorTest.java
+++ b/loadtime/testsrc/org/aspectj/weaver/loadtime/ClassLoaderWeavingAdaptorTest.java
@@ -10,42 +10,484 @@
*******************************************************************************/
package org.aspectj.weaver.loadtime;
+import java.io.File;
+import java.lang.reflect.Field;
import java.net.URL;
import java.net.URLClassLoader;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
import junit.framework.TestCase;
+import org.aspectj.apache.bcel.classfile.JavaClass;
+import org.aspectj.apache.bcel.util.ClassPath;
+import org.aspectj.apache.bcel.util.SyntheticRepository;
+import org.aspectj.lang.annotation.Aspect;
+import org.aspectj.weaver.World;
+import org.aspectj.weaver.World.TypeMap;
+import org.aspectj.weaver.bcel.BcelWorld;
+import org.aspectj.weaver.loadtime.definition.Definition;
+import org.aspectj.weaver.tools.WeavingAdaptor;
+
public class ClassLoaderWeavingAdaptorTest extends TestCase {
public void testClassLoaderWeavingAdaptor() {
ClassLoader loader = new URLClassLoader(new URL[] {}, null);
ClassLoaderWeavingAdaptor adaptor = new ClassLoaderWeavingAdaptor();
- adaptor.initialize(loader,null);
+ adaptor.initialize(loader, null);
}
public void testGetNamespace() {
ClassLoader loader = new URLClassLoader(new URL[] {}, null);
ClassLoaderWeavingAdaptor adaptor = new ClassLoaderWeavingAdaptor();
- adaptor.initialize(loader,null);
+ adaptor.initialize(loader, null);
String namespace = adaptor.getNamespace();
- assertEquals("Namespace should be empty","",namespace);
+ assertEquals("Namespace should be empty", "", namespace);
}
public void testGeneratedClassesExistFor() {
ClassLoader loader = new URLClassLoader(new URL[] {}, null);
ClassLoaderWeavingAdaptor adaptor = new ClassLoaderWeavingAdaptor();
- adaptor.initialize(loader,null);
+ adaptor.initialize(loader, null);
boolean exist = adaptor.generatedClassesExistFor("Junk");
- assertFalse("There should be no generated classes",exist);
+ assertFalse("There should be no generated classes", exist);
}
public void testFlushGeneratedClasses() {
ClassLoader loader = new URLClassLoader(new URL[] {}, null);
ClassLoaderWeavingAdaptor adaptor = new ClassLoaderWeavingAdaptor();
- adaptor.initialize(loader,null);
+ adaptor.initialize(loader, null);
adaptor.flushGeneratedClasses();
boolean exist = adaptor.generatedClassesExistFor("Junk");
- assertFalse("There should be no generated classes",exist);
+ assertFalse("There should be no generated classes", exist);
+ }
+
+ /**
+ * Testing fast excludes of the pattern "com.foo..*". World should not have any new types in it after rejection.
+ */
+ public void testFastExclusionOne() throws Exception {
+ TestClassLoaderWeavingAdaptor adaptor = getAdaptor(null, "testdata..*");
+
+ String orangesSub = "testdata.sub.Oranges";
+ JavaClass orangesClass = getClassFrom(orangesSub);
+ byte[] orangesBytes = orangesClass.getBytes();
+
+ boolean accepted = adaptor.accept(orangesSub, orangesBytes);
+ assertFalse("Should not be accepted", accepted);
+ TypeMap map = accessTypeMap(adaptor);
+
+ // The aspect
+ assertEquals(1, map.getExpendableMap().size());
+
+ // primitives, void and jlObject
+ assertEquals(10, map.getMainMap().size());
+
+ // Important thing here is that the rejection of testdata.sub.Oranges did not require it to be loaded into the world at all
+ }
+
+ /**
+ * Testing fast includes of the pattern "*". World should not have any new types in it after inclusion.
+ */
+ public void testFastInclusionOne() throws Exception {
+ TestClassLoaderWeavingAdaptor adaptor = getAdaptor("*", null);
+
+ String orangesSub = "testdata.sub.Oranges";
+ JavaClass orangesClass = getClassFrom(orangesSub);
+ byte[] orangesBytes = orangesClass.getBytes();
+
+ boolean accepted = adaptor.accept(orangesSub, orangesBytes);
+ assertTrue("Should be accepted", accepted);
+ TypeMap map = accessTypeMap(adaptor);
+
+ // The aspect
+ assertEquals(1, map.getExpendableMap().size());
+
+ // primitives, void and jlObject
+ assertEquals(10, map.getMainMap().size());
+
+ // Important thing here is that the rejection of testdata.sub.Oranges did not require it to be loaded into the world at all
+ }
+
+ /**
+ * Testing fast excludes of the pattern "*Oranges". World should not have any new types in it after rejection.
+ */
+ public void testFastExclusionTwo() throws Exception {
+ TestClassLoaderWeavingAdaptor adaptor = getAdaptor(null, "*Oranges");
+
+ String oranges = "testdata.Oranges";
+ JavaClass orangesClass = getClassFrom(oranges);
+ byte[] orangesBytes = orangesClass.getBytes();
+
+ boolean accepted = adaptor.accept(oranges, orangesBytes);
+ assertFalse("Should not be accepted", accepted);
+ TypeMap map = accessTypeMap(adaptor);
+
+ // The aspect
+ assertEquals(1, map.getExpendableMap().size());
+ // primitives, void and jlObject
+ assertEquals(10, map.getMainMap().size());
+
+ String orangesSub = "testdata.sub.Oranges";
+
+ JavaClass orangesSubClass = getClassFrom(orangesSub);
+ byte[] orangesSubBytes = orangesSubClass.getBytes();
+
+ accepted = adaptor.accept(orangesSub, orangesSubBytes);
+ assertFalse("Should not be accepted", accepted);
+ map = accessTypeMap(adaptor);
+
+ // The aspect
+ assertEquals(1, map.getExpendableMap().size());
+ // primitives, void and jlObject
+ assertEquals(10, map.getMainMap().size());
+ }
+
+ /**
+ * Testing fast excludes of the pattern "*..*Oranges*". World should not have any new types in it after rejection.
+ */
+ public void testFastExclusionThree() throws Exception {
+ TestClassLoaderWeavingAdaptor adaptor = getAdaptor(null, "*..*ran*");
+
+ String oranges = "testdata.Oranges";
+ JavaClass orangesClass = getClassFrom(oranges);
+ byte[] orangesBytes = orangesClass.getBytes();
+
+ boolean accepted = adaptor.accept(oranges, orangesBytes);
+ assertFalse("Should not be accepted", accepted);
+ TypeMap map = accessTypeMap(adaptor);
+
+ // The aspect
+ assertEquals(1, map.getExpendableMap().size());
+
+ // primitives, void and jlObject
+ assertEquals(10, map.getMainMap().size());
+
+ String orangesSub = "testdata.sub.Oranges";
+ JavaClass orangesSubClass = getClassFrom(orangesSub);
+ byte[] orangesSubBytes = orangesSubClass.getBytes();
+
+ accepted = adaptor.accept(orangesSub, orangesSubBytes);
+ assertFalse("Should not be accepted", accepted);
+ map = accessTypeMap(adaptor);
+
+ // The aspect
+ assertEquals(1, map.getExpendableMap().size());
+ // primitives, void and jlObject
+ assertEquals(10, map.getMainMap().size());
+
+ String apples = "testdata.Apples";
+ JavaClass applesClass = getClassFrom(apples);
+ byte[] applesBytes = applesClass.getBytes();
+
+ accepted = adaptor.accept(apples, applesBytes);
+ assertTrue("Should be accepted", accepted);
+ map = accessTypeMap(adaptor);
+
+ // The aspect and the Apples type
+ assertEquals(1, map.getExpendableMap().size());
+ // primitives, void and jlObject
+ assertEquals(10, map.getMainMap().size());
+ }
+
+ /**
+ * Testing fast inclusion checking of exact include names eg. "testdata.sub.Oranges"
+ */
+ public void testFastInclusionTwo() throws Exception {
+ TestClassLoaderWeavingAdaptor adaptor = getAdaptor("testdata.sub.Oranges", null);
+
+ String oranges = "testdata.Oranges";
+ JavaClass orangesClass = getClassFrom(oranges);
+ byte[] orangesBytes = orangesClass.getBytes();
+
+ boolean accepted = adaptor.accept(oranges, orangesBytes);
+ assertFalse("Should not be accepted", accepted);
+ TypeMap map = accessTypeMap(adaptor);
+
+ // The aspect
+ assertEquals(1, map.getExpendableMap().size());
+
+ // primitives, void and jlObject
+ assertEquals(10, map.getMainMap().size());
+
+ String orangesSub = "testdata.sub.Oranges";
+ JavaClass orangesSubClass = getClassFrom(orangesSub);
+ byte[] orangesSubBytes = orangesSubClass.getBytes();
+
+ accepted = adaptor.accept(orangesSub, orangesSubBytes);
+ assertTrue("Should be accepted", accepted);
+ map = accessTypeMap(adaptor);
+
+ // The aspect
+ assertEquals(1, map.getExpendableMap().size());
+ // primitives, void and jlObject
+ assertEquals(10, map.getMainMap().size());
+
+ String apples = "testdata.Apples";
+ JavaClass applesClass = getClassFrom(apples);
+ byte[] applesBytes = applesClass.getBytes();
+
+ accepted = adaptor.accept(apples, applesBytes);
+ assertFalse("Should not be accepted", accepted);
+ map = accessTypeMap(adaptor);
+
+ // The aspect and the Apples type
+ assertEquals(1, map.getExpendableMap().size());
+ // primitives, void and jlObject
+ assertEquals(10, map.getMainMap().size());
}
+ /**
+ * Testing fast excludes of the pattern groovy related pattern -
+ */
+ // public void testFastExclusionFour() throws Exception {
+ // TestClassLoaderWeavingAdaptor adaptor = getAdaptor("*", "testdata..* && !testdata.sub.Oran*");
+ //
+ // String oranges = "testdata.Oranges";
+ // JavaClass orangesClass = getClassFrom(oranges);
+ // byte[] orangesBytes = orangesClass.getBytes();
+ //
+ // boolean accepted = adaptor.accept(oranges, orangesBytes);
+ // assertFalse("Should not be accepted", accepted);
+ // TypeMap map = accessTypeMap(adaptor);
+ //
+ // // The aspect
+ // assertEquals(1, map.getExpendableMap().size());
+ //
+ // // primitives, void and jlObject
+ // assertEquals(10, map.getMainMap().size());
+ //
+ // String orangesSub = "testdata.sub.Oranges";
+ // JavaClass orangesSubClass = getClassFrom(orangesSub);
+ // byte[] orangesSubBytes = orangesSubClass.getBytes();
+ //
+ // accepted = adaptor.accept(orangesSub, orangesSubBytes);
+ // assertTrue("Should be accepted", accepted);
+ // map = accessTypeMap(adaptor);
+ //
+ // // The aspect
+ // assertEquals(1, map.getExpendableMap().size());
+ // // primitives, void and jlObject
+ // assertEquals(10, map.getMainMap().size());
+ // }
+
+ public void testAcceptanceSpeedStarDotDotStar() throws Exception {
+ URLClassLoader loader = new URLClassLoader(new URL[] { new File("../loadtime/bin").toURI().toURL() }, null);
+
+ JavaClass jc = getClassFrom("../loadtime/bin", "org.aspectj.weaver.loadtime.ClassLoaderWeavingAdaptorTest$TestOne");
+ byte[] bs = jc.getBytes();
+ jc = getClassFrom("../loadtime/bin", "org.aspectj.weaver.loadtime.ClassLoaderWeavingAdaptorTest$TestOneCGLIB");
+ byte[] bs2 = jc.getBytes();
+ // InputStream is = loader.getResourceAsStream("org.aspectj.weaver.loadtime.ClassLoaderWeaverAdaptorTests$TestOne");
+ assertNotNull(bs);
+ TestWeavingContext wc = new TestWeavingContext(loader);
+ Definition d = new Definition();
+ d.getExcludePatterns().add("*..*CGLIB*");
+ d.getAspectClassNames().add("org.aspectj.weaver.loadtime.ClassLoaderWeavingAdaptorTest$AnAspect");
+ wc.addDefinition(d);
+ ClassLoaderWeavingAdaptor adaptor = new ClassLoaderWeavingAdaptor();
+ adaptor.initialize(loader, wc);
+ boolean exist = adaptor.generatedClassesExistFor("Junk");
+ assertFalse("There should be no generated classes", exist);
+
+ // before:
+ // Acceptance 331ms
+ // Rejection 3368ms
+
+ // after:
+ // Acceptance 343ms
+ // Rejection 80ms
+
+ long stime = System.currentTimeMillis();
+ for (int i = 0; i < 100000; i++) {
+ boolean b = adaptor.accept("org.aspectj.weaver.loadtime.ClassLoaderWeavingAdaptorTest$TestOne", bs);
+ assertTrue("Should be accepted", b);
+ }
+ long etime = System.currentTimeMillis();
+ System.out.println("Acceptance " + (etime - stime) + "ms");
+ stime = System.currentTimeMillis();
+ for (int i = 0; i < 100000; i++) {
+ adaptor.delegateForCurrentClass = null;
+ boolean b = adaptor.accept("org.aspectj.weaver.loadtime.ClassLoaderWeavingAdaptorTest$TestOneCGLIB", bs2);
+ assertFalse("Should not be accepting CGLIB", b);
+ }
+ etime = System.currentTimeMillis();
+ System.out.println("Rejection " + (etime - stime) + "ms");
+
+ }
+
+ // TODO
+ // shouldn't add it to the type patterns if we are going to fast handle it
+ // include for exact name, what does it mean?
+ // excludes="!xxxx" should also be fast matched...
+
+ public void testAcceptanceSpeedExactName() throws Exception {
+ URLClassLoader loader = new URLClassLoader(new URL[] { new File("../loadtime/bin").toURI().toURL() }, null);
+
+ JavaClass jc = getClassFrom("../loadtime/bin", "org.aspectj.weaver.loadtime.ClassLoaderWeavingAdaptorTest$TestOne");
+ byte[] bs = jc.getBytes();
+ jc = getClassFrom("../loadtime/bin", "org.aspectj.weaver.loadtime.ClassLoaderWeavingAdaptorTest$TestOneCGLIB");
+ byte[] bs2 = jc.getBytes();
+ // InputStream is = loader.getResourceAsStream("org.aspectj.weaver.loadtime.ClassLoaderWeaverAdaptorTests$TestOne");
+ assertNotNull(bs);
+ TestWeavingContext wc = new TestWeavingContext(loader);
+ Definition d = new Definition();
+ d.getExcludePatterns().add("org.aspectj.weaver.loadtime.ClassLoaderWeavingAdaptorTest.TestOneCGLIB");
+ d.getAspectClassNames().add("org.aspectj.weaver.loadtime.ClassLoaderWeavingAdaptorTest$AnAspect");
+ wc.addDefinition(d);
+ TestClassLoaderWeavingAdaptor adaptor = new TestClassLoaderWeavingAdaptor();
+ adaptor.initialize(loader, wc);
+ boolean exist = adaptor.generatedClassesExistFor("Junk");
+ assertFalse("There should be no generated classes", exist);
+
+ // before:
+ // Acceptance 331ms
+ // Rejection 3160ms
+
+ // after:
+ // Acceptance 379ms
+ // Rejection 103ms
+
+ long stime = System.currentTimeMillis();
+ for (int i = 0; i < 100000; i++) {
+ boolean b = adaptor.accept("org.aspectj.weaver.loadtime.ClassLoaderWeavingAdaptorTest$TestOne", bs);
+ assertTrue("Should be accepted", b);
+ }
+ long etime = System.currentTimeMillis();
+ System.out.println("Acceptance " + (etime - stime) + "ms");
+ stime = System.currentTimeMillis();
+ for (int i = 0; i < 100000; i++) {
+ adaptor.delegateForCurrentClass = null;
+ boolean b = adaptor.accept("org.aspectj.weaver.loadtime.ClassLoaderWeavingAdaptorTest$TestOneCGLIB", bs2);
+ assertFalse("Should not be accepting CGLIB", b);
+ }
+ etime = System.currentTimeMillis();
+ System.out.println("Rejection " + (etime - stime) + "ms");
+ BcelWorld world = adaptor.getWorld();
+ Field f = World.class.getDeclaredField("typeMap");
+ f.setAccessible(true);
+ TypeMap typeMap = (TypeMap) f.get(world);
+ System.out.println(typeMap.getExpendableMap().size());
+ System.out.println(typeMap.getMainMap().size());
+ printExpendableMap(typeMap.getExpendableMap());
+ printMainMap(typeMap.getMainMap());
+ }
+
+ // --- infrastructure ---
+
+ private TypeMap accessTypeMap(TestClassLoaderWeavingAdaptor adaptor) {
+ try {
+ BcelWorld world = adaptor.getWorld();
+ Field f = World.class.getDeclaredField("typeMap");
+ f.setAccessible(true);
+ TypeMap typeMap = (TypeMap) f.get(world);
+ return typeMap;
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public TestClassLoaderWeavingAdaptor getAdaptor(String includePattern, String excludePattern) {
+ return getAdaptor(includePattern == null ? null : new String[] { includePattern }, excludePattern == null ? null
+ : new String[] { excludePattern });
+ }
+
+ public TestClassLoaderWeavingAdaptor getAdaptor(String[] includePatterns, String[] excludePatterns) {
+ try {
+ URLClassLoader loader = new URLClassLoader(new URL[] { new File("../loadtime/bin").toURI().toURL() }, null);
+ TestWeavingContext wc = new TestWeavingContext(loader);
+ Definition d = new Definition();
+ if (includePatterns != null) {
+ for (String s : includePatterns) {
+ d.getIncludePatterns().add(s);
+ }
+ }
+ if (excludePatterns != null) {
+ for (String s : excludePatterns) {
+ d.getExcludePatterns().add(s);
+ }
+ }
+ // need some random aspect or the weaver will shut down!
+ d.getAspectClassNames().add("org.aspectj.weaver.loadtime.ClassLoaderWeavingAdaptorTest$AnAspect");
+ wc.addDefinition(d);
+ TestClassLoaderWeavingAdaptor adaptor = new TestClassLoaderWeavingAdaptor();
+ adaptor.initialize(loader, wc);
+ return adaptor;
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ private void printMaps(TypeMap map) {
+ printExpendableMap(map.getExpendableMap());
+ printMainMap(map.getMainMap());
+ }
+
+ private void printExpendableMap(Map m) {
+ for (Object o : m.keySet()) {
+ String sig = (String) o;
+ System.out.println(sig + "=" + m.get(sig));
+ }
+ }
+
+ private void printMainMap(Map m) {
+ for (Object o : m.keySet()) {
+ String sig = (String) o;
+ System.out.println(sig + "=" + m.get(sig));
+ }
+ }
+
+ static class TestClassLoaderWeavingAdaptor extends ClassLoaderWeavingAdaptor {
+
+ public BcelWorld getWorld() {
+ return bcelWorld;
+ }
+ }
+
+ public static JavaClass getClassFrom(String clazzname) throws ClassNotFoundException {
+ return getClassFrom("../loadtime/bin", clazzname);
+ }
+
+ public static JavaClass getClassFrom(String frompath, String clazzname) throws ClassNotFoundException {
+ SyntheticRepository repos = createRepos(frompath);
+ return repos.loadClass(clazzname);
+ }
+
+ public static SyntheticRepository createRepos(String cpentry) {
+ ClassPath cp = new ClassPath(cpentry + File.pathSeparator + System.getProperty("java.class.path"));
+ return SyntheticRepository.getInstance(cp);
+ }
+
+ @Aspect
+ class AnAspect {
+
+ }
+
+ class TestOne {
+
+ }
+
+ class TestOneCGLIB {
+
+ }
+
+ static class TestWeavingContext extends DefaultWeavingContext {
+
+ List testList = new ArrayList();
+
+ public TestWeavingContext(ClassLoader loader) {
+ super(loader);
+ }
+
+ public void addDefinition(Definition d) {
+ testList.add(d);
+ }
+
+ @Override
+ public List getDefinitions(final ClassLoader loader, final WeavingAdaptor adaptor) {
+ return testList;
+ }
+ }
}
+
+// --- testclasses and aspects --- \ No newline at end of file