/** * */ package net.frontlinesms.data.repository.hibernate; import java.util.List; import org.hibernate.criterion.DetachedCriteria; import org.hibernate.criterion.Projections; import org.hibernate.criterion.Restrictions; import org.springframework.dao.support.DataAccessUtils; import org.springframework.transaction.annotation.Transactional; import net.frontlinesms.data.DuplicateKeyException; import net.frontlinesms.data.Order; import net.frontlinesms.data.domain.Contact; import net.frontlinesms.data.domain.Group; import net.frontlinesms.data.domain.GroupMembership; import net.frontlinesms.data.domain.Contact.Field; import net.frontlinesms.data.repository.GroupMembershipDao; /** * @author aga */ public class HibernateGroupMembershipDao extends BaseHibernateDao<GroupMembership> implements GroupMembershipDao { //> CONSTRUCTORS HibernateGroupMembershipDao() { super(GroupMembership.class); } //> DAO METHODS /** @see GroupMembershipDao#addMember(Group, Contact) */ public boolean addMember(Group g, Contact contact) { GroupMembership membership = new GroupMembership(g, contact); try { super.save(membership); return true; } catch (DuplicateKeyException e) { return false; } } /** @see GroupMembershipDao#getActiveMembers(Group) */ public List<Contact> getActiveMembers(Group group) { if(group.isRoot()) { String queryString = "SELECT DISTINCT c FROM Contact AS c WHERE c.active=TRUE"; return getList(Contact.class, queryString); } else { String queryString = "SELECT DISTINCT mem.contact FROM GroupMembership AS mem, Contact AS c WHERE c.active=TRUE AND (mem.group=? OR mem.group.path LIKE ?)"; String childPath = group.getPath() + Group.PATH_SEPARATOR + "%"; return getList(Contact.class, queryString, group, childPath); } } /** @see GroupMembershipDao#getGroups(Contact) */ public List<Group> getGroups(Contact contact) { String queryString = "SELECT mem.group FROM GroupMembership AS mem WHERE mem.contact=?"; return getList(Group.class, queryString, contact); } /** @see GroupMembershipDao#getMemberCount(Group) */ public int getMemberCount(Group group) { if(group.isRoot()) { DetachedCriteria crit = DetachedCriteria.forClass(Contact.class); crit.setProjection(Projections.rowCount()); return DataAccessUtils.intResult(this.getHibernateTemplate().findByCriteria(crit)); } else { String childPath = group.getPath() + Group.PATH_SEPARATOR + "%"; String queryString = "SELECT COUNT(DISTINCT mem.contact) " + "FROM GroupMembership AS mem WHERE mem.group=? OR mem.group.path LIKE ?"; return super.getCount(queryString, group, childPath); } } /** @see GroupMembershipDao#getMembers(Group) */ public List<Contact> getMembers(Group group) { if(group.isRoot()) { return getList(Contact.class, DetachedCriteria.forClass(Contact.class)); } else { String childPath = group.getPath() + Group.PATH_SEPARATOR + "%"; String queryString = "SELECT DISTINCT mem.contact FROM GroupMembership AS mem WHERE mem.group=? OR mem.group.path LIKE ?"; return getList(Contact.class, queryString, new Object[]{group, childPath}); } } /** @see GroupMembershipDao#getFilteredMembers(Group, String) */ public List<Contact> getFilteredMembers(final Group group, String contactFilterString, int startIndex, int limit) { // TODO this is quite an ugly way of doing limits List<Contact> filteredMembers = getFilteredMembers(group, contactFilterString); int toIndex = Math.min(filteredMembers.size(), startIndex + limit); return filteredMembers.subList(startIndex, toIndex); } /** @see GroupMembershipDao#getFilteredMembers(Group, String) */ public List<Contact> getFilteredMembers(final Group group, String contactFilterString) { contactFilterString = getMemberFilterLikeString(contactFilterString); if(group.isRoot()) { String queryString = "SELECT DISTINCT c FROM Contact AS c WHERE LOWER(c.name) LIKE LOWER(?) OR LOWER(c.phoneNumber) LIKE LOWER(?)"; return getList(Contact.class, queryString, contactFilterString, contactFilterString); } else { String queryString = "SELECT DISTINCT mem.contact FROM GroupMembership AS mem WHERE " + "(mem.group=? OR mem.group.path LIKE ?)" + " AND (LOWER(mem.contact.name) LIKE LOWER(?) OR LOWER(mem.contact.phoneNumber) LIKE LOWER(?))"; String childPath = group.getPath() + Group.PATH_SEPARATOR + "%"; return getList(Contact.class, queryString, group, childPath, contactFilterString, contactFilterString); } } /** @see GroupMembershipDao#getFilteredMembersSorted(Group, String) */ public List<Contact> getFilteredMembersSorted(final Group group, String contactFilterString, Field sortBy, Order order, int startIndex, int limit) { // TODO this is quite an ugly way of doing limits List<Contact> filteredMembers = getFilteredMembersSorted(group, contactFilterString, sortBy, order); int toIndex = Math.min(filteredMembers.size(), startIndex + limit); return filteredMembers.subList(startIndex, toIndex); } /** @see GroupMembershipDao#getFilteredMembersSorted(Group, String) */ public List<Contact> getFilteredMembersSorted(final Group group, String contactFilterString, Field sortBy, Order order) { contactFilterString = getMemberFilterLikeString(contactFilterString); if (group.isRoot()) { String queryString = "SELECT DISTINCT c FROM Contact AS c WHERE LOWER(c.name) LIKE LOWER(?) OR LOWER(c.phoneNumber) LIKE LOWER(?)"; if (sortBy != null) { String strSortBy = sortBy.getFieldName(); if (sortBy.equals(Field.EMAIL_ADDRESS)) strSortBy += ", " + Field.NAME.getFieldName(); queryString += " ORDER BY " + strSortBy + " " + order.toHqlString(); } return getList(Contact.class, queryString, contactFilterString, contactFilterString); } else { String queryString = "SELECT DISTINCT mem.contact FROM GroupMembership AS mem WHERE " + "(mem.group=? OR mem.group.path LIKE ?)" + " AND (LOWER(mem.contact.name) LIKE LOWER(?) OR LOWER(mem.contact.phoneNumber) LIKE LOWER(?))"; if (sortBy != null) { String strSortBy = sortBy.getFieldName(); if (sortBy.equals(Field.EMAIL_ADDRESS)) strSortBy += ", mem.contact." + Field.NAME.getFieldName(); queryString += " ORDER BY mem.contact." + strSortBy + " " + order.toHqlString(); } String childPath = group.getPath() + Group.PATH_SEPARATOR + "%"; return getList(Contact.class, queryString, group, childPath, contactFilterString, contactFilterString); } } /** @see GroupMembershipDao#getFilteredMemberCount(Group, String) */ public int getFilteredMemberCount(final Group group, String contactFilterString) { contactFilterString = getMemberFilterLikeString(contactFilterString); if(group.isRoot()) { String queryString = "SELECT COUNT(DISTINCT c) FROM Contact AS c WHERE LOWER(c.name) LIKE LOWER(?) OR LOWER(c.phoneNumber) LIKE LOWER(?)"; return super.getCount(queryString, contactFilterString, contactFilterString); } else { String queryString = "SELECT COUNT(DISTINCT mem.contact) FROM GroupMembership AS mem WHERE " + "(mem.group=? OR mem.group.path LIKE ?)" + " AND (LOWER(mem.contact.name) LIKE LOWER(?) OR LOWER(mem.contact.phoneNumber) LIKE LOWER(?))"; String childPath = group.getPath() + Group.PATH_SEPARATOR + "%"; return super.getCount(queryString, group, childPath, contactFilterString, contactFilterString); } } /** @see GroupMembershipDao#getMembers(Group, int, int) */ public List<Contact> getMembers(Group group, int startIndex, int limit) { List<Contact> allMembers = getMembers(group); return allMembers.subList(startIndex, Math.min(allMembers.size(), startIndex + limit)); } /** @see GroupMembershipDao#isMember(Group, Contact) */ public boolean isMember(Group group, Contact contact) { if(group.isRoot()) return true; String childPath = group.getPath() + Group.PATH_SEPARATOR + "%"; String queryString = "SELECT COUNT(*) FROM GroupMembership AS mem WHERE mem.contact=? AND (mem.group=? OR mem.group.path LIKE ?)"; return super.getCount(queryString, contact, group, childPath) > 0; } /** @see GroupMembershipDao#removeMember(Group, Contact) */ @Transactional public boolean removeMember(Group group, Contact contact) { try { DetachedCriteria crit = getMembershipCriteria(group, contact); this.getHibernateTemplate().delete(DataAccessUtils.uniqueResult(this.getList(crit))); return true; } catch(Exception ex) { return false; } } //> PRIVATE HELPER METHODS /** Convert the filterString passed from the UI to {@link #getFilteredMemberCount(Group, String)} * and {@link #getFilteredMembers(Group, String)} to the pattern for matching in the LIKE clause. */ private String getMemberFilterLikeString(String contactFilterString) { if(contactFilterString == null || contactFilterString.length() == 0) { return "%"; } else { return "%" + contactFilterString + "%"; } } /** @return criteria for fetching a {@link GroupMembership} entity */ private DetachedCriteria getMembershipCriteria(Group group, Contact contact) { DetachedCriteria crit = super.getCriterion(); crit.add(Restrictions.eq("contact", contact)); crit.add(Restrictions.eq("group", group)); return crit; } /** * Gets a list of E matching the supplied criteria. * @param criteria * @return a list of Es matching the supplied criteria */ @SuppressWarnings("unchecked") protected <T> List<T> getList(Class<T> entityClass, DetachedCriteria criteria) { return this.getHibernateTemplate().findByCriteria(criteria); } /** * Gets a list of E matching the supplied HQL query. * @param hqlQuery HQL query * @param values values to insert into the HQL query * @return a list of Es matching the supplied query */ @SuppressWarnings("unchecked") protected <T> List<T> getList(Class<T> entityClass, String hqlQuery, Object... values) { return this.getHibernateTemplate().find(hqlQuery, values); } }