Java tutorial
/** * 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.macker; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.net.MalformedURLException; import java.net.URL; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; import net.innig.macker.Macker; import net.innig.macker.event.ListenerException; import net.innig.macker.event.MackerIsMadException; import net.innig.macker.rule.RulesException; import net.innig.macker.structure.ClassParseException; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.squale.jraf.commons.exception.JrafDaoException; import org.squale.squalecommon.daolayer.result.MeasureDAOImpl; import org.squale.squalecommon.daolayer.rulechecking.ProjectRuleSetDAOImpl; 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.IntegerMetricBO; import org.squale.squalecommon.enterpriselayer.businessobject.result.rulechecking.MackerTransgressionBO; import org.squale.squalecommon.enterpriselayer.businessobject.result.rulechecking.RuleCheckingTransgressionItemBO; import org.squale.squalecommon.enterpriselayer.businessobject.rulechecking.ProjectRuleSetBO; import org.squale.squalecommon.enterpriselayer.businessobject.rulechecking.RuleBO; import org.squale.squalecommon.enterpriselayer.facade.macker.MackerConfigParser; 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.file.FileUtility; /** * Tche Macker.<br/> Vrifie l'architecture du projet auditer.<br/> La tche de compilation java doit avoir t * xcute avant afin que le chemin du rpertoire contenant les ".class" (CLASSES_DIR) soit prsent dans les paramtres * temporaires. */ public class MackerTask extends AbstractTask { /** * Logger */ private static final Log LOGGER = LogFactory.getLog(MackerTask.class); /** Configuration de la tche Macker */ protected MackerConfiguration mConfiguration; /** L'couteur pour les classes java */ protected JavaStorageListener mListener; /** * Constructeur par defaut */ public MackerTask() { super(); mName = "MackerTask"; mConfiguration = new MackerConfiguration(); } // Cette tache n'a pas d'influence dans le calcul de la taille du file system /** * Analyse les fichiers compils afin de relever pour chacun les transgressions des rgles concernant * l'architecture. * * @throws TaskException si erreur */ public void execute() throws TaskException { if (init()) { try { analyze(); // On fait persister les mesures persisteMeasures(mListener.getNbOcc(), mListener.getDetails(), mConfiguration.getRuleSet()); } catch (Exception e) { throw new TaskException(e); } } } /** * Analyse les fichiers * * @throws ClassParseException si erreur * @throws IOException si erreur * @throws RulesException si erreur * @throws ListenerException si erreur * @throws MackerIsMadException si erreur */ protected void analyze() throws ClassParseException, IOException, RulesException, ListenerException, MackerIsMadException { Macker macker = configMacker(mConfiguration.getFilesToAnalyze(), mConfiguration.getConfigFile()); // On modifie le classpath pour excuter Macker afin d'avoir le build classpath pour la rsolution // de l'ensemble des classes. // macker.setClassLoader(new URLClassLoader(getClasspathURLs())); /* On lance l'analyse en attachant notre vnement Macker: */ mListener = new JavaStorageListener(getSession(), mProject, mConfiguration); macker.addListener(mListener); macker.checkRaw(); } /** * Construit le tableau des urls ajouter au classpath pour excuter Macker partir du classpath temporaire * * @return les URLs */ protected URL[] getClasspathURLs() { ArrayList urlsList = new ArrayList(); // On dcoupe le classpath des paramtres temporaires String[] paths = ((String) mData.getData(TaskData.CLASSPATH)).split(";"); for (int i = 0; i < paths.length; i++) { try { urlsList.add(new File(paths[i]).toURL()); } catch (MalformedURLException e) { // On log juste l'erreur LOGGER.warn("Error in temp classpath, malformed url: " + paths[i]); } } return (URL[]) urlsList.toArray(new URL[urlsList.size()]); } /** * Initialise la tche Macker * * @throws TaskException si erreur * @return true si la tche n'est pas annule */ protected boolean init() throws TaskException { // Les donnes du projet doivent fournir le nom du fichier // de configuration MapParameterBO mackerMap = (MapParameterBO) getProject().getParameter(ParametersConstants.MACKER); if (mackerMap == null) { String message = MackerMessages.getString("macker.exception.no_configuration"); // On affiche un warning sans lancer d'exception, la tche ne sera pas excute. initError(message); LOGGER.warn(message); // Les paramtres sont mal configurs, on annule la tche mStatus = CANCELLED; } else { // On rcupre le view_path cre par la tche du source manager en ajoutant un sparateur // Unix en bout au cas o. String root = (String) mData.getData(TaskData.VIEW_PATH); if (null == root) { String message = MackerMessages.getString("macker.exception.view_path_not_found") + TaskData.VIEW_PATH; LOGGER.error(message); // Lance une exception de configuration throw new TaskException(message); } root += "/"; mConfiguration.setRoot(root); // On rcupre les chemins relatifs des rpertoires contenant les .java du projet ListParameterBO sources = (ListParameterBO) getProject().getParameter(ParametersConstants.SOURCES); if (sources == null) { String message = MackerMessages.getString("macker.exception.sources_not_found"); LOGGER.error(message); // Lance une exception de configuration throw new TaskException(message); } mConfiguration.setSources(BuildProjectPath.buildProjectPath(root, sources.getParameters())); // On rcupre les rpertoires contenant les .class du projet analyser // cre par la tche de compilation java List classesDirs = (List) this.getData().getData(TaskData.CLASSES_DIRS); if (classesDirs == null) { String message = MackerMessages.getString("macker.exception.class_dir_not_found"); LOGGER.error(message); // Lance une exception de configuration throw new TaskException(message); } // On gnre la liste des fichiers compils analyser HashSet classes = new HashSet(); for (int i = 0; i < classesDirs.size(); i++) { classes.addAll(mConfiguration.getFilesToAnalyze((String) classesDirs.get(i))); } mConfiguration.setFilesToAnalyze(classes); // Les nom des fichiers qui peuvent tre persists List includedFileNames = FileUtility.getIncludedFiles(root, mConfiguration.getSources(), (ListParameterBO) mProject.getParameter(ParametersConstants.INCLUDED_PATTERNS), (ListParameterBO) mProject.getParameter(ParametersConstants.EXCLUDED_PATTERNS), null, new String[] { ".java" }); mConfiguration.setIncludedFiles(includedFileNames); try { /* On configure Macker */ // On rcupre le fichier de configuration File configFile = getConfigFile(mackerMap, root); // Si le fichier de configuration n'existe pas if (!configFile.exists()) { String message = MackerMessages.getString("macker.exception.configurationfile_not_found") + configFile.toString(); LOGGER.error(message); // Lance une exception de configuration throw new TaskException(message); } mConfiguration.setConfigFile(configFile); // On rcupre la liste des rgles en parsant le fichier de configuration ProjectRuleSetBO projectRuleSet = importMackerConfig(configFile); mConfiguration.setRuleSet(projectRuleSet); } catch (Exception e) { throw new TaskException(e); } } return mStatus != CANCELLED; } /** * @param pConfigFile le fichier de configuration Macker * @throws ConfigurationException si erreur * @throws FileNotFoundException si erreur * @return la liste des rgles Macker */ private ProjectRuleSetBO importMackerConfig(File pConfigFile) throws ConfigurationException, FileNotFoundException { // Importation du fichier MackerConfigParser parser = new MackerConfigParser(); InputStream stream = new FileInputStream(pConfigFile); StringBuffer errors = new StringBuffer(); ProjectRuleSetBO ruleset = parser.parseFile(stream, errors); // Si le parsing s'est mal pass on lance une erreur de configuration if (errors.length() > 0) { String message = MackerMessages.getString("macker.exception.configurationfile_parsing_error") + "(" + pConfigFile.getAbsolutePath() + ")" + errors; LOGGER.error(message); // Lance une exception de configuration throw new ConfigurationException(message); } return ruleset; } /** * Fait persister les mesures * * @param pNbOcc les rsultats obtenus par Macker * @param pDetails le dtail des transgressions * @param pRuleset les rgles * @throws IOException si erreur * @throws JrafDaoException si erreur */ protected void persisteMeasures(HashMap pNbOcc, HashMap pDetails, ProjectRuleSetBO pRuleset) throws IOException, JrafDaoException { // On sauvegarde le ruleset dans la base pRuleset.setProject(mProject); ProjectRuleSetDAOImpl.getInstance().create(getSession(), pRuleset); // Cration de la transgression MackerTransgressionBO transgression = new MackerTransgressionBO(); transgression.setAudit(mAudit); transgression.setComponent(mProject); transgression.setRuleSet(pRuleset); transgression.setTaskName(mName); // On parcourt les rgles connues dans le ruleset Map rules = pRuleset.getRules(); Iterator ruleCodes = rules.keySet().iterator(); while (ruleCodes.hasNext()) { String ruleCode = (String) ruleCodes.next(); // On rcupre les dtails lis cette rgle ArrayList items = (ArrayList) pDetails.get(ruleCode); // si il y en a on modifie la transgression en consquence if (null != items) { RuleBO rule = (RuleBO) rules.get(ruleCode); for (int i = 0; i < items.size(); i++) { RuleCheckingTransgressionItemBO item = (RuleCheckingTransgressionItemBO) items.get(i); item.setRule(rule); transgression.getDetails().add(item); } } Integer value = (Integer) pNbOcc.get(ruleCode); int nbOcc = 0; // Si le parsing n'a pas donn de rsultat, on place 0 comme // nombre de transgression if (null != value) { nbOcc = value.intValue(); } // On ajoute une mtrique de type Integer pour chaque rgle transgresse // avec 0 comme valeur par dfaut IntegerMetricBO metric = new IntegerMetricBO(); metric.setName(ruleCode); metric.setValue(nbOcc); metric.setMeasure(transgression); transgression.putMetric(metric); } // Sauvegarde des donnes dans la base MeasureDAOImpl.getInstance().create(getSession(), transgression); } /** * Configure Macker en lui indiquant le fichier des rgles et les classes qu'il doit analyser * * @param pFilesToAnalyse les fichiers compils analyser * @param pConfigFile le fichier de configuration Macker * @throws ClassParseException si erreur * @throws RulesException si erreur * @throws IOException si erreur * @return Macker le macker configur */ protected Macker configMacker(HashSet pFilesToAnalyse, File pConfigFile) throws RulesException, ClassParseException, IOException { Macker macker = new Macker(); Iterator filesIt = pFilesToAnalyse.iterator(); while (filesIt.hasNext()) { try { macker.addClass(new File((String) filesIt.next())); } catch (IllegalStateException ise) { // On log juste un warning. Cette erreur peut survenir lorsque // l'utilisateur a par exemple laisser des .class dans le rpertoire // de gnration des .class LOGGER.warn(ise.getMessage()); initError(ise.getMessage()); } } // On indique le fichier de configuration macker.addRulesFile(pConfigFile); return macker; } /** * Rcupre le fichier de configuration Macker * * @param pMackerMap les paramtres Macker * @param pViewPath la vue * @return le fichier de configuration * @throws ConfigurationException si erreur */ private File getConfigFile(MapParameterBO pMackerMap, String pViewPath) throws ConfigurationException { File result = new File(""); Map params = pMackerMap.getParameters(); StringParameterBO filePath = (StringParameterBO) params.get(ParametersConstants.MACKER_CONFIGURATION); if (filePath == null) { String message = MackerMessages.getString("macker.exception.no_configuration"); LOGGER.warn(message); // si le fichier n'est pas renseign, on annule la tche. mStatus = CANCELLED; } else { File configFile = new File(filePath.getValue()); // Si le fichier de configuration a un nom absolue et existe, on prend celui-ci if (configFile.isAbsolute() && configFile.exists()) { result = configFile; } else { // Le fichier de configuration est suppos tre relatif la vue result = new File(pViewPath, configFile.getPath()); } } return result; } }