package lawOfDemeter;
import java.util.*;
import org.aspectj.lang.JoinPoint;
/**
* The StatMonitor aspect is part of a Law of Demeter Checker - a set of
* classes and aspects that verify a given program does not violate
* the Law of Demeter. This aspect monitors all of the checks made by the
* Checker aspect, keeping track of various statistics.
*
* An interesting feature of this design is that this aspect uses pointcuts
* defined in the checker aspect that describe methods in the checker aspect
* which signal what type of check has been made. This is has many similarities
* to an event throw -> catch implimentation, but the classes invloved do not
* need to impliment the standard Java Interfaces that would normally be involved.
*
* @author Modifications made by Paul Freeman
*/
public aspect StatMonitor {
// statistcs variables initialized before every main method execution
private long totalChecks;
private long numViolations;
private Vector validChecks;
/**
* @return Returns the total number of checks made.
*/
public long getTotalChecked(){
return totalChecks;
}
/**
* @return Returns the total number of violations found.
*/
public long getTotalViolations(){
return numViolations;
}
/**
* @return Returns the number of valid checks as a Vector where:
* - position 0 = total valid checks
* - position i = total valid checks where i = num of matches perCheck
*/
public Vector getValidChecks(){
return validChecks;
}
// initialize statistical variables
before():
Any.MainMethodExecution(){
totalChecks = 0;
numViolations = 0;
validChecks = new Vector();
validChecks.add(new Long(0)); // set the total valid counts = 0
}
// increase the total count of checks
before():
Any.ToCheck(){
totalChecks++;
}
// increase the violation count
before(JoinPoint tjp):
Checker.Violation(tjp){
numViolations++;
}
// increase the correct count
before(JoinPoint tjp, Vector binsIn):
Checker.Success(tjp, binsIn) {
addToStats(binsIn.size());
}
// Keeps track of the valid count statistics
private void addToStats(int binCount){
//initialize count being increased if necessary
try{
if(validChecks.elementAt(binCount) == null)
validChecks.setElementAt(new Long(0), binCount);
}catch(java.lang.ArrayIndexOutOfBoundsException e){
validChecks.setSize(binCount + 1);
validChecks.setElementAt(new Long(0), binCount);
}
// increase counts
Long val = new Long(((Long)validChecks.elementAt(0)).longValue() + 1); // total count
validChecks.setElementAt(val, 0);
val = new Long(((Long)validChecks.elementAt(binCount)).longValue() + 1);
validChecks.setElementAt(val, binCount);
}
// prints statistics when program is done executing
after():
Any.MainMethodExecution(){
long totalValid = ((Long)validChecks.elementAt(0)).longValue();
// produce headings
System.out.println("\nStatistics:");
System.out.println("Type \t\tCount\t%Total\t%Valid");
System.out.println("Total Checks\t\t" + totalChecks);
// produce violation statistics
System.out.println("Violations \t\t" + numViolations +
"\t"+ percent(numViolations, totalChecks, 2));
// produce valid percents
long thisCount;
for(int i = 0; i < validChecks.size(); i++){
String statement;
if(i==0){statement = "Valid Checks";}
else if(i==1){statement = "As "+i+" Supplier";}
else{statement = "As "+i+" Suppliers";}
if(validChecks.elementAt(i) == null){
thisCount = 0;
}else{
thisCount = ((Long)validChecks.elementAt(i)).longValue();
}
statement += "\t\t" + thisCount +
"\t"+ percent(thisCount, totalChecks, 2);
// add the % of valid stat if applicable
if(i != 0){
statement += "\t" + percent(thisCount, totalValid, 2);
}
System.out.println(statement);
}
}
// returns a double representing the percent of the numerator in the denominator
private double percent(long noom, long denom, int numDec){
if(denom == 0){return 0;}
return fix((double)noom/(double)denom * 100, numDec);
}
// fixes a double to a certain number of decimal places - does not round
private double fix(double aDouble, int numDec){
try{
String d = new String(new Double(aDouble).toString());
int dotPos = d.indexOf('.');
int len = d.length();
int lastPos = dotPos + numDec + 1;
if(lastPos > len){lastPos = len;}
return new Double(d.substring(0, lastPos)).doubleValue();
}catch(java.lang.NumberFormatException e){
return 0;
}
}
}