Package com.infoclinika.mssharing.search

Source Code of com.infoclinika.mssharing.search.SearcherImpl

/*
* C O P Y R I G H T   N O T I C E
* -----------------------------------------------------------------------
* Copyright (c) 2011-2012 InfoClinika, Inc. 5901 152nd Ave SE, Bellevue, WA 98006,
* United States of America.  (425) 442-8058.  http://www.infoclinika.com.
* All Rights Reserved.  Reproduction, adaptation, or translation without prior written permission of InfoClinika, Inc. is prohibited.
* Unpublished--rights reserved under the copyright laws of the United States.  RESTRICTED RIGHTS LEGEND Use, duplication or disclosure by the
*/
package com.infoclinika.mssharing.search;

import com.google.common.base.Function;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
import com.infoclinika.mssharing.model.PaginationItems;
import com.infoclinika.mssharing.model.Searcher;
import com.infoclinika.mssharing.model.internal.CriteriaRules;
import com.infoclinika.mssharing.model.internal.entity.*;
import com.infoclinika.mssharing.model.internal.read.Transformers;
import com.infoclinika.mssharing.model.internal.repository.UserRepository;
import com.infoclinika.mssharing.model.read.DashboardReader;
import org.apache.lucene.search.Sort;
import org.apache.lucene.search.SortField;
import org.hibernate.CacheMode;
import org.hibernate.Criteria;
import org.hibernate.Session;
import org.hibernate.criterion.Restrictions;
import org.hibernate.search.jpa.FullTextEntityManager;
import org.hibernate.search.jpa.FullTextQuery;
import org.hibernate.search.jpa.Search;
import org.hibernate.search.query.dsl.BooleanJunction;
import org.hibernate.search.query.dsl.QueryBuilder;
import org.hibernate.search.query.dsl.TermMatchingContext;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.PostConstruct;
import javax.inject.Inject;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import java.util.List;
import java.util.concurrent.Future;

import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.collect.FluentIterable.from;
import static com.infoclinika.mssharing.model.internal.read.Transformers.PagedItemsTransformer.resolve;
import static com.infoclinika.mssharing.model.read.DashboardReader.InstrumentItem;

/**
* @author Stanislav Kurilin
*/
public class SearcherImpl implements Searcher {
    private final Transformers transformers;
    private final UserRepository userRepository;
    private EntityManager entityManager;
    private CriteriaRules criteriaRules;
    private Future<?> start;

    private boolean useHibernateSearchPaging = false;

    @Inject
    public SearcherImpl(Transformers transformers, UserRepository userRepository, CriteriaRules criteriaRules) {
        this.transformers = transformers;
        this.userRepository = userRepository;
        this.criteriaRules = criteriaRules;
    }

    @PostConstruct
    public void initSearcher() {
        FullTextEntityManager fullTextSession = org.hibernate.search.jpa.Search.getFullTextEntityManager(entityManager);
        start = fullTextSession.createIndexer()
                .purgeAllOnStart(true)
                .cacheMode(CacheMode.IGNORE)
                .optimizeAfterPurge(true)
                .optimizeOnFinish(true)
                .batchSizeToLoadObjects(25)
                .threadsToLoadObjects(5)
                .threadsForSubsequentFetching(20).start();
    }

    @Override
    @Transactional
    public ImmutableList<DashboardReader.ProjectLine> projects(long actor, String query) {
        final Criteria criteria = getProjectsCriteria(actor);
        Iterable<Project> projects = search(criteria, Project.class, query, ImmutableSet.of("areaOfResearch", "description"));
        return from(projects).transform(transformers.projectTransformer).toImmutableList();
    }

    private Criteria getCriteria(Class<?> persistentClass, String alias) {
        final Session session = getSession();
        return session.createCriteria(persistentClass, alias);
    }

    @Override
    @Transactional
    public ImmutableList<DashboardReader.ExperimentLine> experiments(long actor, String query) {
        final Criteria criteria = getExperimentsCriteria(actor);
        Iterable<Experiment> experiments = search(criteria, Experiment.class, query, ImmutableSet.of("experimentData_description"));
        return from(experiments).transform(transformers.experimentOwnerTransformer.apply(actor)).toImmutableList();
    }

    @Override
    @Transactional
    public ImmutableList<DashboardReader.FileLine> files(long actor, String query) {
        final Criteria criteria = getFilesCriteria(actor);
        Iterable<FileMetaData> files = search(criteria, FileMetaData.class, query, ImmutableSet.of("labels"));
        return transformers.transformFiles(from(files)).toImmutableList();
    }

    @Override
    @Transactional
    public ImmutableList<InstrumentItem> instruments(long actor, String query) {

        final Criteria criteria = getInstrumentsCriteria(actor);
        Iterable<Instrument> instruments = search(criteria, Instrument.class, query, ImmutableSet.of("hplc", "peripherals", "serialNumber"));
        final User user = checkNotNull(userRepository.findOne(actor));
        return from(instruments).transform(transformers.instrumentTransformer(user)).toImmutableList();
    }

    @Override
    @Transactional
    public PaginationItems.PagedItem<DashboardReader.ProjectLine> pagedProjects(long actor, PaginationItems.PagedItemInfo pagedItemInfo) {
        final Criteria criteria = getProjectsCriteria(actor);
        final Iterable<Project> items = pagedSearch(criteria, Project.class, ImmutableSet.of("areaOfResearch", "description"), pagedItemInfo);
        int count = countProjects(actor, pagedItemInfo);
        return new PaginationItems.PagedItem<DashboardReader.ProjectLine>(
                count/pagedItemInfo.items,
                count,
                from(items).transform(transformers.projectTransformer).toImmutableSet()
        );
    }

    private Session getSession() {
        return entityManager.unwrap(Session.class);
    }

    @Override
    @Transactional
    public PaginationItems.PagedItem<DashboardReader.ExperimentLine> pagedExperiments(long actor, PaginationItems.PagedItemInfo pagedItemInfo) {
        final Criteria criteria = getExperimentsCriteria(actor);
        final Iterable<Experiment> items = pagedSearch(criteria, Experiment.class, ImmutableSet.of("experimentData_description"), pagedItemInfo);
        int count = countExperiments(actor, pagedItemInfo);
        return  new PaginationItems.PagedItem<DashboardReader.ExperimentLine>(
                count/pagedItemInfo.items,
                count,
                from(items).transform(transformers.experimentOwnerTransformer.apply(actor)).toImmutableSet()
        );
    }

    @Override
    @Transactional
    public PaginationItems.PagedItem<DashboardReader.FileLine> pagedFiles(long actor, PaginationItems.PagedItemInfo pagedItemInfo) {
        final Criteria criteria = getFilesCriteria(actor);
        int count = countFiles(actor, pagedItemInfo);
        final Iterable<FileMetaData> items = pagedSearch(criteria, FileMetaData.class, ImmutableSet.of("labels"), pagedItemInfo);
        return  new PaginationItems.PagedItem<DashboardReader.FileLine>(
                count/pagedItemInfo.items,
                count,
                transformers.transformFiles(from(items)).toImmutableSet()
        );
    }

    @Override
    @Transactional
    public PaginationItems.PagedItem<InstrumentItem> pagedInstruments(long actor, PaginationItems.PagedItemInfo pagedItemInfo) {
        final Criteria criteria = getInstrumentsCriteria(actor);

        Iterable<Instrument> instruments = pagedSearch(criteria, Instrument.class, ImmutableSet.of("hplc", "peripherals", "serialNumber"), pagedItemInfo);
        final User user = checkNotNull(userRepository.findOne(actor));
        int count = countInstruments(actor, pagedItemInfo);
        return new PaginationItems.PagedItem<InstrumentItem>(
                count/pagedItemInfo.items,
                count,
                from(instruments).transform(transformers.instrumentTransformer(user)).toImmutableSet()
        );
    }

    @Override
    @Transactional
    public Count getItemsCount(PaginationItems.PagedItemInfo pagedItemInfo, long actor) {
        final int instruments = countInstruments(actor, pagedItemInfo);
        final int experiments = countExperiments(actor, pagedItemInfo);
        final int files = countFiles(actor, pagedItemInfo);
        final int projects = countProjects(actor, pagedItemInfo);
        return new Count(instruments, projects, files, experiments);
    }

    private <T> Iterable<T> search(final Criteria query, final Class<T> clazz, String keyword, Iterable<String> additionalFields) {
        final FullTextQuery fullTextQuery = getFullTextQuery(query, clazz, keyword, additionalFields);

        //noinspection unchecked
        return Iterables.transform(fullTextQuery.getResultList(), new Function() {
            @Override
            public Object apply(Object input) {
                if (input.getClass().isAssignableFrom(clazz)) return input;
                throw new AssertionError(String.format("Expected: %s. Actual: %s", clazz, input.getClass()));
            }
        });
    }

    private <T> Iterable<T> pagedSearch(final Criteria query, final Class<T> clazz, Iterable<String> additionalFields, final PaginationItems.PagedItemInfo info) {

        final FullTextQuery fullTextQuery = getFullTextQuery(query, clazz, info.filterQuery, additionalFields);
        fullTextQuery.setSort(new Sort(new SortField(resolve(clazz, info.sortingField) + ".sort", SortField.STRING, !info.isSortingAsk)));

        if(useHibernateSearchPaging) {
            return getHibernatePagingResult(clazz, info, fullTextQuery);
        }
        return getNonHibernatePagingResult(clazz, info, fullTextQuery);
    }

    private <T> Iterable<T> getNonHibernatePagingResult(final Class<T> clazz, PaginationItems.PagedItemInfo info, FullTextQuery fullTextQuery) {
        final List list = fullTextQuery.getResultList();
        //noinspection unchecked
        return from(
                Iterables.transform(list, new Function<Object, Object>() {
                    @Override
                    public Object apply(Object input) {
                        if (input.getClass().isAssignableFrom(clazz)) return input;
                        throw new AssertionError(String.format("Expected: %s. Actual: %s", clazz, input.getClass()));
                    }
                })
        ).skip(info.items * info.page).limit(info.items);
    }

    /**
     *  Currently return incorrect result
     *
     * @see org.hibernate.search.query.engine.impl.HSQueryImpl#queryEntityInfos
     * @see org.hibernate.search.query.hibernate.impl.QueryLoader#executeLoad
     * @see org.hibernate.search.query.hibernate.impl.CriteriaObjectsInitializer#initializeObjects - pay attention here
     *
     */
    private <T> Iterable<T> getHibernatePagingResult(final Class<T> clazz, PaginationItems.PagedItemInfo info, FullTextQuery fullTextQuery) {

        fullTextQuery.setFirstResult(info.items * info.page).setMaxResults(info.items);

        final List list = fullTextQuery.getResultList();
        //noinspection unchecked
        return from(Iterables.transform(list, new Function<Object, Object>() {
            @Override
            public Object apply(Object input) {
                if (input.getClass().isAssignableFrom(clazz)) return input;
                throw new AssertionError(String.format("Expected: %s. Actual: %s", clazz, input.getClass()));
            }
        }));
    }

    private <T> int countSearch(Criteria countQuery, final Class<T> clazz, Iterable<String> additionalFields, final PaginationItems.PagedItemInfo info) {
        final FullTextQuery count = getFullTextQuery(countQuery, clazz, info.filterQuery, additionalFields);
        //count.setProjection("id");

        return  count.getResultList().size();
    }


    private <T> FullTextQuery getFullTextQuery(Criteria query, Class<T> clazz, String keyword, Iterable<String> additionalFields) {
        final FullTextEntityManager session = Search.getFullTextEntityManager(entityManager);
        QueryBuilder qb = session.getSearchFactory()
                .buildQueryBuilder().forEntity(clazz).get();

        String[] searchTerms = keyword.split(" ");
        final TermMatchingContext context = qb.keyword().wildcard().onField("name");
        for (String field : additionalFields) {
            context.andField(field);
        }

        BooleanJunction<BooleanJunction> bool = qb.bool();
        for (String searchTerm : searchTerms) {
            bool.must(context.matching(String.format("*%s*", searchTerm.toLowerCase())).createQuery());
        }

        final FullTextQuery fullTextQuery = session.createFullTextQuery(bool.createQuery(), clazz);
        fullTextQuery.setCriteriaQuery(query);
        return fullTextQuery;
    }

    @Override
    public boolean isSearchEnabled() {
        return start.isDone();
    }

    @Override
    public void setHibernateSearchPaging(boolean useHibernateSearchPaging) {
        this.useHibernateSearchPaging = useHibernateSearchPaging;
    }

    @PersistenceContext
    public void setEntityManager(EntityManager entityManager) {
        this.entityManager = entityManager;
    }

    private Criteria getFilesCriteria(long actor) {
        return getCriteria(FileMetaData.class, "f")
                .createAlias("f.instrument", "instrument")
                .add(
                        Restrictions.or(
                                Restrictions.eq("owner.id", actor),
                                criteriaRules.isUserOperatorOfInstrumentForFile(actor, "instrument.id"),
                                criteriaRules.isFileAvailableFromExperiment(actor, "f.id")
                        )
                );
    }

    private Criteria getInstrumentsCriteria(long actor) {
        final Criteria criteria = getCriteria(Instrument.class, "i");
        criteria.createAlias("i.lab", "lab")
                .createAlias("lab.labMemberships", "lm")
                .add(Restrictions.in("lm.user.id", ImmutableSet.of(actor)));
        return criteria;
    }

    private Criteria getExperimentsCriteria(long actor) {
        final Criteria criteria = getCriteria(Experiment.class, "e");
        criteria.createAlias("e.project", "p").createAlias("e.creator", "creator");
        criteriaRules.joinCollaborators(criteria, "p").add(Restrictions.disjunction()
                .add(Restrictions.eq("p.creator.id", actor))
                .add(criteriaRules.isNotOwnedProjectAvailable(actor)));
        return criteria;
    }

    private Criteria getProjectsCriteria(long actor) {
        final Criteria criteria = getCriteria(Project.class, "p" )
                .createAlias("p.creator", "creator");
        criteriaRules.joinCollaborators(criteria, "p")
                .add(
                        Restrictions.or(
                                Restrictions.eq("p.creator.id", actor),
                                criteriaRules.isNotOwnedProjectAvailable(actor)
                        )
                );
        return criteria;
    }

    private int countExperiments(long actor, PaginationItems.PagedItemInfo pagedItemInfo) {
        final Criteria countQuery = getExperimentsCriteria(actor)/*.setProjection(Projections.rowCount())*/;
        return countSearch(countQuery, Experiment.class, ImmutableSet.of("experimentData_description"), pagedItemInfo);
    }

    private int countProjects(long actor, PaginationItems.PagedItemInfo pagedItemInfo) {
        final Criteria countQuery = getProjectsCriteria(actor)/*.setProjection(Projections.rowCount())*/;
        return countSearch(countQuery, Project.class, ImmutableSet.of("areaOfResearch", "description"), pagedItemInfo);
    }

    private int countFiles(long actor, PaginationItems.PagedItemInfo pagedItemInfo) {
        final Criteria countQuery = getFilesCriteria(actor)/*.setProjection(Projections.rowCount())*/;
        return  countSearch(countQuery, FileMetaData.class, ImmutableSet.of("labels"), pagedItemInfo);
    }

    private int countInstruments(long actor, PaginationItems.PagedItemInfo pagedItemInfo) {
        final Criteria countQuery = getInstrumentsCriteria(actor)/*.setProjection(Projections.rowCount())*/;
        return countSearch(countQuery, Instrument.class, ImmutableSet.of("hplc", "peripherals", "serialNumber"), pagedItemInfo);
    }


}
TOP

Related Classes of com.infoclinika.mssharing.search.SearcherImpl

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.