/**
* 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.stats;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collection;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
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.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.config.ProjectProfileDAOImpl;
import org.squale.squalecommon.daolayer.config.web.AbstractDisplayConfDAOImpl;
import org.squale.squalecommon.daolayer.result.MeasureDAOImpl;
import org.squale.squalecommon.daolayer.result.MetricDAOImpl;
import org.squale.squalecommon.daolayer.result.QualityResultDAOImpl;
import org.squale.squalecommon.daolayer.result.SimpleFormulaDAOImpl;
import org.squale.squalecommon.daolayer.stats.SiteAndProfilStatsDICTDAOImpl;
import org.squale.squalecommon.daolayer.stats.SiteStatsDICTDAOImpl;
import org.squale.squalecommon.datatransfertobject.config.ServeurDTO;
import org.squale.squalecommon.enterpriselayer.businessobject.component.ApplicationBO;
import org.squale.squalecommon.enterpriselayer.businessobject.component.AuditBO;
import org.squale.squalecommon.enterpriselayer.businessobject.config.Profile_DisplayConfBO;
import org.squale.squalecommon.enterpriselayer.businessobject.config.ProjectProfileBO;
import org.squale.squalecommon.enterpriselayer.businessobject.config.web.AbstractDisplayConfBO;
import org.squale.squalecommon.enterpriselayer.businessobject.config.web.VolumetryConfBO;
import org.squale.squalecommon.enterpriselayer.businessobject.result.IntegerMetricBO;
import org.squale.squalecommon.enterpriselayer.businessobject.result.QualityResultBO;
import org.squale.squalecommon.enterpriselayer.businessobject.rule.SimpleFormulaBO;
import org.squale.squalecommon.enterpriselayer.businessobject.stats.SiteAndProfilStatsDICTBO;
import org.squale.squalecommon.enterpriselayer.businessobject.stats.SiteStatsDICTBO;
import org.squale.squalecommon.enterpriselayer.facade.roi.RoiFacade;
import org.squale.squalecommon.enterpriselayer.facade.rule.FormulaException;
import org.squale.squalecommon.enterpriselayer.facade.component.ServeurFacade;
import org.squale.squalecommon.util.mapping.Mapping;
import org.squale.squalix.core.CoreMessages;
/**
*/
public class ComputeStats
{
// TODO voir avec laurent et nicolas comment le moteur d'indicateur SQUALE
// fournit ce param�tre (SEB)
/** Le nombre de mois pr�c�dents pris en compte */
private final static int NB_MONTHS = 2;
/** Le nombre de chiffres pour l'arrondi */
private final static int NB_DIGITS = 2;
/**
* Logger
*/
private static final Log LOGGER = LogFactory.getLog( ComputeStats.class );
/**
* Provider de persistance
*/
private static final IPersistenceProvider PERSISTANT_PROVIDER = PersistenceHelper.getPersistenceProvider();
/**
* Session de travail
*/
private ISession mSession;
/** Constructeur */
public ComputeStats()
{
try
{
mSession = PERSISTANT_PROVIDER.getSession();
// on instancie les diff�rents DAO n�cessaires
profileDao = ProjectProfileDAOImpl.getInstance();
appliDao = ApplicationDAOImpl.getInstance();
resultDao = QualityResultDAOImpl.getInstance();
measureDao = MeasureDAOImpl.getInstance();
formulaDAO = SimpleFormulaDAOImpl.getInstance();
metricDao = MetricDAOImpl.getInstance();
siteAndProfilDao = SiteAndProfilStatsDICTDAOImpl.getInstance();
siteDao = SiteStatsDICTDAOImpl.getInstance();
auditDao = AuditDAOImpl.getInstance();
projectDao = ProjectDAOImpl.getInstance();
}
catch ( JrafPersistenceException e )
{
LOGGER.error( CoreMessages.getString( "exception" ), e );
}
}
/** les diff�rents DAO n�cessaires au calcul */
/** pour les stats concernant les profils */
private ProjectProfileDAOImpl profileDao;
/** pour le nombre de projets */
private ProjectDAOImpl projectDao;
/** pour les applications */
private ApplicationDAOImpl appliDao;
/** pour la volum�trie */
private MetricDAOImpl metricDao;
/** pour les audits */
private AuditDAOImpl auditDao;
/** pour les stats facteurs */
private QualityResultDAOImpl resultDao;
/** pour le roi */
private MeasureDAOImpl measureDao;
/** pour la formule du roi */
private SimpleFormulaDAOImpl formulaDAO;
/** Les DAO pour l'enregistrement en base */
/** DAO pour enregistrer les SiteStatsDICTBO */
private SiteAndProfilStatsDICTDAOImpl siteAndProfilDao;
/** DAO pour enregistrer les StatsDICTBO */
private SiteStatsDICTDAOImpl siteDao;
/**
* Calcule et enregistre en base les diff�rents statistiques n�cessaires au calcul des indicateurs SQUALE pour DICT
* Ces statistiques sont: Le nombre total d'appli (par site) Le nombre total d'appli avec un audit ex�cut� depuis n
* mois Le nombre total d'appli avec un audit r�ussi depuis n mois Le nombre de lignes de codes par site et par
* profil Le nombre de facteurs accept�s / accept�s avec r�serves / refus�s Le ROI en ke par site
*/
public void computeDICTStats()
{
try
{
// la liste des StatsDICTBO, un par site
List siteStatsList = new ArrayList( 0 );
// la liste des SiteStatsDICTBO, il y en a
// un par site et par profil, soit nbSites*nbProfils
List siteProfilStatsList = new ArrayList( 0 );
// on r�cup�re la liste des profils disponibles
Collection profiles = profileDao.findAll( mSession );
// Pour chaque site, on cr�e un SiteStatsDICTBO
// Pour chaque combinaison site/profil, on cr�e un SiteStatsDICTBO
Collection lServeurList = new ArrayList();
try
{
lServeurList = ServeurFacade.listeServeurs();
}
catch ( Exception e )
{
}
Iterator lServeurListIt = lServeurList.iterator();
for ( int i = 0; i < lServeurList.size(); i++ )
{
ServeurDTO lServeurDTO = (ServeurDTO) lServeurListIt.next();
long lSiteId = lServeurDTO.getServeurId();
int nbAppli = appliDao.countWhereSite( mSession, lSiteId );
int nbAppliWithAudit = appliDao.countWhereHaveOnlyFailedAudit( mSession, lSiteId );
int nbAppliWithAuditSuccessful =
appliDao.countWhereHaveAuditByStatus( mSession, lSiteId, new Integer( AuditBO.TERMINATED ), null );
int nbAppliWithoutAudits = appliDao.countWhereHaveNoAudits( mSession, lSiteId );
int nbApplisToValidate = appliDao.countNotValidate( mSession, lSiteId );
int nbFactorsAcc =
resultDao.countFactorsByAcceptanceLevelAndSite( mSession, QualityResultBO.ACCEPTED, lSiteId );
int nbFactorsRes =
resultDao.countFactorsByAcceptanceLevelAndSite( mSession, QualityResultBO.RESERVED, lSiteId );
int nbFactorsRef =
resultDao.countFactorsByAcceptanceLevelAndSite( mSession, QualityResultBO.REFUSED, lSiteId );
int nbAuditsFailed = auditDao.countWhereStatusAndSite( mSession, lSiteId, AuditBO.FAILED );
int nbAuditsSuccessfuls = auditDao.countWhereStatusAndSite( mSession, lSiteId, AuditBO.TERMINATED );
int nbAuditsPartials = auditDao.countWhereStatusAndSite( mSession, lSiteId, AuditBO.PARTIAL );
int nbAuditsNotAttempted = auditDao.countWhereStatusAndSite( mSession, lSiteId, AuditBO.NOT_ATTEMPTED );
double roi = calculateGlobalROI( lSiteId );
siteStatsList.add( new SiteStatsDICTBO( lSiteId, nbAppli, nbAppliWithAudit, nbAppliWithAuditSuccessful,
nbAppliWithoutAudits, nbApplisToValidate, nbFactorsAcc,
nbFactorsRes, nbFactorsRef, nbAuditsFailed,
nbAuditsSuccessfuls, nbAuditsPartials, nbAuditsNotAttempted,
roi ) );
// Les stats concernant les profils et les sites
Iterator it = profiles.iterator();
while ( it.hasNext() )
{
ProjectProfileBO profile = (ProjectProfileBO) it.next();
//The name of the profile
String profileName = ( profile ).getName();
//The number of code line by profile
Set profileDisplayConfList = profile.getProfileDisplayConfs();
Iterator<Profile_DisplayConfBO> profileDisplayConfIt = profileDisplayConfList.iterator();
boolean found = false;
//Profile_DisplayConfBO porfileDisplayConf = null;
AbstractDisplayConfBO displayConf = null;
AbstractDisplayConfDAOImpl displayConfDAO = AbstractDisplayConfDAOImpl.getInstance();
while ( profileDisplayConfIt.hasNext() && !found)
{
displayConf = (AbstractDisplayConfBO)displayConfDAO.get( mSession, profileDisplayConfIt.next().getDisplayConf().getId() );
if ( displayConf instanceof VolumetryConfBO && ((VolumetryConfBO)displayConf).getComponentType().equals( "project" ))
{
found = true;
}
}
Set treList = ((VolumetryConfBO)displayConf).getTres();
Iterator<String> treNameIt = treList.iterator();
String volumetryType;
ArrayList<String> metricList = new ArrayList<String>();
while ( treNameIt.hasNext() )
{
String treName = (String) treNameIt.next();
volumetryType = Mapping.getVolumetryType( treName );
if(volumetryType.startsWith( Mapping.VOLUMETRY_NB_CODES_LINES ))
{
metricList.add( treName );
}
}
int nbLines = metricDao.getVolumetryBySiteAndProfil( mSession, lSiteId, profileName,metricList );
// Number of projects by profile
int nbProjects = projectDao.countBySiteAndProfil( mSession, lSiteId, profileName );
siteProfilStatsList.add( new SiteAndProfilStatsDICTBO( lSiteId, profileName, nbLines, nbProjects ) );
}
}
// enregistre les r�sultats en base
storeResults( siteStatsList, siteProfilStatsList );
LOGGER.info( "Statistics 'calculation done" );
}
catch ( JrafDaoException e )
{
LOGGER.error( CoreMessages.getString( "exception" ), e );
}
}
/**
* @return la date courante moins le nombre de mois d�finis
*/
private Date getBeginDate()
{
GregorianCalendar cal = new GregorianCalendar();
long today = Calendar.getInstance().getTimeInMillis();
cal.add( GregorianCalendar.MONTH, 0 - NB_MONTHS );
return cal.getTime();
}
/**
* Enregistre les r�sultats en base
*
* @param siteStatsList la liste des StatsDICTBO, un par site
* @param siteProfilStatsList // la liste des SiteStatsDICTBO, un par site et par profil
* @throws JrafDaoException en cas d'�chec de l'enregistrement en base des stats
*/
private void storeResults( List siteStatsList, List siteProfilStatsList )
throws JrafDaoException
{
// on cr�e une transaction car il faut d'abord enregister les objets
// de type SiteStatsDICTBO , committer et ensuite enregister les
// objets SiteAndProfilStatsDICTBO
for ( int i = 0; i < siteStatsList.size(); i++ )
{
SiteStatsDICTBO site = (SiteStatsDICTBO) siteStatsList.get( i );
// on commence par supprimer toutes les stats concernant ce site
// �vite les doublons et permet d'�viter le test est-ce que ca existe d�j� ou pas
// pour savoir si il faut faire un update ou un create
mSession.beginTransaction();
// suppression
// commence par supprimer les stats annexes sur le site
siteAndProfilDao.removeWhereSite( mSession, site.getServeurBO().getServeurId() );
siteDao.removeWhereSite( mSession, site.getServeurBO().getServeurId() );
mSession.commitTransactionWithoutClose();
mSession.beginTransaction();
// cr�ation
siteDao.create( mSession, site );
mSession.commitTransactionWithoutClose();
}
// maintenant ont peut enregistrer les SiteAndProfilStatsDICTBO
for ( int i = 0; i < siteProfilStatsList.size(); i++ )
{
SiteAndProfilStatsDICTBO siteAndProfil = (SiteAndProfilStatsDICTBO) siteProfilStatsList.get( i );
// on commence par supprimer toutes les stats concernant ce site et ce profil
// �vite les doublons et permet d'�viter le test est-ce que ca existe d�j� ou pas
// pour savoir si il faut faire un update ou un create
mSession.beginTransaction();
// suppression
siteAndProfilDao.removeWhereSiteAndProfil( mSession, siteAndProfil.getServeurBO().getServeurId(),
siteAndProfil.getProfil() );
mSession.commitTransactionWithoutClose();
mSession.beginTransaction();
// cr�ation
siteAndProfilDao.create( mSession, siteAndProfil );
mSession.commitTransactionWithoutClose();
}
}
/**
* Calcul le roi sur l'ensemble des applications du site
*
* @param pSiteId l'id du site
* @return le roi global du site
* @throws JrafDaoException en cas d'�chec
*/
private double calculateGlobalROI( long pSiteId )
throws JrafDaoException
{
int result = 0;
Collection appliList = appliDao.findWhereSite( mSession, pSiteId );
// Pour toutes les applis, on r�cup�re tous les diff�rents nombres de corrections
// sur les audits fait depuis la plage donn�e
Iterator it = appliList.iterator();
while ( it.hasNext() )
{
ApplicationBO appli = (ApplicationBO) it.next();
Collection rois =
metricDao.findROIWhereApplicationSinceDate( mSession, new Long( appli.getId() ), getBeginDate() );
Iterator itRois = rois.iterator();
while ( itRois.hasNext() )
{
IntegerMetricBO roiBo = (IntegerMetricBO) itRois.next();
result += ( (Integer) roiBo.getValue() ).intValue();
}
}
// pour l'instant le r�sultat est en nombre de corrections
// et on doit le calculer en nombre de MHI
// on enregistre la valeur -1 en cas de probl�mes avec le calcul du roi
double ke = -1;
try
{
ke = computeRoiMHI( result );
}
catch ( FormulaException e )
{
LOGGER.error( "Problems encountered while calculating squale's stats: roi formula not found or uncorrect" );
}
return ke;
}
/**
* @param pNbCorrections le nombre total de corrections sur toutes les applications
* @return le roi en ke en fonction du nombre de corrections et de la formule courante
* @throws JrafDaoException en cas d'�chec
* @throws FormulaException si erreur ai niveau de la formule
*/
private double computeRoiMHI( int pNbCorrections )
throws JrafDaoException, FormulaException
{
double result = 0;
// On r�cup�re l'unique formule du ROI en base
SimpleFormulaBO roiFormula = formulaDAO.getRoiFormula( mSession );
float MhiRoi = RoiFacade.calculateROI( pNbCorrections, roiFormula );
// arrondi � NB_DIGITS chiffres apr�s la virgule
int number = (int) Math.pow( 10, NB_DIGITS );
result = ( (int) ( MhiRoi * number ) ) / number;
return result;
}
}