/**
* Copyright (c) Summa-tech.com
*/
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.StringTokenizer;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* FilterGettersAndSetters.java
*
* Takes as piped input the output from the JavaNCSS command below, and filters out all getters and
* setters in order to more accurately calculate the average code complexity of a given system.
* Without filtering getters and setters, the code complexity could look artificially low,
* especially for a system with a large domain model or a great number of DTOs. In these cases, the
* code complexity numbers would be less meaningingful, and comparing to other systems would be
* apples to oranges.
*
* CMD> javancss -function -recursive
*
* After filtering out the getters and setters, it re-calculates the average CCN, average Javadoc,
* and max CCN.
*
* @author Benjamin Northrop, Summa 2009
*/
public class FilterGettersAndSetters {
/** Regular expression patterns for getter and setter methods. */
private final static Pattern getter = Pattern.compile("\\Aget[a-zA-z,\\d]*");
private final static Pattern setter = Pattern.compile("\\Aset[a-zA-z,\\d]");
/**
* Main method, taking piped input the output from the JavaNCSS command.
*/
public static void main(String[] args) throws IOException {
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
String line = null;
int totalCcn = 0;
int totalJavadoc = 0;
int count = 0;
try {
while ((line = reader.readLine()) != null) {
StringTokenizer tokenizer = new StringTokenizer(line);
String[] columns = splitLine(tokenizer);
try {
int ccn = Integer.parseInt(columns[2]);
int javadoc = Integer.parseInt(columns[3]);
/*
* Methods are fully qualified, so split by the '.' and find the last token
* which will be the method.
*/
String method = columns[4];
String[] tokens = method.split("\\.");
String methodName = tokens[tokens.length - 1];
Matcher getterMatcher = getter.matcher(methodName);
Matcher setterMatcher = setter.matcher(methodName);
/*
* If it's a getter or setter and the complexity is 1 (i.e. a simple
* getter/setter), then just continue (i.e. filter it out).
*/
if ((getterMatcher.find() || setterMatcher.find()) && ccn == 1) {
continue;
}
totalCcn += ccn;
totalJavadoc += javadoc;
count++;
} catch (Exception e) {
/*
* Ignore the exception, since may be a header and footer line, and not a normal
* row of data.
*/
}
}
} finally {
if (reader != null) {
reader.close();
}
}
/*
* Calculate the average CCN and Javadoc and print the output.
*/
double averageCcn = (double) totalCcn / (double) count;
double averageJavadoc = (double) totalJavadoc / (double) count;
System.out.println("Total CCN: " + totalCcn);
System.out.println("Average CCN: :" + averageCcn);
System.out.println("Total Javadoc: " + totalJavadoc);
System.out.println("Average Javadoc: :" + averageJavadoc);
}
/**
* Split the output line from JavaNCSS. Expects exactly 5 columns of data, for function number,
* NCSS, CCN, Javadoc, and method name.
*/
private static String[] splitLine(StringTokenizer tokenizer) {
int i = 0;
String columns[] = new String[5];
while (tokenizer.hasMoreElements()) {
String column = tokenizer.nextToken();
if (i < 6) {
columns[i] = column;
}
i++;
}
return columns;
}
}