/** * 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.rsm; import java.io.BufferedWriter; import java.io.File; import java.io.FileWriter; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.Iterator; import java.util.List; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.squale.squalecommon.enterpriselayer.businessobject.component.parameters.ListParameterBO; 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.businessobject.result.ErrorBO; 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.buildpath.BuildProjectPath; import org.squale.squalix.util.csv.CSVParser; import org.squale.squalix.util.file.FileUtility; import org.squale.squalix.util.parser.LanguageParser; import org.squale.squalix.util.process.ProcessErrorHandler; import org.squale.squalix.util.process.ProcessManager; import org.squale.squalix.util.process.ProcessOutputHandler; /** */ public abstract class RSMTask extends AbstractTask implements ProcessErrorHandler, ProcessOutputHandler, CSVParser.CSVHandler { /** Le parser */ protected CSVParser mParser; /** * Logger */ protected static final Log LOGGER = LogFactory.getLog( RSMTask.class ); /** * Instance du persisteur RSM */ protected RSMPersistor mPersistor = null; /** le parser associ� au language */ protected LanguageParser mLanguageParser; /** * Configuration de l'outil d'analyse */ protected RSMConfiguration mConfiguration; /** Le processManager * */ protected ProcessManager mProcess; /** le fichier contenant les noms des fichiers � analyser */ protected File mToAnalyseFileList; /** * Construction des r�pertoires � analyser * * @param pData donn�es de la t�che * @param pProjectParams param�tres du projet * @throws ConfigurationException si erreur * @return la liste des fichiers � analyser */ private List buildFilesToProcess( TaskData pData, MapParameterBO pProjectParams ) throws ConfigurationException { // On prend le view path String viewPath = (String) pData.getData( TaskData.VIEW_PATH ); if ( viewPath == null ) { String message = RSMMessages.getString( "exception.variable.not_found", TaskData.VIEW_PATH ); LOGGER.error( message ); // Renvoi d'une exception de configuration throw new ConfigurationException( message ); } // Pour chaque r�pertoire source on ajoute celui-ci // On r�cup�re les chemins relatifs des r�pertoires contenant les sources du projet ListParameterBO sources = getSourcesDirs( pProjectParams ); if ( sources == null ) { String message = RSMMessages.getString( "exception.sources.notset", "" ); LOGGER.error( message ); // Renvoi d'une exception de configuration throw new ConfigurationException( message ); } List sourcesString = new ArrayList( 0 ); List sourcesStringBO = sources.getParameters(); for ( int i = 0; i < sourcesStringBO.size(); i++ ) { sourcesString.add( ( (StringParameterBO) ( sourcesStringBO.get( i ) ) ).getValue() ); } // Prise en compte des r�pertoires exclus ListParameterBO excludedDirs = getExcludedDirs( pProjectParams ); if ( excludedDirs == null ) { // On affecte une liste vide excludedDirs = new ListParameterBO(); } // Construction des fichiers � traiter List extensions = new ArrayList(); extensions.addAll( Arrays.asList( mConfiguration.getExtensions() ) ); extensions.addAll( Arrays.asList( mConfiguration.getHeaders() ) ); String[] setOfExtensions = (String[]) ( extensions.toArray( new String[extensions.size()] ) ); List resultSources = FileUtility.getIncludedFiles( viewPath, BuildProjectPath.buildProjectPath( viewPath, sources.getParameters() ), (ListParameterBO) mProject.getParameter( ParametersConstants.INCLUDED_PATTERNS ), (ListParameterBO) mProject.getParameter( ParametersConstants.EXCLUDED_PATTERNS ), (ListParameterBO) mProject.getParameter( ParametersConstants.EXCLUDED_DIRS ), setOfExtensions ); return resultSources; } /** * Obtention des r�pertories exclus * * @param pProjectParams param�tres du projet * @return r�pertoires exclus sous la forme de ListParameterBO(StringParameterBO) */ protected ListParameterBO getExcludedDirs( MapParameterBO pProjectParams ) { return (ListParameterBO) pProjectParams.getParameters().get( ParametersConstants.EXCLUDED_DIRS ); } /** * Obtention des sources * * @param pProjectParams param�tres du projet * @return sources sous la forme de ListParameterBO(StringParameterBO) */ protected ListParameterBO getSourcesDirs( MapParameterBO pProjectParams ) { return (ListParameterBO) pProjectParams.getParameters().get( ParametersConstants.SOURCES ); } /** * lance le parsing des classes, la g�n�ration du rapport et le parsing du rapport * * @throws TaskException en cas d'�chec */ public void execute() throws TaskException { try { // initialise la tache RSM initialize(); // construit la liste des r�pertoires � analyser (fichiers sources - exclus) buildDotLstFile( buildFilesToProcess( getData(), mProject.getParameters() ) ); LOGGER.info( RSMMessages.getString( "logs.analyzing" ) + mProject.getParent().getName() + " - " + mProject.getName() ); int execResult = parseSource(); // un nombre n�gatif est une erreur d'ex�cution RSM if ( execResult < 0 ) { throw new TaskException( RSMMessages.getString( "rsm.exec.erreur", new Object[] { new Integer( execResult ) } ) ); } // Si le parsing s'est bien d�roul�, on a g�n�r� le rapport // On parse maintenant le rapport // si le parsing ne s'est pas bien d�roul�, on va tombre dans l'exception // On ne g�re pas le code retour car le comportement de RSM est �trange parseReport( mConfiguration.getReportPath() ); // Une fois que tous les rapports ont �t� g�n�r�s et pars�s, // on peut g�n�rer les r�sultats de niveau projet mPersistor.persistProjectResult(); // positionne les donn�es sur la taille du file System affectFileSystemSize( mConfiguration.getWorkspace(), true ); // Lance les op�rations de cloture de la t�che FileUtility.deleteRecursivelyWithoutDeleteRootDirectory( mConfiguration.getWorkspace() ); } catch ( Exception e ) { throw new TaskException( e ); } } /** * Construit le fichier .txt recensant l'ensemble des fichiers que RSM doit analyser * * @param pFilesToAnalyseList la liste des fichiers � analyser * @throws IOException en cas d'�chec */ private void buildDotLstFile( List pFilesToAnalyseList ) throws IOException { mToAnalyseFileList = new File( mConfiguration.getInputFile() ); BufferedWriter bw = new BufferedWriter( new FileWriter( mToAnalyseFileList ) ); for ( Iterator it = pFilesToAnalyseList.iterator(); it.hasNext(); ) { String filePath = (String) it.next(); bw.write( filePath ); bw.newLine(); } // ferme le buffer bw.close(); } /** * @see org.squale.squalix.util.process.ProcessErrorHandler#processError(java.lang.String) */ public void processError( String pErrorMessage ) { LOGGER.error( RSMMessages.getString( "logs.error.tools_error" ) + pErrorMessage ); ErrorBO error = new ErrorBO(); error.setInitialMessage( pErrorMessage ); error.setMessage( RSMMessages.getString( "error.processing" ) ); error.setLevel( ErrorBO.CRITICITY_FATAL ); mErrors.add( error ); } /** * {@inheritDoc} * * @param pOutputLine {@inheritDoc} * @see org.squale.squalix.util.process.ProcessOutputHandler#processOutput(java.lang.String) */ public void processOutput( String pOutputLine ) { // TODO Auto-generated method stub } /** * Pr�pare l'environnement d'ex�cution de l'analyse : * <ul> * <li>Cr�ation du dossier destination des r�sultats du parsing</li> * <li>Cr�ation du fichier config.pcf</li> * </ul> * * @exception Exception si un probleme d'initialisation apparait */ private void initialize() throws Exception { // On r�cup�re la configuration du module RSM, personnalis�e // avec les param�tres du projet mConfiguration = RSMConfiguration.build( mProject, RSMMessages.getString( "configuration.file" ), getData() ); File workspace = mConfiguration.getWorkspace(); if ( !workspace.exists() || !workspace.isDirectory() || !workspace.canWrite() || !workspace.canRead() ) { // On va v�rifier que le workspace est disponible throw new Exception( RSMMessages.getString( "exception.no_workspace" ) ); } mPersistor = new RSMPersistor( mConfiguration, mAudit, getSession(), getData(), mName, mLanguageParser ); LOGGER.info( RSMMessages.getString( "logs.initialized" ) + mProject.getParent().getName() + " - " + mProject.getName() ); } /** * {@inheritDoc} * * @param pLine {@inheritDoc} * @see org.squale.squalix.util.csv.CSVParser.CSVHandler#processLine(java.util.List) */ public void processLine( List pLine ) { // TODO Auto-generated method stub } /** * Cr�e le ProcessManager. On ne fait pas de new mais un set pour impl�menter le pattern IOC pour pouvoir tester sur * un environnement windows * * @param pArguments arguments * @param pDirectory r�pertoire de lancement * @return le ProcessManager normal */ private ProcessManager createProcessManager( String[] pArguments, File pDirectory ) { return new ProcessManager( pArguments, null, pDirectory ); } /** * Parse les fichiers sources afin d'en extraire les m�triques. * * @return le r�sultat de l'ex�cution * @throws Exception si un probl�me de parsing appara�t. */ private int parseSource() throws Exception { // le r�sultat renvoy� int resultParse = 0; // Execute le parsing des sources avec RSM String[] parseCommand = new String[mConfiguration.getParseParameters().length + 1]; parseCommand[0] = mConfiguration.getExecCommand(); // Parse tous les r�pertoires sources sauf les r�pertoires exclus un par un for ( int i = 1; i < parseCommand.length; i++ ) { String param = mConfiguration.getParseParameters()[i - 1]; // On construit la commande // On met en forme la liste des param�tres pour la passer au process if ( "-O".equals( param ) ) { param += mConfiguration.getReportPath(); } else { if ( "-F".equals( param ) ) { param += mConfiguration.getInputFile(); } } parseCommand[i] = param; } LOGGER.info( RSMMessages.getString( "logs.running_parsing.command", parseCommand ) ); LOGGER.info( RSMMessages.getString( "logs.running_parsing", new Object[] { mProject.getParent().getName(), mProject.getName() } ) ); mProcess = createProcessManager( parseCommand, mConfiguration.getWorkspace() ); // On veut g�rer les informations lanc�es par le processus en sortie mProcess.setOutputHandler( this ); // On cherche � avoir un comportement synchrone pour �tre s�r de ne pas // avoir un �tat des donn�es incoh�rent resultParse = mProcess.startProcess( this ); LOGGER.info( RSMMessages.getString( "logs.return_parsing", new Object[] { mProject.getParent().getName(), mProject.getName(), new Integer( resultParse ) } ) ); return resultParse; } /** * /** Analyse un rapport de m�triques RSM * * @param pReport rapport � parser * @throws Exception si erreur */ private void parseReport( final String pReport ) throws Exception { mPersistor.parseReport( pReport, getData() ); } /** * @return la configuration */ public RSMConfiguration getConfiguration() { return mConfiguration; } /** * @param pConfiguration la configuration */ public void setConfiguration( RSMConfiguration pConfiguration ) { mConfiguration = pConfiguration; } }