//import org.aspectj.org.eclipse.jdt.internal.compiler.ast.ConstructorDeclaration;
import org.aspectj.org.eclipse.jdt.internal.compiler.ast.TypeDeclaration;
import org.aspectj.org.eclipse.jdt.internal.compiler.codegen.CodeStream;
+import org.aspectj.org.eclipse.jdt.internal.compiler.codegen.ExceptionLabel;
import org.aspectj.org.eclipse.jdt.internal.compiler.codegen.Label;
import org.aspectj.org.eclipse.jdt.internal.compiler.env.IGenericType;
import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.*;
// world.makeFieldBinding(
// AjcMemberMaker.perCflowField(
// typeX)));
+ } else if (perClause.getKind() == PerClause.PERTYPEWITHIN) {
+ //PTWIMPL Add field for storing typename in aspect for which the aspect instance exists
+ binding.addField(factory.makeFieldBinding(AjcMemberMaker.perTypeWithinWithinTypeField(typeX,typeX)));
} else {
throw new RuntimeException("unimplemented");
}
generatePerObjectAspectOfMethod(classFile, interfaceType);
generatePerObjectHasAspectMethod(classFile, interfaceType);
generatePerObjectBindMethod(classFile, interfaceType);
+ } else if (perClause.getKind() == PerClause.PERTYPEWITHIN) {
+ //PTWIMPL Generate the methods required *in the aspect*
+ generatePerTypeWithinAspectOfMethod(classFile); // public static <aspecttype> aspectOf(java.lang.Class)
+ generatePerTypeWithinGetInstanceMethod(classFile); // private static <aspecttype> ajc$getInstance(Class c) throws Exception
+ generatePerTypeWithinHasAspectMethod(classFile);
+ generatePerTypeWithinCreateAspectInstanceMethod(classFile); // generate public static X ajc$createAspectInstance(Class forClass) {
+ // PTWIMPL getWithinType() would need this...
+ // generatePerTypeWithinGetWithinTypeMethod(classFile); // generate public Class getWithinType() {
} else {
throw new RuntimeException("unimplemented");
}
}
+ // PTWIMPL Generate aspectOf() method
+ private void generatePerTypeWithinAspectOfMethod(ClassFile classFile) {
+ final EclipseFactory world = EclipseFactory.fromScopeLookupEnvironment(this.scope);
+ generateMethod(classFile, aspectOfMethod, new BodyGenerator() {
+ public void generate(CodeStream codeStream) {
+
+ Label instanceFound = new Label(codeStream);
+
+ ExceptionLabel anythingGoesWrong = new ExceptionLabel(codeStream,world.makeTypeBinding(TypeX.JAVA_LANG_EXCEPTION));
+ codeStream.aload_0();
+ codeStream.invokestatic(world.makeMethodBindingForCall(AjcMemberMaker.perTypeWithinGetInstance(typeX)));
+ codeStream.astore_1();
+ codeStream.aload_1();
+ codeStream.ifnonnull(instanceFound);
+ codeStream.new_(world.makeTypeBinding(AjcMemberMaker.NO_ASPECT_BOUND_EXCEPTION));
+ codeStream.dup();
+
+ codeStream.ldc(typeX.getName());
+ codeStream.aconst_null();
+
+ codeStream.invokespecial(world.makeMethodBindingForCall(AjcMemberMaker.noAspectBoundExceptionInit2()));
+ codeStream.athrow();
+ instanceFound.place();
+ codeStream.aload_1();
+
+ codeStream.areturn();
+ anythingGoesWrong.placeEnd();
+ anythingGoesWrong.place();
+
+ codeStream.astore_1();
+ codeStream.new_(world.makeTypeBinding(AjcMemberMaker.NO_ASPECT_BOUND_EXCEPTION));
+
+ codeStream.dup();
+
+ // Run the simple ctor for NABE
+ codeStream.invokespecial(world.makeMethodBindingForCall(AjcMemberMaker.noAspectBoundExceptionInit()));
+ codeStream.athrow();
+ }});
+ }
+
private void generatePerObjectAspectOfMethod(
ClassFile classFile,
final TypeBinding interfaceType)
}});
}
+ // PTWIMPL Generate hasAspect() method
+ private void generatePerTypeWithinHasAspectMethod(ClassFile classFile) {
+ final EclipseFactory world = EclipseFactory.fromScopeLookupEnvironment(this.scope);
+ generateMethod(classFile, hasAspectMethod, new BodyGenerator() {
+ public void generate(CodeStream codeStream) {
+ ExceptionLabel goneBang = new ExceptionLabel(codeStream,world.makeTypeBinding(TypeX.JAVA_LANG_EXCEPTION));
+ Label noInstanceExists = new Label(codeStream);
+ Label leave = new Label(codeStream);
+ goneBang.placeStart();
+ codeStream.aload_0();
+ codeStream.invokestatic(world.makeMethodBinding(AjcMemberMaker.perTypeWithinGetInstance(typeX)));
+ codeStream.ifnull(noInstanceExists);
+ codeStream.iconst_1();
+ codeStream.goto_(leave);
+ noInstanceExists.place();
+ codeStream.iconst_0();
+ leave.place();
+ goneBang.placeEnd();
+ codeStream.ireturn();
+ goneBang.place();
+ codeStream.astore_1();
+ codeStream.iconst_0();
+ codeStream.ireturn();
+ }});
+ }
+
private void generatePerObjectBindMethod(
ClassFile classFile,
final TypeBinding interfaceType)
}});
}
+ // PTWIMPL Generate getInstance method
+ private void generatePerTypeWithinGetInstanceMethod(ClassFile classFile) {
+ final EclipseFactory world = EclipseFactory.fromScopeLookupEnvironment(this.scope);
+ generateMethod(classFile, AjcMemberMaker.perTypeWithinGetInstance(EclipseFactory.fromBinding(binding)),
+ new BodyGenerator() {
+ public void generate(CodeStream codeStream) {
+ ExceptionLabel exc = new ExceptionLabel(codeStream,world.makeTypeBinding(TypeX.JAVA_LANG_EXCEPTION));
+ exc.placeStart();
+ codeStream.aload_0();
+ codeStream.ldc(NameMangler.perTypeWithinLocalAspectOf(typeX));
+ codeStream.aconst_null();
+ codeStream.invokevirtual(
+ new MethodBinding(
+ 0,
+ "getDeclaredMethod".toCharArray(),
+ world.makeTypeBinding(TypeX.forSignature("Ljava/lang/reflect/Method;")), // return type
+ new TypeBinding[]{world.makeTypeBinding(TypeX.forSignature("Ljava/lang/String;")),
+ world.makeTypeBinding(TypeX.forSignature("[Ljava/lang/Class;"))},
+ new ReferenceBinding[0],
+ (ReferenceBinding)world.makeTypeBinding(TypeX.JAVA_LANG_CLASS)));
+ codeStream.astore_1();
+ codeStream.aload_1();
+ codeStream.aconst_null();
+ codeStream.aconst_null();
+ codeStream.invokevirtual(
+ new MethodBinding(
+ 0,
+ "invoke".toCharArray(),
+ world.makeTypeBinding(TypeX.OBJECT),
+ new TypeBinding[]{world.makeTypeBinding(TypeX.OBJECT),world.makeTypeBinding(TypeX.forSignature("[Ljava/lang/Object;"))},
+ new ReferenceBinding[0],
+ (ReferenceBinding)world.makeTypeBinding(TypeX.JAVA_LANG_REFLECT_METHOD)));
+ codeStream.checkcast(world.makeTypeBinding(typeX));
+ codeStream.astore_2();
+ codeStream.aload_2();
+ exc.placeEnd();
+ codeStream.areturn();
+ exc.place();
+ codeStream.astore_1();
+ codeStream.aload_1();
+ codeStream.athrow();
+ }});
+ }
+
+ private void generatePerTypeWithinCreateAspectInstanceMethod(ClassFile classFile) {
+ final EclipseFactory world = EclipseFactory.fromScopeLookupEnvironment(this.scope);
+ generateMethod(classFile, AjcMemberMaker.perTypeWithinCreateAspectInstance(EclipseFactory.fromBinding(binding)),
+ new BodyGenerator() {
+ public void generate(CodeStream codeStream) {
+
+ codeStream.new_(world.makeTypeBinding(typeX));
+ codeStream.dup();
+ codeStream.invokespecial(new MethodBinding(0, "<init>".toCharArray(),
+ BaseTypes.VoidBinding, new TypeBinding[0],
+ new ReferenceBinding[0], binding));
+ codeStream.astore_1();
+ codeStream.aload_1();
+ codeStream.aload_0();
+ codeStream.putfield(world.makeFieldBinding(AjcMemberMaker.perTypeWithinWithinTypeField(typeX,typeX)));
+ codeStream.aload_1();
+ codeStream.areturn();
+ }});
+ }
+
private void generatePerSingletonAspectOfMethod(ClassFile classFile) {
} else if (perClause.getKind() == PerClause.PEROBJECT) {
aspectOfMethod = AjcMemberMaker.perObjectAspectOfMethod(typeX);
hasAspectMethod = AjcMemberMaker.perObjectHasAspectMethod(typeX);
+ } else if (perClause.getKind() == PerClause.PERTYPEWITHIN) {
+ // PTWIMPL Use these variants of aspectOf()/hasAspect()
+ aspectOfMethod = AjcMemberMaker.perTypeWithinAspectOfMethod(typeX);
+ hasAspectMethod = AjcMemberMaker.perTypeWithinHasAspectMethod(typeX);
} else {
throw new RuntimeException("bad per clause: " + perClause);
}
import junit.framework.Test;
import junit.framework.TestSuite;
-/**
- * @author colyer
- *
- * TODO To change the template for this generated type comment go to
- * Window - Preferences - Java - Code Style - Code Templates
- */
public class AllTestsAspectJ150 {
public static Test suite() {
suite.addTestSuite(AnnotationPointcutsTests.class);
suite.addTestSuite(VarargsTests.class);
suite.addTestSuite(AnnotationRuntimeTests.class);
+ suite.addTestSuite(PerTypeWithinTests.class);
//$JUnit-END$
--- /dev/null
+/*******************************************************************************
+ * Copyright (c) 2005 IBM
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ *
+ * Contributors:
+ * Andy Clement - initial API and implementation
+ *******************************************************************************/
+package org.aspectj.systemtest.ajc150;
+
+import java.io.File;
+import java.util.Iterator;
+import java.util.List;
+
+import org.aspectj.bridge.IMessage;
+import org.aspectj.tools.ajc.CompilationResult;
+
+
+
+public class PerTypeWithinTests extends TestUtils {
+
+ protected void setUp() throws Exception {
+ super.setUp();
+ baseDir = new File("../tests/java5/pertypewithin");
+ }
+
+ /**
+ * First few tests:
+ *
+ * Five types p.A, p.B, p.C, q.D, q.E and an aspect a.X.
+ *
+ * The aspect is pertypewithin(p..*) - this should match A,B,C but not D,E.
+ *
+ * Aspect instances should be accessible for A,B,C but not D,E.
+ * The aspect instances for A,B,C should be different.
+ *
+ * hasAspect(), aspectOf() should work.
+ *
+ * We test these assumptions in A,B,C,D,E.
+ */
+ public void testDoesItWorkAtAll() {
+ CompilationResult cR=ajc(baseDir,new String[]{"A.java","B.java","C.java","D.java","Main.java","X.java"});
+ assertTrue("Expected no errors:"+cR,!cR.hasErrorMessages());
+ // if (verbose) { System.err.println(cR); System.err.println(cR.getStandardError());}
+ RunResult rR = run("p.A");
+ // if (verbose) {System.err.println(rR.getStdErr());}
+ assertTrue("Expected a report from the aspect about 2 calls to sayhi():"+rR.getStdErr(),
+ rR.getStdErr().indexOf("callcount = 2")!=-1);
+ }
+
+ public void testCheckHasAspectWorks() {
+ CompilationResult cR=ajc(baseDir,new String[]{"A.java","B.java","C.java","D.java","Main.java","X.java"});
+ assertTrue("Expected no errors:"+cR,!cR.hasErrorMessages());
+ // if (verbose) { System.err.println(cR); System.err.println(cR.getStandardError());}
+ RunResult rR = run("p.A");
+ rR = run("p.B");
+ // if (verbose) {System.err.println(rR.getStdErr());}
+ assertTrue("Expected a report from the aspect about 3 calls to sayhi():"+rR.getStdErr(),
+ rR.getStdErr().indexOf("callcount = 3")!=-1);
+ }
+
+ public void testCheckAspectOfWorks() {
+ CompilationResult cR=ajc(baseDir,new String[]{"A.java","B.java","C.java","D.java","Main.java","X.java"});
+ assertTrue("Expected no errors:"+cR,!cR.hasErrorMessages());
+ // if (verbose) { System.err.println(cR); System.err.println(cR.getStandardError());}
+ RunResult rR = run("p.A");
+ rR = run("p.C");
+ // if (verbose) {System.err.println(rR.getStdErr());}
+
+ }
+
+ /**
+ * Aspects Q and R match P with a pertypewithin() - they shouldn't clash in any way
+ *
+ */
+ public void testTwoAspectsHittingOneType() {
+ CompilationResult cR=ajc(baseDir,new String[]{"P.java","Q.java","R.java"});
+ assertTrue("Expected no errors:"+cR,!cR.hasErrorMessages());
+ // if (verbose) { System.err.println(cR); System.err.println(cR.getStandardError());}
+ RunResult rR = run("P");
+ // if (verbose) {System.err.println(rR.getStdErr());}
+ assertTrue("Expected message about Q reporting 2: "+rR.getStdErr(),
+ rR.getStdErr().indexOf("Q reporting 2")!=-1);
+ assertTrue("Expected message about R reporting 3: "+rR.getStdErr(),
+ rR.getStdErr().indexOf("R reporting 3")!=-1);
+ }
+
+ /**
+ * Checks the use of pertypewithin() doesn't result in extra join points (i.e. the
+ * infrastructure is properly hidden in ajc$ or synthetic members)
+ */
+ public void testPervasivenessOfWeaving() {
+ CompilationResult cR = ajc(baseDir,new String[]{"U.java","-showWeaveInfo"});
+ List l = cR.getInfoMessages();
+ int cnt = 0;
+ for (Iterator iter = l.iterator(); iter.hasNext();) {
+ IMessage element = (IMessage) iter.next();
+ if (element.getKind()==IMessage.WEAVEINFO) {
+ //System.err.println(element);
+ cnt++;
+ }
+ }
+ int weavingMessagesFromNormalDeploymentModel = cnt;
+ //System.err.println(cnt);
+
+ cR = ajc(baseDir,new String[]{"V.java","-showWeaveInfo"});
+ l = cR.getInfoMessages();
+ cnt = 0;
+ for (Iterator iter = l.iterator(); iter.hasNext();) {
+ IMessage element = (IMessage) iter.next();
+ if (element.getKind()==IMessage.WEAVEINFO) {
+ //System.err.println(element);
+ cnt++;
+ }
+ }
+ int weavingMessagesFromPerTypeWithin = cnt;
+ //System.err.println(cnt);
+ if (weavingMessagesFromNormalDeploymentModel!=weavingMessagesFromPerTypeWithin)
+ fail("Expected same number of messages regardless of perclause but got "+
+ weavingMessagesFromNormalDeploymentModel+" and "+weavingMessagesFromPerTypeWithin);
+
+ }
+
+ public void testBinaryWeaving_ClassesAreBinary() {
+ // Compile the 'ordinary' class G.java into classes
+ CompilationResult cR = ajc(baseDir,new String[]{"G.java","-d","classes2"});
+ setShouldEmptySandbox(false);
+ // Compile the aspect with G.class as input, should be binary woven correctly
+ cR = ajc(baseDir,new String[]{"H.java","-inpath","classes2"});
+ RunResult rR = run("G");
+ assertTrue("Expected aspect related message 'advice running' in output from G",
+ rR.getStdErr().indexOf("advice running")!=-1);
+ setShouldEmptySandbox(true);
+ }
+
+ public void testBinaryWeaving_AspectsAreBinary() {
+ // Compile the aspect H.java into classes3
+ CompilationResult cR = ajc(baseDir,new String[]{"H.java","-outjar","aspects.jar"});
+ setShouldEmptySandbox(false);
+ // Compile the class with H.class as aspectpath, should be binary woven correctly
+ cR = ajc(baseDir,new String[]{"G.java","-aspectpath","aspects.jar"});
+ RunResult rR = run("G");
+ assertTrue("Expected aspect related message 'advice running' in output from G",
+ rR.getStdErr().indexOf("advice running")!=-1);
+ setShouldEmptySandbox(true);
+ }
+
+ // binary weaving case ...
+}
\ No newline at end of file
return ret;
}
+ // PTWIMPL per type within entry advice is what initializes the aspect instance in the matched type
+ public static Advice makePerTypeWithinEntry(World world, Pointcut p, ResolvedTypeX inAspect) {
+ Advice ret = world.concreteAdvice(AdviceKind.PerTypeWithinEntry,p,null,0,p);
+ ret.concreteAspect = inAspect;
+ return ret;
+ }
+
public static Advice makeSoftener(World world, Pointcut entry, TypePattern exceptionType,ResolvedTypeX inAspect,IHasSourceLocation loc) {
Advice ret = world.concreteAdvice(AdviceKind.Softener, entry, null, 0, loc);
case 12: return PerTargetEntry;
case 13: return Softener;
+
+ case 14: return PerTypeWithinEntry;
}
throw new RuntimeException("unimplemented kind: " + key);
}
public static final AdviceKind PerTargetEntry = new AdviceKind("perTargetEntry", 12, 1, false, false);
public static final AdviceKind Softener = new AdviceKind("softener", 13, 1, false, false);
+
+ // PTWIMPL Advice representing when aspect should be initialized
+ public static final AdviceKind PerTypeWithinEntry = new AdviceKind("perTypeWithinEntry",14,1,false,false);
public static AdviceKind stringToKind(String s) {
}
public boolean isPerEntry() {
- return this == PerCflowEntry || this == PerCflowBelowEntry ||
- this == PerThisEntry || this == PerTargetEntry;
+ return
+ this == PerCflowEntry || this == PerCflowBelowEntry ||
+ this == PerThisEntry || this == PerTargetEntry ||
+ this == PerTypeWithinEntry; // PTWIMPL Allow for PTW case
}
public boolean isPerObjectEntry() {
"<init>",
"()V");
}
+
+ public static Member noAspectBoundExceptionInit2() {
+ return new ResolvedMember(
+ Member.METHOD,
+ NO_ASPECT_BOUND_EXCEPTION,
+ Modifier.PUBLIC,
+ "<init>",
+ "(Ljava/lang/String;Ljava/lang/Throwable;)V");
+ }
public static Member noAspectBoundExceptionInitWithCause() {
return new ResolvedMember(
NameMangler.perObjectInterfaceField(aspectType),
TypeX.NONE);
}
+
+ // PTWIMPL ResolvedMember for aspect instance field, declared in matched type
+ public static ResolvedMember perTypeWithinField(TypeX declaringType, ResolvedTypeX aspectType) {
+ int modifiers = Modifier.PRIVATE | Modifier.STATIC;
+ if (!TypeX.SERIALIZABLE.isAssignableFrom(aspectType, aspectType.getWorld())) {
+ modifiers |= Modifier.TRANSIENT;
+ }
+ return new ResolvedMember(Member.FIELD, declaringType, modifiers,
+ aspectType, NameMangler.perTypeWithinFieldForTarget(aspectType), TypeX.NONE);
+ }
+
+ // PTWIMPL ResolvedMember for type instance field, declared in aspect
+ // (holds typename for which aspect instance exists)
+ public static ResolvedMember perTypeWithinWithinTypeField(TypeX declaringType, ResolvedTypeX aspectType) {
+ int modifiers = Modifier.PRIVATE;
+ if (!TypeX.SERIALIZABLE.isAssignableFrom(aspectType, aspectType.getWorld())) {
+ modifiers |= Modifier.TRANSIENT;
+ }
+ return new ResolvedMember(Member.FIELD, declaringType, modifiers,
+ TypeX.forSignature("Ljava/lang/String;"), NameMangler.PERTYPEWITHIN_WITHINTYPEFIELD, TypeX.NONE);
+ }
public static ResolvedMember perObjectBind(TypeX declaringType) {
NameMangler.PEROBJECT_BIND_METHOD,
"(Ljava/lang/Object;)V");
}
+
+ // PTWIMPL ResolvedMember for getInstance() method, declared in aspect
+ public static ResolvedMember perTypeWithinGetInstance(TypeX declaringType) {
+// private static a.X ajc$getInstance(java.lang.Class) throws java/lang/Exception
+ ResolvedMember rm = new ResolvedMember(
+ Member.METHOD,
+ declaringType,
+ PRIVATE_STATIC,
+ declaringType, // return value
+ NameMangler.PERTYPEWITHIN_GETINSTANCE_METHOD,
+ new TypeX[]{TypeX.JAVA_LANG_CLASS},
+ new TypeX[]{TypeX.JAVA_LANG_EXCEPTION}
+ );
+ return rm;
+ }
+
+ public static ResolvedMember perTypeWithinCreateAspectInstance(TypeX declaringType) {
+ // public static a.X ajc$createAspectInstance(java.lang.String)
+ ResolvedMember rm = new ResolvedMember(
+ Member.METHOD,
+ declaringType,
+ PUBLIC_STATIC,
+ declaringType, // return value
+ NameMangler.PERTYPEWITHIN_CREATEASPECTINSTANCE_METHOD,
+ new TypeX[]{TypeX.forSignature("Ljava/lang/String;")},new TypeX[]{}
+ );
+ return rm;
+ }
public static TypeX perObjectInterfaceType(TypeX aspectType) {
"(" + aspectType.getSignature() + ")V");
}
-
-
+ // PTWIMPL ResolvedMember for localAspectOf() method, declared in matched type
+ public static ResolvedMember perTypeWithinLocalAspectOf(TypeX shadowType,TypeX aspectType) {
+ return new ResolvedMember(
+ Member.METHOD,
+ shadowType,//perTypeWithinInterfaceType(aspectType),
+ Modifier.PUBLIC | Modifier.STATIC,
+ NameMangler.perTypeWithinLocalAspectOf(aspectType),
+ "()" + aspectType.getSignature());
+ }
+
public static ResolvedMember perSingletonAspectOfMethod(TypeX declaringType) {
return new ResolvedMember(Member.METHOD,
"(Ljava/lang/Object;)Z");
};
+ // PTWIMPL ResolvedMember for aspectOf(), declared in aspect
+ public static ResolvedMember perTypeWithinAspectOfMethod(TypeX declaringType) {
+ return new ResolvedMember(Member.METHOD,
+ declaringType, PUBLIC_STATIC, "aspectOf",
+ "(Ljava/lang/Class;)" + declaringType.getSignature());
+ }
+
+ // PTWIMPL ResolvedMember for hasAspect(), declared in aspect
+ public static ResolvedMember perTypeWithinHasAspectMethod(TypeX declaringType) {
+ return new ResolvedMember(Member.METHOD,
+ declaringType, PUBLIC_STATIC, "hasAspect",
+ "(Ljava/lang/Class;)Z");
+ };
+
// -- privileged accessors
public static ResolvedMember privilegedAccessMethodForMethod(TypeX aspectType, ResolvedMember method) {
public static final String PERCFLOW_PUSH_METHOD = PREFIX + "perCflowPush";
public static final String PEROBJECT_BIND_METHOD = PREFIX + "perObjectBind";
-
+
+ // PTWIMPL Method and field names
+ public static final String PERTYPEWITHIN_GETINSTANCE_METHOD = PREFIX + "getInstance";
+ public static final String PERTYPEWITHIN_CREATEASPECTINSTANCE_METHOD = PREFIX + "createAspectInstance";
+ public static final String PERTYPEWITHIN_WITHINTYPEFIELD = PREFIX + "withinType";
+
public static final String AJC_PRE_CLINIT_NAME = PREFIX + "preClinit";
public static final String AJC_POST_CLINIT_NAME = PREFIX + "postClinit";
}
+ // PTWIMPL method names that must include aspect type
+ public static String perTypeWithinFieldForTarget(TypeX aspectType) {
+ String s = makeName(aspectType.getNameAsIdentifier(), "ptwAspectInstance");
+ return s;
+ }
+
+ public static String perTypeWithinLocalAspectOf(TypeX aspectType) {
+ return makeName(aspectType.getNameAsIdentifier(), "localAspectOf");
+ }
+
+
public static String privilegedAccessMethodForMethod(String name, TypeX objectType, TypeX aspectType) {
return makeName("privMethod", aspectType.getNameAsIdentifier(),
--- /dev/null
+/* *******************************************************************
+ * Copyright (c) 2005
+ * All rights reserved.
+ * This program and the accompanying materials are made available
+ * under the terms of the Common Public License v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ *
+ * Contributors:
+ * Andy Clement initial implementation
+ * ******************************************************************/
+
+package org.aspectj.weaver;
+
+import java.io.DataOutputStream;
+import java.io.IOException;
+
+import org.aspectj.weaver.patterns.PerTypeWithin;
+import org.aspectj.weaver.patterns.Pointcut;
+import org.aspectj.weaver.patterns.TypePattern;
+
+// PTWIMPL Target type munger adds the localAspectOf() method
+public class PerTypeWithinTargetTypeMunger extends ResolvedTypeMunger {
+ private ResolvedMember localAspectOfMethod;
+ private TypeX aspectType;
+ private PerTypeWithin testPointcut;
+
+
+ public PerTypeWithinTargetTypeMunger(TypeX aspectType, PerTypeWithin testPointcut) {
+ super(PerTypeWithinInterface, null);
+ this.aspectType = aspectType;
+ this.testPointcut = testPointcut;
+ }
+
+
+ public void write(DataOutputStream s) throws IOException {
+ throw new RuntimeException("shouldn't be serialized");
+ }
+
+ public TypeX getAspectType() {
+ return aspectType;
+ }
+
+ public Pointcut getTestPointcut() {
+ return testPointcut;
+ }
+
+ public boolean matches(ResolvedTypeX matchType, ResolvedTypeX aspectType) {
+ return testPointcut.getTypePattern().matches(matchType,TypePattern.STATIC).alwaysTrue();
+ }
+
+}
public static final Kind PrivilegedAccess = new Kind("PrivilegedAccess", 4);
public static final Kind Parent = new Kind("Parent", 6);
+ public static final Kind PerTypeWithinInterface = new Kind("PerTypeWithinInterface",7); // PTWIMPL not serialized, used during concretization of aspects
public static final String SUPER_DISPATCH_NAME = "superDispatch";
public static final TypeX AT_RETENTION = forSignature("Ljava/lang/annotation/Retention;");
public static final TypeX ENUM = forSignature("Ljava/lang/Enum;");
public static final TypeX ANNOTATION = forSignature("Ljava/lang/annotation/Annotation;");
+ public static final TypeX JAVA_LANG_CLASS = forSignature("Ljava/lang/Class;");
+ public static final TypeX JAVA_LANG_EXCEPTION = forSignature("Ljava/lang/Exception;");
+ public static final TypeX JAVA_LANG_REFLECT_METHOD = forSignature("Ljava/lang/reflect/Method;");
// ---- helpers
shadow.weavePerObjectEntry(this, (BcelVar)shadow.getTargetVar());
} else if (getKind() == AdviceKind.Softener) {
shadow.weaveSoftener(this, ((ExactTypePattern)exceptionType).getType());
+ } else if (getKind() == AdviceKind.PerTypeWithinEntry) {
+ // PTWIMPL Entry to ptw is the static initialization of a type that matched the ptw type pattern
+ shadow.weavePerTypeWithinAspectInitialization(this,shadow.getEnclosingType());
} else {
throw new BCException("unimplemented kind: " + getKind());
}
import org.aspectj.apache.bcel.generic.MULTIANEWARRAY;
import org.aspectj.apache.bcel.generic.NEW;
import org.aspectj.apache.bcel.generic.ObjectType;
+import org.aspectj.apache.bcel.generic.PUSH;
import org.aspectj.apache.bcel.generic.ReturnInstruction;
import org.aspectj.apache.bcel.generic.SWAP;
import org.aspectj.apache.bcel.generic.StoreInstruction;
range.insert(entryInstructions, Range.InsideBefore);
}
+
+ // PTWIMPL Create static initializer to call the aspect factory
+ /**
+ * Causes the aspect instance to be *set* for later retrievable through localAspectof()/aspectOf()
+ */
+ public void weavePerTypeWithinAspectInitialization(final BcelAdvice munger,TypeX t) {
+ final InstructionFactory fact = getFactory();
+
+ InstructionList entryInstructions = new InstructionList();
+ InstructionList entrySuccessInstructions = new InstructionList();
+
+ BcelObjectType aspectType = BcelWorld.getBcelObjectType(munger.getConcreteAspect());
+ String aspectname = munger.getConcreteAspect().getName();
+
+ String ptwField = NameMangler.perTypeWithinFieldForTarget(munger.getConcreteAspect());
+ entrySuccessInstructions.append(new PUSH(fact.getConstantPool(),t.getName()));
+
+ entrySuccessInstructions.append(fact.createInvoke(aspectname,"ajc$createAspectInstance",new ObjectType(aspectname),
+ new Type[]{new ObjectType("java.lang.String")},Constants.INVOKESTATIC));
+ entrySuccessInstructions.append(fact.createPutStatic(t.getName(),ptwField,
+ new ObjectType(aspectname)));
+
+ entryInstructions.append(entrySuccessInstructions);
+
+ range.insert(entryInstructions, Range.InsideBefore);
+ }
public void weaveCflowEntry(final BcelAdvice munger, final Member cflowField) {
import org.aspectj.weaver.NewMethodTypeMunger;
import org.aspectj.weaver.NewParentTypeMunger;
import org.aspectj.weaver.PerObjectInterfaceTypeMunger;
+//import org.aspectj.weaver.PerTypeWithinTargetTypeMunger;
import org.aspectj.weaver.PrivilegedAccessMunger;
import org.aspectj.weaver.ResolvedMember;
import org.aspectj.weaver.ResolvedTypeMunger;
} else if (munger.getKind() == ResolvedTypeMunger.PerObjectInterface) {
changed = mungePerObjectInterface(weaver, (PerObjectInterfaceTypeMunger)munger);
worthReporting = false;
+ } else if (munger.getKind() == ResolvedTypeMunger.PerTypeWithinInterface) {
+ // PTWIMPL Transform the target type (add the aspect instance field)
+ changed = mungePerTypeWithinTransformer(weaver);
+ worthReporting = false;
} else if (munger.getKind() == ResolvedTypeMunger.PrivilegedAccess) {
changed = mungePrivilegedAccess(weaver, (PrivilegedAccessMunger)munger);
worthReporting = false;
return false;
}
}
+
+ // PTWIMPL Add field to hold aspect instance and an accessor
+ private boolean mungePerTypeWithinTransformer(BcelClassWeaver weaver) {
+ LazyClassGen gen = weaver.getLazyClassGen();
+
+ // if (couldMatch(gen.getBcelObjectType(), munger.getTestPointcut())) {
+
+ // Add (to the target type) the field that will hold the aspect instance
+ // e.g ajc$com_blah_SecurityAspect$ptwAspectInstance
+ FieldGen fg = makeFieldGen(gen, AjcMemberMaker.perTypeWithinField(gen.getType(), aspectType));
+ gen.addField(fg.getField(),getSourceLocation());
+
+ // Add an accessor for this new field, the ajc$<aspectname>$localAspectOf() method
+ // e.g. "public com_blah_SecurityAspect ajc$com_blah_SecurityAspect$localAspectOf()"
+ Type fieldType = BcelWorld.makeBcelType(aspectType);
+ LazyMethodGen mg = new LazyMethodGen(
+ Modifier.PUBLIC | Modifier.STATIC,fieldType,
+ NameMangler.perTypeWithinLocalAspectOf(aspectType),
+ new Type[0], new String[0],gen);
+ InstructionList il = new InstructionList();
+ //PTWIMPL ?? Should check if it is null and throw NoAspectBoundException
+ InstructionFactory fact = gen.getFactory();
+ il.append(fact.createFieldAccess(
+ gen.getClassName(),
+ fg.getName(),
+ fieldType, Constants.GETSTATIC));
+ il.append(InstructionFactory.createReturn(fieldType));
+ mg.getBody().insert(il);
+ gen.addMethodGen(mg);
+ return true;
+// } else {
+// return false;
+// }
+ }
+ // ??? Why do we have this method? I thought by now we would know if it matched or not
private boolean couldMatch(
BcelObjectType bcelObjectType,
Pointcut pointcut) {
return parsePerCflow(false);
} else if (name.equals("percflowbelow")) {
return parsePerCflow(true);
+ } else if (name.equals("pertypewithin")) { // PTWIMPL Parse the pertypewithin clause
+ return parsePerTypeWithin();
} else {
return null;
}
eat(")");
return new PerObject(entry, isThis);
}
+
+ private PerClause parsePerTypeWithin() {
+ parseIdentifier();
+ eat("(");
+ TypePattern withinTypePattern = parseTypePattern();
+ eat(")");
+ return new PerTypeWithin(withinTypePattern);
+ }
private PerClause parsePerSingleton() {
import org.aspectj.util.TypeSafeEnum;
import org.aspectj.weaver.*;
+// PTWIMPL New kind added to this class, can be (de)serialized
public abstract class PerClause extends Pointcut {
protected ResolvedTypeX inAspect;
else if (kind == PERCFLOW) return PerCflow.readPerClause(s, context);
else if (kind == PEROBJECT) return PerObject.readPerClause(s, context);
else if (kind == FROMSUPER) return PerFromSuper.readPerClause(s, context);
+ else if (kind == PERTYPEWITHIN) return PerTypeWithin.readPerClause(s,context);
throw new BCException("unknown kind: " + kind);
}
case 2: return PERCFLOW;
case 3: return PEROBJECT;
case 4: return FROMSUPER;
+ case 5: return PERTYPEWITHIN;
}
throw new BCException("weird kind " + key);
}
public static final Kind PERCFLOW = new Kind("percflow", 2);
public static final Kind PEROBJECT = new Kind("perobject", 3);
public static final Kind FROMSUPER = new Kind("fromsuper", 4);
+ public static final Kind PERTYPEWITHIN = new Kind("pertypewithin",5);
}
--- /dev/null
+/* *******************************************************************
+ * Copyright (c) 2005 IBM
+ * All rights reserved.
+ * This program and the accompanying materials are made available
+ * under the terms of the Common Public License v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ *
+ * Contributors:
+ * Andy Clement initial implementation
+ * ******************************************************************/
+
+package org.aspectj.weaver.patterns;
+
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.util.HashSet;
+import java.util.Set;
+
+import org.aspectj.bridge.IMessage;
+import org.aspectj.bridge.ISourceLocation;
+import org.aspectj.bridge.Message;
+import org.aspectj.util.FuzzyBoolean;
+import org.aspectj.weaver.Advice;
+import org.aspectj.weaver.AjcMemberMaker;
+import org.aspectj.weaver.ISourceContext;
+import org.aspectj.weaver.Member;
+//import org.aspectj.weaver.PerTypeWithinTargetTypeMunger;
+import org.aspectj.weaver.PerTypeWithinTargetTypeMunger;
+import org.aspectj.weaver.ResolvedTypeMunger;
+import org.aspectj.weaver.ResolvedTypeX;
+import org.aspectj.weaver.Shadow;
+import org.aspectj.weaver.VersionedDataInputStream;
+import org.aspectj.weaver.World;
+import org.aspectj.weaver.ast.Expr;
+import org.aspectj.weaver.ast.Literal;
+import org.aspectj.weaver.ast.Test;
+
+
+// PTWIMPL Represents a parsed pertypewithin()
+public class PerTypeWithin extends PerClause {
+
+ private TypePattern typePattern;
+
+ // Any shadow could be considered within a pertypewithin() type pattern
+ private static final Set kindSet = new HashSet(Shadow.ALL_SHADOW_KINDS);
+
+ public TypePattern getTypePattern() {
+ return typePattern;
+ }
+
+ public PerTypeWithin(TypePattern p) {
+ this.typePattern = p;
+ }
+
+ public Set couldMatchKinds() {
+ return kindSet;
+ }
+
+ // -----
+ public FuzzyBoolean fastMatch(FastMatchInfo info) {
+ if (typePattern.annotationPattern instanceof AnyAnnotationTypePattern) {
+ return isWithinType(info.getType());
+ }
+ return FuzzyBoolean.MAYBE;
+ }
+
+
+ protected FuzzyBoolean matchInternal(Shadow shadow) {
+ ResolvedTypeX enclosingType = shadow.getIWorld().resolve(shadow.getEnclosingType(),true);
+ if (enclosingType == ResolvedTypeX.MISSING) {
+ //PTWIMPL ?? Add a proper message
+ IMessage msg = new Message(
+ "Cant find type pertypewithin matching...",
+ shadow.getSourceLocation(),true,new ISourceLocation[]{getSourceLocation()});
+ shadow.getIWorld().getMessageHandler().handleMessage(msg);
+ }
+ typePattern.resolve(shadow.getIWorld());
+ return isWithinType(enclosingType);
+ }
+
+ public void resolveBindings(IScope scope, Bindings bindings) {
+ typePattern = typePattern.resolveBindings(scope, bindings, false, false);
+ }
+
+ protected Test findResidueInternal(Shadow shadow, ExposedState state) {
+ Member ptwField = AjcMemberMaker.perTypeWithinField(shadow.getEnclosingType(),inAspect);
+
+ Expr myInstance =
+ Expr.makeCallExpr(AjcMemberMaker.perTypeWithinLocalAspectOf(shadow.getEnclosingType(),inAspect/*shadow.getEnclosingType()*/),
+ Expr.NONE,inAspect);
+ state.setAspectInstance(myInstance);
+
+ // this worked at one point
+ //Expr myInstance = Expr.makeFieldGet(ptwField,shadow.getEnclosingType().resolve(shadow.getIWorld()));//inAspect);
+ //state.setAspectInstance(myInstance);
+
+
+// return Test.makeFieldGetCall(ptwField,null,Expr.NONE);
+ // cflowField, cflowCounterIsValidMethod, Expr.NONE
+
+ // This is what is in the perObject variant of this ...
+// Expr myInstance =
+// Expr.makeCallExpr(AjcMemberMaker.perTypeWithinAspectOfMethod(inAspect),
+// new Expr[] {getVar(shadow)}, inAspect);
+// state.setAspectInstance(myInstance);
+// return Test.makeCall(AjcMemberMaker.perTypeWithinHasAspectMethod(inAspect),
+// new Expr[] { getVar(shadow) });
+//
+
+
+ return match(shadow).alwaysTrue()?Literal.TRUE:Literal.FALSE;
+ }
+
+
+ public PerClause concretize(ResolvedTypeX inAspect) {
+ PerTypeWithin ret = new PerTypeWithin(typePattern);
+ ret.copyLocationFrom(this);
+ ret.inAspect = inAspect;
+ if (inAspect.isAbstract()) return ret;
+
+
+ World world = inAspect.getWorld();
+
+ SignaturePattern sigpat = new SignaturePattern(
+ Member.STATIC_INITIALIZATION,
+ ModifiersPattern.ANY,
+ TypePattern.ANY,
+ typePattern,
+ NamePattern.ANY,
+ TypePatternList.ANY,
+ ThrowsPattern.ANY,
+ AnnotationTypePattern.ANY
+ );
+ Pointcut testPc = new KindedPointcut(Shadow.StaticInitialization,sigpat);
+ Pointcut testPc2= new WithinPointcut(typePattern);
+ // This munger will initialize the aspect instance field in the matched type
+ inAspect.crosscuttingMembers.addConcreteShadowMunger(Advice.makePerTypeWithinEntry(world, testPc, inAspect));
+
+ ResolvedTypeMunger munger = new PerTypeWithinTargetTypeMunger(inAspect, ret);
+ inAspect.crosscuttingMembers.addTypeMunger(world.concreteTypeMunger(munger, inAspect));
+ return ret;
+
+ }
+
+ public void write(DataOutputStream s) throws IOException {
+ PERTYPEWITHIN.write(s);
+ typePattern.write(s);
+ writeLocation(s);
+ }
+
+ public static PerClause readPerClause(VersionedDataInputStream s, ISourceContext context) throws IOException {
+ PerClause ret = new PerTypeWithin(TypePattern.read(s, context));
+ ret.readLocation(context, s);
+ return ret;
+ }
+
+ public PerClause.Kind getKind() {
+ return PERTYPEWITHIN;
+ }
+
+ public String toString() {
+ return "pertypewithin("+typePattern+")";
+ }
+
+ private FuzzyBoolean isWithinType(ResolvedTypeX type) {
+ while (type != null) {
+ if (typePattern.matchesStatically(type)) {
+ return FuzzyBoolean.YES;
+ }
+ type = type.getDeclaringType();
+ }
+ return FuzzyBoolean.NO;
+ }
+}