/*
* Copyright (c) 2011-2012 Lockheed Martin Corporation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.eurekastreams.server.action.execution;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.apache.commons.logging.Log;
import org.eurekastreams.commons.actions.ExecutionStrategy;
import org.eurekastreams.commons.actions.context.PrincipalActionContext;
import org.eurekastreams.commons.exceptions.ExecutionException;
import org.eurekastreams.commons.logging.LogFactory;
import org.eurekastreams.commons.util.CollectionListAdapter;
import org.eurekastreams.server.domain.EntityType;
import org.eurekastreams.server.domain.Follower.FollowerStatus;
import org.eurekastreams.server.domain.dto.DisplayInfoSettable;
import org.eurekastreams.server.domain.dto.StreamDTO;
import org.eurekastreams.server.domain.dto.StreamDiscoverListsDTO;
import org.eurekastreams.server.domain.strategies.DisplayInfoSettableDataPopulator;
import org.eurekastreams.server.domain.strategies.FollowerStatusPopulator;
import org.eurekastreams.server.persistence.comparators.StreamDTOFollowerCountDescendingComparator;
import org.eurekastreams.server.persistence.mappers.DomainMapper;
import org.eurekastreams.server.persistence.mappers.requests.SuggestedStreamsRequest;
import org.eurekastreams.server.search.modelview.DomainGroupModelView;
import org.eurekastreams.server.search.modelview.PersonModelView;
import edu.emory.mathcs.backport.java.util.Collections;
/**
* Execution strategy to get suggested group and people streams for a user.
*/
public class GetStreamDiscoverListsDTOExecution implements ExecutionStrategy<PrincipalActionContext>
{
/**
* Logger.
*/
private final Log log = LogFactory.make();
/**
* Mapper to get suggested people streams.
*/
private final DomainMapper<SuggestedStreamsRequest, List<PersonModelView>> suggestedPersonMapper;
/**
* Mapper to get suggested group streams.
*/
private final DomainMapper<SuggestedStreamsRequest, List<DomainGroupModelView>> suggestedGroupMapper;
/**
* Mapper to get the stream discovery lists that are the same for everyone.
*/
private final DomainMapper<Serializable, StreamDiscoverListsDTO> streamDiscoveryListsMapper;
/**
* Data populator for setting the DisplayName and avatar id on DisplayInfoSettables.
*/
private final DisplayInfoSettableDataPopulator displayInfoSettableDataPopulator;
/**
* {@link FollowerStatusPopulator}.
*/
private final FollowerStatusPopulator<DisplayInfoSettable> followerStatusPopulator;
/**
* Mapper to get a list of PersonModelViews from a list of AccountIds.
*/
private final DomainMapper<List<Long>, List<PersonModelView>> getPersonModelViewsByIdsDAO;
/**
* The number of stream suggestions to get.
*/
final int suggestionCount;
/**
* Constructor.
*
* @param inSuggestedPersonMapper
* mapper to get suggested people streams
* @param inSuggestedGroupMapper
* mapper to get suggested group streams
* @param inSuggestionCount
* the number of suggested streams to get
* @param inStreamDiscoveryListsMapper
* mapper to get the stream discovery lists that are the same for everyone
* @param inDisplayInfoSettableDataPopulator
* data populator for setting the DisplayName and avatar id on DisplayInfoSettables
* @param inFollowerStatusPopulator
* list of DisplayInfoSettable.
* @param inGetPersonModelViewsByIdsDAO
* Mapper to get a list of PersonModelViews from a list of AccountIds.
*/
public GetStreamDiscoverListsDTOExecution(
final DomainMapper<SuggestedStreamsRequest, List<PersonModelView>> inSuggestedPersonMapper,
final DomainMapper<SuggestedStreamsRequest, List<DomainGroupModelView>> inSuggestedGroupMapper,
final int inSuggestionCount,
final DomainMapper<Serializable, StreamDiscoverListsDTO> inStreamDiscoveryListsMapper,
final DisplayInfoSettableDataPopulator inDisplayInfoSettableDataPopulator,
final FollowerStatusPopulator<DisplayInfoSettable> inFollowerStatusPopulator,
final DomainMapper<List<Long>, List<PersonModelView>> inGetPersonModelViewsByIdsDAO)
{
suggestedPersonMapper = inSuggestedPersonMapper;
suggestedGroupMapper = inSuggestedGroupMapper;
suggestionCount = inSuggestionCount;
streamDiscoveryListsMapper = inStreamDiscoveryListsMapper;
displayInfoSettableDataPopulator = inDisplayInfoSettableDataPopulator;
followerStatusPopulator = inFollowerStatusPopulator;
getPersonModelViewsByIdsDAO = inGetPersonModelViewsByIdsDAO;
}
/**
* Get the StreamDiscoverListsDTO for the current user, which includes data for all users along with suggestions for
* the current user. Integer representing how many suggestions to get
*
* @param inActionContext
* the action context
* @return StreamDiscoverListsDTO representing all of the discover page lists and the featured streams.
* @throws ExecutionException
* (never)
*/
@Override
public Serializable execute(final PrincipalActionContext inActionContext) throws ExecutionException
{
Long personId = inActionContext.getPrincipal().getId();
log.info("BEGIN getting the lists of streams that apply to all users.");
StreamDiscoverListsDTO result = streamDiscoveryListsMapper.execute(null);
log.info("END getting the lists of streams that apply to all users.");
log.info("BEGIN getting the list of suggested streams for user " + personId);
getSuggestionsForPerson(personId, result);
log.info("END getting the list of suggested streams for user " + personId);
// put all of the streams in a single list for transient data population
List<DisplayInfoSettable> displayInfoSettables = new ArrayList<DisplayInfoSettable>();
displayInfoSettables.addAll(result.getFeaturedStreams());
displayInfoSettables.addAll(result.getMostFollowedStreams());
displayInfoSettables.addAll(result.getMostRecentStreams());
displayInfoSettables.addAll(result.getMostViewedStreams());
displayInfoSettables.addAll(result.getSuggestedStreams());
displayInfoSettables.addAll(result.getMostActiveStreams().getResultsSublist());
// determine list of allowed people (not locked/deactivated)
Set<Long> allowedPeople = getAllowedPeopleList(displayInfoSettables);
// remove all unallowed people from lists
filterList(result.getFeaturedStreams(), allowedPeople);
filterList(result.getMostFollowedStreams(), allowedPeople);
filterList(result.getMostRecentStreams(), allowedPeople);
filterList(result.getMostViewedStreams(), allowedPeople);
filterList(result.getSuggestedStreams(), allowedPeople);
int oldCount = result.getMostActiveStreams().getResultsSublist().size();
filterList(result.getMostActiveStreams().getResultsSublist(), allowedPeople);
result.getMostActiveStreams().setTotalResultsCount(
result.getMostActiveStreams().getTotalResultsCount()
- (oldCount - result.getMostActiveStreams().getResultsSublist().size()));
// fill in the avatars and display names of all of the StreamDTOs
log.info("BEGIN setting the display info on " + displayInfoSettables.size()
+ " GroupModelViews and PersonModelViews");
displayInfoSettableDataPopulator.execute(displayInfoSettables);
log.info("END setting the display info on " + displayInfoSettables.size()
+ " GroupModelViews and PersonModelViews");
// Set follower status on all dtos.
log.info("BEGIN setting the follower statuses on " + displayInfoSettables.size()
+ " GroupModelViews and PersonModelViews");
followerStatusPopulator.execute(personId, displayInfoSettables, FollowerStatus.NOTFOLLOWING);
log.info("END setting the follower statuses on " + displayInfoSettables.size()
+ " GroupModelViews and PersonModelViews");
return result;
}
/**
* Get the suggested streams for the current user, and populate them in the input StreamDiscoverListsDTO.
*
* @param inPersonId
* the person id to fetch suggested streams for
* @param inStreamDiscoverLists
* the StreamDiscoverListsDTO to add the results to
*/
private void getSuggestionsForPerson(final Long inPersonId, final StreamDiscoverListsDTO inStreamDiscoverLists)
{
SuggestedStreamsRequest mapperRequest = new SuggestedStreamsRequest(inPersonId, suggestionCount);
ArrayList<StreamDTO> suggestions = new ArrayList<StreamDTO>();
suggestions.addAll(suggestedPersonMapper.execute(mapperRequest));
suggestions.addAll(suggestedGroupMapper.execute(mapperRequest));
// sort the list
Collections.sort(suggestions, new StreamDTOFollowerCountDescendingComparator());
// return those requested
if (suggestions.size() > suggestionCount)
{
suggestions = new ArrayList<StreamDTO>(suggestions.subList(0, suggestionCount));
}
inStreamDiscoverLists.setSuggestedStreams(suggestions);
}
/**
* Given the list of streams, determines which person streams are allowed to be shown.
*
* @param displayInfoSettables
* List of streams.
* @return Which person streams are allowed to be shown.
*/
private Set<Long> getAllowedPeopleList(final List<DisplayInfoSettable> displayInfoSettables)
{
Set<Long> ids = new HashSet<Long>();
for (DisplayInfoSettable ds : displayInfoSettables)
{
if (EntityType.PERSON.equals(ds.getEntityType()))
{
ids.add(ds.getEntityId());
}
}
List<PersonModelView> people = getPersonModelViewsByIdsDAO.execute(new CollectionListAdapter<Long>(ids));
Set<Long> allowedIds = new HashSet<Long>();
for (PersonModelView person : people)
{
if (!person.isAccountLocked())
{
allowedIds.add(person.getId());
}
}
return allowedIds;
}
/**
* Removes any non-allowed people (locked, deactivated) from the list.
*
* @param list
* List to update.
* @param allowedPeople
* IDs of people to allow.
*/
private void filterList(final List< ? extends DisplayInfoSettable> list, final Set<Long> allowedPeople)
{
for (int i = 0; i < list.size(); i++)
{
DisplayInfoSettable item = list.get(i);
if (EntityType.PERSON.equals(item.getEntityType()) && !allowedPeople.contains(item.getEntityId()))
{
list.remove(i);
i--;
}
}
}
}