/*
* 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;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import javax.persistence.FlushModeType;
import javax.persistence.Query;
import org.eurekastreams.commons.hibernate.QueryOptimizer;
import org.eurekastreams.server.domain.DomainGroup;
import org.eurekastreams.server.domain.Followable;
import org.eurekastreams.server.domain.GroupFollower;
import org.eurekastreams.server.domain.PagedSet;
import org.eurekastreams.server.domain.Person;
import org.eurekastreams.server.persistence.strategies.DescendantOrganizationStrategy;
/**
* This class provides the mapper functionality for DomainGroup entities.
*/
@Deprecated
public class DomainGroupMapper extends DomainEntityMapper<DomainGroup> implements FollowMapper, CompositeEntityMapper
{
/**
* Constructor.
*
* @param inQueryOptimizer
* the QueryOptimizer to use for specialized functions.
*/
public DomainGroupMapper(final QueryOptimizer inQueryOptimizer)
{
super(inQueryOptimizer);
}
/**
* The descendant organization strategy.
*/
private DescendantOrganizationStrategy descendantOrgStrategy;
/**
* Set the DescendantOrgStrategy.
*
* @param inDescendantOrgStrategy
* the descendantOrgStrategy to set
*/
public void setDescendantOrgStrategy(final DescendantOrganizationStrategy inDescendantOrgStrategy)
{
descendantOrgStrategy = inDescendantOrgStrategy;
}
/**
* Get the descendant organization strategy.
*
* @return the descendantOrgStrategy the descendant org strategy
*/
protected DescendantOrganizationStrategy getDescendantOrgStrategy()
{
if (descendantOrgStrategy == null)
{
throw new NullPointerException("descendantOrgStrategy is null - make sure to set it on JpaPersonMapper.");
}
return descendantOrgStrategy;
}
/**
* Look up a group by its short name.
*
* @param groupShortName
* the short name of a group to look for
* @return the DomainGroup corresponding to the provided short name
*/
@SuppressWarnings("unchecked")
public DomainGroup findByShortName(final String groupShortName)
{
Query q = getEntityManager().createQuery("from DomainGroup where shortname = :inName").setParameter("inName",
groupShortName.toLowerCase()).setFlushMode(FlushModeType.COMMIT);
List results = q.getResultList();
return (results.size() == 0) ? null : (DomainGroup) results.get(0);
}
/**
* @return the entity's type
*/
@Override
protected String getDomainEntityName()
{
return "DomainGroup";
}
/**
* Creates a follower/following relationship between two entities.
*
* @param followerId
* The id of the follower Person
* @param followingId
* The entity id being Followed.
*/
public void addFollower(final long followerId, final long followingId)
{
Query q = getEntityManager().createQuery(
"FROM GroupFollower where followerId=:followerId and followingId=:followingId").setParameter(
"followerId", followerId).setParameter("followingId", followingId);
if (q.getResultList().size() > 0)
{
// already following
return;
}
// Shift down the groupstreamindex of the existing followed groups
getEntityManager().createQuery(
"update GroupFollower set groupstreamindex = groupstreamindex + 1 where followerId=:followerId")
.setParameter("followerId", followerId).executeUpdate();
// add follower, groupstreamindex defaults to 0
getEntityManager().persist(new GroupFollower(followerId, followingId));
// now update the counts for persons.
getEntityManager().createQuery(
"update versioned Person set groupsCount = followingGroup.size,"
+ " groupStreamHiddenLineIndex = groupStreamHiddenLineIndex + 1 where id=:followerId")
.setParameter("followerId", followerId).executeUpdate();
getEntityManager().createQuery(
"update versioned DomainGroup set followersCount = followers.size where id=:followingId").setParameter(
"followingId", followingId).executeUpdate();
getEntityManager().flush();
getEntityManager().clear();
DomainGroup followingEntity = findById(followingId);
// reindex the following in the search index
getFullTextSession().index(followingEntity);
}
/**
* Returns a set of People following the specified DomainGroup.
*
* @param shortName
* The shortName of the DomainGroup for whom to get followers.
* @param start
* paging start.
* @param end
* paging end.
* @return paged set of followers.
*/
public PagedSet<Person> getFollowers(final String shortName, final int start, final int end)
{
HashMap<String, Object> parameters = new HashMap<String, Object>();
parameters.put("shortName", shortName.toLowerCase());
String query = "select g.followers from DomainGroup g where g.shortName = :shortName";
// although the line above is just concatenating a query string
// and this implies vulnerability to SQL injection attacks,
// the call to this.getPagedResults() actually parameterizes the SQL
// so there is not actually risk of SQL injection here.
PagedSet<Person> results = getTypedPagedResults(start, end, query, parameters);
return results;
}
/**
* Returns a set of DomainGroups that are being followed by the specified person.
*
* @param accountId
* The id of the DomainGroup for whom to get following.
* @param start
* paging start.
* @param end
* paging end.
* @return paged set of following.
*/
public PagedSet<Followable> getFollowing(final String accountId, final int start, final int end)
{
HashMap<String, Object> parameters = new HashMap<String, Object>();
parameters.put("accountId", accountId);
String query = "select p.followingGroup from Person p where p.accountId = :accountId";
// although the line above is just concatenating a query string
// and this implies vulnerability to SQL injection attacks,
// the call to this.getPagedResults() actually parameterizes the SQL
// so there is not actually risk of SQL injection here.
PagedSet<Followable> results = getTypedPagedResults(start, end, query, parameters);
return results;
}
/**
* Returns true if follower/following relationship exists false otherwise.
*
* @param followerAccountId
* The follower person's account Id.
* @param shortName
* The short name of the group being followed
* @return True if follower/following relationship exists false otherwise.
*/
@SuppressWarnings("unchecked")
public boolean isFollowing(final String followerAccountId, final String shortName)
{
Query q = getEntityManager().createQuery(
"FROM Person as follower" + " inner join follower.followingGroup as following"
+ " where follower.accountId=:followerAccountId and"
+ " following.shortName=:followingShortName").setParameter("followerAccountId",
followerAccountId).setParameter("followingShortName", shortName.toLowerCase());
List<Person> results = q.getResultList();
return (results.size() != 0);
}
/**
* Removes a follower/following relationship between a Person and a DomainGroup.
*
* @param followerId
* The if of the follower Person
* @param followingId
* The group id being Followed.
*/
public void removeFollower(final long followerId, final long followingId)
{
// Shift up the groupstreamindex of the remaining followed groups
getEntityManager().createQuery(// \n
"update GroupFollower gf1 set gf1.groupStreamIndex = gf1.groupStreamIndex - 1 "// \n
+ "where gf1.groupStreamIndex > " // \n
+ "(select gf2.groupStreamIndex from GroupFollower gf2 " // \n
+ "where gf2.pk.followerId=gf1.pk.followerId and gf2.pk.followingId=:followingId)" // \n
+ "AND gf1.pk.followerId=:followerId") // \n
.setParameter("followerId", followerId).setParameter("followingId", followingId).executeUpdate();
int rowsDeleted = getEntityManager().createQuery(
"DELETE FROM GroupFollower where followerId=:followerId and followingId=:followingId").setParameter(
"followerId", followerId).setParameter("followingId", followingId).executeUpdate();
if (rowsDeleted == 0)
{
// not following, short circuit.
return;
}
// now update the counts for persons.
getEntityManager().createQuery(
"update versioned Person set groupsCount = followingGroup.size where id=:followerId").setParameter(
"followerId", followerId).executeUpdate();
getEntityManager().createQuery(
"update versioned DomainGroup set followersCount = followers.size where id=:followingId").setParameter(
"followingId", followingId).executeUpdate();
getEntityManager().flush();
getEntityManager().clear();
DomainGroup followingEntity = findById(followingId);
// reindex the following in the search index
getFullTextSession().index(followingEntity);
}
/**
* Get a String representation the Person.id of all of the Person.ids for coordinators and followers of the input
* group.
*
* @param domainGroup
* the DomainGroup to find coordinators and followers for
* @return an array of all of the Person.ids for coordinators and followers of the input group
*/
@SuppressWarnings("unchecked")
public Long[] getFollowerAndCoordinatorPersonIds(final DomainGroup domainGroup)
{
// use a set to eliminate duplicates
HashSet<Long> peopleIds = new HashSet<Long>();
Query q = getEntityManager().createQuery("SELECT pk.followerId FROM GroupFollower WHERE followingId=:groupId")
.setParameter("groupId", domainGroup.getId());
peopleIds.addAll(q.getResultList());
q = getEntityManager().createQuery(
"SELECT p.id FROM Person p, DomainGroup g WHERE p MEMBER OF g.coordinators AND g.id=:groupId")
.setParameter("groupId", domainGroup.getId());
peopleIds.addAll(q.getResultList());
return peopleIds.toArray(new Long[peopleIds.size()]);
}
/**
* Delete this group.
*
* @param id
* the id of the group to delete.
*/
public void deleteById(final long id)
{
DomainGroup group = findById(id);
getEntityManager().remove(group);
getEntityManager().flush();
}
}