/**
* 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.daolayer.result;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hibernate.Hibernate;
import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.hibernate.type.Type;
import org.squale.jraf.commons.exception.JrafDaoException;
import org.squale.jraf.provider.persistence.hibernate.AbstractDAOImpl;
import org.squale.jraf.provider.persistence.hibernate.SessionImpl;
import org.squale.jraf.spi.persistence.ISession;
import org.squale.squalecommon.daolayer.DAOMessages;
import org.squale.squalecommon.daolayer.DAOUtils;
import org.squale.squalecommon.daolayer.component.AbstractComponentDAOImpl;
import org.squale.squalecommon.enterpriselayer.businessobject.component.AbstractComplexComponentBO;
import org.squale.squalecommon.enterpriselayer.businessobject.component.AbstractComponentBO;
import org.squale.squalecommon.enterpriselayer.businessobject.component.AuditBO;
import org.squale.squalecommon.enterpriselayer.businessobject.result.MeasureBO;
import org.squale.squalecommon.util.mapping.Mapping;
/**
* @author M400843
*/
public class MeasureDAOImpl
extends AbstractDAOImpl
{
/**
* Instance singleton
*/
private static MeasureDAOImpl instance = null;
/**
* log
*/
private static final Log LOG = LogFactory.getLog( MeasureDAOImpl.class );
/** initialisation du singleton */
static
{
instance = new MeasureDAOImpl();
}
/**
* Constructeur prive
*
* @throws JrafDaoException
*/
private MeasureDAOImpl()
{
initialize( MeasureBO.class );
}
/**
* Retourne un singleton du DAO
*
* @return singleton du DAO
*/
public static MeasureDAOImpl getInstance()
{
return instance;
}
/**
* Sauve une collection de mesures.<br />
* L'id de l'audit li� � la mesure doit �tre valu�.
*
* @param pSession la session
* @param pMeasures les mesures (r�sultats McCabe, ClearCase, ...)
* @throws JrafDaoException si une erreur � lieu
*/
public void saveAll( ISession pSession, Collection pMeasures )
throws JrafDaoException
{
Iterator it = pMeasures.iterator();
while ( it.hasNext() )
{
Object element = it.next();
if ( element instanceof MeasureBO )
{
MeasureBO measure = (MeasureBO) element;
// on affecte l'audit � tout les parents
AbstractComponentBO component = measure.getComponent();
while ( component != null )
{
if ( !component.containsAuditById( measure.getAudit().getId() ) )
{
component.addAudit( measure.getAudit() );
}
component = component.getParent();
}
AbstractComponentDAOImpl.getInstance().save( pSession, measure.getComponent() );
// Appel de la m�thode h�rit�e car la m�thode
// save est surcharg�e pour �mettre un warning
super.save( pSession, measure );
}
else
{
String tab[] = { element.toString() };
LOG.error( DAOMessages.getString( "measure.bad_object", tab ) );
}
}
}
/**
* Cr� la mesure en base (apr�s v�rification du lien entre composant et audit)
*
* @param pSession la session
* @param pMeasure la mesure
* @throws JrafDaoException si une erreur � lieu ou si la mesure existe d�j�
*/
public void create( ISession pSession, MeasureBO pMeasure )
throws JrafDaoException
{
// Obtention des iids du composant et de l'audit
Long projectId = new Long( pMeasure.getComponent().getId() );
Long auditId = new Long( pMeasure.getAudit().getId() );
// Si la mesure existe d�j� pour le composant et l'audit donn� : erreur
if ( null != load( pSession, projectId, auditId, pMeasure.getClass() ) )
{
// Une seule mesure d'un type donn� est autoris�e pour un couple composant, audit
String[] tab = { auditId.toString(), projectId.toString(), pMeasure.getClass().getName() };
throw new JrafDaoException( DAOMessages.getString( "measure.exception.many.audit_component_tr", tab ) );
}
else
{
// si le composant concern� par la mesure ne contient pas l'audit rattach� � la mesure:
if ( !pMeasure.getComponent().containsAuditById( pMeasure.getAudit().getId() ) )
{
pMeasure.getComponent().addAudit( pMeasure.getAudit() );
// on affecte l'audit � tout les parents
AbstractComponentBO component = pMeasure.getComponent().getParent();
while ( component != null )
{
if ( !component.getAudits().contains( pMeasure.getAudit() ) )
{
component.addAudit( pMeasure.getAudit() );
}
component = component.getParent();
}
// sauvegarde du composant (et de ses parents)
AbstractComponentDAOImpl.getInstance().save( pSession, pMeasure.getComponent() );
}
// sauvegarde de la mesure
super.create( pSession, pMeasure );
}
}
/**
* Efface toutes les mesures li�s � un composant (recursivement ou non)
*
* @param pSession la session
* @param pComponent le composant
* @param pAudit l'audit, si <code>null</code> la suppression est effectu�e pour tout les audits.
* @param pRecursive <code>true</code> pour supprimer les mesures de tout les composants enfants
* @throws JrafDaoException si une erreur � lieu
*/
public void removeWhereComponent( final ISession pSession, final AbstractComponentBO pComponent,
final AuditBO pAudit, final boolean pRecursive )
throws JrafDaoException
{
// Cr�ation de la clause where
String whereClause = "where ";
if ( null != pAudit )
{
// si un audit est sp�cifi� on l'ajoute dans la clause where
whereClause += getAlias() + ".audit.id = " + pAudit.getId();
whereClause += " AND ";
}
whereClause += getAlias() + ".component.id = ";
// la clause ne contient pas l'id du composant qui est ajout� au moment du remove
removeWhere( pSession, whereClause + pComponent.getId() );
// si la suppression doit etre r�cursive est que l'on a un composant
// qui peut avoir des fils (AbstractComplexComponentBO)
if ( pRecursive && ( pComponent instanceof AbstractComplexComponentBO ) )
{
Iterator itChildren = ( (AbstractComplexComponentBO) pComponent ).getChildren().iterator();
while ( itChildren.hasNext() )
{
// pour chaque enfant on rappelle la m�thode
AbstractComponentBO child = (AbstractComponentBO) itChildren.next();
removeWhereComponent( pSession, child, pAudit, pRecursive );
}
}
}
/**
* Permet de r�cup�rer les notes en fonction d'une liste de noms de TREs.
*
* @param pSession session Hibernate
* @param pComponentID identifiant du composant
* @param pAuditID identifiant de l'audit
* @param pTrClasses classes des TR
* @return collection des valeurs ordonn�s par rapport a la liste des TREs
* @throws JrafDaoException exception DAO
*/
public Collection findWhere( ISession pSession, Long pComponentID, Long pAuditID, Collection pTrClasses )
throws JrafDaoException
{
List marks = new ArrayList();
Iterator it = pTrClasses.iterator();
while ( it.hasNext() )
{
Class trClass = (Class) it.next();
marks.add( load( pSession, pComponentID, pAuditID, trClass ) );
}
return marks;
}
/**
* Retourne la liste des TOP (valeur les plus elev�)
*
* @param pSession Session Jraf
* @param pProjectId Id du projet
* @param pComponentClass Class du composant � r�cuoperer (MethodBO ou ClassBO)
* @param pAuditId Id de l'audit courant
* @param pTreKey Tre � recuperer / tri�
* @param pMax nombre maxi de valeur remont�
* @return Liste de ComponentBO / Integer correspondant aux tops
* @throws JrafDaoException si pb de BD
*/
public Collection findTop( ISession pSession, long pProjectId, Class pComponentClass, long pAuditId,
String pTreKey, Integer pMax )
throws JrafDaoException
{
SessionImpl sessionHibernate = (SessionImpl) pSession;
List results = null;
try
{
// remonte les tops "pMax" en une seule requete pour des raisons de perf
Query q =
sessionHibernate.getSession().createQuery(
"select c,metric.value from " + pComponentClass.getName()
+ " c," + "NumberMetricBO metric"
+ " where metric.measure.audit.id=" + pAuditId
+ " and metric.measure.component.id=c.id"
+ " and metric.measure.class="
+ Mapping.getMetricClass( pTreKey ).getName()
+ " and metric.name = '"
+ pTreKey.substring( pTreKey.lastIndexOf( '.' ) + 1 )
+ "'" + " and " + pAuditId + " in elements(c.audits)"
+ " and c.project.id=" + pProjectId
+ " order by metric.value desc" ).setMaxResults(
pMax.intValue() );
results = q.list();
}
catch ( HibernateException e )
{
throw new JrafDaoException( e );
}
return results;
}
/**
* Retourne les valeur distinct de mesure de type Integer donn�es par leur TRE. Le TRE ne peut pas porter sur un
* projet ou application!
*
* @param pSession Session Jraf
* @param pProjectId Id du projet
* @param pAuditId Id de l'audit courant
* @param pTreKey Liste des Tre � recuperer / tri�
* @return Liste de masures distinctes (Collection de Object[])
* @throws JrafDaoException si pb de BD
*/
public Collection findDistinct( ISession pSession, long pProjectId, long pAuditId, String[] pTreKey )
throws JrafDaoException
{
SessionImpl sessionHibernate = (SessionImpl) pSession;
List results = null;
String from = "";
String distinct = "";
String where = "";
// Creation de la requete
// /!\ Requete optimis�e car longue en prod
// TOUTES MODIF DOIT ETRE TESTEES EN FAISANT LE SELECT EN PROD !!
// Cette requ�te prend moins d'1 seconde en production
for ( int i = 0; i < pTreKey.length; i++ )
{
// selecte sur n metric
// => construction des selects, from, et where de la query
if ( i > 0 )
{
distinct += ",";
}
distinct += "metric" + i + ".value";
from += ",IntegerMetricBO metric" + i;
where +=
" and metric" + i + ".measure.audit.id=" + pAuditId + " and metric" + i + ".measure.component.id=c.id"
+ " and metric" + i + ".measure.class=" + Mapping.getMetricClass( pTreKey[i] ).getName()
+ " and metric" + i + ".name = '" + pTreKey[i].substring( pTreKey[i].lastIndexOf( '.' ) + 1 ) + "'";
}
// execution de la requete
try
{
// remonte les valeurs distinctes en une seule requete pour des raisons de perf
Query q =
sessionHibernate.getSession().createQuery(
"select "
+ distinct
+ ", count(*), min(c.id) from "
// On ne recherche pas le type du composant afin
// d'optimiser la requ�te car la recherche
// est d�j� faite par le type de la m�trique.
+ AbstractComponentBO.class.getName() + " c" + from
+ " where (c.project.id =" + pProjectId + ")" + where
+ " group by " + distinct );
results = q.list();
}
catch ( HibernateException e )
{
throw new JrafDaoException( e );
}
return results;
}
/**
* Permet de r�cup�rer la note en fonction d'un audit
*
* @param pSession session Hiebrnate
* @param pComponentID identifiant du composant
* @param pAuditID identifiant de l'audit
* @param pTreClass classe du TRE
* @return une mesure ou <code>null</code>
* @throws JrafDaoException exception DAO
*/
public MeasureBO load( ISession pSession, Long pComponentID, Long pAuditID, Class pTreClass )
throws JrafDaoException
{
String whereClause = "where ";
whereClause += getAlias() + ".component.id = '" + pComponentID + "'";
whereClause += " and ";
whereClause += getAlias() + ".audit.id = '" + pAuditID + "'";
MeasureBO measure = null;
LOG.trace( "whereClause : " + whereClause );
int index = pTreClass.getName().lastIndexOf( "." );
String className = pTreClass.getName().substring( index + 1 );
String requete = "from " + className + " as " + getAlias() + " " + whereClause;
Collection col = find( pSession, requete );
if ( col.size() >= 1 )
{
measure = (MeasureBO) col.iterator().next();
if ( col.size() > 1 )
{
String tab[] = { pAuditID.toString(), pComponentID.toString(), pTreClass.getName() };
LOG.warn( DAOMessages.getString( "measure.many.audit_component_tr", tab ) );
}
}
return measure;
}
/**
* R�cup�ration des mesures sur un audit
*
* @param pSession session Hiebrnate
* @param pComponentID identifiant du composant
* @param pAuditID identifiant de l'audit
* @return ensemble des mesures � l'exclusion des transgressions
* @throws JrafDaoException exception DAO
*/
public Collection findWhere( ISession pSession, Long pComponentID, Long pAuditID )
throws JrafDaoException
{
String whereClause = "where ";
whereClause += getAlias() + ".component.id = '" + pComponentID + "'";
whereClause += " and ";
whereClause += getAlias() + ".audit.id = '" + pAuditID + "'";
// Un nom de subclass correspondant � une transgression doit finir par 'Transgression'
// TODO : Il faudra s�rement consid�rer les transgressions comme des mesures � part...
whereClause += " and " + getAlias() + ".class not like '%Transgression'";
MeasureBO measure = null;
LOG.trace( "whereClause : " + whereClause );
Collection col = findWhere( pSession, whereClause );
return col;
}
/**
* Retourne toutes les mesures des composants d�rivant du parent et dont le type est sp�cifi�
*
* @param pSession session hibernate
* @param pParentComponentID identifiant du composant parent
* @param pAuditID identifiant de l'audit
* @return ensemble des mesures des composants d�rivant du parent sauf les transgressions
* @throws JrafDaoException exception DAO
*/
public Collection findWhereParent( ISession pSession, Long pParentComponentID, Long pAuditID, String pType )
throws JrafDaoException
{
String whereClause = "where ";
whereClause += getAlias() + ".component.parent.id=?";
whereClause += " and " + getAlias() + ".audit.id =?";
whereClause += " and " + getAlias() + ".class = '" + pType + "'";
Object[] values = { pParentComponentID, pAuditID };
Type[] types = { Hibernate.LONG, Hibernate.LONG };
LOG.trace( "findWhereParent: " + whereClause );
Collection col = findWhere( pSession, whereClause, values, types );
return col;
}
/**
* @see org.squale.jraf.spi.persistence.IPersistenceDAO#create(org.squale.jraf.spi.persistence.ISession,
* java.lang.Object)
* @deprecated utiliser create (cette methode ne fait aucun test d'int�grit�)
*/
public void create( ISession pSession, Object pObj )
throws JrafDaoException
{
String message = DAOMessages.getString( "dao.forbiden_method" );
LOG.warn( message );
throw new JrafDaoException( message );
}
/**
* @see org.squale.jraf.spi.persistence.IPersistenceDAO#save(org.squale.jraf.spi.persistence.ISession,
* java.lang.Object)
* @deprecated utiliser saveAll (cette methode ne fait aucun test d'int�grit�)
*/
public void save( ISession pSession, Object pObj )
throws JrafDaoException
{
String message = DAOMessages.getString( "dao.forbiden_method" );
LOG.warn( message );
throw new JrafDaoException( message );
}
/**
* @param pSession la session
* @param pApplicationId l'id de l'application dont on veut le ROI. Si il est � "-1" alors on veut le r�sultat pour
* toutes les applications
* @param pStart la date du premier audit � r�cup�rer
* @return la liste des mesures de ROI pour une application (ou toutes les applications) r�alis�es � partir de
* <code>pStart</code>
* @throws JrafDaoException si erreur
*/
public Collection getRoiMeasures( ISession pSession, long pApplicationId, Date pStart )
throws JrafDaoException
{
String date = DAOUtils.makeQueryDate( pStart );
String whereClause = " where ";
whereClause += getAlias() + ".class='Roi'";
whereClause += " and ";
whereClause += getAlias() + ".audit.date >= " + date;
whereClause += " and ";
whereClause += "(" + getAlias() + ".audit.historicalDate is null";
whereClause += " or ";
whereClause += getAlias() + ".audit.historicalDate >= " + date + ")";
if ( -1 != pApplicationId )
{
// Si on veut les r�sultats que pour une application
whereClause += " and ";
whereClause += getAlias() + ".component.id=" + pApplicationId;
}
whereClause += " order by " + getAlias() + " .audit.date asc";
LOG.info( "Mesures ROI : " + whereClause );
return findWhere( pSession, whereClause );
}
}