/**
* Copyright (C) 2011 JTalks.org Team
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
package org.jtalks.jcommune.model.dao.hibernate;
import org.hibernate.Query;
import org.hibernate.SessionFactory;
import org.hibernate.criterion.DetachedCriteria;
import org.hibernate.criterion.Projections;
import org.hibernate.criterion.Property;
import org.hibernate.criterion.Restrictions;
import org.joda.time.DateTime;
import org.jtalks.common.model.dao.hibernate.GenericDao;
import org.jtalks.common.model.entity.Branch;
import org.jtalks.common.model.entity.Group;
import org.jtalks.jcommune.model.dao.TopicDao;
import org.jtalks.jcommune.model.dto.PageRequest;
import org.jtalks.jcommune.model.entity.JCUser;
import org.jtalks.jcommune.model.entity.SubscriptionAwareEntity;
import org.jtalks.jcommune.model.entity.Topic;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import java.util.*;
/**
* Hibernate DAO implementation from the {@link Topic}.
*
* @author Pavel Vervenko
* @author Kirill Afonin
* @author Vitaliy Kravchenko
* @author Eugeny Batov
* @author Anuar Nurmakanov
*/
public class TopicHibernateDao extends GenericDao<Topic> implements TopicDao {
private static final String BRANCH = "branch";
private static final String MAX_MOD_DATE = "maxModDate";
private static final String GROUP_IDS = "groupIds";
private static final String UNCHECKED = "unchecked";
/**
* @param sessionFactory The SessionFactory.
*/
public TopicHibernateDao(SessionFactory sessionFactory) {
super(sessionFactory, Topic.class);
}
/**
* {@inheritDoc}
*/
@Override
public Page<Topic> getTopicsUpdatedSince(DateTime timeStamp, PageRequest pageRequest, JCUser user) {
if (!user.isAnonymous()) {
return getRecentTopicsByGroupIds(getGroupIds(user), timeStamp, pageRequest);
}
return getRecentTopicsForAnonymousUser(timeStamp, pageRequest);
}
/**
* {@inheritDoc}
*/
@Override
public Page<Topic> getUnansweredTopics(PageRequest pageRequest, JCUser user) {
if (!user.isAnonymous()) {
return getUnansweredTopicsByGroupIds(getGroupIds(user), pageRequest);
}
return getUnansweredTopicsForAnonymousUser(pageRequest);
}
/**
* Return group ids for select branches with VIEW_TOPICS permission
*
* @param user current user
* @return group ids
*/
private List<String> getGroupIds(JCUser user) {
List<Group> groups = user.getGroups();
List<String> groupIds = new ArrayList<String>();
for (Group g : groups) {
groupIds.add(g.getId() + "");
}
return groupIds;
}
/**
* Return unanswered topics with VIEW_TOPICS permission by group ids
*
* @param groupIds group ids
* @param pageRequest ontains information for pagination: page number, page size
* @return unanswered topics
*/
private PageImpl<Topic> getUnansweredTopicsByGroupIds(List<String> groupIds, PageRequest pageRequest) {
if (!groupIds.isEmpty()) {
Query query = session().getNamedQuery("getCountUnansweredTopicsByGroups");
query.setParameterList(GROUP_IDS, groupIds);
Number totalCount = (Number) query.uniqueResult();
pageRequest.adjustPageNumber(totalCount.intValue());
query = session().getNamedQuery("getUnansweredTopicsByGroups");
query.setParameterList(GROUP_IDS, groupIds);
query.setFirstResult(pageRequest.getOffset()).setMaxResults(pageRequest.getPageSize());
@SuppressWarnings(UNCHECKED)
List<Topic> unansweredTopics = (List<Topic>) query.list();
return new PageImpl<Topic>(unansweredTopics, pageRequest, totalCount.intValue());
}
return new PageImpl<Topic>(new ArrayList<Topic>(), pageRequest, 0);
}
/**
* Return unanswered topics with VIEW_TOPICS permission for anonymous user
*
* @param pageRequest ontains information for pagination: page number, page size
* @return unanswered topics
*/
private PageImpl<Topic> getUnansweredTopicsForAnonymousUser(PageRequest pageRequest) {
Query query = session().getNamedQuery("getCountUnansweredTopicsForAnonymousUser");
Number totalCount = (Number) query.uniqueResult();
pageRequest.adjustPageNumber(totalCount.intValue());
query = session().getNamedQuery("getUnansweredTopicsForAnonymousUser");
query.setFirstResult(pageRequest.getOffset()).setMaxResults(pageRequest.getPageSize());
@SuppressWarnings(UNCHECKED)
List<Topic> unansweredTopics = (List<Topic>) query.list();
return new PageImpl<Topic>(unansweredTopics, pageRequest, totalCount.intValue());
}
/**
* Return recent topics with VIEW_TOPICS permission by group ids
*
* @param groupIds group ids
* @param timeStamp user's last login date and time
* @param pageRequest ontains information for pagination: page number, page size
* @return recent topics
*/
private PageImpl<Topic> getRecentTopicsByGroupIds(List<String> groupIds, DateTime timeStamp,
PageRequest pageRequest) {
if (!groupIds.isEmpty()) {
Query query = session().getNamedQuery("getCountRecentTopicsByGroups");
query.setParameter(MAX_MOD_DATE, timeStamp);
query.setParameterList(GROUP_IDS, groupIds);
Number totalCount = (Number) query.uniqueResult();
pageRequest.adjustPageNumber(totalCount.intValue());
query = session().getNamedQuery("getRecentTopicsByGroups");
query.setParameter(MAX_MOD_DATE, timeStamp);
query.setParameterList(GROUP_IDS, groupIds);
query.setFirstResult(pageRequest.getOffset()).setMaxResults(pageRequest.getPageSize());
@SuppressWarnings(UNCHECKED)
List<Topic> recentTopics = (List<Topic>) query.list();
return new PageImpl<Topic>(recentTopics, pageRequest, totalCount.intValue());
}
return new PageImpl<Topic>(new ArrayList<Topic>(), pageRequest, 0);
}
/**
* Return recent topics with VIEW_TOPICS permission for anonymous user
*
* @param timeStamp user's last login date and time
* @param pageRequest ontains information for pagination: page number, page size
* @return recent topics
*/
private PageImpl<Topic> getRecentTopicsForAnonymousUser(DateTime timeStamp, PageRequest pageRequest) {
Query query = session().getNamedQuery("getCountRecentTopicsForAnonymousUser");
query.setParameter(MAX_MOD_DATE, timeStamp);
Number totalCount = (Number) query.uniqueResult();
pageRequest.adjustPageNumber(totalCount.intValue());
query = session().getNamedQuery("getRecentTopicsForAnonymousUser");
query.setParameter(MAX_MOD_DATE, timeStamp);
query.setFirstResult(pageRequest.getOffset()).setMaxResults(pageRequest.getPageSize());
@SuppressWarnings(UNCHECKED)
List<Topic> recentTopics = (List<Topic>) query.list();
return new PageImpl<Topic>(recentTopics, pageRequest, totalCount.intValue());
}
/**
* {@inheritDoc}
*/
@Override
public Topic getLastUpdatedTopicInBranch(Branch branch) {
//find the last topic in the branch
String modificationDateProperty = "modificationDate";
DetachedCriteria topicMaxModificationDateCriteria =
DetachedCriteria.forClass(Topic.class)
.setProjection(Projections.max(modificationDateProperty))
.add(Restrictions.eq(BRANCH, branch));
//possible that the two topics will be modified at the same time
@SuppressWarnings(UNCHECKED)
List<Topic> topics = (List<Topic>) session()
.createCriteria(Topic.class)
.add(Restrictions.eq(BRANCH, branch))
.add(Property.forName(modificationDateProperty).eq(topicMaxModificationDateCriteria))
.list();
return topics.isEmpty() ? null : topics.get(0);
}
/**
* {@inheritDoc}
*/
@Override
public Page<Topic> getTopics(Branch branch, PageRequest pageRequest) {
int totalCount = countTopics(branch);
Query query = session().getNamedQuery("getTopicsInBranch")
.setParameter(BRANCH, branch);
pageRequest.adjustPageNumber(totalCount);
query = query.setFirstResult(pageRequest.getOffset())
.setMaxResults(pageRequest.getPageSize());
@SuppressWarnings(UNCHECKED)
List<Topic> topics = (List<Topic>) query.list();
return new PageImpl<Topic>(topics, pageRequest, totalCount);
}
/**
* {@inheritDoc}
*/
@Override
public int countTopics(Branch branch) {
Number count = (Number) session()
.getNamedQuery("getCountTopicsInBranch")
.setParameter(BRANCH, branch)
.uniqueResult();
return count.intValue();
}
/**
* {@inheritDoc}
*/
@Override
public Collection<JCUser> getAllowedSubscribers(SubscriptionAwareEntity entity) {
// use set for remove duplicates
@SuppressWarnings("unchecked")
Set<JCUser> foundUsers = new HashSet<JCUser>(session()
.getNamedQuery("getAllowedSubscribersForTopic")
.setParameter("topic", entity)
.list());
return foundUsers;
}
/**
* {@inheritDoc}
*/
@Override
public List<Long> getForbiddenBranchesIds(JCUser user) {
Query query = session().getNamedQuery("getForbiddenBranchesIds");
if (user.isAnonymous()) {
query.setString("sid", user.getClass().getSimpleName());
} else {
query.setParameterList("sid", getGroupIds(user));
}
return query.list();
}
/**
* {@inheritDoc}
*/
@Override
public List<Long> getAllowedBranchesIds(JCUser user) {
List<Long> result = new ArrayList<>();
Query queryForbidden = session().getNamedQuery("getForbiddenBranchesIds");
Query queryAllowed = session().getNamedQuery("getAllowedBranchesIds");
if (user.isAnonymous()) {
queryForbidden.setString("sid", user.getClass().getSimpleName());
queryAllowed.setString("sid", user.getClass().getSimpleName());
} else {
queryForbidden.setParameterList("sid", getGroupIds(user));
queryAllowed.setParameterList("sid", getGroupIds(user));
}
List<Long> forbidden = queryForbidden.list();
List<Long> allowed = queryAllowed.list();
for (Long aLong : allowed) {
if (!forbidden.contains(aLong)) {
result.add(aLong);
}
}
return result;
}
}