package fi.otavanopisto.muikku.plugins.communicator.dao;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import javax.persistence.EntityManager;
import javax.persistence.TypedQuery;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Join;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import javax.persistence.criteria.Subquery;
import fi.otavanopisto.muikku.model.base.Tag;
import fi.otavanopisto.muikku.model.users.UserEntity;
import fi.otavanopisto.muikku.plugins.CorePluginsDAO;
import fi.otavanopisto.muikku.plugins.communicator.CommunicatorFolderType;
import fi.otavanopisto.muikku.plugins.communicator.model.CommunicatorLabel;
import fi.otavanopisto.muikku.plugins.communicator.model.CommunicatorMessage;
import fi.otavanopisto.muikku.plugins.communicator.model.CommunicatorMessageCategory;
import fi.otavanopisto.muikku.plugins.communicator.model.CommunicatorMessageId;
import fi.otavanopisto.muikku.plugins.communicator.model.CommunicatorMessageIdLabel;
import fi.otavanopisto.muikku.plugins.communicator.model.CommunicatorMessageIdLabel_;
import fi.otavanopisto.muikku.plugins.communicator.model.CommunicatorMessageRecipient;
import fi.otavanopisto.muikku.plugins.communicator.model.CommunicatorMessageRecipient_;
import fi.otavanopisto.muikku.plugins.communicator.model.CommunicatorMessage_;
public class CommunicatorMessageDAO extends CorePluginsDAO<CommunicatorMessage> {
private static final long serialVersionUID = -8721990589622544635L;
public CommunicatorMessage create(CommunicatorMessageId communicatorMessageId, Long sender,
CommunicatorMessageCategory category, String caption, String content, Date created, Set<Tag> tags) {
CommunicatorMessage msg = new CommunicatorMessage();
int s = tags != null ? tags.size() : 0;
Set<Long> tagIds = new HashSet<Long>(s);
if (tags != null) {
for (Tag t : tags)
tagIds.add(t.getId());
}
msg.setCommunicatorMessageId(communicatorMessageId);
msg.setSender(sender);
msg.setCategory(category);
msg.setCaption(caption);
msg.setContent(content);
msg.setCreated(created);
msg.setTags(tagIds);
msg.setArchivedBySender(false);
msg.setTrashedBySender(false);
getEntityManager().persist(msg);
return msg;
}
private List<CommunicatorThreadBasicInfo> listUserThreadBasicInfos(UserEntity userEntity, CommunicatorFolderType type, CommunicatorLabel label) {
EntityManager entityManager = getEntityManager();
CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
CriteriaQuery<CommunicatorThreadBasicInfo> criteria = criteriaBuilder.createQuery(CommunicatorThreadBasicInfo.class);
switch (type) {
case UNREAD: {
Root<CommunicatorMessageRecipient> root = criteria.from(CommunicatorMessageRecipient.class);
Join<CommunicatorMessageRecipient, CommunicatorMessage> messageJoin = root.join(CommunicatorMessageRecipient_.communicatorMessage);
criteria.multiselect(messageJoin.get(CommunicatorMessage_.communicatorMessageId), criteriaBuilder.greatest(messageJoin.get(CommunicatorMessage_.created)));
criteria.where(
criteriaBuilder.and(
criteriaBuilder.equal(root.get(CommunicatorMessageRecipient_.recipient), userEntity.getId()),
criteriaBuilder.equal(root.get(CommunicatorMessageRecipient_.readByReceiver), Boolean.FALSE),
criteriaBuilder.equal(root.get(CommunicatorMessageRecipient_.trashedByReceiver), Boolean.FALSE),
criteriaBuilder.equal(root.get(CommunicatorMessageRecipient_.archivedByReceiver), Boolean.FALSE)
)
);
criteria.groupBy(messageJoin.get(CommunicatorMessage_.communicatorMessageId));
}
break;
case LABEL: {
Root<CommunicatorMessageRecipient> root = criteria.from(CommunicatorMessageRecipient.class);
Join<CommunicatorMessageRecipient, CommunicatorMessage> messageJoin = root.join(CommunicatorMessageRecipient_.communicatorMessage);
Join<CommunicatorMessage, CommunicatorMessageId> threadJoin = messageJoin.join(CommunicatorMessage_.communicatorMessageId);
criteria.multiselect(messageJoin.get(CommunicatorMessage_.communicatorMessageId), criteriaBuilder.greatest(messageJoin.get(CommunicatorMessage_.created)));
Root<CommunicatorMessageIdLabel> labelRoot = criteria.from(CommunicatorMessageIdLabel.class);
criteria.where(
criteriaBuilder.and(
criteriaBuilder.equal(root.get(CommunicatorMessageRecipient_.recipient), userEntity.getId()),
criteriaBuilder.equal(root.get(CommunicatorMessageRecipient_.trashedByReceiver), Boolean.FALSE),
criteriaBuilder.equal(root.get(CommunicatorMessageRecipient_.archivedByReceiver), Boolean.FALSE),
threadJoin.in(labelRoot.get(CommunicatorMessageIdLabel_.communicatorMessageId)),
criteriaBuilder.equal(labelRoot.get(CommunicatorMessageIdLabel_.label), label)
)
);
criteria.groupBy(messageJoin.get(CommunicatorMessage_.communicatorMessageId));
}
break;
case SENT: {
Root<CommunicatorMessage> root = criteria.from(CommunicatorMessage.class);
criteria.multiselect(root.get(CommunicatorMessage_.communicatorMessageId), criteriaBuilder.greatest(root.get(CommunicatorMessage_.created)));
criteria.where(
criteriaBuilder.and(
criteriaBuilder.equal(root.get(CommunicatorMessage_.sender), userEntity.getId()),
criteriaBuilder.equal(root.get(CommunicatorMessage_.archivedBySender), Boolean.FALSE),
criteriaBuilder.equal(root.get(CommunicatorMessage_.trashedBySender), Boolean.FALSE)
)
);
criteria.groupBy(root.get(CommunicatorMessage_.communicatorMessageId));
}
break;
case INBOX:
case TRASH:
Root<CommunicatorMessageRecipient> root = criteria.from(CommunicatorMessageRecipient.class);
Join<CommunicatorMessageRecipient, CommunicatorMessage> messageJoin = root.join(CommunicatorMessageRecipient_.communicatorMessage);
criteria.multiselect(messageJoin.get(CommunicatorMessage_.communicatorMessageId), criteriaBuilder.greatest(messageJoin.get(CommunicatorMessage_.created)));
criteria.where(
criteriaBuilder.and(
criteriaBuilder.equal(root.get(CommunicatorMessageRecipient_.recipient), userEntity.getId()),
criteriaBuilder.equal(root.get(CommunicatorMessageRecipient_.trashedByReceiver), type == CommunicatorFolderType.TRASH),
criteriaBuilder.equal(root.get(CommunicatorMessageRecipient_.archivedByReceiver), Boolean.FALSE)
)
);
criteria.groupBy(messageJoin.get(CommunicatorMessage_.communicatorMessageId));
break;
}
List<CommunicatorThreadBasicInfo> threads = entityManager.createQuery(criteria).getResultList();
Collections.sort(threads, new Comparator<CommunicatorThreadBasicInfo>() {
@Override
public int compare(CommunicatorThreadBasicInfo o1, CommunicatorThreadBasicInfo o2) {
return o2.getLatestThread().compareTo(o1.getLatestThread());
}
});
return threads;
}
public CommunicatorMessageId findOlderThreadId(UserEntity userEntity, CommunicatorMessageId threadId, CommunicatorFolderType type, CommunicatorLabel label) {
List<CommunicatorThreadBasicInfo> threads = listUserThreadBasicInfos(userEntity, type, label);
int index = 0;
while ((index < threads.size()) && (!Objects.equals(threadId.getId(), threads.get(index).getThreadId().getId()))) {
index++;
}
// Next, older thread
if ((index >= 0) && (index < threads.size() - 1))
return threads.get(index + 1).getThreadId();
else
return null;
}
public CommunicatorMessageId findNewerThreadId(UserEntity userEntity, CommunicatorMessageId threadId, CommunicatorFolderType type, CommunicatorLabel label) {
List<CommunicatorThreadBasicInfo> threads = listUserThreadBasicInfos(userEntity, type, label);
int index = 0;
while ((index < threads.size()) && (!Objects.equals(threadId.getId(), threads.get(index).getThreadId().getId()))) {
index++;
}
// Previous, newer thread
if ((index > 0) && (index < threads.size()))
return threads.get(index - 1).getThreadId();
else
return null;
}
public List<CommunicatorMessage> listThreadsInTrash(UserEntity user, Integer firstResult, Integer maxResults) {
EntityManager entityManager = getEntityManager();
CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
CriteriaQuery<CommunicatorMessage> criteria = criteriaBuilder.createQuery(CommunicatorMessage.class);
Root<CommunicatorMessageRecipient> root = criteria.from(CommunicatorMessageRecipient.class);
Join<CommunicatorMessageRecipient, CommunicatorMessage> messageJoin = root.join(CommunicatorMessageRecipient_.communicatorMessage);
Join<CommunicatorMessage, CommunicatorMessageId> threadJoin = messageJoin.join(CommunicatorMessage_.communicatorMessageId);
// SubQuery finds the latest date in a thread when linked to the main query
// and thus allows finding the latest message in the thread.
Subquery<Date> subQuery = criteria.subquery(Date.class);
Root<CommunicatorMessageRecipient> subQueryRoot = subQuery.from(CommunicatorMessageRecipient.class);
Join<CommunicatorMessageRecipient, CommunicatorMessage> subMessageJoin = subQueryRoot.join(CommunicatorMessageRecipient_.communicatorMessage);
subQuery.select(criteriaBuilder.greatest(subMessageJoin.get(CommunicatorMessage_.created)));
subQuery.where(
criteriaBuilder.and(
criteriaBuilder.equal(subMessageJoin.get(CommunicatorMessage_.communicatorMessageId), messageJoin.get(CommunicatorMessage_.communicatorMessageId)),
criteriaBuilder.or(
criteriaBuilder.and(
criteriaBuilder.equal(subQueryRoot.get(CommunicatorMessageRecipient_.recipient), user.getId()),
criteriaBuilder.equal(subQueryRoot.get(CommunicatorMessageRecipient_.trashedByReceiver), Boolean.TRUE),
criteriaBuilder.equal(subQueryRoot.get(CommunicatorMessageRecipient_.archivedByReceiver), Boolean.FALSE)
),
criteriaBuilder.and(
criteriaBuilder.equal(subMessageJoin.get(CommunicatorMessage_.sender), user.getId()),
criteriaBuilder.equal(subMessageJoin.get(CommunicatorMessage_.trashedBySender), Boolean.TRUE),
criteriaBuilder.equal(subMessageJoin.get(CommunicatorMessage_.archivedBySender), Boolean.FALSE)
)
)
)
);
criteria.select(messageJoin);
criteria.where(
criteriaBuilder.and(
criteriaBuilder.equal(messageJoin.get(CommunicatorMessage_.created), subQuery),
criteriaBuilder.or(
criteriaBuilder.and(
criteriaBuilder.equal(root.get(CommunicatorMessageRecipient_.recipient), user.getId()),
criteriaBuilder.equal(root.get(CommunicatorMessageRecipient_.trashedByReceiver), Boolean.TRUE),
criteriaBuilder.equal(root.get(CommunicatorMessageRecipient_.archivedByReceiver), Boolean.FALSE)
),
criteriaBuilder.and(
criteriaBuilder.equal(messageJoin.get(CommunicatorMessage_.sender), user.getId()),
criteriaBuilder.equal(messageJoin.get(CommunicatorMessage_.trashedBySender), Boolean.TRUE),
criteriaBuilder.equal(messageJoin.get(CommunicatorMessage_.archivedBySender), Boolean.FALSE)
)
)
)
);
criteria.groupBy(threadJoin);
criteria.orderBy(criteriaBuilder.desc(
messageJoin.get(CommunicatorMessage_.created)
));
TypedQuery<CommunicatorMessage> query = entityManager.createQuery(criteria);
query.setFirstResult(firstResult);
query.setMaxResults(maxResults);
return query.getResultList();
}
public List<CommunicatorMessage> listThreadsInInbox(UserEntity recipient, CommunicatorLabel label, boolean onlyUnread, Integer firstResult, Integer maxResults) {
EntityManager entityManager = getEntityManager();
CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
CriteriaQuery<CommunicatorMessage> criteria = criteriaBuilder.createQuery(CommunicatorMessage.class);
Root<CommunicatorMessageRecipient> root = criteria.from(CommunicatorMessageRecipient.class);
Join<CommunicatorMessageRecipient, CommunicatorMessage> messageJoin = root.join(CommunicatorMessageRecipient_.communicatorMessage);
Join<CommunicatorMessage, CommunicatorMessageId> threadJoin = messageJoin.join(CommunicatorMessage_.communicatorMessageId);
criteria.select(messageJoin);
// SubQuery finds the latest date in a thread when linked to the main query
// and thus allows finding the latest message in the thread.
Subquery<Date> subQuery = criteria.subquery(Date.class);
Root<CommunicatorMessageRecipient> subQueryRoot = subQuery.from(CommunicatorMessageRecipient.class);
Join<CommunicatorMessageRecipient, CommunicatorMessage> subMessageJoin = subQueryRoot.join(CommunicatorMessageRecipient_.communicatorMessage);
Join<CommunicatorMessage, CommunicatorMessageId> subThreadJoin = subMessageJoin.join(CommunicatorMessage_.communicatorMessageId);
subQuery.select(criteriaBuilder.greatest(subMessageJoin.get(CommunicatorMessage_.created)));
List<Predicate> subQueryPredicates = new ArrayList<Predicate>();
subQueryPredicates.add(criteriaBuilder.equal(subMessageJoin.get(CommunicatorMessage_.communicatorMessageId), messageJoin.get(CommunicatorMessage_.communicatorMessageId)));
subQueryPredicates.add(criteriaBuilder.equal(subQueryRoot.get(CommunicatorMessageRecipient_.recipient), recipient.getId()));
subQueryPredicates.add(criteriaBuilder.equal(subQueryRoot.get(CommunicatorMessageRecipient_.trashedByReceiver), Boolean.FALSE));
subQueryPredicates.add(criteriaBuilder.equal(subQueryRoot.get(CommunicatorMessageRecipient_.archivedByReceiver), Boolean.FALSE));
if (onlyUnread)
subQueryPredicates.add(criteriaBuilder.equal(subQueryRoot.get(CommunicatorMessageRecipient_.readByReceiver), Boolean.FALSE));
if (label != null) {
Root<CommunicatorMessageIdLabel> subLabelRoot = criteria.from(CommunicatorMessageIdLabel.class);
subQueryPredicates.add(subThreadJoin.in(subLabelRoot.get(CommunicatorMessageIdLabel_.communicatorMessageId)));
subQueryPredicates.add(criteriaBuilder.equal(subLabelRoot.get(CommunicatorMessageIdLabel_.label), label));
}
subQuery.where(criteriaBuilder.and(subQueryPredicates.toArray(new Predicate[0])));
// Main Query
List<Predicate> predicates = new ArrayList<Predicate>();
predicates.add(criteriaBuilder.equal(messageJoin.get(CommunicatorMessage_.created), subQuery));
predicates.add(criteriaBuilder.equal(root.get(CommunicatorMessageRecipient_.recipient), recipient.getId()));
predicates.add(criteriaBuilder.equal(root.get(CommunicatorMessageRecipient_.trashedByReceiver), Boolean.FALSE));
predicates.add(criteriaBuilder.equal(root.get(CommunicatorMessageRecipient_.archivedByReceiver), Boolean.FALSE));
if (onlyUnread)
predicates.add(criteriaBuilder.equal(root.get(CommunicatorMessageRecipient_.readByReceiver), Boolean.FALSE));
if (label != null) {
Root<CommunicatorMessageIdLabel> labelRoot = criteria.from(CommunicatorMessageIdLabel.class);
predicates.add(threadJoin.in(labelRoot.get(CommunicatorMessageIdLabel_.communicatorMessageId)));
predicates.add(criteriaBuilder.equal(labelRoot.get(CommunicatorMessageIdLabel_.label), label));
}
criteria.where(criteriaBuilder.and(predicates.toArray(new Predicate[0])));
criteria.groupBy(threadJoin);
criteria.orderBy(criteriaBuilder.desc(
messageJoin.get(CommunicatorMessage_.created)
));
TypedQuery<CommunicatorMessage> query = entityManager.createQuery(criteria);
query.setFirstResult(firstResult);
query.setMaxResults(maxResults);
return query.getResultList();
}
public List<CommunicatorMessage> listThreadsInSent(UserEntity sender, Integer firstResult, Integer maxResults) {
EntityManager entityManager = getEntityManager();
CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
CriteriaQuery<CommunicatorMessage> criteria = criteriaBuilder.createQuery(CommunicatorMessage.class);
Root<CommunicatorMessage> root = criteria.from(CommunicatorMessage.class);
criteria.select(root);
criteria.where(
criteriaBuilder.and(
criteriaBuilder.equal(root.get(CommunicatorMessage_.sender), sender.getId()),
criteriaBuilder.equal(root.get(CommunicatorMessage_.trashedBySender), Boolean.FALSE),
criteriaBuilder.equal(root.get(CommunicatorMessage_.archivedBySender), Boolean.FALSE)
)
);
criteria.groupBy(root.get(CommunicatorMessage_.communicatorMessageId));
criteria.orderBy(criteriaBuilder.desc(criteriaBuilder.greatest(root.get(CommunicatorMessage_.created))));
TypedQuery<CommunicatorMessage> query = entityManager.createQuery(criteria);
query.setFirstResult(firstResult);
query.setMaxResults(maxResults);
return query.getResultList();
}
public List<CommunicatorMessage> listMessagesInThread(UserEntity user, CommunicatorMessageId communicatorMessageId, boolean trashed, boolean archived) {
EntityManager entityManager = getEntityManager();
CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
CriteriaQuery<CommunicatorMessage> criteria;
Root<CommunicatorMessage> CommunicatorMessage;
criteria = criteriaBuilder.createQuery(CommunicatorMessage.class);
CommunicatorMessage = criteria.from(CommunicatorMessage.class);
Root<CommunicatorMessageRecipient> recipient = criteria.from(CommunicatorMessageRecipient.class);
Join<CommunicatorMessageRecipient, CommunicatorMessage> recipientMessage =
criteriaBuilder.treat(recipient.join(CommunicatorMessageRecipient_.communicatorMessage), CommunicatorMessage.class);
criteria.select(CommunicatorMessage);
criteria.where(
criteriaBuilder.and(
criteriaBuilder.equal(CommunicatorMessage.get(CommunicatorMessage_.id), recipientMessage.get(CommunicatorMessage_.id)),
criteriaBuilder.equal(recipientMessage.get(CommunicatorMessage_.communicatorMessageId), communicatorMessageId),
criteriaBuilder.equal(recipient.get(CommunicatorMessageRecipient_.recipient), user.getId()),
criteriaBuilder.equal(recipient.get(CommunicatorMessageRecipient_.trashedByReceiver), trashed),
criteriaBuilder.equal(recipient.get(CommunicatorMessageRecipient_.archivedByReceiver), archived)
)
);
return entityManager.createQuery(criteria).getResultList();
}
/**
* Returns the number of messages the user can see in a thread in either inbox/sent or in trash
* depending on the value of trashed parameter.
*
* @param user
* @param communicatorMessageId
* @param trashed
* @return
*/
public Long countMessagesByUserAndMessageId(UserEntity user, CommunicatorMessageId communicatorMessageId, boolean trashed) {
EntityManager entityManager = getEntityManager();
CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
CriteriaQuery<Long> criteria = criteriaBuilder.createQuery(Long.class);
Root<CommunicatorMessageRecipient> root = criteria.from(CommunicatorMessageRecipient.class);
Join<CommunicatorMessageRecipient, CommunicatorMessage> msgJoin = root.join(CommunicatorMessageRecipient_.communicatorMessage);
criteria.select(criteriaBuilder.countDistinct(msgJoin));
criteria.where(
criteriaBuilder.or(
criteriaBuilder.and(
criteriaBuilder.equal(msgJoin.get(CommunicatorMessage_.communicatorMessageId), communicatorMessageId),
criteriaBuilder.equal(root.get(CommunicatorMessageRecipient_.recipient), user.getId()),
criteriaBuilder.equal(root.get(CommunicatorMessageRecipient_.trashedByReceiver), trashed),
criteriaBuilder.equal(root.get(CommunicatorMessageRecipient_.archivedByReceiver), Boolean.FALSE)
),
criteriaBuilder.and(
criteriaBuilder.equal(msgJoin.get(CommunicatorMessage_.communicatorMessageId), communicatorMessageId),
criteriaBuilder.equal(msgJoin.get(CommunicatorMessage_.sender), user.getId()),
criteriaBuilder.equal(msgJoin.get(CommunicatorMessage_.trashedBySender), trashed),
criteriaBuilder.equal(msgJoin.get(CommunicatorMessage_.archivedBySender), Boolean.FALSE)
)
)
);
return entityManager.createQuery(criteria).getSingleResult();
}
public List<CommunicatorMessage> listMessagesInSentThread(UserEntity sender, CommunicatorMessageId communicatorMessageId, boolean trashed, boolean archived) {
EntityManager entityManager = getEntityManager();
CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
CriteriaQuery<CommunicatorMessage> criteria = criteriaBuilder.createQuery(CommunicatorMessage.class);
Root<CommunicatorMessage> root = criteria.from(CommunicatorMessage.class);
criteria.select(root);
criteria.where(
criteriaBuilder.and(
criteriaBuilder.equal(root.get(CommunicatorMessage_.communicatorMessageId), communicatorMessageId),
criteriaBuilder.equal(root.get(CommunicatorMessage_.sender), sender.getId()),
criteriaBuilder.equal(root.get(CommunicatorMessage_.trashedBySender), trashed),
criteriaBuilder.equal(root.get(CommunicatorMessage_.archivedBySender), archived)
)
);
return entityManager.createQuery(criteria).getResultList();
}
public CommunicatorMessage updateTrashedBySender(CommunicatorMessage msg, boolean trashed) {
msg.setTrashedBySender(trashed);
getEntityManager().persist(msg);
return msg;
}
public CommunicatorMessage updateArchivedBySender(CommunicatorMessage msg, boolean archived) {
msg.setArchivedBySender(archived);
getEntityManager().persist(msg);
return msg;
}
@Override
public void delete(CommunicatorMessage e) {
super.delete(e);
}
}