/*
* Copyright 2000-2013 Enonic AS
* http://www.enonic.com/license
*/
package com.enonic.cms.store.dao;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import org.hibernate.Query;
import org.hibernate.Session;
import com.enonic.cms.framework.hibernate.support.InClauseBuilder;
import com.enonic.cms.framework.hibernate.support.SelectBuilder;
import com.enonic.cms.core.content.ContentEntity;
import com.enonic.cms.core.content.ContentKey;
import com.enonic.cms.core.structure.menuitem.section.SectionContentEntity;
class FindContentByKeysQuerier
{
public static final int EAGER_FETCH_NUMBER_OF_SECTIONS_THRESHOLD = 10;
public static final int MAXIMUM_NUMBER_OF_PARAMETER_MARKERS = 1000;
private Session hibernateSession;
private ContentEagerFetches contentEagerFetches;
private boolean fetchEntitiesAsReadOnly = true;
FindContentByKeysQuerier( final Session hibernateSession, final ContentEagerFetches contentEagerFetches,
final boolean fetchEntitiesAsReadOnly )
{
this.hibernateSession = hibernateSession;
this.contentEagerFetches = contentEagerFetches;
this.fetchEntitiesAsReadOnly = fetchEntitiesAsReadOnly;
}
List<ContentEntity> queryContent( final Collection<ContentKey> contentKeys )
{
if ( contentKeys.size() <= MAXIMUM_NUMBER_OF_PARAMETER_MARKERS )
{
return queryContentPart( contentKeys );
}
else
{
List<ContentEntity> result = new ArrayList<ContentEntity>( contentKeys.size() );
final int numberOfBatches = (contentKeys.size() - 1) / MAXIMUM_NUMBER_OF_PARAMETER_MARKERS + 1;
ArrayList<List<ContentKey>> batches = new ArrayList<List<ContentKey>>( numberOfBatches );
for ( int i = 0; i < numberOfBatches; i++ )
{
batches.add(new ArrayList<ContentKey>( MAXIMUM_NUMBER_OF_PARAMETER_MARKERS ));
}
int i = 0, batchNumber;
for ( ContentKey key : contentKeys )
{
batchNumber = i / MAXIMUM_NUMBER_OF_PARAMETER_MARKERS;
batches.get( batchNumber ).add( key );
i++;
}
for (List<ContentKey> batch : batches ){
result.addAll(queryContentPart( batch ));
}
return result;
}
}
private List<ContentEntity> queryContentPart( final Collection<ContentKey> contentKeys )
{
if (contentKeys.size() == 0) {
return new ArrayList<ContentEntity>( );
}
final SelectBuilder hqlQuery = new SelectBuilder( 0 );
hqlQuery.addSelect( "c" );
hqlQuery.addFromTable( ContentEntity.class.getName(), "c", SelectBuilder.NO_JOIN, null );
if ( eagerFetchingIsSafe( contentKeys ) )
{
if ( contentEagerFetches.hasTable( ContentEagerFetches.Table.ACCESS ) )
{
hqlQuery.addFromTable( "c.contentAccessRights", null, SelectBuilder.LEFT_JOIN_FETCH, null );
}
if ( contentEagerFetches.hasTable( ContentEagerFetches.Table.MAIN_VERSION ) )
{
hqlQuery.addFromTable( "c.mainVersion", null, SelectBuilder.LEFT_JOIN_FETCH, null );
}
if ( contentEagerFetches.hasTable( ContentEagerFetches.Table.SECTION_CONTENT ) )
{
hqlQuery.addFromTable( "c.sectionContents", null, SelectBuilder.LEFT_JOIN_FETCH, null );
}
if ( contentEagerFetches.hasTable( ContentEagerFetches.Table.DIRECT_MENUITEM_PLACEMENT ) )
{
hqlQuery.addFromTable( "c.directMenuItemPlacements", null, SelectBuilder.LEFT_JOIN_FETCH, null );
}
if ( contentEagerFetches.hasTable( ContentEagerFetches.Table.CONTENT_HOME ) )
{
hqlQuery.addFromTable( "c.contentHomes", null, SelectBuilder.LEFT_JOIN_FETCH, null );
}
}
hqlQuery.addFilter( "AND", new InClauseBuilder<ContentKey>( "c.key", contentKeys )
{
public void appendValue( StringBuffer sql, ContentKey value )
{
sql.append( value.toString() );
}
}.toString() );
final Query compiled = hibernateSession.createQuery( hqlQuery.toString() );
compiled.setReadOnly( fetchEntitiesAsReadOnly );
compiled.setCacheable( false );
//noinspection unchecked
return compiled.list();
}
private boolean eagerFetchingIsSafe( final Collection<ContentKey> contentKeys )
{
if ( !contentEagerFetches.hasTable( ContentEagerFetches.Table.SECTION_CONTENT ) )
{
return true;
}
final SelectBuilder hqlQuery = new SelectBuilder( 0 );
hqlQuery.addSelect( "count(*)" );
hqlQuery.addFromTable( SectionContentEntity.class.getName(), "sc", SelectBuilder.NO_JOIN, null );
hqlQuery.addFilter( "AND", ( new InClauseBuilder<ContentKey>( "sc.content.key", contentKeys )
{
@Override
public void appendValue( StringBuffer sql, ContentKey value )
{
sql.append( value.toString() );
}
}.toString() ) );
final Query compiled = hibernateSession.createQuery( hqlQuery.toString() );
compiled.setCacheable( false );
compiled.setReadOnly( true );
int count = ( (Number) compiled.uniqueResult() ).intValue();
return count <= ( EAGER_FETCH_NUMBER_OF_SECTIONS_THRESHOLD * contentKeys.size() );
}
}