org.squale.squalecommon.enterpriselayer.facade.rule.AuditComputing.java Source code

Java tutorial

Introduction

Here is the source code for org.squale.squalecommon.enterpriselayer.facade.rule.AuditComputing.java

Source

/**
 * 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.squalecommon.enterpriselayer.facade.rule;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hibernate.FlushMode;
import org.hibernate.HibernateException;
import org.hibernate.Session;

import org.squale.jraf.commons.exception.JrafDaoException;
import org.squale.jraf.provider.persistence.hibernate.SessionImpl;
import org.squale.jraf.spi.persistence.ISession;
import org.squale.squalecommon.daolayer.component.AbstractComponentDAOImpl;
import org.squale.squalecommon.daolayer.component.AuditDAOImpl;
import org.squale.squalecommon.daolayer.component.AuditDisplayConfDAOImpl;
import org.squale.squalecommon.daolayer.component.AuditGridDAOImpl;
import org.squale.squalecommon.daolayer.config.AdminParamsDAOImpl;
import org.squale.squalecommon.daolayer.result.MarkDAOImpl;
import org.squale.squalecommon.daolayer.result.MeasureDAOImpl;
import org.squale.squalecommon.daolayer.result.QualityResultDAOImpl;
import org.squale.squalecommon.enterpriselayer.businessobject.component.AbstractComponentBO;
import org.squale.squalecommon.enterpriselayer.businessobject.component.AuditBO;
import org.squale.squalecommon.enterpriselayer.businessobject.component.AuditDisplayConfBO;
import org.squale.squalecommon.enterpriselayer.businessobject.component.AuditGridBO;
import org.squale.squalecommon.enterpriselayer.businessobject.component.ProjectBO;
import org.squale.squalecommon.enterpriselayer.businessobject.config.AdminParamsBO;
import org.squale.squalecommon.enterpriselayer.businessobject.config.Profile_DisplayConfBO;
import org.squale.squalecommon.enterpriselayer.businessobject.result.CriteriumResultBO;
import org.squale.squalecommon.enterpriselayer.businessobject.result.FactorResultBO;
import org.squale.squalecommon.enterpriselayer.businessobject.result.MarkBO;
import org.squale.squalecommon.enterpriselayer.businessobject.result.MeasureBO;
import org.squale.squalecommon.enterpriselayer.businessobject.result.PracticeResultBO;
import org.squale.squalecommon.enterpriselayer.businessobject.result.QualityResultCommentBO;
import org.squale.squalecommon.enterpriselayer.businessobject.rule.AbstractFormulaBO;
import org.squale.squalecommon.enterpriselayer.businessobject.rule.CriteriumRuleBO;
import org.squale.squalecommon.enterpriselayer.businessobject.rule.FactorRuleBO;
import org.squale.squalecommon.enterpriselayer.businessobject.rule.PracticeRuleBO;
import org.squale.squalecommon.util.manualmark.TimeLimitationParser;
import org.squale.squalecommon.util.mapping.Mapping;

/**
 * Calcul d'un audit Le calcul d'un audit s'appuie sur des rgles dcrites dans la grille qualit, celle-ci est
 * rattache  un projet. Les rgles sont exprimes en fonction de mtriques obtenues par des outils comme mccabe par
 * exemple.
 */
public final class AuditComputing {
    /** Log */
    private static Log LOG = LogFactory.getLog(AuditComputing.class);

    /**
     * Define whether or not we need at least two values to compute criterias or factors.
     * 1 if we need two values. 
     * 0 if one is enough
     */
    private static int MIN_NUMBER_OF_PRACTICES_OR_CRITERIAS = 1;

    /**
     * Define private constructor for utility class
     */
    private AuditComputing() {
    }

    /**
     * Calcul d'un audit Le calcul d'un audit se fait  partir des pratiques pour remonter vers les facteurs
     * 
     * @param pSession session
     * @param pProject projet
     * @param pAudit audit
     * @return true If the last mark for a manual practice is out of date
     * @throws JrafDaoException si erreur
     */
    public static boolean computeAuditResult(ISession pSession, ProjectBO pProject, AuditBO pAudit)
            throws JrafDaoException {
        boolean warning = false;
        try {
            LOG.info(RuleMessages.getString("computation.start"));
            // Dcomposition de la grille en facteurs, criteres, pratiques
            Map factors = new Hashtable();
            Map criteria = new Hashtable();
            Map practices = new Hashtable();

            // Les maps contiennent en clef la rgle et en valeur le rsultat calcul
            flattenQualitfyGrid(pSession, pProject, pAudit, factors, criteria, practices);

            // Le traitement se fait dans l'ordre hirarchique inverse
            // cel permet d'viter les calculs multiples pour des facteurs
            // ou des critres plusieurs fois prsents
            // first : do we need at least two practices or two criterias to compute criterias or factors
            List adminParamsList = AdminParamsDAOImpl.getInstance().findByKey(pSession,
                    AdminParamsBO.TWO_TO_COMPUTE);
            //we check if the parameter TWO_TO_COMPUTE exists
            if (adminParamsList.size() > 0) {
                AdminParamsBO paramsBO = (AdminParamsBO) adminParamsList.get(0);
                //we check the value and change the min number of criterias / practices if necessary
                if (paramsBO.getParamValue().equals("false")) {
                    MIN_NUMBER_OF_PRACTICES_OR_CRITERIAS = 0;
                } else {
                    MIN_NUMBER_OF_PRACTICES_OR_CRITERIAS = 1;
                }
            }
            // Traitement des pratiques
            warning = computePracticesResults(pSession, pProject, pAudit, practices);
            // Traitement des criteres
            computeCriteriaResults(pSession, criteria, practices);
            // Traitement des facteurs
            computeFactorsResults(pSession, factors, criteria, practices);
            // Ajout de la grille qualit
            AuditGridBO auditGrid = new AuditGridBO();
            auditGrid.setGrid(pProject.getQualityGrid());
            auditGrid.setProject(pProject);
            auditGrid.setAudit(pAudit);
            AuditGridDAOImpl.getInstance().create(pSession, auditGrid);
            // Ajout  l'audit
            pAudit.addAuditGrid(auditGrid);
            // Ajout des configurations
            Collection confs = pProject.getProfile().getProfileDisplayConfs();
            for (Iterator it = confs.iterator(); it.hasNext();) {
                AuditDisplayConfBO auditConf = new AuditDisplayConfBO();
                auditConf.setDisplayConf(((Profile_DisplayConfBO) it.next()).getDisplayConf());
                auditConf.setProject(pProject);
                auditConf.setAudit(pAudit);
                AuditDisplayConfDAOImpl.getInstance().create(pSession, auditConf);
                // Ajout  l'audit
                pAudit.addAuditDisplayConf(auditConf);
            }
            AuditDAOImpl.getInstance().save(pSession, pAudit);
        } finally {
            LOG.info(RuleMessages.getString("computation.end"));
        }
        return warning;
    }

    /**
     * Mise  plat d'une grille qualit La structure hirarchique de la grille qualit est mise  plat sous la forme de
     * 3 maps qui contiennent les rgles en fonction de leur typologie
     * 
     * @param pSession session
     * @param pProject projet
     * @param pAudit audit
     * @param pFactors map des facteurs
     * @param pCriteria map des critres
     * @param pPractices map des pratiques
     * @throws JrafDaoException si erreur
     */
    private static void flattenQualitfyGrid(ISession pSession, ProjectBO pProject, AuditBO pAudit, Map pFactors,
            Map pCriteria, Map pPractices) throws JrafDaoException {
        // Le parcours consiste  construire 3 maps avec les facteurs, criteres et pratiques
        // Ce partionnement permet le traitement plus efficace d'au audit dans le cas o des critres
        // ou des pratiques apparaissent de faon multiple
        // On place aussi dans ces map, en tant que valeur le rsultat associ, par exemple
        // la map des facteurs contient les FactorRuleBO et les FactorResultBO
        Iterator factors = pProject.getQualityGrid().getFactors().iterator();
        // Parcours des facteurs
        while (factors.hasNext()) {
            FactorRuleBO factor = (FactorRuleBO) factors.next();
            // Cration du rsultat associ
            FactorResultBO fResult = new FactorResultBO();
            fResult.setRule(factor);
            fResult.setProject(pProject);
            fResult.setAudit(pAudit);
            pFactors.put(factor, fResult);
            QualityResultDAOImpl.getInstance().create(pSession, fResult);
            Iterator criteria = factor.getCriteria().keySet().iterator();
            // Parcours des critres
            while (criteria.hasNext()) {
                CriteriumRuleBO criterium = (CriteriumRuleBO) criteria.next();
                // Un critre peut tre prsent dans plusieurs facteurs
                // On ne le rajoute que si ncessaire
                if (pCriteria.get(criterium) == null) {
                    // Cration du rsultat associ
                    CriteriumResultBO cResult = new CriteriumResultBO();
                    cResult.setRule(criterium);
                    cResult.setProject(pProject);
                    cResult.setAudit(pAudit);
                    QualityResultDAOImpl.getInstance().create(pSession, cResult);
                    // Ajout dans la map
                    pCriteria.put(criterium, cResult);
                }
                Iterator practices = criterium.getPractices().keySet().iterator();
                // Parcours des pratiques
                while (practices.hasNext()) {
                    PracticeRuleBO practice = (PracticeRuleBO) practices.next();
                    // Une pratique peut tre prsente dans plusieurs critres
                    // On ne le rajoute que si ncessaire
                    if (pPractices.get(practice) == null) {
                        // Cration du rsultat associ
                        PracticeResultBO pResult = new PracticeResultBO();
                        pResult.setRule(practice);
                        pResult.setProject(pProject);
                        pResult.setAudit(pAudit);
                        QualityResultDAOImpl.getInstance().create(pSession, pResult);
                        // Ajout dans la map
                        pPractices.put(practice, pResult);
                    }
                }
            }
        }
    }

    /**
     * Calcul des facteurs Chaque facteur est calcul en fonction des critres qui le composent
     * 
     * @param pSession session
     * @param pFactors facteurs
     * @param pCriteria critres
     * @param pPractices pratiques
     * @throws JrafDaoException si erreur
     */
    private static void computeFactorsResults(ISession pSession, Map pFactors, Map pCriteria, Map pPractices)
            throws JrafDaoException {
        // On parcourt chaque facteur et on calcule son rsultat
        Iterator factors = pFactors.keySet().iterator();
        while (factors.hasNext()) {
            // Rcupration du facteur et du rsultat
            FactorRuleBO factor = (FactorRuleBO) factors.next();
            LOG.info(RuleMessages.getString("computation.factor", new Object[] { factor.getName() }));
            FactorResultBO result = (FactorResultBO) pFactors.get(factor);
            // Le calcul se fait par une moyenne simple sur les critres
            // calculs si au moins 2 criteres ont t calculs
            int nbCriteria = 0; // Nombre de criteres calculs
            float sumOfCriteriaWeight = 0;
            float criteriaSum = 0; // Note cumule
            // Parcours des criteres du facteur
            Iterator it = factor.getCriteria().keySet().iterator();
            // Pour chaque critre, on rcupre les valeurs calcules
            while (it.hasNext()) {
                CriteriumResultBO criteriumResult = (CriteriumResultBO) pCriteria.get(it.next());
                // Nota : criteriumResult ne peut pas tre null
                if (-1 != criteriumResult.getMeanMark()) {
                    float criteriaWeight = ((Float) factor.getCriteria().get(criteriumResult.getRule()))
                            .floatValue();
                    criteriaSum += criteriumResult.getMeanMark() * criteriaWeight;
                    sumOfCriteriaWeight += criteriaWeight;
                    nbCriteria++;
                }
            }
            // the value of MIN_NUMBER_OF_PRACTICES_OR_CRITERIAS depends on whether or not we 
            // need at least two values to compute factors. This param is set in squale-config file
            if (nbCriteria > MIN_NUMBER_OF_PRACTICES_OR_CRITERIAS) {
                // calcul de la note du facteur
                result.setMeanMark(criteriaSum / sumOfCriteriaWeight);
                QualityResultDAOImpl.getInstance().save(pSession, result);
            } else {
                LOG.debug(RuleMessages.getString("nocomputation", new Object[] { factor.getName() }));
            }
        }
    }

    /**
     * Calcul des critres Chaque critre est calcul en fonction des rsultats de ses pratiques
     * 
     * @param pSession session
     * @param pCriteria critres
     * @param pPractices pratiques
     * @throws JrafDaoException si erreur
     */
    private static void computeCriteriaResults(ISession pSession, Map pCriteria, Map pPractices)
            throws JrafDaoException {
        // On parcourt chaque critre et on calcule son rsultat
        Iterator criteria = pCriteria.keySet().iterator();
        while (criteria.hasNext()) {
            // Rcupration du critre et de son rsultat
            CriteriumRuleBO criterium = (CriteriumRuleBO) criteria.next();
            LOG.info(RuleMessages.getString("computation.criterium", new Object[] { criterium.getName() }));
            CriteriumResultBO result = (CriteriumResultBO) pCriteria.get(criterium);
            // La moyenne se fait par un moyenne simple sur les pratiques
            // calculs si au moins deux pratiques ont t calcules
            int nbPractices = 0;
            float sumOfPracticesWeight = 0;
            float practicesSum = 0; // Note cumule
            // Parcours des pratiques du critre
            Iterator it = criterium.getPractices().keySet().iterator();
            // Pour chaque critre, on rcupre les valeurs calcules
            while (it.hasNext()) {
                PracticeResultBO praticeResult = (PracticeResultBO) pPractices.get(it.next());
                // Nota : criteriumResult ne peut pas tre null
                if (-1 != praticeResult.getMeanMark()) {
                    float practiceWeight = ((Float) criterium.getPractices().get(praticeResult.getRule()))
                            .floatValue();
                    practicesSum += praticeResult.getMeanMark() * practiceWeight;
                    sumOfPracticesWeight += practiceWeight;
                    nbPractices++;
                }
            }
            // the value of MIN_NUMBER_OF_PRACTICES_OR_CRITERIAS depends on whether or not we 
            // need at least two values to compute criterias. This param is set in squale-config file 
            if (nbPractices > MIN_NUMBER_OF_PRACTICES_OR_CRITERIAS) {
                // calcul de la note du facteur
                result.setMeanMark(practicesSum / sumOfPracticesWeight);
                QualityResultDAOImpl.getInstance().save(pSession, result);
            } else {
                LOG.debug(RuleMessages.getString("nocomputation", new Object[] { criterium.getName() }));
            }
        }
    }

    /**
     * Calcul des pratiques Chaque pratique est calcule, son rsultat est crit en base de donnes
     * 
     * @param pSession session
     * @param pProject projet
     * @param pAudit audit
     * @param pPractices pratiques
     * @return true If the last mark for a manual practice is out of date
     * @throws JrafDaoException si erreur
     */
    private static boolean computePracticesResults(ISession pSession, ProjectBO pProject, AuditBO pAudit,
            Map pPractices) throws JrafDaoException {
        boolean warning = false;
        // Les pratiques sont tries par par type
        // de composant pour eviter les appels multiples de recuperation des
        // composants du projet
        Map kindPractices = splitPracticesByKind(pPractices);
        // On traite sparement les pratiques de niveau projet
        computeProjectPractices(pSession, pProject, pAudit, (Collection) kindPractices.remove("project"),
                pPractices);
        // Processing of the manual practices
        warning = computeManualPractices(pSession, pProject, (Collection) kindPractices.remove(""), pPractices);
        Iterator kinds = kindPractices.keySet().iterator();
        while (kinds.hasNext()) {
            String kind = (String) kinds.next();
            LOG.info(RuleMessages.getString("computation.kind", new Object[] { kind }));
            // sauvegarde du mode actuel de flush
            Session hibernateSession = ((SessionImpl) pSession).getSession();
            FlushMode oldFlushMode = hibernateSession.getFlushMode();
            // On ne traite pas les pratiques qui n'ont pas de composant associ
            // (elles n'ont pas de formule)
            if (kind.length() > 0) {
                try {
                    // flush de la session
                    hibernateSession.flush();
                    // le flush automatique est dsactiv pendant tout le calcul de chaque notes
                    hibernateSession.setFlushMode(FlushMode.NEVER);

                    // Recupration des enfants de bons niveaux...
                    Collection children = AbstractComponentDAOImpl.getInstance().findProjectChildren(pSession,
                            pProject, pAudit, Mapping.getComponentClass("component." + kind));
                    Iterator practices = ((Collection) kindPractices.get(kind)).iterator();
                    while (practices.hasNext()) {
                        PracticeRuleBO practice = (PracticeRuleBO) practices.next();
                        LOG.info(RuleMessages.getString("computation.practice",
                                new Object[] { practice.getName() }));
                        PracticeResultBO practiceResult = (PracticeResultBO) pPractices.get(practice);
                        // Vrification de la formule
                        FormulaInterpreter interpreter = new FormulaInterpreter();
                        try {
                            // Vrification de la syntaxe de la formule
                            // un exception est leve si elle est incorrecte
                            interpreter.checkSyntax(practice.getFormula());
                            // Calcul de notes pour chaque enfant
                            Collection marks = computePracticeResults(pSession, pAudit, interpreter, practice,
                                    practiceResult, children);
                            // Calcul de la note globale de la pratique
                            computePracticeMark(practice, practiceResult, marks);
                        } catch (FormulaException fe) {
                            // Si une erreur se produit sur le calcul d'une formule
                            // on stoppe le calcul pour cette pratique
                            LOG.error(RuleMessages.getString("formula.error", new Object[] { practice.getName() }),
                                    fe);
                        } catch (WeightFunctionException wfe) {
                            // Si une erreur se produit sur le calcul d'une formule
                            // on stoppe le calcul pour cette pratique
                            LOG.error(
                                    RuleMessages.getString("function.error",
                                            new Object[] { practice.getWeightFunction(), practice.getName() }),
                                    wfe);
                        }

                        // Sauvegarde des rsultats de la pratique
                        QualityResultDAOImpl.getInstance().save(pSession, practiceResult);
                    }
                } catch (HibernateException e) {
                    // Cette erreur est lie  la gestion du flushmode, dans ce cas on se contente de remonter
                    // une exception JRAF
                    throw new JrafDaoException(e);
                } finally {
                    // Remise du mode de flush au mode prcedent
                    hibernateSession.setFlushMode(oldFlushMode);
                }
            }
        }
        return warning;
    }

    /**
     * Traitement des pratiques de niveau projet Les pratiques calcules au niveau d'un projet sont traites de faon
     * spcifique, la formule donne une note directement sans avoir  collecter des notes pour chaque composant (comme
     * c'est le cas au niveau de classes ou des mthodes)
     * 
     * @param pSession session
     * @param pProject projet
     * @param pAudit audit
     * @param pProjectPractices pratiques de niveau projet
     * @param pPractices pratiques
     * @throws JrafDaoException si erreur
     */
    private static void computeProjectPractices(ISession pSession, ProjectBO pProject, AuditBO pAudit,
            Collection pProjectPractices, Map pPractices) throws JrafDaoException {
        if (pProjectPractices != null) {
            try {
                Iterator practices = pProjectPractices.iterator();
                while (practices.hasNext()) {
                    PracticeRuleBO practice = (PracticeRuleBO) practices.next();
                    LOG.info(RuleMessages.getString("computation.practice", new Object[] { practice.getName() }));
                    PracticeResultBO practiceResult = (PracticeResultBO) pPractices.get(practice);
                    // Vrification de la formule
                    FormulaInterpreter interpreter = new FormulaInterpreter();
                    try {
                        // Vrification de la syntaxe de la formule
                        // un exception est leve si elle est incorrecte
                        interpreter.checkSyntax(practice.getFormula());
                        // Calcul de la note globale de la pratique
                        computeProjectPracticeMark(pSession, pProject, pAudit, interpreter, practice,
                                practiceResult);
                    } catch (FormulaException e) {
                        // Si une erreur se produit sur le calcul d'une formule
                        // on stoppe le calcul pour cette pratique
                        LOG.error(RuleMessages.getString("formula.error", new Object[] { practice.getName() }), e);
                    }
                    // Sauvegarde des rsultats de la pratique
                    QualityResultDAOImpl.getInstance().save(pSession, practiceResult);
                }
            } catch (HibernateException e) {
                // Cette erreur est lie  la gestion du flushmode, dans ce cas on se contente de remonter
                // une exception JRAF
                throw new JrafDaoException(e);
            }
        }

    }

    /**
     * Calcul de la note sur un projet Le calcul de la note sur un projet se fait directement au moyen de la formule
     * associe
     * 
     * @param pSession session
     * @param pProject projet
     * @param pAudit audit
     * @param pInterpreter interprte
     * @param pPractice pratique
     * @param pPracticeResult rsultat
     * @throws FormulaException si erreur
     * @throws JrafDaoException si erreur
     */
    private static void computeProjectPracticeMark(ISession pSession, ProjectBO pProject, AuditBO pAudit,
            FormulaInterpreter pInterpreter, PracticeRuleBO pPractice, PracticeResultBO pPracticeResult)
            throws JrafDaoException, FormulaException {
        // Rcupration des types de mesure traits par la formule
        AbstractFormulaBO formula = pPractice.getFormula();
        String[] measureKinds = new String[formula.getMeasureKinds().size()];
        formula.getMeasureKinds().toArray(measureKinds);
        MeasureBO[] measures = new MeasureBO[formula.getMeasureKinds().size()];
        Long projectId = new Long(pProject.getId());
        // Rcupration de chaque mesure
        boolean measuresNotNull = true;
        Long auditId = new Long(pAudit.getId());
        for (int i = 0; i < measureKinds.length; i++) {
            MeasureBO measure = (MeasureBO) MeasureDAOImpl.getInstance().load(pSession, projectId, auditId,
                    Mapping.getMeasureClass(measureKinds[i] + "." + formula.getComponentLevel()));
            measures[i] = measure;
            // Une mesure peut tre absente, ce qui serait li  un problme de cration des mesures
            // dans la phase qui prcde le calcul des notes
            if (measure == null) {
                measuresNotNull = false;
                // On indique le type de mesure qui n'est pas trouv ainsi que le composant concern
                LOG.warn(RuleMessages.getString("missingmeasure",
                        new Object[] { measureKinds[i], projectId, auditId }));
            }
        }
        // On calcul la note seulement si toutes les mesures requises sont bien prsentes
        if (measuresNotNull) {
            // Calcul de la note
            // L'exception dans le calcul est remonte telle quelle
            Number value = pInterpreter.evaluate(pPractice.getFormula(), measures);
            // On place une note -1 si la formule n'a pu tre calcule
            if (value != null) {
                pPracticeResult.setMeanMark(value.floatValue());
            }
        }
    }

    /**
     * Calcul de la note d'une pratique
     * 
     * @param pPractice pratique
     * @param pPracticeResult rsultats de la pratique
     * @param pMarks les notes des composants impliqus
     * @throws WeightFunctionException si erreur
     */
    private static void computePracticeMark(PracticeRuleBO pPractice, PracticeResultBO pPracticeResult,
            Collection pMarks) throws WeightFunctionException {
        /*
         * Formule : meanMark = weigh^-1(1/N sum(weight(note(component)))) Cela revient  faire la moyenne des notes
         * auxquelles on applique la fonction la fonction de pondration weight puis  appliquer la fonction inverse
         */
        // Moyenne des notes : 1/N * sum(weight(note(component))
        float num = 0;
        float denum = 0;
        float average = -1;
        // Interpreteur python
        WeightFunctionInterpreter interpreter = new WeightFunctionInterpreter();
        for (Iterator marksIt = pMarks.iterator(); marksIt.hasNext();) {
            // note(component)
            float mark = ((MarkBO) marksIt.next()).getValue();
            // Si la note sur le composant a t calcul
            if (mark != MarkBO.NOT_NOTED_VALUE) {
                // weigth(note(component))
                float weightMark = interpreter.exec(pPractice.getWeightFunction(), mark);
                num += weightMark;
                denum++;
            }

        }
        if (denum != 0) {
            // Moyenne
            average = num / denum;
            // weight^-1(average)
            Float meanMark = inverse(interpreter, pPractice.getWeightFunction(), average);
            pPracticeResult.setMeanMark(meanMark.floatValue());
        } else {
            LOG.debug(RuleMessages.getString("nocomputation", new Object[] { pPractice.getName() }));
        }
    }

    /**
     * Fait le calcul de la fonction inverse.
     * 
     * @param pInterpreter l'interprteur pour une fonction de pondration
     * @param pFunction la fonction de pondration
     * @param pY : pFunction(x) = pY
     * @return x tel que f(x) = pY
     * @throws WeightFunctionException si erreur
     */
    private static Float inverse(WeightFunctionInterpreter pInterpreter, String pFunction, float pY)
            throws WeightFunctionException {
        // prcision de x : 10^-3
        final double signi = 3;
        final double pow = 10;
        double epsilon = Math.pow(pow, -signi) / 2;
        // x est compris entre 0 et 3
        final float minMark = 0;
        final float maxMark = 3;
        float x1 = minMark, x2 = (minMark + maxMark) / 2, x3 = maxMark;
        float fX1 = pInterpreter.exec(pFunction, x1), fX2 = pInterpreter.exec(pFunction, x2);
        float fX3 = pInterpreter.exec(pFunction, x3);
        float old = x1;
        // Tant que x n'est pas avec la prcision voulu
        while (Math.abs(x2 - old) > epsilon) {
            old = x2;
            // si y est entre fX1 et fX2
            if ((fX1 <= pY && fX2 > pY) || (fX1 >= pY && fX2 < pY)) {
                // On se recale entre x1 et x2
                x3 = x2;
                fX3 = fX2;
            } else {
                // On se recale entre x2 et x3
                x1 = x2;
                fX1 = fX2;
            }
            // nouvelle valeur cible par dichotomie
            x2 = (x1 + x3) / 2;
            fX2 = pInterpreter.exec(pFunction, x2);
        }
        // Arrondie au nombre de chiffres significatifs
        final double round = 0.5;
        double num = (x2 * Math.pow(pow, signi) + round);
        return new Float((double) ((int) (x2 * Math.pow(pow, signi) + round)) / Math.pow(pow, signi));
    }

    /**
     * Sparation des pratiques par type de composant
     * 
     * @param pPractices pratiques
     * @return map de la forme (string,collection) o string donne le type de composant et collection la liste des
     *         pratiques sur ce type de composant (string peut tre "")
     */
    private static Map splitPracticesByKind(Map pPractices) {
        Hashtable result = new Hashtable();
        Iterator practices = pPractices.keySet().iterator();
        while (practices.hasNext()) {
            PracticeRuleBO practice = (PracticeRuleBO) practices.next();
            // Les pratiques sans formule sont regroupes
            // avec un kind vide
            String kind = "";
            if (practice.getFormula() != null) {
                kind = practice.getFormula().getComponentLevel();
            }
            Collection practicesKind = (Collection) result.get(kind);
            if (practicesKind == null) {
                practicesKind = new ArrayList();
                result.put(kind, practicesKind);
            }
            practicesKind.add(practice);
        }
        return result;
    }

    /**
     * Calcul des pratiques sur les composants
     * 
     * @param pSession session
     * @param pAudit audit
     * @param pInterpreter interprteur
     * @param pPractice pratique
     * @param pPracticeResult rsultat
     * @param pChildren composants fils
     * @return les notes
     * @throws FormulaException si erreur
     * @throws JrafDaoException si erreur
     */

    private static Collection computePracticeResults(ISession pSession, AuditBO pAudit,
            FormulaInterpreter pInterpreter, PracticeRuleBO pPractice, PracticeResultBO pPracticeResult,
            Collection pChildren) throws FormulaException, JrafDaoException {
        // Reinitialisation des rpartitions
        pPracticeResult.resetRepartitions();
        // Rcupration des types de mesure traits par la formule
        AbstractFormulaBO formula = pPractice.getFormula();
        String[] measureKinds = new String[formula.getMeasureKinds().size()];
        formula.getMeasureKinds().toArray(measureKinds);
        MeasureBO[] measures = new MeasureBO[formula.getMeasureKinds().size()];
        Long componentId = null;
        // Traitement de la note pour chaque composant
        Iterator it = pChildren.iterator();
        // On stocke les notes
        ArrayList marks = new ArrayList();
        while (it.hasNext()) {
            AbstractComponentBO child = (AbstractComponentBO) it.next();
            componentId = new Long(child.getId());
            // Rcupration de chaque mesure
            boolean measuresNotNull = true;
            for (int i = 0; i < measureKinds.length; i++) {
                Long auditId = new Long(pAudit.getId());
                MeasureBO measure = (MeasureBO) MeasureDAOImpl.getInstance().load(pSession, componentId, auditId,
                        Mapping.getMeasureClass(measureKinds[i] + "." + formula.getComponentLevel()));
                measures[i] = measure;
                // Une mesure peut tre absente, ce qui serait li  un problme de cration des mesures
                // dans la phase qui prcde le calcul des notes
                if (measure == null) {
                    measuresNotNull = false;
                    // On indique le type de mesure qui n'est pas trouv ainsi que le composant concern
                    LOG.debug(RuleMessages.getString("missingmeasure",
                            new Object[] { measureKinds[i], componentId, auditId }));
                }
            }
            // On calcul la note seulement si toutes les mesures requises sont bien prsentes
            if (measuresNotNull) {
                MarkBO mark = computeMark(pSession, pInterpreter, measures, pPractice, pPracticeResult, child);
                marks.add(mark);
            }
        }
        return marks;
    }

    /**
     * Calcul d'une note sur un composant
     * 
     * @param pSession session
     * @param pInterpreter interprte
     * @param pMeasures mesures
     * @param pPractice pratique
     * @param pPracticeResult rsultat de pratique
     * @param pChild composant
     * @return la note
     * @throws FormulaException si erreur
     * @throws JrafDaoException si erreur
     */

    private static MarkBO computeMark(ISession pSession, FormulaInterpreter pInterpreter, MeasureBO[] pMeasures,
            PracticeRuleBO pPractice, PracticeResultBO pPracticeResult, AbstractComponentBO pChild)
            throws FormulaException, JrafDaoException {
        MarkBO mark = new MarkBO();
        mark.setComponent(pChild);
        mark.setPractice(pPracticeResult);
        // Calcul de la note
        // L'exception dans le calcul est remonte telle quelle
        Number value = pInterpreter.evaluate(pPractice.getFormula(), pMeasures);
        // On place une note -1 si la formule n'a pu tre calcule
        if (value == null) {
            mark.setValue(MarkBO.NOT_NOTED_VALUE);
        } else {
            mark.setValue(value.floatValue());
        }
        // Mise  jour de la rpartition des notes
        pPracticeResult.incrementRepartition(mark.getValue());
        // Enregistrement de la note
        MarkDAOImpl.getInstance().save(pSession, mark);
        return mark;
    }

    /**
     * This method push into the base, for the current audit, the manual mark which are filled and still valid
     * 
     * @param session Hibernate session
     * @param project The project
     * @param manualPractices collection of practice without level (manual practice)
     * @param practicesMap map of all the practice.
     * @return true If the last mark for a manual practice is out of date
     * @throws JrafDaoException Exception happened during hibernate work
     */
    private static boolean computeManualPractices(ISession session, ProjectBO project, Collection manualPractices,
            Map practicesMap) throws JrafDaoException {
        boolean warning = false;
        if (manualPractices != null) {
            try {
                QualityResultDAOImpl dao = QualityResultDAOImpl.getInstance();

                // For each manual practice we try to set a mark for the audit
                Iterator<PracticeRuleBO> practicesIt = manualPractices.iterator();
                while (practicesIt.hasNext()) {
                    PracticeRuleBO practice = practicesIt.next();
                    LOG.info(RuleMessages.getString("computation.practice", new Object[] { practice.getName() }));

                    // search of the last manual mark inserted
                    PracticeResultBO manualPraticeResult = dao.findLastManualMark(session, project.getId(),
                            practice.getId());

                    // If there is one manual mark inserted
                    if (manualPraticeResult != null) {
                        // recovering of the PracticeResultBO which will recorded
                        PracticeResultBO practiceResult = (PracticeResultBO) practicesMap.get(practice);

                        /*
                         * If the current date is before the date of creation of the manual mark plus the period of
                         * validity then we put the mark for the current audit.
                         */
                        if (isMarkValid(practice, manualPraticeResult)) {
                            practiceResult.setMeanMark(manualPraticeResult.getMeanMark());
                            practiceResult.setCreationDate(manualPraticeResult.getCreationDate());
                            //We add the comments if it exists
                            if (manualPraticeResult.getManualMarkComment() != null) {
                                QualityResultCommentBO practiceResultComments = new QualityResultCommentBO();
                                practiceResultComments.setQualityResult(practiceResult);
                                practiceResultComments
                                        .setComments(manualPraticeResult.getManualMarkComment().getComments());
                                practiceResult.setManualMarkComment(practiceResultComments);
                            }
                            dao.save(session, practiceResult);
                        } else {
                            warning = true;
                        }
                    }
                }
            } catch (HibernateException e) {
                throw new JrafDaoException(e);
            }
        }
        return warning;
    }

    /**
     * This method determine whether the mark is valid (according to the period validity)
     * 
     * @param practice The practice for the current audit
     * @param manualPraticeResult The last manualPratice inserted
     * @return true if the the mark is valid
     */
    private static boolean isMarkValid(PracticeRuleBO practice, PracticeResultBO manualPraticeResult) {

        boolean valid = true;

        // Date of creation of the manual mark
        Date creationDate = manualPraticeResult.getCreationDate();

        // The validity period
        String validityPeriod = practice.getTimeLimitation();

        // Test the validity of the mark
        valid = TimeLimitationParser.isMarkValid(validityPeriod, creationDate);

        return valid;
    }
}