/** * Copyright (C) 2008-2010, Squale Project - http://www.squale.org * * This file is part of Squale. * * Squale is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation, either version 3 of the * License, or any later version. * * Squale is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with Squale. If not, see <http://www.gnu.org/licenses/>. */ package org.squale.squalix.tools.pmd; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import net.sourceforge.pmd.Report; import net.sourceforge.pmd.RuleViolation; import net.sourceforge.pmd.Report.ProcessingError; import org.squale.jraf.commons.exception.JrafDaoException; import org.squale.jraf.spi.persistence.ISession; import org.squale.squalecommon.daolayer.result.MeasureDAOImpl; import org.squale.squalecommon.enterpriselayer.businessobject.component.AuditBO; import org.squale.squalecommon.enterpriselayer.businessobject.component.ProjectBO; import org.squale.squalecommon.enterpriselayer.businessobject.result.IntegerMetricBO; import org.squale.squalecommon.enterpriselayer.businessobject.result.rulechecking.JavaPmdTransgressionBO; import org.squale.squalecommon.enterpriselayer.businessobject.result.rulechecking.JspPmdTransgressionBO; import org.squale.squalecommon.enterpriselayer.businessobject.result.rulechecking.RuleCheckingTransgressionBO; import org.squale.squalecommon.enterpriselayer.businessobject.result.rulechecking.RuleCheckingTransgressionItemBO; import org.squale.squalecommon.enterpriselayer.businessobject.rulechecking.RuleBO; import org.squale.squalecommon.enterpriselayer.businessobject.rulechecking.pmd.PmdRuleSetBO; /** * Persistance des donn�es de Pmd Les donn�es sont stock�es dans une ruleset dynamique, ce ruleset contient une r�gle * par langage */ public class PmdPersistor { /** * Logger */ private static final Log LOGGER = LogFactory.getLog( PmdPersistor.class ); /** Transgression */ private RuleCheckingTransgressionBO mTransgression; /** RuleSet */ private PmdRuleSetBO mRuleSet; /** * Constructeur * * @param pProjectBO projet * @param pAuditBO audit * @param pRuleSet ruleset * @param pLanguage langage * @throws PmdFactoryException si langage inconnu */ public PmdPersistor( ProjectBO pProjectBO, AuditBO pAuditBO, PmdRuleSetBO pRuleSet, String pLanguage ) throws PmdFactoryException { mRuleSet = pRuleSet; mTransgression = createTransgression( pProjectBO, pAuditBO, pLanguage ); } /** * Cr�ation de la transgression * * @param pProjectBO projet * @param pAuditBO audit * @param pLanguage langage * @return transgression * @throws PmdFactoryException si langage inconnu */ protected RuleCheckingTransgressionBO createTransgression( ProjectBO pProjectBO, AuditBO pAuditBO, String pLanguage ) throws PmdFactoryException { // Cr�ation de la transgression RuleCheckingTransgressionBO transgression; if ( pLanguage.equals( "java" ) ) { transgression = new JavaPmdTransgressionBO(); } else if ( pLanguage.equals( "jsp" ) ) { transgression = new JspPmdTransgressionBO(); } else { throw new PmdFactoryException( PmdMessages.getString( "exception.unknown.language", pLanguage ) ); } transgression.setAudit( pAuditBO ); transgression.setComponent( pProjectBO ); transgression.setRuleSet( mRuleSet ); transgression.setTaskName( "PmdTask" ); return transgression; } /** * Sauvegarde des r�sultats * * @param pSession session * @param pReport rapport * @throws JrafDaoException si erreur */ public void storeResults( ISession pSession, Report pReport ) throws JrafDaoException { HashMap results = new HashMap(); // On r�cup�re les erreurs de parsing et on les consid�re comme des transgressions // de la r�gle concernant le XHTML car toutes les JSPs doivent �tre conforme au XHTML // pour pouvoir �tre pars�e. Iterator itErrors = pReport.errors(); while ( itErrors.hasNext() ) { ProcessingError error = (ProcessingError) itErrors.next(); processTransgression( results, error ); } // Parcours des violations Iterator itViolations = pReport.iterator(); while ( itViolations.hasNext() ) { RuleViolation violation = (RuleViolation) itViolations.next(); processTransgression( results, violation ); } // Ecriture des violations dans la mesure Iterator itRules = mRuleSet.getRules().values().iterator(); while ( itRules.hasNext() ) { RuleBO rule = (RuleBO) itRules.next(); Collection details = (Collection) results.get( rule.getCode() ); // On r�cup�re le nombre de transgression qui existe d�j� int nbOcc = findNbOccWhereName( mTransgression.getMetrics(), rule.getCode() ); // Si le parsing n'a pas donn� de r�sultat, on place 0 comme // nombre de transgression if ( details != null ) { nbOcc += details.size(); // On parcourt le d�tail des transgressions int cpt = RuleCheckingTransgressionBO.MAX_DETAILS; for ( Iterator detailIt = details.iterator(); detailIt.hasNext() && cpt > 0; cpt-- ) { RuleCheckingTransgressionItemBO item = (RuleCheckingTransgressionItemBO) detailIt.next(); item.setRule( rule ); mTransgression.getDetails().add( item ); } } // On ajoute une m�trique de type Integer pour chaque r�gle transgress�e // avec 0 comme valeur par d�faut IntegerMetricBO metric = new IntegerMetricBO(); metric.setName( rule.getCode() ); metric.setValue( nbOcc ); metric.setMeasure( mTransgression ); mTransgression.putMetric( metric ); } // On parcourt les r�gles non trouv�es dans le ruleset Iterator ruleCodes = results.keySet().iterator(); while ( ruleCodes.hasNext() ) { String ruleCode = (String) ruleCodes.next(); // Chaque r�gle non trouv�e est signal�e comme // manquante if ( false == mRuleSet.getRules().containsKey( ruleCode ) ) { LOGGER.warn( PmdMessages.getString( "rule.ignored", ruleCode ) ); } } // Sauvegarde des donn�es dans la base MeasureDAOImpl.getInstance().create( pSession, mTransgression ); } /** * @param pDetails d�tails des transgression MAP<rulename,Collection<RuleCheckingTransgressionItemBO>> * @param pError l'erreur de parsing caus� par le XHTML */ private void processTransgression( Map pDetails, ProcessingError pError ) { Collection col = (Collection) pDetails.get( PmdRuleSetBO.XHTML_RULE_NAME ); if ( col == null ) { col = new ArrayList(); pDetails.put( PmdRuleSetBO.XHTML_RULE_NAME, col ); } // On cr�e une transgression que l'on ajoute RuleCheckingTransgressionItemBO item = new RuleCheckingTransgressionItemBO(); // Construction du message en fonction du nom de fichier et du message item.setComponentFile( pError.getFile() ); StringBuffer detail = new StringBuffer( RuleCheckingTransgressionItemBO.PATH_KEY ); detail.append( " is not XHTML compliant" ); // Troncature du message si besoin item.setMessage( truncMessage( detail ) ); col.add( item ); } /** * @param pDetails d�tails des transgression MAP<rulename,Collection<RuleCheckingTransgressionItemBO>> * @param pViolation violation � traiter */ protected void processTransgression( Map pDetails, RuleViolation pViolation ) { Collection col = (Collection) pDetails.get( pViolation.getRule().getName() ); if ( col == null ) { col = new ArrayList(); pDetails.put( pViolation.getRule().getName(), col ); } // On cr�e une transgression que l'on ajoute RuleCheckingTransgressionItemBO item = new RuleCheckingTransgressionItemBO(); // Construction du message en fonction du nom de fichier, num�ro de ligne et du message item.setComponentFile( pViolation.getFilename() ); StringBuffer detail = new StringBuffer( RuleCheckingTransgressionItemBO.PATH_KEY ); item.setLine( pViolation.getBeginLine() ); detail.append( " line " + RuleCheckingTransgressionItemBO.LINE_KEY ); if ( pViolation.getBeginLine() != pViolation.getEndLine() ) { detail.append( " to " + pViolation.getEndLine() ); } detail.append( ": " + pViolation.getDescription() ); // Troncature du message si besoin item.setMessage( truncMessage( detail ) ); col.add( item ); } /** * @param pMessage le message � tronquer * @return le message tronqu� si il d�passe la limite */ private String truncMessage( StringBuffer pMessage ) { StringBuffer result = pMessage; // Taille maximale pour les d�tails final int MAX_LENGTH = 3000; // Troncature du message si besoin if ( pMessage.length() > MAX_LENGTH ) { pMessage.substring( MAX_LENGTH - 1 ); } return result.toString(); } /** * @param pMetrics les m�triques * @param pCode le code de la r�gle � chercher * @return le nombre d'occurence de la r�gle */ private int findNbOccWhereName( Map pMetrics, String pCode ) { int nbOcc = 0; IntegerMetricBO metric = (IntegerMetricBO) pMetrics.get( pCode ); if ( metric != null ) { nbOcc = ( (Integer) metric.getValue() ).intValue(); } return nbOcc; } }