16.7.08

Extendiendo PMD con nuevos renderers

PMD es una herramienta de verificación que código Java que permite aplicar un conjunto de reglas (actualmente tiene aproximadamente 240 reglas) y generar un informe con los resultados. En una entrada anterior (http://rincew.blogspot.com/2008/02/escribiendo-reglas-en-pmd.html) conté como escribir una nueva regla. En esta entrada voy a dar unas ideas de cómo desarrollar un nuevo informe de resultados.

Los encargados de procesar los resultados de la verificación se llaman renderers. PMD trae un conjunto de renderers ya construidos para mostrar los resultados como texto, o como HTML, o CSV, o XML. Es útil crear un renderer propio cuando se quiere hacer un procesado adicional, cuando queremos generar un nuevo tipo de resultado, por ejemplo un informa en RTF o añadir el resultado a una BBDD, o cuando queremos ampliar alguno de los renderers ya existentes para incluya información adicional. Hay que recalcar que todas las acciones anteriores pueden hacerse e otra manera, por ejemplo utilizando transformaciones XSLT o las opciones de importación de CSV de la mayoría de sistemas de BBDD.

En PMD, un renderer es una clase que implementa la interfaz Renderer del paquete net.sourceforge.pmd.renderers. Esta interfaz permite que un rederer se comporte como una máquina de estados. Al inicializar el renderer se invoca el método start(), cada vez que se ha aplicado un nuevo conjunto de reglas se invoca al método renderFileReport(Report report) y una vez que se ha acabado el proceso se invoca al método end(). Existen más métodos en esta interfaz, sin embargo no será necesario utilizarlos en este ejemplo.

Como es habitual en muchas librerías y herramientas, PMD ya ofrece una implementación base de esta interfaz en la clase AbstractRenderer (que se mantiene por motivos de compatibilidad con versiones antiguas). A pesar de su nombre, esta clase no es abstracta ni ninguno de sus métodos son abstractos. Tampoco usaremos esta clase como base para los renderers, en su lugar utilizaremos su hija OnTheFlyRenderer, la cuál sí tiene tres métodos abstractos: start, renderFileViolations y end. El funcionamiento de start y end es el mismo que el definido anteriormente, sin embargo, para cada conjunto de reglas, el método invocado será el método renderFileViolations(Iterator violations)


Este método, recibe un iterador con todas las violaciones detectadas para un conjunto de reglas concreto. Una violación es un objetivo de una clase que implementa la interfaz IRuleViolation. A partir de los métodos get de esta interfaz podemos conocer toda la información que PMD maneja del error como el nombre del archivo (método getFilename), la clase y el método de la violación (getClassName y getMethodName), etc.
Además, también podemos obtener toda la información referente a la regla que se ha incumplido con el método getRule. Este método devuelve un objeto que implementa la interfaz Rule y que tiene varios métodos get para conocer el nombre de la regla (getName), su prioridad (getPriority), etc.
A modo de ejemplo, a continuación se muestra un nuevo renderer que también genera una salida de texto plano pero con una información distinta y un orden distinto al renderer de texto que viene de serie en PMD.


import net.sourceforge.pmd.IRuleViolation;
import net.sourceforge.pmd.PMD;
import net.sourceforge.pmd.renderers.OnTheFlyRenderer;
import java.io.IOException;
import java.io.Writer;
import java.util.Iterator;

public class RendererTexto extends OnTheFlyRenderer {


public void start() throws IOException {

}

public void renderFileViolations(Iterator violations)
throws IOException
{
Writer writer = getWriter();
StringBuffer buf = new StringBuffer();

while (violations.hasNext()) {
IRuleViolation rv = violations.next();
buf.append(PMD.EOL);
buf.append(rv.getFilename());
buf.append(':');
buf.append(Integer.toString(rv.getBeginLine()));
buf.append('\t');
buf.append(rv.getRule().getName());
buf.append(": ");
buf.append(rv.getDescription());

writer.write(buf.toString());
}
}

public void end() throws IOException {
getWriter().write("Ok.");
}

}



Como heredamos de OnTheFlyRenderer solo nos tenemos que preocupar de los tres métodos antes mencionados. En concreto, en el método start no hemos nada. En el método renderFileViolations recorremos cada una de las violaciones mostrando el nombre del fichero y la línea donde ocurre, el nombre de la regla y su descripción. En el método end escribimos la cadena de texto Ok para indicar que el proceso terminó con éxito.
Por último, será necesario indicar a PMD que utilice el nuevo renderer. Para ello es necesario que la clase esté disponible en el classpath del PMD (por ejemplo poniendo el nuevo renderer en una archivo jar y modificando el archivo pmd.bat para que añada dicho jar al classpath en cada ejecución).
Una vez hecho, solo es necesario indicar el nombre de la clase (indicando su paquete) como segundo parámetro. Por ejemplo, si la clase mostrada más arriba está guardada en el paquete pmdext, para utilizar habría que escribir:


PMD c:\src pmdext. RendererTexto basic



Con la línea anterior se verificarían todas las reglas de conjunto de regla basic en todo el código Java dentro de la carpeta src.
En verdad, el mundo de los renderes en PMD es un poco más complejo, ya que no hemos hablado de los writers (aunque se usan en el ejemplo de más arriba). Además, el report no solo nos informa de las violaciones de las reglas sino de los errores que han podido seguir a la hora de procesar un archivo o de las supresiones, es decir, bloques de código marcados para ser ignorados por PMD.
Sin embargo, con estas nociones básicas no es difícil estudiar el código de la clase OnTheFlyRenderer y ver los detalles que no hemos mencionado.
Como comentario final, quiero mencionar que el diseño del mecanismo de renders de PMD no es todo lo bueno y homogéneo que pudiera ser, por suerte es bastante sencillo de usar. Ya se ha anunciado que para la versión 5 se van a hacer cambios de código importantes y se va a romper la compatibilidad hacia atrás, por lo que tengo esperanzas de que mejoren este mecanismo.

1 comment:

Anonymous said...

Yes if the truth be known, in some moments I can phrase that I acquiesce in with you, but you may be considering other options.
to the article there is still a suspect as you did in the go over like a lead balloon a fall in love with issue of this solicitation www.google.com/ie?as_q=super video splitter 4.7 ?
I noticed the axiom you procure not used. Or you profit by the dreary methods of promotion of the resource. I possess a week and do necheg