Defining Your Own Reporters

One of the strengths of the project-filstatistics ant plug-in is the ability to create new reporters (i.e. classes that output the statistical data) that can write content to a file, the console, or both. In some cases only one output location will be used. In this example we will create a simple reporter that outputs both to the console and to the filesystem.

The Average Reporter

This reporter outputs data to both the console and a text file. The console output is always printed, the text file is only written where the outputDirectory is set in the task definition.

Sub-class the AbstractReporter class

The initial class which will be named com.example.AverageReporter extends the above class which gives it access to the StatisticsBean which holds all of the statistics about the files that were processed.

Initially, the stub-class is as follows:

package com.example;

import synapticloop.ant.reporter.AbstractReporter;

public class AverageReporter extends AbstractReporter {

}

If we compile this in, and update the task definition thusly:

<project-filestatistics ignoreBinary="true" outputDirectory="${basedir}" pluginList="com.example.AverageReporter">

Note: When using a custom reporter, the fully-qualified class name must be used.

We should get output as follows:

[project-filestatistics] WARNING:AverageReporter cannot be printed to a file.  Ignoring.
[project-filestatistics] WARNING:AverageReporter cannot be printed to the console.  Ignoring.

As we have over-ridden neither of the methods the above message will appear. The two methods that we need to over-ride are shown below:

@Override
protected void printToConsole() {
}

@Override
protected void printToFile() {
}

Re-running the code will give us blank input.

Implement the Methods

For this rather simple example, we will be reporting on the average number of lines per file. Utilising the StatisticsBean as follows:

@Override
protected void printToConsole() {
	System.out.println("Total # files: " + statisticsBean.getTotalFileCount());
	System.out.println("Total # lines: " + statisticsBean.getTotalLineCount());
	System.out.println("Average lines/file: " + statisticsBean.getTotalLineCount()/statisticsBean.getTotalFileCount());
}

Which outputs:

[project-filestatistics] Total # files: 23
[project-filestatistics] Total # lines: 6093
[project-filestatistics] Average lines/file: 264

To write out to the file-system we do the same:

@Override
protected void printToFile() {
	String fileOutputLocation = outputDirectory + "/" + this.getClass().getName() + ".txt";
	try {
		// Save as PNG
		File file = new File(fileOutputLocation);
		BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(file));
		bufferedWriter.write("Total # files: " + statisticsBean.getTotalFileCount() +"\n");
		bufferedWriter.write("Total # lines: " + statisticsBean.getTotalLineCount() +"\n");
		bufferedWriter.write("Average lines/file: " + statisticsBean.getTotalLineCount()/statisticsBean.getTotalFileCount() +"\n");
		bufferedWriter.flush();
		bufferedWriter.close();
	} catch (IOException jiioex) {
		System.out.println("FATAL: Could not write file " + fileOutputLocation + ", ignoring.");
	}
}

This will create a file named com.example.AverageReporter.txt which contains the following text:

Total # files: 24
Total # lines: 6112
Average lines/file: 254

Not the greatest reporter - so if we clean up the code a little bit and start using the synapticloop.util.PrintfFormat and synaptlicloop.util.PrintHelper helper classes we get the output printed thusly:

[project-filestatistics] Total # files:        25
[project-filestatistics] Total # lines:      6134
[project-filestatistics] ------------------- ----
[project-filestatistics] Average lines/file:  245
[project-filestatistics] =================== ====

The complete code listing:

package com.example;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;

import synapticloop.ant.reporter.AbstractReporter;
import synapticloop.util.PrintHelper;
import synapticloop.util.PrintfFormat;

public class AverageReporter extends AbstractReporter {
	private static final String AVERAGE_LINES_FILE = "Average lines/file:";
	private static final String TOTAL_LINES = "Total # lines:     ";
	private static final String TOTAL_FILES = "Total # files:     ";

	private StringBuffer stringBuffer = null;

	@Override
	protected void printToConsole() {
		System.out.println(getOutput().toString());
	}

	@Override
	protected void printToFile() {
		String fileOutputLocation = outputDirectory + "/" + this.getClass().getName() + ".txt";
		try {
			// Save as PNG
			File file = new File(fileOutputLocation);
			BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(file));
			bufferedWriter.write(getOutput().toString() + "\n");
			bufferedWriter.flush();
			bufferedWriter.close();
		} catch (IOException jiioex) {
			System.out.println("FATAL: Could not write file " + fileOutputLocation + ", ignoring.");
		}
	}
	
	/**
	 * Generate the output for the reporter and buffer it for second usage
	 *  
	 * @return The stringBuffer containing the output.
	 */
	private StringBuffer getOutput() {
		if(stringBuffer == null) {
			int length = new String(statisticsBean.getTotalLineCount() + "").length();
			stringBuffer = new StringBuffer();
			stringBuffer.append(TOTAL_FILES + " " + new PrintfFormat("%" + length + "i").sprintf(statisticsBean.getTotalFileCount()) + "\n");
			stringBuffer.append(TOTAL_LINES + " " + new PrintfFormat("%" + length + "i").sprintf(statisticsBean.getTotalLineCount()) + "\n");
			stringBuffer.append(PrintHelper.underline('-', AVERAGE_LINES_FILE.length()) + " " + PrintHelper.underline('-', length) + "\n");
			stringBuffer.append(AVERAGE_LINES_FILE + " " + new PrintfFormat("%" + length + "i").sprintf(statisticsBean.getTotalLineCount()/statisticsBean.getTotalFileCount()) +"\n");
			stringBuffer.append(PrintHelper.underline('=', AVERAGE_LINES_FILE.length()) + " " + PrintHelper.underline('=', length));
		}
		return (stringBuffer);
	}
}

Of course this code is contained within the source download. in the src/main/java/com/example/ package.