/** * 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.cpptest; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.util.Collection; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import java.util.Map.Entry; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.squale.jraf.commons.exception.JrafEnterpriseException; import org.squale.squalecommon.datatransfertobject.rulechecking.CppTestRuleSetDTO; import org.squale.squalecommon.enterpriselayer.businessobject.component.parameters.MapParameterBO; import org.squale.squalecommon.enterpriselayer.businessobject.component.parameters.ParametersConstants; import org.squale.squalecommon.enterpriselayer.businessobject.component.parameters.StringParameterBO; import org.squale.squalecommon.enterpriselayer.facade.cpptest.CppTestFacade; import org.squale.squalix.core.AbstractTask; import org.squale.squalix.core.TaskData; import org.squale.squalix.core.TaskException; import org.squale.squalix.core.exception.ConfigurationException; import org.squale.squalix.util.file.FileUtility; import org.squale.squalix.util.process.ProcessErrorHandler; import org.squale.squalix.util.process.ProcessManager; import org.squale.squalix.util.process.ProcessOutputHandler; /** * T�che CppTest Cette t�che r�alise l'interface avec l'outil CppTest pour collecter les donn�es concernant les r�gles * de codage non respect�es. Les donn�es de configuration indiquent la liste des scripts de compilation � lancer */ public class CppTestTask extends AbstractTask implements ProcessErrorHandler, ProcessOutputHandler { /** * Logger */ private static final Log LOGGER = LogFactory.getLog( CppTestTask.class ); /** Filtre d'erreur */ private ErrorFilter mErrorFilter; /** * Constructeur */ public CppTestTask() { mName = "CppTestTask"; mErrorFilter = new ErrorFilter(); } /** * Ex�cution de la t�che CppTest * * @throws TaskException en cas d'�chec */ public void execute() throws TaskException { try { // Lecture de la configuration du projet CppTestConfiguration conf = new CppTestConfiguration(); conf.parse( new FileInputStream( "config/cpptest-config.xml" ) ); // Les donn�es du projet doivent fournir le nom du fichier // de configuration MapParameterBO cppTestMap = (MapParameterBO) getProject().getParameter( ParametersConstants.CPPTEST ); if ( cppTestMap == null ) { String message = CppTestMessages.getString( "exception.variable.not_found", ParametersConstants.CPPTEST ); LOGGER.error( message ); // Renvoi d'une exception de configuration throw new ConfigurationException( message ); } // Obtention du ruleset CppTestRuleSetDTO ruleset = getRuleSet( cppTestMap ); // Espace de travail pour CppTest CppTestWorkSpace workspace = new CppTestWorkSpace( new File( conf.getReportDirectory(), "project" + getProjectId() + "_audit" + getAuditId() ) ); // Lancement de la commande externe de g�n�ration du rapport generateReport( workspace, ruleset, cppTestMap, conf.getLogger() ); // Exploitation des donn�es du rapport parseReport( workspace, ruleset ); // positionne les donn�es sur la taille du file System affectFileSystemSize( conf.getReportDirectory(), true ); // Nettoyage du workspace workspace.cleanup(); } catch ( Exception e ) { throw new TaskException( e ); } } /** * G�n�ration du rapport XML Le rapport XML est g�n�r� en une seule �tape par le lancement d'une commande cpptest * qui r�alise l acr�ation du projet et le lancement de l'audit sur les r�gles * * @param pWorkSpace espace de travail CppTest * @param pCppTestMap param�tres de la t�che * @param pRuleSet ruleset utilis� * @param pLogger le fichier de log * @throws Exception si erreur */ protected void generateReport( CppTestWorkSpace pWorkSpace, CppTestRuleSetDTO pRuleSet, MapParameterBO pCppTestMap, String pLogger ) throws Exception { // R�cup�ration des informations de configuration du projet String ruleSet = pRuleSet.getCppTestName(); File script; StringParameterBO scriptConf = (StringParameterBO) pCppTestMap.getParameters().get( ParametersConstants.CPPTEST_SCRIPT ); if ( scriptConf == null ) { String message = CppTestMessages.getString( "exception.variable.not_found", ParametersConstants.CPPTEST_SCRIPT ); LOGGER.error( message ); // Renvoi d'une exception de configuration throw new ConfigurationException( message ); } else { script = new File( scriptConf.getValue() ); } // D�termination du script � ex�cuter script = computeScriptLocation( script ); // Lancement de la commande String viewPath = (String) getData().getData( TaskData.VIEW_PATH ); String[] command = { script.getAbsolutePath(), viewPath, ruleSet, pWorkSpace.getProjectFile().getAbsolutePath(), pWorkSpace.getReportDirectory().getAbsolutePath() }; LOGGER.info( CppTestMessages.getString( "report.command", command ) ); executeCommand( command, pLogger ); } /** * Obtention du DTO du ruleset * * @param pCppTestMap param�tres de la t�che * @return nom du ruleset CppTest * @throws ConfigurationException si erreur * @throws JrafEnterpriseException si erreur */ private CppTestRuleSetDTO getRuleSet( MapParameterBO pCppTestMap ) throws ConfigurationException, JrafEnterpriseException { // R�cup�ration des informations de configuration du projet StringParameterBO ruleSetName = (StringParameterBO) pCppTestMap.getParameters().get( ParametersConstants.CPPTEST_RULESET_NAME ); if ( ruleSetName == null ) { String message = CppTestMessages.getString( "exception.variable.not_found", ParametersConstants.CPPTEST_RULESET_NAME ); LOGGER.error( message ); // Renvoi d'une exception de configuration throw new ConfigurationException( message ); } // Obtention du ruleset dans la base CppTestRuleSetDTO dto = CppTestFacade.getCppTestConfiguration( ruleSetName.getValue() ); if ( dto == null ) { String message = CppTestMessages.getString( "exception.ruleset.not_found", ruleSetName.getValue() ); LOGGER.error( message ); // Renvoi d'une exception de configuration throw new ConfigurationException( message ); } return dto; } /** * Localisation du script * * @param pScript script � tester * @return script � lancer * @throws ConfigurationException si erreur */ private File computeScriptLocation( File pScript ) throws ConfigurationException { File result; // Si le script a un nom absolue et existe, on prend celui-ci if ( pScript.isAbsolute() && pScript.exists() ) { result = pScript; } else { // Le script est suppos� �tre relatif � la vue String viewPath = (String) getData().getData( TaskData.VIEW_PATH ); if ( viewPath == null ) { String message = CppTestMessages.getString( "exception.variable.not_found", TaskData.VIEW_PATH ); LOGGER.error( message ); // Renvoi d'une exception de configuration throw new ConfigurationException( message ); } result = new File( viewPath, pScript.getPath() ); if ( !result.exists() ) { String message = CppTestMessages.getString( "error.script.not_found", result.getAbsolutePath() ); LOGGER.error( message ); // Renvoi d'une exception de configuration throw new ConfigurationException( message ); } } return result; } /** * Ex�cution de la commande * * @param command commande � lancer * @param pLogger le fichier de log * @throws IOException si erreur * @throws InterruptedException si erreur */ protected void executeCommand( String[] command, String pLogger ) throws IOException, InterruptedException { // la sortie va �tre redirig�e vers un fichier de log et non vers squalix.txt ProcessManager mgr = new ProcessManager( command, null, null, FileUtility.getLogFile( pLogger ) ); mgr.setOutputHandler( this ); int result = mgr.startProcess( this ); if ( result != 0 ) { String message = CppTestMessages.getString( "exception.command", result + "" ); LOGGER.error( message ); throw new IOException( message ); } } /** * Lecture du rapport CppTest Le rapport est lu dans le r�pertoire contenant celui-ci, puis les donn�es associ�es au * rapport sont enregistr�es dans la base * * @param pWorkSpace espace de travail CppTest * @param pRuleSet ruleset * @throws Exception si erreur */ protected void parseReport( CppTestWorkSpace pWorkSpace, CppTestRuleSetDTO pRuleSet ) throws Exception { // Recherche des rapports Collection files = pWorkSpace.getReportFiles(); if ( files.size() == 0 ) { String message = CppTestMessages.getString( "error.noreport", pWorkSpace.getReportDirectory() ); LOGGER.error( message ); // Aucun rapport n'a �t� g�n�r�, lev�e d'une exception throw new Exception( message ); } // Traitement des rapports Iterator it = files.iterator(); ReportParser rp = new ReportParser(); HashMap rules = new HashMap(); while ( it.hasNext() ) { File file = (File) it.next(); Map result = rp.parse( new FileInputStream( file ), (String) getData().getData( TaskData.VIEW_PATH ) ); // On fusionne les r�sultats avec ceux obtenus jusqu'alors mergeResults( rules, result ); } // Sauvegarde des donn�es dans la base CppTestPersistor persistor = new CppTestPersistor(); persistor.storeResults( getSession(), getProject(), getAudit(), rules, pRuleSet ); } /** * Fusion des r�sultats dans la MAP * * @param pResult r�sultat de la fusion * @param pMerged donn�es � fusionner */ protected void mergeResults( Map pResult, Map pMerged ) { Iterator entries = pMerged.entrySet().iterator(); while ( entries.hasNext() ) { Map.Entry entry = (Entry) entries.next(); Collection val = (Collection) pResult.get( entry.getKey() ); if ( val == null ) { val = (Collection) entry.getValue(); pResult.put( entry.getKey(), val ); } else { val.addAll( (Collection) entry.getValue() ); } } } /** * (non-Javadoc) * * @see org.squale.squalix.util.process.ProcessErrorHandler#processError(java.lang.String) */ public void processError( String pErrorMessage ) { initError( pErrorMessage ); } /** * (non-Javadoc) * * @see org.squale.squalix.util.process.ProcessOutputHandler#processOutput(java.lang.String) */ public void processOutput( String pOutputLine ) { // CPPTEST ecrit ses erreurs sur le flux stdout ! // Le script est suppos� �crit comme ayant le param�tre -Zoe // cens� limiter les traces mErrorFilter.processLine( pOutputLine ); if ( mErrorFilter.errorAvailable() ) { initError( mErrorFilter.consumeError() ); } } }