kr.debop4j.data.ogm.dao.HibernateOgmDao.java Source code

Java tutorial

Introduction

Here is the source code for kr.debop4j.data.ogm.dao.HibernateOgmDao.java

Source

/*
 * Copyright 2011-2013 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package kr.debop4j.data.ogm.dao;

import com.google.common.collect.Lists;
import kr.debop4j.core.Guard;
import kr.debop4j.core.Local;
import kr.debop4j.core.collection.IPagedList;
import kr.debop4j.core.collection.PaginatedList;
import kr.debop4j.core.parallelism.AsyncTool;
import kr.debop4j.core.tools.ArrayTool;
import kr.debop4j.core.tools.StringTool;
import kr.debop4j.data.hibernate.tools.HibernateTool;
import kr.debop4j.data.hibernate.unitofwork.UnitOfWorks;
import kr.debop4j.search.tools.SearchTool;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.Sort;
import org.hibernate.*;
import org.hibernate.search.FullTextQuery;
import org.hibernate.search.FullTextSession;
import org.hibernate.search.ProjectionConstants;
import org.hibernate.search.Search;
import org.hibernate.search.query.DatabaseRetrievalMethod;
import org.hibernate.search.query.ObjectLookupMethod;
import org.hibernate.search.query.dsl.QueryBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.concurrent.Future;

import static kr.debop4j.core.Guard.shouldNotBeNull;

/**
 * Hibernate-OGM  DAO .<br />
 * hibernate? Criteria ?   , Criteria ? hibernate-search .
 *
 * @author ? ( sunghyouk.bae@gmail.com )
 * @since 13. 4. 15.  5:42
 */
@Component
@SuppressWarnings("unchecked")
public class HibernateOgmDao implements IHibernateOgmDao {

    private static final Logger log = LoggerFactory.getLogger(HibernateOgmDao.class);
    private static final boolean isTraceEnabled = log.isTraceEnabled();
    private static final boolean isDebugEnabled = log.isDebugEnabled();

    @Override
    public synchronized final Session getSession() {
        return UnitOfWorks.getCurrentSession();
    }

    @Override
    public synchronized final FullTextSession getFullTextSession() {
        FullTextSession fts = Local.get(IHibernateOgmDao.FULL_TEXT_SESSION_KEY, FullTextSession.class);
        if (fts == null || !fts.isOpen()) {
            fts = Search.getFullTextSession(getSession());
            Local.put(IHibernateOgmDao.FULL_TEXT_SESSION_KEY, fts);
            log.debug(" FullTextSession? ?.");
        }
        return fts;
    }

    @Override
    public final QueryBuilder getQueryBuilder(Class<?> clazz) {
        return getFullTextSession().getSearchFactory().buildQueryBuilder().forEntity(clazz).get();
    }

    @Override
    public FullTextQuery getFullTextQuery(Query luceneQuery, Class<?>... entities) {
        if (isTraceEnabled)
            log.trace("FullTextQuery ?... luceneQuery=[{}], entities=[{}]", luceneQuery,
                    StringTool.listToString(entities));

        FullTextQuery ftq = getFullTextSession().createFullTextQuery(luceneQuery, entities);

        // !!! object lookup ? DB   
        //
        ftq.initializeObjectsWith(ObjectLookupMethod.SKIP, DatabaseRetrievalMethod.FIND_BY_ID);
        return ftq;
    }

    @Override
    public <T> T get(Class<T> clazz, Serializable id) {
        return (T) getFullTextSession().get(clazz, id);
    }

    @Override
    public <T> List<T> find(Class<T> clazz) {
        return find(clazz, getQueryBuilder(clazz).all().createQuery());
    }

    @Override
    public <T> List<T> find(Class<T> clazz, Query luceneQuery) {
        return find(clazz, luceneQuery, -1, -1, null, null);
    }

    @Override
    public <T> List<T> find(Class<T> clazz, Query luceneQuery, Sort luceneSort) {
        return find(clazz, luceneQuery, -1, -1, luceneSort, null);
    }

    @Override
    public <T> List<T> find(Class<T> clazz, Query luceneQuery, int firstResult, int maxResults, Sort luceneSort) {
        return find(clazz, luceneQuery, firstResult, maxResults, luceneSort, null);
    }

    @Override
    public <T> List<T> find(Class<T> clazz, Query luceneQuery, int firstResult, int maxResults, Sort luceneSort,
            Criteria criteria) {
        if (isTraceEnabled)
            log.trace(
                    " . clazz=[{}], luceneQuery=[{}], fitstResult=[{}], maxResults=[{}], sort=[{}], criteria=[{}]",
                    clazz, luceneQuery, firstResult, maxResults, luceneSort, criteria);

        if (luceneQuery == null)
            luceneQuery = getQueryBuilder(clazz).all().createQuery();

        FullTextQuery ftq = getFullTextQuery(luceneQuery, clazz);
        HibernateTool.setPaging(ftq, firstResult, maxResults);

        if (luceneSort != null)
            ftq.setSort(luceneSort);
        if (criteria != null)
            ftq.setCriteriaQuery(criteria);

        return ftq.list();
    }

    @Override
    public List<Serializable> findIds(Class<?> clazz, Query luceneQuery) {
        return findIds(clazz, luceneQuery, -1, -1, null, null);
    }

    @Override
    public List<Serializable> findIds(Class<?> clazz, Query luceneQuery, int firstResult, int maxResults,
            Sort luceneSort) {
        return findIds(clazz, luceneQuery, firstResult, maxResults, luceneSort, null);
    }

    @Override
    public List<Serializable> findIds(Class<?> clazz, Query luceneQuery, int firstResult, int maxResults,
            Sort luceneSort, Criteria criteria) {

        List<Object[]> fields = findProjections(clazz, luceneQuery, new String[] { ProjectionConstants.ID },
                firstResult, maxResults, luceneSort, criteria);
        List<Serializable> ids = new ArrayList<>();

        for (Object[] field : fields) {
            ids.add((Serializable) field[0]);
        }
        return ids;
    }

    @Override
    public List<Object[]> findProjections(Class<?> clazz, Query luceneQuery, String[] fields) {
        return findProjections(clazz, luceneQuery, fields, -1, -1, null, null);
    }

    @Override
    public List<Object[]> findProjections(Class<?> clazz, Query luceneQuery, String[] fields, Sort luceneSort) {
        return findProjections(clazz, luceneQuery, fields, -1, -1, luceneSort, null);
    }

    @Override
    public List<Object[]> findProjections(Class<?> clazz, Query luceneQuery, String[] fields, Sort luceneSort,
            Criteria criteria) {
        return findProjections(clazz, luceneQuery, fields, -1, -1, luceneSort, criteria);
    }

    @Override
    public List<Object[]> findProjections(Class<?> clazz, Query luceneQuery, String[] fields, int firstResult,
            int maxResults, Sort luceneSort, Criteria criteria) {
        shouldNotBeNull(fields, "fields");
        Guard.shouldBe(fields.length > 0, "   .");

        if (isTraceEnabled)
            log.trace(
                    "Project . clazz=[{}], luceneQuery=[{}], fields=[{}], firstResult=[{}], maxResults=[{}], luceneSort=[{}], criteria=[{}]",
                    clazz, luceneQuery, StringTool.listToString(fields), firstResult, maxResults, luceneSort,
                    criteria);

        if (luceneQuery == null)
            luceneQuery = getQueryBuilder(clazz).all().createQuery();

        FullTextQuery ftq = getFullTextQuery(luceneQuery, clazz);
        HibernateTool.setPaging(ftq, firstResult, maxResults);
        ftq.setProjection(fields);

        if (luceneSort != null)
            ftq.setSort(luceneSort);
        if (criteria != null)
            ftq.setCriteriaQuery(criteria);

        return ftq.list();
    }

    @Override
    public <T> IPagedList<T> getPage(Class<T> clazz, Query luceneQuery, int pageNo, int pageSize) {
        return getPage(clazz, luceneQuery, pageNo, pageSize, null, null);
    }

    @Override
    public <T> IPagedList<T> getPage(Class<T> clazz, Query luceneQuery, int pageNo, int pageSize, Sort luceneSort) {
        return getPage(clazz, luceneQuery, pageNo, pageSize, luceneSort, null);
    }

    @Override
    public <T> IPagedList<T> getPage(Class<T> clazz, Query luceneQuery, int pageNo, int pageSize, Sort luceneSort,
            Criteria criteria) {

        log.trace(
                " ? . clazz=[{}], luceneQuery=[{}], pageNo=[{}], pageSize=[{}], sort=[{}], criteria=[{}]",
                clazz, luceneQuery, pageNo, pageSize, luceneSort, criteria);

        long totalCount = count(clazz, luceneQuery);
        FullTextQuery ftq = this.getFullTextQuery(luceneQuery, clazz);

        HibernateTool.setPaging(ftq, (pageNo - 1) * pageSize, pageSize);

        if (luceneSort != null)
            ftq.setSort(luceneSort);
        if (criteria != null)
            ftq.setCriteriaQuery(criteria); // fetching strategy ? ?   .

        return new PaginatedList<T>(ftq.list(), pageNo, pageSize, totalCount);
    }

    @Override
    public IPagedList<Serializable> getIdPage(Class<?> clazz, Query luceneQuery, int pageNo, int pageSize) {
        return getIdPage(clazz, luceneQuery, pageNo, pageSize, null, null);
    }

    @Override
    public IPagedList<Serializable> getIdPage(Class<?> clazz, Query luceneQuery, int pageNo, int pageSize,
            Sort luceneSort) {
        return getIdPage(clazz, luceneQuery, pageNo, pageSize, luceneSort, null);
    }

    @Override
    public IPagedList<Serializable> getIdPage(Class<?> clazz, Query luceneQuery, int pageNo, int pageSize,
            Sort luceneSort, Criteria criteria) {
        IPagedList<Object[]> list = getProjectionPage(clazz, luceneQuery, new String[] { FullTextQuery.ID }, pageNo,
                pageSize, luceneSort, criteria);
        List<Serializable> ids = Lists.newArrayList();
        for (Object[] fields : list.getList()) {
            ids.add((Serializable) fields[0]);
        }
        return new PaginatedList<>(ids, pageNo, pageSize, list.getItemCount());
    }

    @Override
    public IPagedList<Object[]> getProjectionPage(Class<?> clazz, Query luceneQuery, String[] fields, int pageNo,
            int pageSize) {
        return getProjectionPage(clazz, luceneQuery, fields, pageNo, pageSize, null, null);
    }

    @Override
    public IPagedList<Object[]> getProjectionPage(Class<?> clazz, Query luceneQuery, String[] fields, int pageNo,
            int pageSize, Sort luceneSort) {
        return getProjectionPage(clazz, luceneQuery, fields, pageNo, pageSize, luceneSort, null);
    }

    @Override
    public IPagedList<Object[]> getProjectionPage(Class<?> clazz, Query luceneQuery, String[] fields, int pageNo,
            int pageSize, Sort luceneSort, Criteria criteria) {
        long count = this.count(clazz, luceneQuery);
        List<Object[]> projections = this.findProjections(clazz, luceneQuery, fields, (pageNo - 1) * pageSize,
                pageSize, luceneSort, criteria);

        return new PaginatedList<>(projections, pageNo, pageSize, count);
    }

    @Override
    public long count(Class<?> clazz) {
        return count(clazz, getQueryBuilder(clazz).all().createQuery(), null);
    }

    @Override
    public long count(Class<?> clazz, Query luceneQuery) {
        return count(clazz, luceneQuery, null);
    }

    @Override
    public long count(Class<?> clazz, Query luceneQuery, Criteria criteria) {
        FullTextQuery ftq = getFullTextQuery(luceneQuery, clazz);

        if (criteria != null)
            ftq.setCriteriaQuery(criteria);

        int count = ftq.getResultSize();

        if (isTraceEnabled)
            log.trace("entity counting. entity=[{}], query=[{}], count=[{}]", clazz.getSimpleName(), luceneQuery,
                    count);

        return count;
    }

    @Override
    public boolean exists(Class<?> clazz) {
        return exists(clazz, getQueryBuilder(clazz).all().createQuery());
    }

    @Override
    public boolean exists(Class<?> clazz, Query luceneQuery) {
        List<Serializable> ids = findIds(clazz, luceneQuery, 0, 1, null);
        return (ids != null && ids.size() > 0);
    }

    @Override
    public void persist(Object entity) {
        getFullTextSession().persist(entity);
    }

    @Override
    public Object merge(Object entity) {
        return getFullTextSession().merge(entity);
    }

    @Override
    public Serializable save(Object entity) {
        return getFullTextSession().save(entity);
    }

    @Override
    public void saveOrUpdate(Object entity) {
        getFullTextSession().saveOrUpdate(entity);
    }

    @Override
    public void update(Object entity) {
        getFullTextSession().update(entity);
    }

    @Override
    public void delete(Object entity) {
        if (entity == null)
            return;
        getFullTextSession().delete(entity);
    }

    @Override
    public void deleteById(Class<?> clazz, Serializable id) {
        Object entity = getFullTextSession().load(clazz, id);
        delete(entity);
    }

    @Override
    public void deleteByIds(Class<?> clazz, Collection<? extends Serializable> ids) {
        if (isTraceEnabled)
            log.trace("Id ?  ? . clazz=[{}], ids=[{}]", clazz,
                    StringTool.listToString(ids));

        FullTextSession fts = getFullTextSession();
        for (Serializable id : ids)
            delete(fts.load(clazz, id));
    }

    @Override
    public void deleteAll(Class<?> clazz) {
        deleteAll(clazz, getQueryBuilder(clazz).all().createQuery());
    }

    @Override
    public void deleteAll(Class<?> clazz, Query luceneQuery) {
        deleteByIds(clazz, findIds(clazz, luceneQuery));
    }

    @Override
    public void deleteAll(Collection<?> entities) {
        if (ArrayTool.isEmpty(entities))
            return;

        if (isDebugEnabled)
            log.debug(" ? ? ... entity count=[{}]", entities.size());

        FullTextSession fts = getFullTextSession();
        for (Object entity : entities) {
            fts.delete(entity);
        }
    }

    @Override
    public void purge(Class<?> clazz, Serializable id) {
        if (isTraceEnabled)
            log.trace("?? . clazz=[{}], id=[{}]", clazz, id);
        getFullTextSession().purge(clazz, id);
    }

    @Override
    public void purgeAll(Class<?> clazz) {
        log.info("? ?  ? ?? . clazz=[{}]", clazz);
        getFullTextSession().purgeAll(clazz);
    }

    @Override
    public void flushToIndexes() {
        getFullTextSession().flushToIndexes();
    }

    @Override
    public <T> void index(T entity) {
        shouldNotBeNull(entity, "entity");
        if (isTraceEnabled)
            log.trace("?  ?? . entity=[{}]", entity);

        getFullTextSession().index(entity);
    }

    @Override
    public void indexAll(Class<?> clazz, int batchSize) {
        if (isDebugEnabled)
            log.debug("[{}]?  ?  ??? ...", clazz);

        clearIndex(clazz);

        if (batchSize < DEFAUALT_BATCH_SIZE)
            batchSize = DEFAUALT_BATCH_SIZE;

        FullTextSession fts = getFullTextSession();

        FlushMode currentFlushMode = fts.getFlushMode();
        CacheMode currentCacheMode = fts.getCacheMode();
        fts.setFlushMode(FlushMode.MANUAL);
        fts.setCacheMode(CacheMode.IGNORE);

        try {
            Transaction tx = fts.beginTransaction();
            ScrollableResults results = fts.createCriteria(clazz).scroll(ScrollMode.FORWARD_ONLY);
            int index = 0;
            while (results.next()) {
                fts.index(results.get(0));
                if (++index % batchSize == 0) {
                    fts.flushToIndexes();
                    fts.clear();
                    if (isTraceEnabled)
                        log.trace("?? . index=[{}]", index);
                }
            }
            fts.flushToIndexes();
            tx.commit();

            log.info("[{}]?   [{}]   ??? !!!", clazz,
                    index);
        } finally {
            fts.setFlushMode(currentFlushMode);
            fts.setCacheMode(currentCacheMode);
        }
    }

    @Override
    public Future<Void> indexAllAsync(final Class<?> clazz, final int batchSize) {
        if (isDebugEnabled)
            log.debug(
                    "? ? ?  ??? ... clazz=[{}], batchSize=[{}]",
                    clazz, batchSize);

        // TODO: Session? Thread-safe  ,  Thread  ?.
        indexAll(clazz, batchSize);
        return AsyncTool.getTaskHasResult(null);

        //        final FullTextSession fts = getFullTextSession();
        //        return AsyncTool.startNew(new Callable<Void>() {
        //            @Override
        //            public Void call() {
        //                try {
        //                    indexAll(clazz, batchSize);
        //                    return null;
        //                } finally {
        //                    fts.close();
        //                }
        //            }
        //        });
    }

    @Override
    public void clearIndex(Class<?> clazz) {
        if (isDebugEnabled)
            log.debug("?   ??  ... clazz=[{}]", clazz);

        getFullTextSession().purgeAll(clazz); // remove obsolete index
        getFullTextSession().flushToIndexes(); // apply purge before optimize
        optimize(clazz); // physically clear space
    }

    @Override
    public void clearIndexAll() {
        log.info(" ?   ??  ...");

        FullTextSession fts = getFullTextSession();
        for (Class clazz : SearchTool.getIndexedClasses(fts.getSessionFactory())) {
            fts.purgeAll(clazz);
            fts.flushToIndexes();
        }
        optimizeAll();
    }

    @Override
    public void optimize(Class<?> clazz) {
        log.info("? ? ?? ?. clazz=[{}]", clazz);
        getFullTextSession().getSearchFactory().optimize(clazz);
    }

    @Override
    public void optimizeAll() {
        log.info(" ? ?? ?.");
        getFullTextSession().getSearchFactory().optimize();
    }

    @Override
    public void flush() {
        if (isDebugEnabled)
            log.debug("?    ? ?...");
        getFullTextSession().flush();
    }

    @Override
    public void flushIndexes() {
        if (isDebugEnabled)
            log.debug("?  ??   ...");
        getFullTextSession().flushToIndexes();
    }
}