/*
* Copyright 2000-2013 Enonic AS
* http://www.enonic.com/license
*/
package com.enonic.cms.core.content;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.joda.time.DateTime;
import com.enonic.cms.core.content.resultset.RelatedChildContent;
import com.enonic.cms.core.content.resultset.RelatedContent;
import com.enonic.cms.core.content.resultset.RelatedContentResultSetImpl;
import com.enonic.cms.core.content.resultset.RelatedParentContent;
import com.enonic.cms.core.portal.livetrace.RelatedContentFetchTrace;
import com.enonic.cms.core.portal.livetrace.RelatedContentFetchTracer;
import com.enonic.cms.core.security.group.GroupKey;
import com.enonic.cms.store.dao.ContentDao;
import com.enonic.cms.store.dao.RelatedChildContentQuery;
public abstract class AbstractRelatedContentFetcher
{
protected final ContentDao contentDao;
protected Integer maxChildrenLevel;
protected RelatedContentResultSetImpl relatedContentResultSet;
private boolean includeOfflineContent;
protected Collection<GroupKey> securityFilter;
protected Date availableCheckDate;
private Map<ContentVersionKey, RelatedContent> relatedContentByVersionKey = new HashMap<ContentVersionKey, RelatedContent>();
private Map<ContentKey, RelatedParentContent> relatedParentContentByContentKey = new HashMap<ContentKey, RelatedParentContent>();
protected Set<ContentKey> visitedParentRelatedContent = new HashSet<ContentKey>();
protected Set<ContentKey> visitedChildRelatedContent = new HashSet<ContentKey>();
protected final RelatedContentFetchTrace trace;
protected AbstractRelatedContentFetcher( ContentDao contentDao, final RelatedContentFetchTrace trace )
{
this.contentDao = contentDao;
this.trace = trace;
}
public void setMaxChildrenLevel( Integer value )
{
maxChildrenLevel = value;
}
public void setSecurityFilter( Collection<GroupKey> securityFilter )
{
this.securityFilter = securityFilter;
}
public void setAvailableCheckDate( Date value )
{
availableCheckDate = value;
}
public void setIncludeOfflineContent( boolean value )
{
includeOfflineContent = value;
}
public boolean includeOfflineContent()
{
return includeOfflineContent;
}
public Integer getMaxChildrenLevel()
{
return maxChildrenLevel;
}
protected Collection<RelatedChildContent> doFindRelatedChildren( Collection<ContentVersionEntity> versions )
{
// new code:
// if ( versions.size() == 0 )
// {
// return new ArrayList<RelatedChildContent>();
// }
//
// List<RelatedChildContent> relatedChildContents = new ArrayList<RelatedChildContent>();
// for ( ContentVersionEntity version : versions )
// {
// // TODO: alternative: version.getRelatedChildren( false ) faster?
// for ( ContentKey relatedChildKey : version.getContentData().resolveRelatedContentKeys() )
// {
// ContentEntity relatedChild = contentDao.findByKey( relatedChildKey );
// if ( !relatedChild.isDeleted() )
// {
// relatedChildContents.add( new RelatedChildContent( version.getKey(), relatedChild ) );
// }
// }
// }
// // TODO: needs to be sorted on createdAt?
// return relatedChildContents;
if ( versions.size() == 0 )
{
return new ArrayList<RelatedChildContent>();
}
// TODO: This logic could probably be rewritten to resolve RelatedChildContents from version.getContentData instead,
// this would probably performfaster too, since we then would be using the entity cache instead to retrieve the related content.
final List<ContentVersionKey> versionKeys = ContentVersionKey.createList( versions );
RelatedChildContentQuery relatedChildContentQuery = new RelatedChildContentQuery();
relatedChildContentQuery.contentVersions( versionKeys );
relatedChildContentQuery.now( new DateTime( availableCheckDate ) );
relatedChildContentQuery.includeOfflineContent( includeOfflineContent() );
relatedChildContentQuery.securityFilter( securityFilter );
return contentDao.findRelatedChildrenByKeys( relatedChildContentQuery );
}
protected List<RelatedChildContent> doAddAndFetchChildren( final Collection<RelatedChildContent> children, final int level,
boolean includeVisited )
{
final int nextLevel = level - 1;
final boolean atLastLevel = nextLevel == 0;
final List<RelatedChildContent> addedRelatedContent = new ArrayList<RelatedChildContent>();
final List<ContentEntity> addedContent = new ArrayList<ContentEntity>();
for ( RelatedChildContent relatedToAdd : children )
{
if ( isAddable( relatedToAdd, includeVisited ) )
{
addedRelatedContent.add( relatedToAdd );
addedContent.add( relatedToAdd.getContent() );
relatedContentResultSet.add( relatedToAdd );
registerForFastAccess( relatedToAdd );
// connect the related content to the other related content it belong to
doConnectRelatedContent( relatedToAdd );
}
visitedChildRelatedContent.add( relatedToAdd.getContent().getKey() );
}
// fetch more children...
if ( !atLastLevel )
{
final Collection<RelatedChildContent> nextLevelChildren =
doFindRelatedChildren( gatherMainVersionsFromContent( addedContent ) );
RelatedContentFetchTracer.traceChildrenFetch( level, nextLevelChildren.size(), trace );
if ( nextLevelChildren.size() > 0 )
{
doAddAndFetchChildren( nextLevelChildren, nextLevel, includeVisited );
}
}
return addedRelatedContent;
}
protected abstract boolean isAddable( RelatedContent relatedToAdd, boolean includeVisited );
protected void registerForFastAccess( RelatedChildContent relatedChildContent )
{
relatedContentByVersionKey.put( relatedChildContent.getContent().getMainVersion().getKey(), relatedChildContent );
}
protected void registerForFastAccess( RelatedParentContent relatedParentContent )
{
relatedContentByVersionKey.put( relatedParentContent.getParentMainVersionKey(), relatedParentContent );
relatedParentContentByContentKey.put( relatedParentContent.getContent().getKey(), relatedParentContent );
}
protected void doConnectRelatedContent( RelatedChildContent relatedContent )
{
RelatedContent parent = relatedContentByVersionKey.get( relatedContent.getParentVersionKey() );
if ( parent != null )
{
parent.addRelatedChild( relatedContent );
}
}
protected void doConnectRelatedContent( RelatedParentContent relatedContent )
{
RelatedParentContent child = relatedParentContentByContentKey.get( relatedContent.getChildContentKey() );
if ( child != null )
{
child.addRelatedParent( relatedContent );
}
}
protected List<ContentVersionEntity> gatherMainVersionsFromContent( final Collection<ContentEntity> contents )
{
final List<ContentVersionEntity> versions = new ArrayList<ContentVersionEntity>( contents.size() );
for ( ContentEntity content : contents )
{
versions.add( content.getMainVersion() );
}
return versions;
}
protected List<ContentKey> gatherContentKeysFromContent( final Collection<ContentEntity> contents )
{
final List<ContentKey> keys = new ArrayList<ContentKey>( contents.size() );
for ( ContentEntity content : contents )
{
keys.add( content.getKey() );
}
return keys;
}
}