/** * 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.search.hibernate; import java.util.Collections; import java.util.List; import org.apache.commons.lang.StringUtils; import org.hibernate.Criteria; import org.hibernate.SessionFactory; import org.hibernate.criterion.Restrictions; import org.hibernate.search.FullTextQuery; import org.hibernate.search.FullTextSession; import org.hibernate.search.query.dsl.QueryBuilder; import org.jtalks.jcommune.model.dao.search.TopicSearchDao; import org.jtalks.jcommune.model.dto.PageRequest; import org.jtalks.jcommune.model.entity.Post; import org.jtalks.jcommune.model.entity.Topic; import org.jtalks.jcommune.model.search.SearchRequestFilter; import org.springframework.data.domain.Page; import org.springframework.data.domain.PageImpl; /** * Hibernate Search DAO implementation for operations with a {@link Topic}. * * @author Anuar Nurmakanov */ public class TopicHibernateSearchDao extends AbstractHibernateSearchDao implements TopicSearchDao { /** * List of filters. */ private List<SearchRequestFilter> filters = Collections.emptyList(); /** * @param sessionFactory the Hibernate SessionFactory * @param filters the list of filters to correct the dirty search requests */ public TopicHibernateSearchDao(SessionFactory sessionFactory, List<SearchRequestFilter> filters) { super(sessionFactory); this.filters = filters; } /** * Injects filters for search requests. It needed for testing. * * @param filters the list of filters to correct the dirty search requests */ void setFilters(List<SearchRequestFilter> filters) { this.filters = filters; } /** * {@inheritDoc} */ @Override public Page<Topic> searchByTitleAndContent(String searchText, PageRequest pageRequest, List<Long> allowedBranchesIds) { Page<Topic> searchResults = doSearch(searchText, pageRequest, allowedBranchesIds); if (isSearchedAboveLastPage(searchResults)) { pageRequest.adjustPageNumber(Long.valueOf(searchResults.getTotalElements()).intValue()); searchResults = doSearch(searchText, pageRequest, allowedBranchesIds); } return searchResults; } /** * Perform actual search * * @param searchText the search text * @param pageRequest contains information for pagination: page number, page * size * @param allowedBranchesIds list of allowed branches * @return object that contains search results for one page(note, that one * page may contain all search results) and information for pagination */ @SuppressWarnings("unchecked") private Page<Topic> doSearch(String searchText, PageRequest pageRequest, List<Long> allowedBranchesIds) { List<Topic> topics = Collections.emptyList(); int resultSize = 0; //TODO The latest versions of the library filtering is not needed. String filteredSearchText = applyFilters(searchText, filters).trim(); if (!StringUtils.isEmpty(filteredSearchText)) { FullTextQuery query = createSearchQuery(getFullTextSession(), filteredSearchText, pageRequest); Criteria criteria = getFullTextSession().createCriteria(Topic.class).add( Restrictions.in("branch.id", allowedBranchesIds) ); query.setCriteriaQuery(criteria); topics = query.list(); resultSize = query.getResultSize(); } return new PageImpl<Topic>(topics, pageRequest, resultSize); } /** * Checks if this search was by made with too big page number specified * * @param searchResults search results * @return true if page number is too big */ private boolean isSearchedAboveLastPage(Page<Topic> searchResults) { return !searchResults.hasContent() && searchResults.getNumber() > searchResults.getTotalPages(); } /** * Builds a search query. * * @param fullTextSession the Hibernate Search session * @param searchText the search text * @param pageRequest contains information for pagination: page number, page size * @return the search query */ private FullTextQuery createSearchQuery( FullTextSession fullTextSession, String searchText, PageRequest pageRequest) { QueryBuilder queryBuilder = fullTextSession. getSearchFactory(). buildQueryBuilder(). forEntity(Topic.class). get(); org.apache.lucene.search.Query luceneQuery = queryBuilder. keyword(). onField(Topic.TOPIC_TITLE_FIELD_DEF). andField(Topic.TOPIC_TITLE_FIELD_RU). andField(Topic.TOPIC_POSTS_PREFIX + Post.POST_CONTENT_FIELD_DEF). andField(Topic.TOPIC_POSTS_PREFIX + Post.POST_CONTENT_FIELD_RU). matching(searchText). createQuery(); FullTextQuery query = fullTextSession.createFullTextQuery(luceneQuery); query.setFirstResult(pageRequest.getOffset()); query.setMaxResults(pageRequest.getPageSize()); return query; } /** * This method filters the text. * * @param searchText the search text * @param filters the list of filters * @return the filtered search text */ private String applyFilters(String searchText, List<SearchRequestFilter> filters) { for (SearchRequestFilter filter : filters) { searchText = filter.filter(searchText); } return searchText; } /** * {@inheritDoc} */ @Override public void rebuildIndex() { getFullTextSession().createIndexer(Topic.class).start(); } }