/* * Copyright (c) 2009-2011 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.persistence.mappers.stream; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; import org.apache.commons.logging.Log; import org.eurekastreams.commons.hibernate.ModelViewResultTransformer; import org.eurekastreams.commons.logging.LogFactory; import org.eurekastreams.server.domain.EntityType; import org.eurekastreams.server.domain.dto.StreamDTO; import org.eurekastreams.server.domain.stream.Activity; import org.eurekastreams.server.domain.stream.ActivityDTO; import org.eurekastreams.server.domain.stream.StreamEntityDTO; import org.eurekastreams.server.persistence.mappers.BaseArgDomainMapper; import org.eurekastreams.server.persistence.mappers.DomainMapper; import org.eurekastreams.server.search.factories.ActivityDTOFactory; import org.eurekastreams.server.search.modelview.CommentDTO; import org.eurekastreams.server.search.modelview.DomainGroupModelView; import org.eurekastreams.server.search.modelview.PersonModelView; import org.hibernate.Criteria; import org.hibernate.criterion.ProjectionList; import org.hibernate.criterion.Projections; import org.hibernate.criterion.Restrictions; /** * Gets a list of ActivityDTO objects for a given list of activity ids. */ public class BulkActivitiesDbMapper extends BaseArgDomainMapper<List<Long>, List<ActivityDTO>> implements DomainMapper<List<Long>, List<ActivityDTO>> { /** * Local logger instance. */ private final Log logger = LogFactory.make(); /** * Mapper to get PersonModelView by account id. */ private final DomainMapper<String, PersonModelView> getPersonModelViewByAccountIdMapper; /** * Mapper to get PersonModelViews by account ids. */ private final DomainMapper<List<String>, List<PersonModelView>> getPersonModelViewsByAccountIdsMapper; /** * Group Mapper. */ private final GetDomainGroupsByShortNames groupMapper; /** * DAO for comment id list. */ private final DomainMapper<Long, List<Long>> commentIdListDAO; /** * DAO for comments by id. */ private final DomainMapper<List<Long>, List<CommentDTO>> commentsByIdDAO; /** * @param inGetPersonModelViewByAccountIdMapper * Mapper to get single PersonModelView by account id. * @param inGetPersonModelViewsByAccountIdsMapper * Mapper to get multiple PersonModelViews by account ids. * @param inGroupMapper * mapper to get domain groups by short name * @param inCommentIdListDAO * comment ID list DAO. * @param inCommentsByIdDAO * comments by ID DAO. */ public BulkActivitiesDbMapper(final DomainMapper<String, PersonModelView> inGetPersonModelViewByAccountIdMapper, final DomainMapper<List<String>, List<PersonModelView>> inGetPersonModelViewsByAccountIdsMapper, final GetDomainGroupsByShortNames inGroupMapper, final DomainMapper<Long, List<Long>> inCommentIdListDAO, final DomainMapper<List<Long>, List<CommentDTO>> inCommentsByIdDAO) { getPersonModelViewByAccountIdMapper = inGetPersonModelViewByAccountIdMapper; getPersonModelViewsByAccountIdsMapper = inGetPersonModelViewsByAccountIdsMapper; groupMapper = inGroupMapper; commentIdListDAO = inCommentIdListDAO; commentsByIdDAO = inCommentsByIdDAO; } /** * Looks in cache for the necessary activity DTOs and returns them if found. Otherwise, makes a database call, puts * them in cache, and returns them. * * @param activityIds * the list of ids that should be found. * @return list of ActivityDTO objects. */ @Override @SuppressWarnings("unchecked") public List<ActivityDTO> execute(final List<Long> activityIds) { Criteria criteria = getHibernateSession().createCriteria(Activity.class); ProjectionList fields = Projections.projectionList(); fields.add(getColumn("id")); fields.add(getColumn("verb")); fields.add(getColumn("baseObjectType")); fields.add(Projections.property("baseObject").as("baseObjectProperties")); fields.add(Projections.property("recipStreamScope.destinationEntityId").as("destinationStreamEntityId")); fields.add(Projections.property("recipStreamScope.id").as("destinationStreamScopeId")); fields.add(Projections.property("recipStreamScope.scopeType").as("destinationStreamScopeType")); fields.add(Projections.property("recipStreamScope.uniqueKey").as("destinationStreamUniqueKey")); fields.add(getColumn("isDestinationStreamPublic")); fields.add(getColumn("actorType")); fields.add(getColumn("originalActorType")); fields.add(Projections.property("actorId").as("actorUniqueIdentifier")); fields.add(Projections.property("originalActorId").as("originalActorUniqueIdentifier")); fields.add(getColumn("postedTime")); fields.add(getColumn("mood")); fields.add(getColumn("location")); fields.add(getColumn("annotation")); fields.add(getColumn("appId")); fields.add(getColumn("appSource")); fields.add(getColumn("appName")); fields.add(getColumn("showInStream")); criteria.createAlias("recipientStreamScope", "recipStreamScope"); criteria.setProjection(fields); criteria.add(Restrictions.in("this.id", activityIds)); final Map<Long, ActivityDTO> activityMap = new HashMap<Long, ActivityDTO>(); ModelViewResultTransformer<ActivityDTO> resultTransformer = new ModelViewResultTransformer<ActivityDTO>( new ActivityDTOFactory()); criteria.setResultTransformer(resultTransformer); List<ActivityDTO> results = criteria.list(); for (ActivityDTO activity : results) { activityMap.put(activity.getId(), activity); // fills in data from cached view of stream List<Long> streamIds = new ArrayList<Long>(); streamIds.add(activity.getDestinationStream().getId()); // get the display name for the destination stream if (activity.getDestinationStream().getUniqueIdentifier() != null) { if (activity.getDestinationStream().getType() == EntityType.PERSON) { PersonModelView person = getPersonModelViewByAccountIdMapper.execute(activity .getDestinationStream().getUniqueIdentifier()); activity.getDestinationStream().setDisplayName(person.getDisplayName()); } else if (activity.getDestinationStream().getType() == EntityType.GROUP) { DomainGroupModelView group = groupMapper.fetchUniqueResult(activity.getDestinationStream() .getUniqueIdentifier()); activity.getDestinationStream().setDisplayName(group.getName()); } } final StreamEntityDTO actor = activity.getActor(); if (actor.getType() == EntityType.PERSON) { List<PersonModelView> people = getPersonModelViewsByAccountIdsMapper.execute(Collections .singletonList(actor.getUniqueIdentifier())); if (!people.isEmpty()) { final PersonModelView person = people.get(0); actor.setId(person.getEntityId()); actor.setDestinationEntityId(person.getEntityId()); actor.setDisplayName(person.getDisplayName()); actor.setAvatarId(person.getAvatarId()); } } else if (actor.getType() == EntityType.GROUP) { List<DomainGroupModelView> groups = groupMapper.execute(Collections.singletonList(actor .getUniqueIdentifier())); if (!groups.isEmpty()) { final DomainGroupModelView group = groups.get(0); actor.setId(group.getEntityId()); actor.setDestinationEntityId(group.getEntityId()); actor.setDisplayName(group.getName()); actor.setAvatarId(group.getAvatarId()); } } // fills in data from cached view of original actor final StreamEntityDTO originalActor = activity.getOriginalActor(); if (originalActor != null) { StreamDTO originalActorStreamDTO = null; if (originalActor.getType() == EntityType.PERSON) { List<PersonModelView> people = getPersonModelViewsByAccountIdsMapper.execute(Collections .singletonList(originalActor.getUniqueIdentifier())); if (!people.isEmpty()) { originalActorStreamDTO = people.get(0); } } if (originalActor.getType() == EntityType.GROUP) { List<DomainGroupModelView> oagroups = groupMapper.execute(Collections.singletonList(originalActor .getUniqueIdentifier())); if (!oagroups.isEmpty()) { originalActorStreamDTO = oagroups.get(0); } } if (originalActorStreamDTO != null) { originalActor.setId(originalActorStreamDTO.getEntityId()); originalActor.setDestinationEntityId(originalActorStreamDTO.getEntityId()); originalActor.setDisplayName(originalActorStreamDTO.getDisplayName()); originalActor.setAvatarId(originalActorStreamDTO.getAvatarId()); } else { // this is to prevent JSON serializer from dying on a nulled out StreamEntityDTO. activity.setOriginalActor(null); // log this out so we don't just swallow problem. logger.warn("Nulled out originalActor value for activity " + activity.getId() + ". Could not find values for uniqueId: " + originalActor.getUniqueIdentifier() + " type: " + originalActor.getType()); } } loadCommentInfo(activity); // set the first/last comment and comment count. } final List<ActivityDTO> orderedResults = new LinkedList<ActivityDTO>(); for (int i = 0; i < activityIds.size(); i++) { if (activityMap.containsKey(activityIds.get(i))) { orderedResults.add(activityMap.get(activityIds.get(i))); } } return orderedResults; } /** * Load the first/last comments of an activity if present, also sets the comment count. * * @param activity * ActivityDTO to load comment info for. */ private void loadCommentInfo(final ActivityDTO activity) { List<Long> commentIds = commentIdListDAO.execute(activity.getId()); int numOfComments = commentIds.size(); activity.setCommentCount(numOfComments); // short circuit if nothing to do. if (numOfComments == 0) { return; } // get the ids for the first and last comments. ArrayList<Long> firstLastCommentIds = new ArrayList<Long>(); firstLastCommentIds.add(commentIds.get(0)); if (numOfComments > 1) { firstLastCommentIds.add(commentIds.get(commentIds.size() - 1)); } // get the commentDTOs. List<CommentDTO> firstLastCommentDTOs = commentsByIdDAO.execute(firstLastCommentIds); // make sure we got what we asked for. if (firstLastCommentDTOs.size() != firstLastCommentIds.size()) { throw new RuntimeException("Error loading first/last comments for Activity: " + activity.getId()); } // set the commentDTOs in the activity appropriately. activity.setFirstComment(firstLastCommentDTOs.get(0)); if (firstLastCommentDTOs.size() > 1) { activity.setLastComment(firstLastCommentDTOs.get(1)); } } }