org.squale.squalix.core.Scheduler.java Source code

Java tutorial

Introduction

Here is the source code for org.squale.squalix.core.Scheduler.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.squalix.core;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collection;
import java.util.GregorianCalendar;
import java.util.Iterator;
import java.util.List;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.squale.jraf.commons.exception.JrafDaoException;
import org.squale.jraf.commons.exception.JrafEnterpriseException;
import org.squale.jraf.commons.exception.JrafPersistenceException;
import org.squale.jraf.helper.PersistenceHelper;
import org.squale.jraf.spi.persistence.IPersistenceProvider;
import org.squale.jraf.spi.persistence.ISession;
import org.squale.squalecommon.daolayer.component.ApplicationDAOImpl;
import org.squale.squalecommon.daolayer.component.AuditDAOImpl;
import org.squale.squalecommon.daolayer.component.ProjectDAOImpl;
import org.squale.squalecommon.daolayer.result.MarkDAOImpl;
import org.squale.squalecommon.daolayer.result.MeasureDAOImpl;
import org.squale.squalecommon.daolayer.result.rulechecking.RuleCheckingTransgressionDAOImpl;
import org.squale.squalecommon.datatransfertobject.config.ServeurDTO;
import org.squale.squalecommon.datatransfertobject.config.SqualixConfigurationDTO;
import org.squale.squalecommon.datatransfertobject.result.SqualeReferenceDTO;
import org.squale.squalecommon.datatransfertobject.transform.component.AuditTransform;
import org.squale.squalecommon.datatransfertobject.transform.config.AuditFrequencyTransform;
import org.squale.squalecommon.enterpriselayer.businessobject.component.ApplicationBO;
import org.squale.squalecommon.enterpriselayer.businessobject.component.AuditBO;
import org.squale.squalecommon.enterpriselayer.businessobject.component.ProjectBO;
import org.squale.squalecommon.enterpriselayer.businessobject.result.roi.RoiMetricsBO;
import org.squale.squalecommon.enterpriselayer.facade.config.ServeurFacade;
import org.squale.squalecommon.enterpriselayer.facade.config.SqualixConfigFacade;
import org.squale.squalecommon.enterpriselayer.facade.quality.SqualeReferenceFacade;
import org.squale.squalecommon.util.SqualeCommonConstants;
import org.squale.squalecommon.util.SqualeCommonUtils;
import org.squale.squalecommon.util.mail.IMailerProvider;
import org.squale.squalecommon.util.mail.MailerHelper;
import org.squale.squalix.core.exception.ConfigurationException;
import org.squale.squalix.core.export.Export;
import org.squale.squalix.core.purge.Purge;
import org.squale.squalix.messages.MessageMailManager;
import org.squale.squalix.messages.Messages;
import org.squale.squalix.stats.ComputeStats;
import org.squale.squalix.util.sourcesrecovering.SourcesRecoveringOptimisation;
import org.squale.squalix.util.stoptime.StopTimeHelper;

/**
 * A partir du fichier de configuration globale, il dtermine la squence des actions pour le projet associ et les
 * excute.<br />
 * Le scheduler assure :
 * <ul>
 * <li>la rcupration de la configuration du moteur de tches,</li>
 * <li>la rcupration des audits  lancer,</li>
 * <li>la cration d'un excuteur d'analyse (AuditExecutor) pour chacun des projets associs aux audits,</li>
 * <li>le lancement des tches indpendantes d'un projet,</li>
 * <li>le lancement des excuteurs d'analyse,</li>
 * <li>le lancement des tches calculant les rsultats au niveau du projet (graphes,...),</li>
 * <li>la modification du statut de l'audit lorsque celui-ci est termin, et la cration ventuelle du prochain audit
 * dans le cas d'un audit de suivi.</li>
 * </ul>
 * <br />
 * Tous les audits et tches sont excuts via des pools de threads, grs par le gestionnaire de ressources.<br />
 * Voir la documentation de la classe <code>ResourcesManager</code> pour plus de renseignements sur son fonctionnement. <br />
 * <br />
 * Lorsque tous les audits ont t lancs, les scheduler est bloqu tant que les pools sont ouverts.<br />
 * Pour s'assurer que ceux-ci sont ouverts, on utilise un <code>CountDownLatch</code> dcrment par le gestionnaire de
 * ressources lorsqu'il ferme ses pools. <br />
 * <br />
 * Les tches non lies  un projet et les excuteurs d'analyse sont associs au scheduler par un pattern
 * Observateur-Observable, dans lequel le scheduler est l'observateur. Sa mthode <code>update()</code> est appele
 * lorsque l'excuteur ou la tche est termin.
 * 
 * @see org.squale.squalix.core.ResourcesManager
 * @see org.squale.squalix.core.AuditExecutor
 * @author m400842
 * @version 1.0
 */
public class Scheduler implements Runnable {

    /**
     * L'objet contenant les configurations
     */
    private SqualixConfigurationDTO mConf;

    /**
     * Logger
     */
    private static final Log LOGGER = LogFactory.getLog(Scheduler.class);

    /**
     * Liste des audits executeur cres.
     */
    private List mAudits = new ArrayList(0);

    /**
     * Cl du site hbergeant l'application.
     */
    private long mSiteId;

    /**
     * Provider de persistance
     */
    private static final IPersistenceProvider PERSISTANT_PROVIDER = PersistenceHelper.getPersistenceProvider();

    /**
     * Session de travail
     */
    private ISession mSession;

    /**
     * Le calendrier permettant de savoir  quel heure  t lanc le batch
     */
    private Calendar mLaunchingCal;

    /** la liste des projets d'un audit */
    private List mProjectsByAudit;

    /** pour envoyer des mails */
    private IMailerProvider mMailer = MailerHelper.getMailerProvider();

    /**
     * Instantiate a scheduler.
     * 
     * @param pSiteId Technical id of the Squalix server.
     * @param launchMail boolean which indicate if we want launch a mail
     * @throws ConfigurationException Si un problme de configuration apparat.
     * @roseuid 42935241035F
     */
    public Scheduler(long pSiteId, boolean launchMail) throws ConfigurationException {
        try {
            mSession = PERSISTANT_PROVIDER.getSession();
            mConf = SqualixConfigFacade.getConfig();
            mLaunchingCal = Calendar.getInstance();

            // If launchMail is true then we launch a mail fro indicat to the admins that squalix has been launched
            if (launchMail) {
                String sender = Messages.getString("mail.sender.squalix");
                MessageMailManager mail = new MessageMailManager();
                String object = sender + Messages.getString("mail.squalix.launch.object");
                mail.addContent("mail.header", null);
                mail.addContent("mail.squalix.launch.content", null);
                String content = mail.getContent();
                SqualeCommonUtils.notifyByEmail(mMailer, null, SqualeCommonConstants.ONLY_ADMINS, null, object,
                        content, false);
            }
        } catch (JrafEnterpriseException e) {
            LOGGER.error(CoreMessages.getString("exception"), e);
        } catch (JrafPersistenceException e) {
            LOGGER.error(CoreMessages.getString("exception"), e);
        }
        mSiteId = pSiteId;
    }

    /**
     * Rcupre les audits  raliser le jour prsent.
     * 
     * @param pStopTime timer donnant l'arrt du batch
     * @return la liste des audits  raliser ce jour
     * @throws JrafDaoException si un probleme de rcupration apparat.
     * @roseuid 42B7E4E30396
     */
    private List getAudits(StopTimeHelper pStopTime) throws JrafDaoException {
        mSession.beginTransaction();
        // Rcupre les audits dont la date d'excution est
        // antrieure  la date limite d'excution
        List audits = (List) AuditDAOImpl.getInstance().findBeforeBySiteAndStatus(mSession, mSiteId,
                AuditBO.NOT_ATTEMPTED, pStopTime.getLimitCal().getTime());
        mSession.commitTransactionWithoutClose();
        LOGGER.info(CoreMessages.getString("audits.toprocess", new Object[] { new Integer(audits.size()) }));
        return audits;
    }

    /**
     * Rcupre la liste des projets d'un audit, et excute les analyses dans l'ordre. L'audit est rattach  chaque
     * projet
     * 
     * @param pAudit Audit pour lequel on dsire obtenir la liste des projets
     * @return La collection des projets lis  l'audit
     * @roseuid 42B7E54D0127
     */
    private List getProjectsByAudit(final AuditBO pAudit) {
        List list = new ArrayList();
        try {
            Long id = new Long(pAudit.getId());
            mSession.beginTransaction();
            ApplicationBO application = ApplicationDAOImpl.getInstance().loadByAuditId(mSession, id);
            Collection children = application.getChildren();
            if (null != children) {
                // Si l'application contient des projets, on les ajoute
                //  la liste des projets  analyser
                // pour cet audit.
                Iterator it = children.iterator();
                Object obj = null;
                while (it.hasNext()) {
                    obj = it.next();
                    if (obj instanceof ProjectBO) {
                        ProjectBO project = (ProjectBO) obj;
                        // Rattachement de l'audit au projet si celui-ci est actif
                        if (project.getStatus() == ProjectBO.ACTIVATED) {
                            project.addAudit(pAudit);
                            ProjectDAOImpl.getInstance().save(mSession, project);
                            list.add(project);
                        }
                    }
                }
            }
            mSession.commitTransactionWithoutClose();
        } catch (Exception e) {
            // Si un problme de DAO apparat, l'exception est loggue
            LOGGER.error(CoreMessages.getString("exception"), e);
        }
        return list;
    }

    /**
     * Lance le scheduleur.<br>
     * 
     * @roseuid 42CD2F0B0287
     */
    public void run() {
        try {
            // On lance le monitoring de la mmoire
            // MemoryMonitor.startMonitoring(new MemoryMonitorConfiguration());
            StopTimeHelper stop = new StopTimeHelper(mConf, mLaunchingCal);
            if (LOGGER.isDebugEnabled()) {
                LOGGER.debug(CoreMessages.getString("time.limit", stop.getLimitCal().getTime()));
            }
            boolean canContinue = true;

            List audits = getAudits(stop);

            // Launch the export for the shared repository 
            Thread export = null;
            Export exportTools = new Export();
            export = exportTools.launchExport(mSiteId);

            // purge dans un thread parallele
            Purge prg = new Purge(mSiteId, audits);
            prg.start();

            // Test si il y a des audits avec le status en cours pour le site concern
            // Si oui, c'est anormal, on prvient les administrateurs mais on continue quand meme
            // car c'est peut etre simplement un audit qui a t interrompu brutalement et a n'empechera
            // donc pas le nouveau de tourner
            if (existsAlreadyRunningAudits(mSiteId)) {
                // On envoie un mail pour signaler qu'un audit est en cours sur l'application
                String sender = Messages.getString("mail.sender.squalix");
                String object = sender + Messages.getString("mail.running_audit.exists.object");

                MessageMailManager mail = new MessageMailManager();
                mail.addContent("mail.header", null);
                mail.addContent("mail.running_audit.exists.content", null);
                String content = mail.getContent();

                String dest = SqualeCommonConstants.ONLY_ADMINS;
                // On envoir le mail qu'aux abonns
                SqualeCommonUtils.notifyByEmail(mMailer, null, dest, null, object, content, false);
            }
            // Excuter les audits
            launchAudits(audits, stop);
            // Mise  jour des indicateurs DICT pour squale
            if (!audits.isEmpty()) {
                new ComputeStats().computeDICTStats();
            }
            // Correction automatique de la frquence des audits si la configuration existe
            if (null != mConf.getFrequencies() && mConf.getFrequencies().size() > 0) {
                manageAuditFrequency();
            }

            // Wait the end of the purge thread
            prg.join();
            if (export != null) {
                export.join();
            }

            LOGGER.info(CoreMessages.getString("endofexec"));
            // Fermeture de la session
            mSession.closeSession();
        } catch (JrafDaoException e) {
            LOGGER.error(CoreMessages.getString("exception"), e);
        } catch (ConfigurationException e) {
            LOGGER.error(CoreMessages.getString("exception"), e);
        } catch (InterruptedException e) {
            // On n'a pas pu effectuer la purge correctement
            // On prvient les admins
            String sender = Messages.getString("mail.sender.squalix");
            String object = sender + Messages.getString("mail.rotation.audit.shutDown.object");

            MessageMailManager mail = new MessageMailManager();
            mail.addContent("mail.header", null);
            mail.addContent("mail.rotation.audit.shutDown.content", null);
            String content = mail.getContent();
            SqualeCommonUtils.notifyByEmail(mMailer, null, SqualeCommonConstants.ONLY_ADMINS, null, object, content,
                    false);
        }
    }

    /**
     * On fait une passe sur toutes les applications ayant un audit programm pour vrifier les rgles dfini dans le
     * paramtrage de la frquence. On baisse ensuite la frquence des applications si besoin et on envoie un mail de
     * notification de changement de paramtrage  l'administrateur de l'application et aux admins SQUALE.
     * 
     * @throws JrafDaoException si erreur
     */
    private void manageAuditFrequency() throws JrafDaoException {
        mSession.beginTransaction();
        // On rcupre les applications du site qui ont un audit de suivi programm
        Collection applis = ApplicationDAOImpl.getInstance().findWhereHaveNotAttemptedAuditBySite(mSession,
                mSiteId);
        // Pour toutes les applis, on modifie la frquence en fonction de son dernier accs utilisateur
        ApplicationBO appli = null;
        // On sauvegarde l'ancienne valeur de la frquence pour le message du mail
        int oldFreq = 0;
        for (Iterator it = applis.iterator(); it.hasNext();) {
            appli = (ApplicationBO) it.next();
            oldFreq = appli.getAuditFrequency();
            // On change la frquence si ncessaire
            if (appli.changeFrequency(AuditFrequencyTransform.dto2bo(mConf.getFrequencies()))) {
                LOGGER.info("frequency has been changed for " + appli.getName());
                // On sauvegarde les modifications
                ApplicationDAOImpl.getInstance().save(mSession, appli);
                // On envoit un mail d'information aux managers de l'application et aux admins SQUALE
                String sender = Messages.getString("mail.sender.squalix");
                String object = sender + Messages.getString("mail.application_frequency.changed.object");

                MessageMailManager mail = new MessageMailManager();
                mail.addContent("mail.header", null);
                mail.addContent("mail.application_frequency.changed.content",
                        new String[] { appli.getName(), "" + oldFreq, "" + appli.getAuditFrequency() });
                String content = mail.getContent();
                SqualeCommonUtils.notifyByEmail(mMailer, null, SqualeCommonConstants.MANAGERS_AND_ADMINS, null,
                        object, content, false);
            }
        }
        mSession.commitTransactionWithoutClose();
    }

    /**
     * @param pSiteId le nom du site
     * @return true si il existe des audits avec le status running pour ce site
     * @throws JrafDaoException en cas d'chec
     */
    private boolean existsAlreadyRunningAudits(long pSiteId) throws JrafDaoException {
        return AuditDAOImpl.getInstance().countWhereStatusAndSite(mSession, pSiteId, AuditBO.RUNNING) != 0;
    }

    /**
     * @return un boolen indiquant si il faut faire la rpartition des audits ou pas
     * @throws JrafDaoException en cas d'echec de rcupration de l'audit
     */
    private boolean isRotationDay() throws JrafDaoException {
        AuditDAOImpl auditDao = AuditDAOImpl.getInstance();
        Calendar today = Calendar.getInstance();
        Calendar auditDate = Calendar.getInstance();
        Collection coll;
        boolean result = false;
        coll = auditDao.findRotationAudit(mSession);
        if (coll != null && coll.size() != 0) {
            Iterator it = coll.iterator();
            // Normalement un seul rsultat
            while (it.hasNext()) {
                AuditBO audit = (AuditBO) it.next();
                auditDate.setTime(audit.getDate());
                result = audit.getDate() != null
                        && auditDate.get(Calendar.DAY_OF_WEEK) <= today.get(Calendar.DAY_OF_WEEK);
            }
        } else {
            // On a pas pu trouver l'audit de rotation des partitions,
            // On en informe les admins
            ServeurDTO serveur = new ServeurDTO();
            serveur = ServeurFacade.getServeur(mSiteId);
            String sender = Messages.getString("mail.sender.squalix");
            String object = sender
                    + Messages.getString("mail.rotation.audit.unknown.object", new String[] { serveur.getName() });

            MessageMailManager mail = new MessageMailManager();
            mail.addContent("mail.header", null);
            mail.addContent("mail.rotation.audit.unknown.content", null);
            String content = mail.getContent();

            SqualeCommonUtils.notifyByEmail(mMailer, null, SqualeCommonConstants.ONLY_ADMINS, null, object, content,
                    false);
        }
        return result;
    }

    /**
     * Lance les excutions des audits
     * 
     * @param pAudits audits  raliser.
     * @param pStopTime timer d'arrt du scheduler
     * @roseuid 42CE34390161
     */
    private void launchAudits(List pAudits, StopTimeHelper pStopTime) {
        if (null != pAudits) {
            Iterator it = pAudits.iterator();
            AuditBO audit = null;
            // pour chaque audit lance les auditExecutors associs
            while (it.hasNext() && !pStopTime.isTimeToStop()) {
                SourcesRecoveringOptimisation.reinit();
                audit = (AuditBO) it.next();
                audit.setRealBeginningDate(Calendar.getInstance().getTime());
                launchAudit(audit);
                audit.setEndDate(Calendar.getInstance().getTime());
                // met  jour le champ dure de l'audit en calculant
                //  partir des dates de dbut et de fin
                audit.calculeDuration();
                // Ne stocke pas la taille de la JVM car le rsultat n'est pas pertinent
            }
            // Affichage d'un message s'il reste des audits  traiter
            if (it.hasNext()) {
                LOGGER.warn(CoreMessages.getString("time.limitreached"));
            }
        }
    }

    /**
     * Lance l'excution d'un audit et donc de tous ses excuteurs d'audit pour les projets que l'application contient
     * 
     * @param pCurrentAudit l'audit lanc
     */
    private void launchAudit(AuditBO pCurrentAudit) {
        AuditBO previousAudit = null;
        ApplicationBO application = null;
        // on passe tout de suite le status de l'audit  "en cours" et on cre de suite
        // un nouvel audit pour viter les problmes lis  l'interruption brutale du batch
        // enregistrement de l'audit
        try {
            mSession.beginTransaction();
            pCurrentAudit.setStatus(AuditBO.RUNNING);
            // On met  jour la version de SQUALE
            pCurrentAudit.setSqualeVersion(AuditBO.getCurrentSqualeVersion());
            // On met la date tout de suite pour ne pas avoir de problmes avec les audits interrompus
            pCurrentAudit.setDate(Calendar.getInstance().getTime());
            AuditDAOImpl.getInstance().save(mSession, pCurrentAudit);
            application = ApplicationDAOImpl.getInstance().loadByAuditId(mSession, new Long(pCurrentAudit.getId()));

            // On rcupre l'audit prcdent
            AuditDAOImpl dao = AuditDAOImpl.getInstance();
            previousAudit = dao.getLastAuditByApplication(mSession, application.getId(), null, AuditBO.TERMINATED);

            createNewAudit(pCurrentAudit, application);
            mSession.commitTransactionWithoutClose();
            // On met la variable  termin par dfaut, de toute faon si on l'affecte alors la bonne valeur
            // a t traite dans la boucle suivante, et si on ne rentre pas dans la boucle
            // c'est qu'on avait rien  faire mais on a pas eu d'erreurs
            int status = AuditBO.TERMINATED;
            // rcupre la liste des auditsExecutors
            // un AuditExecutor par projet de l'application de l'audit
            List aeList = getAuditExecutors(pCurrentAudit);
            // le nombre de projets pour cet audit
            // aeList ne peut pas etre null, au pire vide
            // lance les taches de l'auditExecutor
            for (int i = 0; i < aeList.size(); i++) {
                launchTasks((AuditExecutor) aeList.get(i));
                // un audit failed est dfinitif
                if (status != AuditBO.FAILED) {
                    // Si il n'est pas non plus partiel, on rcupre la valeur courante
                    // Sinon, un status partial ne peut etre chang que pour un status failed
                    // car failed est prioritaire sur partial
                    int newStatus = ((AuditExecutor) aeList.get(i)).getFinalStatus();
                    if (status != AuditBO.PARTIAL || (status == AuditBO.PARTIAL && newStatus == AuditBO.FAILED)) {
                        status = newStatus;
                    }
                }
            }
            // on met  jour le status de l'audit que si on a effectu tous les projets de l'application de l'audit
            pCurrentAudit.setStatus(status);
            // sauvegarde l'audit
            saveCurrentAudit(pCurrentAudit, application);
            // Notification : en cas de russite, on prvient les managers de l'application
            // que l'audit s'est bien pass
            String[] infos = new String[] { application.getName(), application.getServeurBO().getName() };
            manageResultMailing(pCurrentAudit.getStatus(), infos, application.getId());
            // On excute le calcul du ROI si l'audit a fonctionn et si l'application a un audit
            // termin qui prcde le courant
            if (pCurrentAudit.getStatus() == AuditBO.TERMINATED && null != previousAudit) {
                mSession.beginTransaction();
                int nbCorrections = calculateNbCorrection(previousAudit, pCurrentAudit);
                createROI(nbCorrections, application, pCurrentAudit);
                mSession.commitTransactionWithoutClose();
            }

        } catch (JrafDaoException e) {
            LOGGER.error(CoreMessages.getString("exception"), e);
        }
    }

    /**
     * Mthode qui gre l'envoi de mail en fonction du rsultat de l'audit
     * 
     * @param pStatus le status de l'audit
     * @param pInfos les informations concernant l'audit pour le mail
     * @param pApplicationId l'id de l'application concerne
     */
    private void manageResultMailing(int pStatus, String[] pInfos, long pApplicationId) {
        String dest = "";
        String object = "";
        String content = "";
        boolean sendMail = false;
        String sender = Messages.getString("mail.sender.squalix.task", pInfos);
        MessageMailManager mail = new MessageMailManager();
        if (pStatus == AuditBO.TERMINATED) {
            object = sender + Messages.getString("mail.audit.terminated.object", pInfos);
            mail.addContent("mail.header", null);
            mail.addContent("mail.audit.terminated.content", pInfos);
            content = mail.getContent();
            dest = SqualeCommonConstants.MANAGERS_AND_READERS;
            sendMail = true;
        } else {
            // en cas d'chec, on prvient les administrateurs de SQUALE et
            // les managers de l'application concerne de l'chec
            if (pStatus == AuditBO.FAILED) {
                object = sender + Messages.getString("mail.audit.failed.object", pInfos);
                mail.addContent("mail.header", null);
                mail.addContent("mail.audit.failed.content", pInfos);
                content = mail.getContent();
                dest = SqualeCommonConstants.MANAGERS_AND_ADMINS;
                sendMail = true;
            } else {
                // en cas d'chec, on prvient les administrateurs de SQUALE et
                // les managers de l'application concerne de l'chec
                if (pStatus == AuditBO.PARTIAL) {
                    object = sender + Messages.getString("mail.audit.partial.object", pInfos);
                    mail.addContent("mail.header", null);
                    mail.addContent("mail.audit.partial.content", pInfos);
                    content = mail.getContent();
                    dest = SqualeCommonConstants.MANAGERS_AND_ADMINS;
                    sendMail = true;
                }
            }
        }
        // On envoie un email aux utilisateurs abonns selon le statut de l'audit
        if (sendMail) {
            // complment d'infos
            SqualeCommonUtils.notifyByEmail(mMailer, null, dest, new Long(pApplicationId), object, content, false);
        }
    }

    /**
     * Sauvegarde le roi calcul en base
     * 
     * @param pValue le nombre de correction
     * @param pApplication l'application courante
     * @param pAudit l'audit courant
     * @throws JrafDaoException si erreur
     */
    public void createROI(int pValue, ApplicationBO pApplication, AuditBO pAudit) throws JrafDaoException {
        RoiMetricsBO roi = new RoiMetricsBO();
        roi.setNbCorrections(pValue);
        roi.setComponent(pApplication);
        roi.setAudit(pAudit);
        // Initialisation du DAO
        MeasureDAOImpl roiDAO = MeasureDAOImpl.getInstance();
        roiDAO.create(mSession, roi);
    }

    /**
     * Calcule le nombre de corrections pour l'audit courant pour le ROI
     * 
     * @param pPreviousAudit l'audit prcdent
     * @param pCurrentAudit l'audit courant
     * @return le nombre de corrections faites entre les deux audits
     * @throws JrafDaoException si erreur
     */
    public int calculateNbCorrection(AuditBO pPreviousAudit, AuditBO pCurrentAudit) throws JrafDaoException {
        int nbProgressions = 0;
        int nbSuppressions = 0;
        int transgressionDiff = 0;
        if (pCurrentAudit.getRealDate().before(pPreviousAudit.getRealDate())) {
            // On ne calcule pas le nombre de correction si il s'agit d'un audit de jalon intercal
            LOGGER.info(
                    CoreMessages.getString("roi.not_calculated", new Object[] { new Long(pCurrentAudit.getId()) }));
        } else {
            /* On rcupre le nombre de corrections faites entre les deux audits */
            Long auditId = new Long(pCurrentAudit.getId());
            Long previousAuditId = new Long(pPreviousAudit.getId());
            MarkDAOImpl markDao = MarkDAOImpl.getInstance();
            // Les composants qui sont passs de zro  1, 2 ou 3
            nbProgressions = markDao.findCorrectionsWithProgessions(mSession, auditId, previousAuditId);
            // Les composants qui taient  zro et qui n'existent plus
            nbSuppressions = markDao.findCorrectionsWithSuppressions(mSession, auditId, previousAuditId);
            // La progression du nombre de transgressions de niveau erreur et warning
            RuleCheckingTransgressionDAOImpl ruleDao = RuleCheckingTransgressionDAOImpl.getInstance();
            int nbTransgressions = ruleDao.findNbErrorAndWarning(mSession, auditId);
            int nbPreviousTransgressions = ruleDao.findNbErrorAndWarning(mSession, previousAuditId);
            transgressionDiff = nbPreviousTransgressions - nbTransgressions;
            if (transgressionDiff <= 0) {
                transgressionDiff = 0;
            }
        }
        return nbProgressions + nbSuppressions + transgressionDiff;
    }

    /**
     * Lance les tches .
     * 
     * @param pAuditExec l'executeur d'audit .
     * @roseuid 42CE30D601DD
     */
    private void launchTasks(AuditExecutor pAuditExec) {
        // lance les taches de l'auditExecutor
        pAuditExec.run();
    }

    /**
     * @param pAudit audit d'applications  raliser.
     * @return Retourne une liste d'executeur d'audits pour l'audit en parametre.<br>
     * @roseuid 42CE37D70124
     */
    private List getAuditExecutors(final AuditBO pAudit) {
        AuditExecutor ae = null;
        List aeList = new ArrayList(0);
        ProjectBO project = null;
        // La liste des taches  effectuer
        List analyze = new ArrayList(0);
        // La liste des taches de terminaison  effectuer dans tous les cas
        List termination = new ArrayList(0);
        // La liste des taches  effectuer pour rcuprer les sources
        List analyzeSource = new ArrayList(0);
        // La liste des taches de terminaison  effectuer pour la rcupration
        // de sources, comme le dmontage de la vue clearcase...
        List terminationSource = new ArrayList(0);
        // La liste des taches de profil
        List analyzeProfil = new ArrayList(0);
        // La liste des taches de terminaison de profil  effectuer
        List terminationProfil = new ArrayList(0);
        try {
            // On rcupre tous les projets  analyser pour cet audit
            mProjectsByAudit = getProjectsByAudit(pAudit);
            Iterator it = mProjectsByAudit.iterator();
            while (it.hasNext()) {
                // Pour chaque projet, on cre un excuteur d'audit,
                // grant le type de rcuprateur de source associ au projet et
                // dpendant du profil du projet
                project = (ProjectBO) it.next();
                analyzeSource = project.getSourceManager().getAnalysisTasks();
                terminationSource = project.getSourceManager().getTerminationTasks();
                String profile = project.getProfile().getName();
                analyzeProfil = project.getProfile().getAnalysisTasks();
                terminationProfil = project.getProfile().getTerminationTasks();
                // Il y a 2 types de taches (analyse ou terminale) combinable
                // avec 2 types de fonction (rcupration de source ou profil)
                // il faut faire dans l'ordre:
                // * Taches d'analyse de rcupration de source
                // * Taches d'analyse du profil
                // * Taches terminales du profil
                // * Taches terminales de rcupration de source
                analyze.addAll(analyzeSource);
                analyze.addAll(analyzeProfil);
                termination.addAll(terminationProfil);
                termination.addAll(terminationSource);
                // Es-ce le dernier projet de l'audit ?
                boolean lastProject = false;
                if (!it.hasNext()) {
                    lastProject = true;
                }
                // creation de lauditexecutor associ
                ae = new AuditExecutor(analyze, termination, pAudit, project, lastProject);
                ae.setScheduler(this);
                aeList.add(ae);
                mAudits.add(ae);
                analyze = new ArrayList(0);
                termination = new ArrayList(0);
            }
        } catch (Exception e) {
            LOGGER.error(CoreMessages.getString("exception"), e);
            pAudit.setStatus(AuditBO.FAILED);
        }
        return aeList;
    }

    /**
     * Ralise les tches de niveau application (cration des graphes, calculs,...)
     * 
     * @param pCurrentAudit l'audit courant.
     * @param pApplicationBO l'application sur lequel calculer les rsultats.
     * @roseuid 42CE40E102B8
     */
    private void createNewAudit(final AuditBO pCurrentAudit, final ApplicationBO pApplicationBO) {
        ApplicationBO application = null;
        // on ne cre pas de nouvelles transactions car il faut faut que la transaction
        // pour cette mthode soit la meme que pour la mthode appelante de cette mthode
        try {
            Long applicationId = new Long(pApplicationBO.getId());
            application = (ApplicationBO) ApplicationDAOImpl.getInstance().get(mSession, applicationId);
            GregorianCalendar cal = new GregorianCalendar();
            // Cration d'un nouvel audit si il s'agit d'un audit de suivi
            if (pCurrentAudit.getType().equals(AuditBO.NORMAL)) {
                // Cration d'un nouvel audit
                AuditBO audit = new AuditBO();
                // Ajout de la frquence d'audit  la date courante
                cal.add(Calendar.DATE, pApplicationBO.getAuditFrequency());
                audit.setDate(cal.getTime());
                audit.setStatus(AuditBO.NOT_ATTEMPTED);
                audit.setType(pCurrentAudit.getType());
                AuditDAOImpl.getInstance().create(mSession, audit);
                // Ajout du nouvel audit  l'application
                application.addAudit(audit);
                ApplicationDAOImpl.getInstance().save(mSession, application);
            }
        } catch (Exception e) {
            LOGGER.error(CoreMessages.getString("exception"), e);
        }
    }

    /**
     * enregistre l'audit courant
     * 
     * @param pCurrentAudit l'audit courant
     * @param pApplicationBO l'application lie  l'audit
     */
    private void saveCurrentAudit(final AuditBO pCurrentAudit, final ApplicationBO pApplicationBO) {
        ApplicationBO application = null;
        try {
            Long applicationId = new Long(pApplicationBO.getId());
            mSession.beginTransaction();
            application = (ApplicationBO) ApplicationDAOImpl.getInstance().get(mSession, applicationId);
            Long auditId = new Long(pCurrentAudit.getId());
            GregorianCalendar cal = new GregorianCalendar();
            AuditBO finishedAudit = (AuditBO) AuditDAOImpl.getInstance().get(mSession, auditId);
            // Remet  jour la date relle de l'audit
            finishedAudit.setDate(Calendar.getInstance().getTime());
            finishedAudit.setStatus(pCurrentAudit.getStatus());
            // sauvegarde l'audit
            AuditDAOImpl.getInstance().save(mSession, finishedAudit);
            // on commit pour sauvegarder le status de l'audit
            mSession.commitTransactionWithoutClose();
            mSession.beginTransaction();
            // Ajoute l'audit russit dans le Referenciel
            manageSqualeReference(finishedAudit, pApplicationBO.getName(), pApplicationBO.getId());
            mSession.commitTransactionWithoutClose();

        } catch (Exception e) {
            LOGGER.error(CoreMessages.getString("exception"), e);
        }
    }

    /**
     * @param pAudit l'audit courant termin
     * @param pAppliName le nom de l'application recherch
     * @param pAppliId l'id de l'application pour la transformation
     * @throws JrafEnterpriseException en cas d'chec de sauvegarde de l'outil
     */
    private void manageSqualeReference(AuditBO pAudit, String pAppliName, long pAppliId)
            throws JrafEnterpriseException {
        boolean insert = false;
        SqualeReferenceDTO storedAudit = SqualeReferenceFacade.getReferencedAudit(pAppliName, mSession);
        // Les diffrentes rgles suivantes sont priorises
        // 1) On ne peut ajouter au rfrentiel que des audits termins
        // 2) Si aucun audit n'est dj prsent en base, on insre le courant de toute facon
        // 3) les audits de jalon sont prioritaires
        // 4) On garde l'audit le plus rcent
        if (pAudit.getStatus() == AuditBO.TERMINATED
                && (null == storedAudit || ((AuditBO.NORMAL.equals(storedAudit.getAuditType())
                        && AuditBO.MILESTONE.equals(pAudit.getType()))
                        || (storedAudit.getAuditType().equals(pAudit.getType())
                                && pAudit.getDate().getTime() > storedAudit.getDate().getTime())))) {
            SqualeReferenceFacade.insertAudit(AuditTransform.bo2Dto(pAudit, pAppliId), mSession);
        }
    }

}