--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+ <classpathentry excluding="com/kronos/aspects/AnnotatedProcessAspect.java" kind="src" path="src"/>
+ <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
+ <classpathentry kind="con" path="org.eclipse.ajdt.core.ASPECTJRT_CONTAINER"/>
+ <classpathentry kind="output" path="bin"/>
+</classpath>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>EnforceProcess</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>org.eclipse.ajdt.core.ajbuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>org.eclipse.ajdt.ui.ajnature</nature>
+ <nature>org.eclipse.jdt.core.javanature</nature>
+ </natures>
+</projectDescription>
--- /dev/null
+package com.kronos.aspects;
+
+import com.kronos.code.MyProcessor;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.util.HashMap;
+import com.kronos.code.OkToIgnore;
+import java.lang.reflect.Modifier;
+
+import org.aspectj.lang.JoinPoint;
+import org.aspectj.lang.annotation.*;
+
+@Aspect("perthis(initMyProcessor(com.kronos.code.MyProcessor))")
+class AnnotatedProcessAspect {
+
+ HashMap<String, Field> fieldList = new HashMap<String, Field>();
+
+ @Pointcut("initialization(com.kronos.code.MyProcessor+.new(..)) && this(myProcessor)")
+ public void initMyProcessor(MyProcessor myProcessor){}
+
+
+
+ @Pointcut("execution(* com.kronos.code.MyProcessor+.process()) && this(myProcessor)")
+ public void executesProcess(MyProcessor myProcessor){}
+
+ @Pointcut("get(* com.kronos.code.MyProcessor+.*) && cflow(executesProcess(myProcessor))")
+ public void fieldAccessor(MyProcessor myProcessor){}
+
+ // find all of the public fields or fields with public accessors
+ @After("initMyProcessor(myProcessor)")
+ public void adterInitMyProcessor(MyProcessor myProcessor){
+ Field[] fields = myProcessor.getClass().getDeclaredFields();
+ for (Field field : fields) {
+ // make sure it should not be ignored
+ if(field.getAnnotation(OkToIgnore.class) == null){
+ boolean addField = false;
+ // if public
+ if(field.getModifiers() == Modifier.PUBLIC){
+ addField = true;
+ }else {
+ // find a public accessor if it exists - assumes convention of getFieldName
+ Method[] methods = myProcessor.getClass().getMethods();
+ for (Method method : methods) {
+ String methodName = method.getName();
+ if(methodName.equalsIgnoreCase("get" + field.getName()) && method.getModifiers() == Modifier.PUBLIC){
+ addField = true;
+ }
+ }
+ }
+
+ if(addField){
+ fieldList.put(field.getName().toString(), field);
+ }
+ }
+ }
+ }
+
+ // check where the process method is defined
+ @Before("executesProcess(myProcessor)")
+ public void beforeExecutesProcess(MyProcessor myProcessor, JoinPoint thisJoinPoint){
+ Class declaringType = thisJoinPoint.getSignature().getDeclaringType();
+ System.out.println(myProcessor.getClass().toString() + " execution OK: " + myProcessor.getClass().equals(declaringType));
+ }
+
+ // check access of the fields
+ @Before("fieldAccessor(myProcessor)")
+ public void beforeFieldAccessor(MyProcessor myProcessor, JoinPoint thisJoinPoint){
+ String fieldName = thisJoinPoint.getSignature().getName().toString();
+ // remove the fields from the field list as they are accessed
+ if(fieldList.containsKey(fieldName)){
+ fieldList.remove(fieldName);
+ }
+ }
+
+ @After("executesProcess(myProcessor)")
+ public void afterExecutesProcess(MyProcessor myProcessor){
+ // report the missing field accessors
+ for(String fieldName : fieldList.keySet()){
+ System.out.println("Failed to process " + fieldName + " in " + myProcessor.getClass().toString());
+ }
+ }
+
+}
--- /dev/null
+package com.kronos.aspects;
+
+import com.kronos.code.MyProcessor;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.util.HashMap;
+import com.kronos.code.OkToIgnore;
+import java.lang.reflect.Modifier;
+import java.util.ArrayList;
+
+public aspect ProcessAspect perthis(initMyProcessor(MyProcessor)) {
+
+ HashMap<String, Field> fieldList = new HashMap<String, Field>();
+
+ pointcut initMyProcessor(MyProcessor myProcessor) : initialization(MyProcessor+.new(..)) && this(myProcessor);
+
+ pointcut executesProcess(MyProcessor myProcessor) : execution(* MyProcessor+.process()) && this(myProcessor);
+
+ pointcut fieldAccessor(MyProcessor myProcessor) : get(* MyProcessor+.*) && cflow(executesProcess(myProcessor));
+
+ // find all of the public fields or fields with public accessors
+ after(MyProcessor myProcessor): initMyProcessor(myProcessor) {
+ // this advice is executed for each type in the hierarchy, including the interface
+ // so you will get all of the fields and methods for each type in the hierarchy
+ System.out.println(thisJoinPoint.getArgs()); Class currentType = thisJoinPointStaticPart.getSourceLocation().getWithinType();
+System.out.println(thisEnclosingJoinPointStaticPart); Field[] fields = currentType.getDeclaredFields();
+ for (Field field : fields) {
+ // make sure it should not be ignored
+ if(field.getAnnotation(OkToIgnore.class) == null){
+ boolean addField = false;
+ // if public
+ if(field.getModifiers() == Modifier.PUBLIC){
+ addField = true;
+ }else {
+ // find a public accessor if it exists - assumes convention of getFieldName
+ Method[] methods = currentType.getMethods();
+ for (Method method : methods) {
+ String methodName = method.getName();
+ if(methodName.equalsIgnoreCase("get" + field.getName()) && method.getModifiers() == Modifier.PUBLIC){
+ addField = true;
+ }
+ }
+ }
+
+ if(addField){
+ fieldList.put(field.getName().toString(), field);
+ }
+ }
+ }
+ }
+
+
+ // check where the process method is defined
+ before(MyProcessor myProcessor): executesProcess(myProcessor) && !cflowbelow(executesProcess(MyProcessor)){
+ Class declaringType = thisJoinPointStaticPart.getSignature().getDeclaringType();
+ System.out.println(myProcessor.getClass().toString() + " execution OK: " + myProcessor.getClass().equals(declaringType));
+ }
+
+ // check access of the fields
+ before(MyProcessor myProcessor): fieldAccessor(myProcessor){
+ String fieldName = thisJoinPointStaticPart.getSignature().getName().toString();
+ // remove the fields from the field list as they are accessed
+ if(fieldList.containsKey(fieldName)){
+ fieldList.remove(fieldName);
+ }
+ }
+
+ after(MyProcessor myProcessor): executesProcess(myProcessor) && !cflowbelow(executesProcess(MyProcessor)){
+ // report the missing field accessors
+ for(String fieldName : fieldList.keySet()){
+ System.out.println("Failed to process " + fieldName + " in " + myProcessor.getClass().toString());
+ }
+ }
+
+}
--- /dev/null
+package com.kronos.code;
+
+public class Main {
+
+ /**
+ * @param args
+ */
+ public static void main(String[] args) {
+ Processor1 p1 = new Processor1();
+ p1.process();
+ Processor2 p2 = new Processor2();
+ p2.process();
+ Processor3 p3 = new Processor3();
+ p3.process();
+ }
+
+}
--- /dev/null
+package com.kronos.code;
+
+public interface MyProcessor {
+ public void process();
+}
--- /dev/null
+package com.kronos.code;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.FIELD)
+public @interface OkToIgnore {
+
+}
--- /dev/null
+package com.kronos.code;
+public class Processor1 implements MyProcessor {
+
+ private int p1;
+
+ public int getP1() {
+ return p1;
+ }
+
+ public void process() {
+ // TODO Auto-generated method stub
+ int x = p1;
+ }
+
+}
--- /dev/null
+package com.kronos.code;
+
+public class Processor2 extends Processor1 {
+
+}
--- /dev/null
+package com.kronos.code;
+
+public class Processor3 extends Processor1 {
+
+ @OkToIgnore
+ public int u = 0; // should pass it is marked as ok to ignore
+ private int v = 0; // should fail it has public accessor but is not processed
+ private int w = 0; // should pass it has public accessor and is processed
+ public int x = 0; // should pass it is public and is processed
+ public int y = 0; // should fail it is public and is not processed
+ private int z = 0; // should pass it is private and does not have a public accessor
+
+ public void process() {
+ int a = x;
+ int b = w;
+ super.process();
+ }
+
+ public int getW(){
+ return w;
+ }
+
+ public int getV(){
+ return v;
+ }
+}
}
- public void testX() throws IOException {
+ public void testHandleCountersForAdvice() throws IOException {
String p = "prx";
initialiseProject(p);
build(p);
+// System.out.println("Handle Counters For Advice Output");
IProgramElement root = getModelFor(p).getHierarchy().getRoot();
- dumptree(getModelFor(p).getHierarchy().getRoot(), 0);
- PrintWriter pw = new PrintWriter(System.out);
- getModelFor(p).dumprels(pw);
- pw.flush();
-
+// dumptree(getModelFor(p).getHierarchy().getRoot(), 0);
+// PrintWriter pw = new PrintWriter(System.out);
+// getModelFor(p).dumprels(pw);
+// pw.flush();
IProgramElement ff = findFile(root,"ProcessAspect.aj");
-
assertEquals("=prx<com.kronos.aspects*ProcessAspect.aj}ProcessAspect&after&QMyProcessor;", findElementAtLine(root, 22).getHandleIdentifier());
assertEquals("=prx<com.kronos.aspects*ProcessAspect.aj}ProcessAspect&after&QMyProcessor;!2", findElementAtLine(root, 68).getHandleIdentifier());
}