/* * Copyright (c) 2009-2010 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.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; import org.eurekastreams.commons.hibernate.ModelViewResultTransformer; import org.eurekastreams.server.domain.EntityType; import org.eurekastreams.server.domain.stream.Activity; import org.eurekastreams.server.domain.stream.ActivityDTO; 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>> { /** * Mapper to get PersonModelView by account id. */ private DomainMapper<String, PersonModelView> getPersonModelViewByAccountIdMapper; /** * Mapper to get PersonModelViews by account ids. */ private DomainMapper<List<String>, List<PersonModelView>> getPersonModelViewsByAccountIdsMapper; /** * Group Mapper. */ private GetDomainGroupsByShortNames groupMapper; /** * DAO for comment id list. */ private DomainMapper<Long, List<Long>> commentIdListDAO; /** * DAO for comments by id. */ private 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. */ @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(Projections.property("recipientParentOrg.id").as("recipientParentOrgId")); 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()); } } if (activity.getActor().getType() == EntityType.PERSON) { List<String> peopleIds = new ArrayList<String>(); peopleIds.add(activity.getActor().getUniqueIdentifier()); List<PersonModelView> people = getPersonModelViewsByAccountIdsMapper.execute(peopleIds); if (people.size() > 0) { activity.getActor().setId(people.get(0).getEntityId()); activity.getActor().setDisplayName(people.get(0).getDisplayName()); activity.getActor().setAvatarId(people.get(0).getAvatarId()); } } else if (activity.getActor().getType() == EntityType.GROUP) { List<String> groupIds = new ArrayList<String>(); groupIds.add(activity.getActor().getUniqueIdentifier()); List<DomainGroupModelView> groups = groupMapper.execute(groupIds); if (groups.size() > 0) { activity.getActor().setId(groups.get(0).getEntityId()); activity.getActor().setDisplayName(groups.get(0).getName()); activity.getActor().setAvatarId(groups.get(0).getAvatarId()); } } // fills in data from cached view of original actor if (activity.getOriginalActor().getType() == EntityType.PERSON) { List<String> peopleIds = new ArrayList<String>(); peopleIds.add(activity.getOriginalActor().getUniqueIdentifier()); List<PersonModelView> people = getPersonModelViewsByAccountIdsMapper.execute(peopleIds); if (people.size() > 0) { activity.getOriginalActor().setId(people.get(0).getEntityId()); activity.getOriginalActor().setDisplayName(people.get(0).getDisplayName()); activity.getOriginalActor().setAvatarId(people.get(0).getAvatarId()); } } 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 = this.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)); } } }