/**
* 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.applicationcomponent.administration.sharedrepository;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.squale.jraf.commons.exception.JrafEnterpriseException;
import org.squale.jraf.commons.exception.JrafException;
import org.squale.jraf.commons.exception.JrafPersistenceException;
import org.squale.jraf.helper.PersistenceHelper;
import org.squale.jraf.provider.accessdelegate.DefaultExecuteComponent;
import org.squale.jraf.spi.persistence.IPersistenceProvider;
import org.squale.jraf.spi.persistence.ISession;
import org.squale.sharedrepository.export.SegmentEx;
import org.squale.sharedrepository.segmentref.Label;
import org.squale.sharedrepository.segmentref.SegmentCategoryRef;
import org.squale.sharedrepository.segmentref.SegmentRef;
import org.squale.sharedrepository.segmentref.SegmentsReference;
import org.squale.sharedrepository.stat.ComponentStat;
import org.squale.sharedrepository.stat.DataStat;
import org.squale.sharedrepository.stat.ModuleStat;
import org.squale.sharedrepository.stat.RepositoryStat;
import org.squale.sharedrepository.stat.SegmentationStat;
import org.squale.sharedrepository.stat.Statistic;
import org.squale.squalecommon.datatransfertobject.config.SqualeParamsDTO;
import org.squale.squalecommon.datatransfertobject.message.MessageDTO;
import org.squale.squalecommon.datatransfertobject.sharedrepository.SegmentationDTO;
import org.squale.squalecommon.datatransfertobject.sharedrepository.SharedRepoStatsDTO;
import org.squale.squalecommon.datatransfertobject.sharedrepository.segment.SegmentCategoryDTO;
import org.squale.squalecommon.datatransfertobject.sharedrepository.segment.SegmentDTO;
import org.squale.squalecommon.enterpriselayer.applicationcomponent.ACMessages;
import org.squale.squalecommon.enterpriselayer.businessobject.config.SqualeParamsBO.SqualeParams;
import org.squale.squalecommon.enterpriselayer.facade.config.SqualeParamsFacade;
import org.squale.squalecommon.enterpriselayer.facade.message.MessageFacade;
import org.squale.squalecommon.enterpriselayer.facade.sharedrepository.SegmentationFacade;
import org.squale.squalecommon.enterpriselayer.facade.sharedrepository.SharedRepoStatsFacade;
import org.squale.squalecommon.enterpriselayer.facade.sharedrepository.segment.SegmentCategoryFacade;
import org.squale.squalecommon.enterpriselayer.facade.sharedrepository.segment.SegmentFacade;
import org.squale.squalemodel.definition.ElementType;
import org.squale.squalemodel.definition.StatisticType;
import com.thoughtworks.xstream.XStream;
/**
* This class is the component access for all works around the reference import
*/
public class ReferenceImportComponentAccess
extends DefaultExecuteComponent
{
/**
* UID
*/
private static final long serialVersionUID = 3489364847165011361L;
/**
* log
*/
private static final Log LOG = LogFactory.getLog( ReferenceImportComponentAccess.class );
/**
* Persistence provider
*/
private static final IPersistenceProvider PERSISTENTPROVIDER = PersistenceHelper.getPersistenceProvider();
/**
* <p>
* This method is the entry point to import a new reference file in Squale.
* </p>
* <p>
* If the new reference xml file content in the stream given in argument is newer than the one already loaded, or if
* there is no reference already load then this method returns the version of the new reference inserted and the new
* xml file is loaded. <br/>
* Else this method returns null and the reference version previously loaded is keeping.
* </p>
*
* @param is The stream to download
* @param currentReferenceVersion The version of the current reference inserted (null if there is no reference
* already inserted)
* @return the version number of the reference file if this one is newer than the one already loaded, else it
* returns null
* @throws JrafEnterpriseException Exception occurs during the import
*/
public Integer importReference( InputStream is, Integer currentReferenceVersion )
throws JrafEnterpriseException
{
RepositoryStat reference = xmlToObj( is );
Integer newRefrenceVersion = null;
if ( currentReferenceVersion == null || currentReferenceVersion.intValue() < reference.getVersion() )
{
// Update the segment reference
updateSegmentsReference( reference );
// Remove previous stats reference
removeReference();
// Insert the new stat reference
addReference( reference );
// Update the reference version number
updateVersion( reference.getVersion() );
newRefrenceVersion = Integer.valueOf( reference.getVersion() );
}
return newRefrenceVersion;
}
/**
* This method create or update the segments reference
*
* @param reference the new reference
* @throws JrafEnterpriseException Exception occurs during the update
*/
private void updateSegmentsReference( RepositoryStat reference )
throws JrafEnterpriseException
{
ISession session;
try
{
session = PERSISTENTPROVIDER.getSession();
session.beginTransaction();
HashMap<Long, Long> mapCategory = createMapCategory( session );
SegmentsReference ref = reference.getSegmentReference();
List<MessageDTO> messageList = new ArrayList<MessageDTO>();
// for each segment category of the reference file
for ( SegmentCategoryRef catRef : ref.getCategoryList() )
{
boolean newCategory = true;
SegmentCategoryDTO category =
new SegmentCategoryDTO( catRef.getKeyName(), catRef.getCatId(), catRef.getType(),
catRef.isDeprecated() );
messageList.addAll( messageToAdd( category.getFullKey(), catRef.getLabelList() ) );
// We search if the segment category already exist in the database. If yes the method updates it, else
// the method creates it
if ( mapCategory.containsKey( catRef.getCatId() ) )
{
category.setTechnicalId( mapCategory.get( catRef.getCatId() ) );
newCategory = false;
}
// The method saves or updates the category
SegmentCategoryFacade.saveOrUpdate( session, category );
HashMap<Long, Long> mapSegment = new HashMap<Long, Long>();
if ( !newCategory )
{
mapSegment = createMapSegment( session, category );
}
// For each segment of the category the method tests if the segment already exist. If yes, we update it
// else we create it
List<SegmentDTO> segmentDtoToUpdate = new ArrayList<SegmentDTO>();
for ( SegmentRef segRef : catRef.getSegmentList() )
{
SegmentDTO seg =
new SegmentDTO( segRef.getKeyName(), segRef.getSegmentId(), segRef.isDeprecated(), category );
messageList.addAll( messageToAdd( seg.getFullKey(), segRef.getLabelList() ) );
if ( mapSegment.containsKey( segRef.getSegmentId() ) )
{
seg.setTechnicalId( mapSegment.get( segRef.getSegmentId() ) );
}
segmentDtoToUpdate.add( seg );
}
// The method execute the update
SegmentFacade.saveOrUpdateForACategory( session, segmentDtoToUpdate );
}
MessageFacade.importSegmentMessage( session, messageList );
session.commitTransaction();
}
catch ( JrafPersistenceException e )
{
String message = ACMessages.getString( "ac.exception.generic.retrieveHibernateSession" );
LOG.error( message, e );
throw new JrafEnterpriseException( message, e );
}
}
/**
* This methods creates a list of MessageDTO for each label of a category
*
* @param keyName The key name
* @param labelList The list of label ( one per language ) for the category
* @return The list of messageDTO for the category
* @throws JrafEnterpriseException Exception launched when labeList is empty
*/
private List<MessageDTO> messageToAdd( String keyName, List<Label> labelList )
throws JrafEnterpriseException
{
List<MessageDTO> messageList = new ArrayList<MessageDTO>();
MessageDTO message;
if ( labelList != null && labelList.size() > 0 )
{
for ( Label label : labelList )
{
message = new MessageDTO();
message.setKey( keyName );
message.setLang( label.getLang() );
message.setText( label.getLabel() );
messageList.add( message );
}
}
else
{
String msg = ACMessages.getString( "ac.exception.reference.import.segment.nolabel" );
LOG.error( msg );
throw new JrafEnterpriseException( msg );
}
return messageList;
}
/**
* This method create a map. Each entry of the map represents a segment category. The key is the identifier of the
* category and the value is the technical id of the segment category
*
* @param session The hibernate session
* @return A map category identifier <=> category technical id
* @throws JrafEnterpriseException Exception occurs during the creation of the map
*/
private HashMap<Long, Long> createMapCategory( ISession session )
throws JrafEnterpriseException
{
HashMap<Long, Long> mapCatIdentifierTechnicalId = new HashMap<Long, Long>();
mapCatIdentifierTechnicalId = SegmentCategoryFacade.getAllIdentifier( session );
return mapCatIdentifierTechnicalId;
}
/**
* This method create a map. This map contains the list of segment for a category. Each entry of the map represents
* a segment. The key is the identifier of the segment and the value is the technical id of the segment
*
* @param session The hibernate session
* @param category The parent category
* @return The segment identifier <=> segment technical id for a category
* @throws JrafEnterpriseException exception occurs during the search
*/
private HashMap<Long, Long> createMapSegment( ISession session, SegmentCategoryDTO category )
throws JrafEnterpriseException
{
HashMap<Long, Long> mapSegIdentifierTechnicalId = new HashMap<Long, Long>();
mapSegIdentifierTechnicalId =
SegmentFacade.getSegmentIdentifierTechnicalIdForACategory( session, category.getTechnicalId() );
return mapSegIdentifierTechnicalId;
}
/**
* This method parses an xml file (InpuStream) and 'transform' the data into java objects
*
* @param is The stream which contains the xml file to parse
* @return Return a tree object which represents the xml file
* @throws JrafEnterpriseException Exception launch during the close of the InputStream
*/
private RepositoryStat xmlToObj( InputStream is )
throws JrafEnterpriseException
{
RepositoryStat reference = null;
try
{
XStream xstream = new XStream();
xstream.processAnnotations( RepositoryStat.class );
reference = (RepositoryStat) xstream.fromXML( is );
is.close();
}
catch ( IOException e )
{
String message = ACMessages.getString( "ac.exception.reference.import.fileinputstream" );
throw new JrafEnterpriseException( message, e );
}
return reference;
}
/**
* This method removes the reference already load in Squale
*
* @throws JrafEnterpriseException A problem occurs during the work with the database
*/
private void removeReference()
throws JrafEnterpriseException
{
ISession session;
try
{
session = PERSISTENTPROVIDER.getSession();
/*
* This method remove all the segmentation. By cascade the stats and the segmentation_tag linked to the
* segmentation are also remove
*/
SegmentationFacade.removeAll( session );
}
catch ( JrafPersistenceException e )
{
String message = ACMessages.getString( "ac.exception.generic.retrieveHibernateSession" );
LOG.error( message, e );
throw new JrafEnterpriseException( message, e );
}
}
/**
* This method insert a new reference in the database
*
* @param reference The new reference to insert
* @throws JrafEnterpriseException Exception occurs during the insert of the new reference
*/
private void addReference( RepositoryStat reference )
throws JrafEnterpriseException
{
ISession session = null;
try
{
session = PERSISTENTPROVIDER.getSession();
session.beginTransaction();
List<SegmentationStat> segmentationList = reference.getSegmentationList();
if ( segmentationList != null )
{
for ( SegmentationStat segmentationStat : segmentationList )
{
// For each segmentation of the reference we create the segmentation in the database.
SegmentationDTO segmentation = new SegmentationDTO();
for ( SegmentEx segmentEx : segmentationStat.getSegmentIdList() )
{
SegmentDTO segmentDto = new SegmentDTO( segmentEx.getSegmentId() );
segmentation.addSegment( segmentDto );
}
SegmentationFacade.create( session, segmentation );
// For this segmentation we create the statistic at the module Level
ModuleStat moduleStat = segmentationStat.getModule();
String elementType = ElementType.MODULE.toString();
List<SharedRepoStatsDTO> statsList =
createStatList( moduleStat.getDatas(), elementType, segmentation );
// For this segmentation we create the statistic at the component level (class, method, ...)
List<ComponentStat> componentStatList = segmentationStat.getComponents();
for ( ComponentStat componentStat : componentStatList )
{
elementType = ElementType.valueOf( componentStat.getType() ).toString();
statsList.addAll( createStatList( componentStat.getDatas(), elementType, segmentation ) );
}
SharedRepoStatsFacade.saveAll( session, statsList );
}
}
session.commitTransaction();
}
catch ( JrafException e )
{
if ( session != null )
{
session.rollbackTransaction();
}
String message = ACMessages.getString( "ac.exception.generic.retrieveHibernateSession" );
LOG.error( message, e );
throw new JrafEnterpriseException( message, e );
}
}
/**
* This method create the list of statistic for one element type (module, class, method, ...)
*
* @param dataList The list of statistic for the current element type
* @param elementType The type of element
* @param segmentation The current segmentation
* @return a list of stats to add to the segmentation
*/
private List<SharedRepoStatsDTO> createStatList( List<DataStat> dataList, String elementType,
SegmentationDTO segmentation )
{
List<SharedRepoStatsDTO> statsDtoList = new ArrayList<SharedRepoStatsDTO>();
for ( DataStat dataStat : dataList )
{
// For each data type we create its stats list
SharedRepoStatsDTO statDto =
new SharedRepoStatsDTO( elementType, dataStat.getType(), dataStat.getGenericName(),
dataStat.getLanguage(), segmentation );
List<Statistic> statsList = dataStat.getStatList();
for ( Statistic statistic : statsList )
{
addStat( statDto, statistic );
}
statsDtoList.add( statDto );
}
return statsDtoList;
}
/**
* This method fills the statistic dto object given in argument with the statistic informations provide by the
* statistic object The statistic object come from the parse of the xml reference file
*
* @param statDto The statistic dto object to fill
* @param statistic The statistic object which provide the statistic informations
*/
private void addStat( SharedRepoStatsDTO statDto, Statistic statistic )
{
// According to the statistic type, the method fills the right fields in the statistics dto
if ( statistic.getStatName().equals( StatisticType.MEAN.toString() ) )
{
float value = Float.parseFloat( statistic.getStatValue() );
statDto.setMean( value );
}
else if ( statistic.getStatName().equals( StatisticType.MAX.toString() ) )
{
float value = Float.parseFloat( statistic.getStatValue() );
statDto.setMax( value );
}
else if ( statistic.getStatName().equals( StatisticType.MIN.toString() ) )
{
float value = Float.parseFloat( statistic.getStatValue() );
statDto.setMin( value );
}
else if ( statistic.getStatName().equals( StatisticType.DEVIATION.toString() ) )
{
float value = Float.parseFloat( statistic.getStatValue() );
statDto.setDeviation( value );
}
else if ( statistic.getStatName().equals( StatisticType.ELEMENTS.toString() ) )
{
int value = Integer.parseInt( statistic.getStatValue() );
statDto.setElements( value );
}
}
/**
* This method updates the reference version inserted in the database. The version parameters is updated with the
* version number given in argument
*
* @param version The new version
* @throws JrafEnterpriseException Problem occurs with the database
*/
private void updateVersion( int version )
throws JrafEnterpriseException
{
ISession session;
try
{
session = PERSISTENTPROVIDER.getSession();
SqualeParamsDTO squaleParamDto = new SqualeParamsDTO();
// The method tries to retrieve the squale params for the reference version
squaleParamDto.setSqualeParam( SqualeParams.referenceVersion.toString(), Integer.toString( version ) );
SqualeParamsFacade.createOrUpdate( squaleParamDto, session );
}
catch ( JrafPersistenceException e )
{
String message = ACMessages.getString( "ac.exception.generic.retrieveHibernateSession" );
LOG.error( message, e );
throw new JrafEnterpriseException( message, e );
}
}
/**
* This method returns the current version of the reference inserted.
*
* @return the version number of the reference inserted. It returns null if there is no reference already inserted
* @throws JrafEnterpriseException Problems occurs during the retrieve of the version number of the reference
* inserted
*/
public Integer currentReferenceVersion()
throws JrafEnterpriseException
{
Integer recordVersion = null;
ISession session;
try
{
session = PERSISTENTPROVIDER.getSession();
SqualeParamsDTO dto =
SqualeParamsFacade.getSqualeParams( SqualeParams.referenceVersion.toString(), session );
if ( dto != null && dto.getParamValue() != null )
{
recordVersion = Integer.valueOf( dto.getParamValue() );
}
}
catch ( JrafPersistenceException e )
{
String message = ACMessages.getString( "ac.exception.generic.retrieveHibernateSession" );
LOG.error( message, e );
throw new JrafEnterpriseException( message, e );
}
return recordVersion;
}
}