package fi.otavanopisto.pyramus.dao.users; import java.util.List; import java.util.Set; import javax.ejb.Stateless; import javax.enterprise.event.Event; import javax.inject.Inject; import javax.persistence.EntityManager; import javax.persistence.PersistenceException; import javax.persistence.TypedQuery; import javax.persistence.criteria.CriteriaBuilder; import javax.persistence.criteria.CriteriaQuery; import javax.persistence.criteria.Join; import javax.persistence.criteria.ListJoin; import javax.persistence.criteria.Root; import org.apache.commons.lang.StringUtils; import org.apache.lucene.analysis.standard.StandardAnalyzer; import org.apache.lucene.queryparser.classic.ParseException; import org.apache.lucene.queryparser.classic.QueryParser; import org.apache.lucene.search.MatchAllDocsQuery; import org.apache.lucene.search.Sort; import org.apache.lucene.search.SortField; import org.hibernate.search.jpa.FullTextEntityManager; import org.hibernate.search.jpa.FullTextQuery; import org.hibernate.search.jpa.Search; import fi.otavanopisto.pyramus.dao.DAOFactory; import fi.otavanopisto.pyramus.dao.PyramusEntityDAO; import fi.otavanopisto.pyramus.domainmodel.base.ContactInfo; import fi.otavanopisto.pyramus.domainmodel.base.ContactInfo_; import fi.otavanopisto.pyramus.domainmodel.base.ContactType; import fi.otavanopisto.pyramus.domainmodel.base.ContactType_; import fi.otavanopisto.pyramus.domainmodel.base.Email; import fi.otavanopisto.pyramus.domainmodel.base.Email_; import fi.otavanopisto.pyramus.domainmodel.base.Person; import fi.otavanopisto.pyramus.domainmodel.base.Tag; import fi.otavanopisto.pyramus.domainmodel.users.Role; import fi.otavanopisto.pyramus.domainmodel.users.StaffMember; import fi.otavanopisto.pyramus.domainmodel.users.StaffMember_; import fi.otavanopisto.pyramus.domainmodel.users.User; import fi.otavanopisto.pyramus.domainmodel.users.UserVariable; import fi.otavanopisto.pyramus.domainmodel.users.UserVariableKey; import fi.otavanopisto.pyramus.domainmodel.users.UserVariable_; import fi.otavanopisto.pyramus.domainmodel.users.User_; import fi.otavanopisto.pyramus.events.StaffMemberCreatedEvent; import fi.otavanopisto.pyramus.events.StaffMemberDeletedEvent; import fi.otavanopisto.pyramus.events.StaffMemberUpdatedEvent; import fi.otavanopisto.pyramus.persistence.search.SearchResult; @Stateless public class StaffMemberDAO extends PyramusEntityDAO<StaffMember> { @Inject private Event<StaffMemberCreatedEvent> staffMemberCreatedEvent; @Inject private Event<StaffMemberUpdatedEvent> staffMemberUpdatedEvent; @Inject private Event<StaffMemberDeletedEvent> staffMemberDeletedEvent; public StaffMember create(String firstName, String lastName, Role role, Person person, Boolean archived) { ContactInfo contactInfo = new ContactInfo(); StaffMember staffMember = new StaffMember(); staffMember.setFirstName(firstName); staffMember.setLastName(lastName); staffMember.setRole(role); staffMember.setContactInfo(contactInfo); staffMember.setPerson(person); // TODO: allow archive on StaffMember staffMember.setArchived(archived); persist(staffMember); person.addUser(staffMember); getEntityManager().persist(person); staffMemberCreatedEvent.fire(new StaffMemberCreatedEvent(staffMember.getId())); return staffMember; } public List<StaffMember> listByUserVariable(String key, String value) { UserVariableKeyDAO variableKeyDAO = DAOFactory.getInstance().getUserVariableKeyDAO(); UserVariableKey userVariableKey = variableKeyDAO.findByVariableKey(key); EntityManager entityManager = getEntityManager(); CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder(); CriteriaQuery<StaffMember> criteria = criteriaBuilder.createQuery(StaffMember.class); Root<UserVariable> uvRoot = criteria.from(UserVariable.class); Root<StaffMember> smRoot = criteria.from(StaffMember.class); Join<UserVariable, User> userJoin = uvRoot.join(UserVariable_.user); criteria.select(smRoot); criteria.where( criteriaBuilder.and( criteriaBuilder.equal(uvRoot.get(UserVariable_.user), smRoot), criteriaBuilder.equal(uvRoot.get(UserVariable_.key), userVariableKey), criteriaBuilder.equal(uvRoot.get(UserVariable_.value), value), criteriaBuilder.equal(userJoin.get(User_.archived), Boolean.FALSE) )); return entityManager.createQuery(criteria).getResultList(); } public List<StaffMember> listByNotRole(Role role) { return listByNotRole(role, null, null); } public List<StaffMember> listByNotRole(Role role, Integer firstResult, Integer maxResults) { EntityManager entityManager = getEntityManager(); CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder(); CriteriaQuery<StaffMember> criteria = criteriaBuilder.createQuery(StaffMember.class); Root<StaffMember> root = criteria.from(StaffMember.class); criteria.select(root); criteria.where( criteriaBuilder.and( criteriaBuilder.notEqual(root.get(StaffMember_.role), role), criteriaBuilder.notEqual(root.get(StaffMember_.archived), Boolean.FALSE) ) ); TypedQuery<StaffMember> query = entityManager.createQuery(criteria); if (firstResult != null) { query.setFirstResult(firstResult); } if (maxResults != null) { query.setMaxResults(maxResults); } return query.getResultList(); } public List<StaffMember> listByPerson(Person person) { EntityManager entityManager = getEntityManager(); CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder(); CriteriaQuery<StaffMember> criteria = criteriaBuilder.createQuery(StaffMember.class); Root<StaffMember> root = criteria.from(StaffMember.class); criteria.select(root); criteria.where( criteriaBuilder.and( criteriaBuilder.equal(root.get(StaffMember_.archived), Boolean.FALSE), criteriaBuilder.equal(root.get(StaffMember_.person), person) )); return entityManager.createQuery(criteria).getResultList(); } public StaffMember findByUniqueEmail(String email) { EntityManager entityManager = getEntityManager(); CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder(); CriteriaQuery<StaffMember> criteria = criteriaBuilder.createQuery(StaffMember.class); Root<StaffMember> root = criteria.from(StaffMember.class); Join<StaffMember, ContactInfo> contactInfoJoin = root.join(StaffMember_.contactInfo); ListJoin<ContactInfo, Email> emailJoin = contactInfoJoin.join(ContactInfo_.emails); Join<Email, ContactType> contactTypeJoin = emailJoin.join(Email_.contactType); criteria.select(root); criteria.where( criteriaBuilder.and( criteriaBuilder.equal(emailJoin.get(Email_.address), email), criteriaBuilder.equal(contactTypeJoin.get(ContactType_.nonUnique), Boolean.FALSE), criteriaBuilder.equal(root.get(StaffMember_.archived), Boolean.FALSE) ) ); return getSingleResult(entityManager.createQuery(criteria)); } public StaffMember findByPerson(Person person) { EntityManager entityManager = getEntityManager(); CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder(); CriteriaQuery<StaffMember> criteria = criteriaBuilder.createQuery(StaffMember.class); Root<StaffMember> root = criteria.from(StaffMember.class); criteria.select(root); criteria.where( criteriaBuilder.and( criteriaBuilder.equal(root.get(StaffMember_.person), person), criteriaBuilder.equal(root.get(StaffMember_.archived), Boolean.FALSE) ) ); return getSingleResult(entityManager.createQuery(criteria)); } @SuppressWarnings("unchecked") public SearchResult<StaffMember> searchUsersBasic(int resultsPerPage, int page, String text) { int firstResult = page * resultsPerPage; StringBuilder queryBuilder = new StringBuilder(); queryBuilder.append("+("); addTokenizedSearchCriteria(queryBuilder, "firstName", text, false); addTokenizedSearchCriteria(queryBuilder, "lastName", text, false); addTokenizedSearchCriteria(queryBuilder, "tags.text", text, false); addTokenizedSearchCriteria(queryBuilder, "contactInfo.emails.address", text, false); queryBuilder.append(")"); EntityManager entityManager = getEntityManager(); FullTextEntityManager fullTextEntityManager = Search.getFullTextEntityManager(entityManager); try { String queryString = queryBuilder.toString(); org.apache.lucene.search.Query luceneQuery; QueryParser parser = new QueryParser("", new StandardAnalyzer()); if (StringUtils.isBlank(queryString)) { luceneQuery = new MatchAllDocsQuery(); } else { luceneQuery = parser.parse(queryString); } FullTextQuery query = (FullTextQuery) fullTextEntityManager.createFullTextQuery(luceneQuery, StaffMember.class) .setSort(new Sort(new SortField[] { SortField.FIELD_SCORE, new SortField("lastNameSortable", SortField.Type.STRING), new SortField("firstNameSortable", SortField.Type.STRING) })) .setFirstResult(firstResult) . setMaxResults(resultsPerPage); int hits = query.getResultSize(); int pages = hits / resultsPerPage; if (hits % resultsPerPage > 0) { pages++; } int lastResult = Math.min(firstResult + resultsPerPage, hits) - 1; return new SearchResult<>(page, pages, hits, firstResult, lastResult, query.getResultList()); } catch (ParseException e) { throw new PersistenceException(e); } } @SuppressWarnings("unchecked") public SearchResult<StaffMember> searchUsers(int resultsPerPage, int page, String firstName, String lastName, String tags, String email, Role[] roles) { int firstResult = page * resultsPerPage; boolean hasFirstName = !StringUtils.isBlank(firstName); boolean hasLastName = !StringUtils.isBlank(lastName); boolean hasTags = !StringUtils.isBlank(tags); boolean hasEmail = !StringUtils.isBlank(email); StringBuilder queryBuilder = new StringBuilder(); if (hasFirstName || hasLastName || hasEmail) { queryBuilder.append("+("); if (hasFirstName) addTokenizedSearchCriteria(queryBuilder, "firstName", firstName, false); if (hasLastName) addTokenizedSearchCriteria(queryBuilder, "lastName", lastName, false); if (hasTags) addTokenizedSearchCriteria(queryBuilder, "tags.text", tags, false); if (hasEmail) addTokenizedSearchCriteria(queryBuilder, "contactInfo.emails.address", email, false); queryBuilder.append(")"); } if (roles.length > 0) { queryBuilder.append("+("); for (Role role : roles) { addTokenizedSearchCriteria(queryBuilder, "role", role.toString(), false); } queryBuilder.append(")"); } EntityManager entityManager = getEntityManager(); FullTextEntityManager fullTextEntityManager = Search.getFullTextEntityManager(entityManager); try { String queryString = queryBuilder.toString(); org.apache.lucene.search.Query luceneQuery; QueryParser parser = new QueryParser("", new StandardAnalyzer()); if (StringUtils.isBlank(queryString)) { luceneQuery = new MatchAllDocsQuery(); } else { luceneQuery = parser.parse(queryString); } FullTextQuery query = (FullTextQuery) fullTextEntityManager.createFullTextQuery(luceneQuery, StaffMember.class) .setSort(new Sort(new SortField[] { SortField.FIELD_SCORE, new SortField("lastNameSortable", SortField.Type.STRING), new SortField("firstNameSortable", SortField.Type.STRING) })) .setFirstResult(firstResult) .setMaxResults(resultsPerPage); int hits = query.getResultSize(); int pages = hits / resultsPerPage; if (hits % resultsPerPage > 0) { pages++; } int lastResult = Math.min(firstResult + resultsPerPage, hits) - 1; return new SearchResult<>(page, pages, hits, firstResult, lastResult, query.getResultList()); } catch (ParseException e) { throw new PersistenceException(e); } } public StaffMember update(StaffMember staffMember, String firstName, String lastName, Role role) { staffMember.setFirstName(firstName); staffMember.setLastName(lastName); staffMember.setRole(role); persist(staffMember); staffMemberUpdatedEvent.fire(new StaffMemberUpdatedEvent(staffMember.getId())); return staffMember; } public StaffMember updateTags(StaffMember staffMember, Set<Tag> tags) { staffMember.setTags(tags); persist(staffMember); staffMemberUpdatedEvent.fire(new StaffMemberUpdatedEvent(staffMember.getId())); return staffMember; } public StaffMember updateTitle(StaffMember staffMember, String title) { staffMember.setTitle(title); persist(staffMember); staffMemberUpdatedEvent.fire(new StaffMemberUpdatedEvent(staffMember.getId())); return staffMember; } @Override public void delete(StaffMember user) { Long id = user.getId(); if (user.getPerson() != null) user.getPerson().removeUser(user); super.delete(user); staffMemberDeletedEvent.fire(new StaffMemberDeletedEvent(id)); } }