org.web4thejob.orm.DataReaderServiceImpl.java Source code

Java tutorial

Introduction

Here is the source code for org.web4thejob.orm.DataReaderServiceImpl.java

Source

/*
 * Copyright (c) 2012-2014 Veniamin Isaias.
 *
 * This file is part of web4thejob.
 *
 * Web4thejob 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 3 of the License, or any later version.
 *
 * Web4thejob 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 web4thejob.  If not, see <http://www.gnu.org/licenses/>.
 */

package org.web4thejob.orm;

import org.hibernate.Criteria;
import org.hibernate.FlushMode;
import org.hibernate.SessionFactory;
import org.hibernate.criterion.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.util.StringUtils;
import org.web4thejob.context.ContextUtil;
import org.web4thejob.orm.query.*;
import org.web4thejob.orm.query.Criterion;

import java.io.Serializable;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author Veniamin Isaias
 * @since 1.0.0
 */

/* package */class DataReaderServiceImpl implements DataReaderService {
    // ------------------------------ FIELDS ------------------------------

    @Autowired
    private SessionFactory sessionFactory;

    // ------------------------ INTERFACE METHODS ------------------------

    // --------------------- Interface DataReaderService ---------------------

    @Override
    @SuppressWarnings("unchecked")
    public <E extends Entity> E findById(Class<E> entityType, Serializable id) {
        return (E) sessionFactory.getCurrentSession().get(entityType, id);
    }

    @Override
    @SuppressWarnings("unchecked")
    public <E extends Entity> List<E> findByQuery(Query query) {
        Criteria criteria = toDetachedCriteria(query).getExecutableCriteria(sessionFactory.getCurrentSession())
                .setCacheable(query.isCached());

        //Issue #21
        criteria.setFlushMode(FlushMode.MANUAL);

        if (StringUtils.hasText(query.getCacheRegion())) {
            criteria.setCacheRegion(query.getCacheRegion());
        }
        return criteria.list();
    }

    @Override
    @SuppressWarnings("unchecked")
    public <E extends Entity> E findFirstByQuery(Query query) {
        Criteria criteria = toDetachedCriteria(query).getExecutableCriteria(sessionFactory.getCurrentSession())
                .setMaxResults(1).setCacheable(query.isCached());
        if (StringUtils.hasText(query.getCacheRegion())) {
            criteria.setCacheRegion(query.getCacheRegion());
        }

        //Issue #21
        criteria.setFlushMode(FlushMode.MANUAL);

        final List<E> list = criteria.list();
        if (list.size() > 0) {
            return list.get(0);
        }
        return null;
    }

    @Override
    @SuppressWarnings("unchecked")
    public <E extends Entity> E findUniqueByQuery(Query query) {
        Criteria criteria = toDetachedCriteria(query).getExecutableCriteria(sessionFactory.getCurrentSession())
                .setMaxResults(2).setCacheable(query.isCached());
        if (StringUtils.hasText(query.getCacheRegion())) {
            criteria.setCacheRegion(query.getCacheRegion());
        }

        //Issue #21
        criteria.setFlushMode(FlushMode.MANUAL);

        final List<E> list = criteria.list();
        if (list.size() == 0) {
            return null;
        } else if (list.size() == 1) {
            return list.get(0);
        } else {
            throw new DataIntegrityViolationException("expecting unique result but got many");
        }
    }

    @Override
    @SuppressWarnings("unchecked")
    public <E extends Entity> E get(Class<E> entityType, Serializable id) {
        return (E) sessionFactory.getCurrentSession().get(entityType, id);
    }

    @Override
    @SuppressWarnings("unchecked")
    public <E extends Entity> List<E> getAll(Class<E> entityType) {
        return DetachedCriteria.forClass(entityType).getExecutableCriteria(sessionFactory.getCurrentSession())
                .setFlushMode(FlushMode.MANUAL).list(); //Issue #21
    }

    @Override
    public <E extends Entity> E getOne(Class<E> entityType) {
        return findFirstByQuery(ContextUtil.getBean(EntityFactory.class).buildQuery(entityType));
    }

    @Override
    @SuppressWarnings("unchecked")
    public <E extends Entity> E refresh(E entity) {
        sessionFactory.getCurrentSession().refresh(entity);
        return entity;
    }

    @Override
    public void evictCache() {
        if (sessionFactory.getCache() != null) {
            sessionFactory.getCache().evictCollectionRegions();
            sessionFactory.getCache().evictEntityRegions();
            sessionFactory.getCache().evictNaturalIdRegions();
            sessionFactory.getCache().evictQueryRegions();
        }
    }

    // -------------------------- OTHER METHODS --------------------------

    private DetachedCriteria toDetachedCriteria(Query query) {
        return toDetachedCriteria(query, "this");
    }

    private DetachedCriteria toDetachedCriteria(Query query, String alias) {
        boolean hasOneToManyAssociation = false;
        DetachedCriteria detachedCriteria;
        if (alias != null) {
            detachedCriteria = DetachedCriteria.forClass(query.getTargetType(), alias);
        } else {
            detachedCriteria = DetachedCriteria.forClass(query.getTargetType());
        }

        final Map<String, String> aliases = new HashMap<String, String>();
        for (final Criterion w4tjCriterion : query.getCriteria()) {
            if (w4tjCriterion.getCondition() != null
                    && (w4tjCriterion.getCondition().getOperandsNo() == 0 || (w4tjCriterion.getValue() != null
                            && StringUtils.hasText(w4tjCriterion.getValue().toString())))) {
                if (!hasOneToManyAssociation) {
                    hasOneToManyAssociation = w4tjCriterion.getPropertyPath().hasOneToManySteps();
                }

                org.hibernate.criterion.Criterion hibCriterion;

                if (w4tjCriterion.isLocal()) {
                    hibCriterion = toHibernateCriterion(w4tjCriterion, detachedCriteria.getAlias());
                } else {
                    String aliasPath = null;
                    for (final PropertyMetadata propertyMetadata : w4tjCriterion.getPropertyPath().getSteps()) {
                        if (propertyMetadata.equals(w4tjCriterion.getPropertyPath().getLastStep())) {
                            break;
                        } else if (propertyMetadata.equals(w4tjCriterion.getPropertyPath().getFirstStep())) {
                            aliasPath = propertyMetadata.getName();
                        } else {
                            aliasPath += "." + propertyMetadata.getName();
                        }

                        buildAlias(detachedCriteria, aliases, aliasPath);
                    }

                    hibCriterion = toHibernateCriterion(w4tjCriterion, aliases.get(aliasPath));
                }

                detachedCriteria = detachedCriteria.add(hibCriterion);
            }
        }

        if (!query.getSubqueries().isEmpty()) {
            String masterId = detachedCriteria.getAlias() + "."
                    + ContextUtil.getMRS().getEntityMetadata(query.getTargetType()).getIdentifierName();
            int subqindex = 0;
            for (Subquery subquery : query.getSubqueries()) {
                subqindex += 1;
                detachedCriteria = detachedCriteria
                        .add(toHibernateSubcriterion(masterId, String.valueOf(subqindex), subquery));
            }
        }

        for (final OrderBy orderBy : query.getOrderings()) {
            PathMetadata pathMetadata = ContextUtil.getMRS().getPropertyPath(query.getTargetType(),
                    StringUtils.delimitedListToStringArray(orderBy.getProperty(), Path.DELIMITER));

            String property;
            if (pathMetadata.isMultiStep()) {
                String aliasPath = null;

                if (!hasOneToManyAssociation) {
                    hasOneToManyAssociation = pathMetadata.hasOneToManySteps();
                }

                for (PropertyMetadata propertyMetadata : pathMetadata.getSteps()) {
                    if (propertyMetadata.equals(pathMetadata.getLastStep())) {
                        break;
                    } else if (propertyMetadata.equals(pathMetadata.getFirstStep())) {
                        aliasPath = propertyMetadata.getName();
                    } else {
                        aliasPath += "." + propertyMetadata.getName();
                    }

                    buildAlias(detachedCriteria, aliases, aliasPath);
                }
                property = aliases.get(aliasPath) + "." + pathMetadata.getLastStep().getName();
            } else {
                property = orderBy.getProperty();
            }

            if (orderBy.isDescending()) {
                detachedCriteria = detachedCriteria.addOrder(Order.desc(property));
            } else {
                detachedCriteria = detachedCriteria.addOrder(Order.asc(property));
            }
        }

        if (hasOneToManyAssociation) {
            detachedCriteria = detachedCriteria.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);
        }

        return detachedCriteria;
    }

    private String buildAlias(DetachedCriteria detachedCriteria, Map<String, String> aliases, String aliasPath) {
        if (!aliases.containsKey(aliasPath)) {
            String alias = aliasPath.replaceAll("\\.", "_");
            aliases.put(aliasPath, alias);
            detachedCriteria.createAlias(aliasPath, alias);
        }

        return aliases.get(aliasPath);
    }

    private org.hibernate.criterion.Criterion toHibernateCriterion(Criterion criterion, String alias) {
        org.hibernate.criterion.Criterion hibernate_criterion;
        String propertyName = criterion.getPropertyPath().getLastStep().getName();
        if (alias != null) {
            propertyName = alias + "." + propertyName;
        }

        if (criterion.getCondition().equals(Condition.EQ)) {
            hibernate_criterion = Property.forName(propertyName).eq(criterion.getValue());
        } else if (criterion.getCondition().equals(Condition.NE)) {
            hibernate_criterion = Property.forName(propertyName).ne(criterion.getValue());
        } else if (criterion.getCondition().equals(Condition.GT)) {
            hibernate_criterion = Property.forName(propertyName).gt(criterion.getValue());
        } else if (criterion.getCondition().equals(Condition.GTE)) {
            hibernate_criterion = Property.forName(propertyName).ge(criterion.getValue());
        } else if (criterion.getCondition().equals(Condition.LT)) {
            hibernate_criterion = Property.forName(propertyName).lt(criterion.getValue());
        } else if (criterion.getCondition().equals(Condition.LTE)) {
            hibernate_criterion = Property.forName(propertyName).le(criterion.getValue());
        } else if (criterion.getCondition().equals(Condition.NL)) {
            hibernate_criterion = Property.forName(propertyName).isNull();
        } else if (criterion.getCondition().equals(Condition.NNL)) {
            hibernate_criterion = Property.forName(propertyName).isNotNull();
        } else if (criterion.getCondition().equals(Condition.SW)) {
            hibernate_criterion = Property.forName(propertyName).like(criterion.getValue().toString(),
                    MatchMode.START);
        } else if (criterion.getCondition().equals(Condition.NSW)) {
            hibernate_criterion = Restrictions
                    .not(Property.forName(propertyName).like(criterion.getValue().toString(), MatchMode.START));
        } else if (criterion.getCondition().equals(Condition.CN)) {
            hibernate_criterion = Property.forName(propertyName).like(criterion.getValue().toString(),
                    MatchMode.ANYWHERE);
        } else if (criterion.getCondition().equals(Condition.NCN)) {
            hibernate_criterion = Restrictions
                    .not(Property.forName(propertyName).like(criterion.getValue().toString(), MatchMode.ANYWHERE));
        } else if (criterion.getCondition().equals(Condition.EW)) {
            hibernate_criterion = Property.forName(propertyName).like(criterion.getValue().toString(),
                    MatchMode.END);
        } else if (criterion.getCondition().equals(Condition.NEW)) {
            hibernate_criterion = Restrictions
                    .not(Property.forName(propertyName).like(criterion.getValue().toString(), MatchMode.END));
        } else if (criterion.getCondition().equals(Condition.IN)) {
            hibernate_criterion = Restrictions.in(propertyName, (Collection) criterion.getValue());
        } else if (criterion.getCondition().equals(Condition.NIN)) {
            hibernate_criterion = Restrictions
                    .not(Restrictions.in(propertyName, (Collection) criterion.getValue()));
        } else if (criterion.getCondition().equals(Condition.EX)
                || criterion.getCondition().equals(Condition.NEX)) {
            EntityMetadata target = criterion.getPropertyPath().getLastStep().getAssociatedEntityMetadata();
            Subquery subquery;
            if (criterion.getCondition().equals(Condition.EX)) {
                subquery = new Subquery(Subquery.SubqueryType.TYPE_EXISTS, target);
            } else {
                subquery = new Subquery(Subquery.SubqueryType.TYPE_NOT_EXISTS, target);
            }

            for (PropertyMetadata propertyMetadata : target.getPropertiesMetadata()) {
                if (criterion.getPropertyPath().getLastStep().isAssociatedWith(propertyMetadata)) {
                    subquery.addCriterion(
                            ContextUtil.getMRS().getPropertyPath(target.getEntityType(),
                                    new Path(propertyMetadata.getName())),
                            Condition.EQ, Subquery.MASTER_ID_PLACEHOLDER);
                    break;
                }
            }
            if (subquery.getCriteria().isEmpty()) {
                throw new RuntimeException("subquery failed: " + criterion.toString());
            }

            hibernate_criterion = toHibernateSubcriterion(
                    alias + "." + criterion.getPropertyPath().getLastStep().getName(), alias, subquery);
        } else {
            throw new RuntimeException("unknown condition encountered: " + criterion.getCondition().toString());
        }

        return hibernate_criterion;
    }

    private org.hibernate.criterion.Criterion toHibernateSubcriterion(String masterId, String subqueryAlias,
            Subquery subquery) {
        String alias = "subq_" + subqueryAlias;

        DetachedCriteria detachedCriteria = DetachedCriteria.forClass(subquery.getTarget().getEntityType(), alias);
        for (Criterion criterion : subquery.getCriteria()) {
            if (Subquery.MASTER_ID_PLACEHOLDER == criterion.getValue()) {
                String subProperty = alias + "." + criterion.getPropertyPath().getPath();
                detachedCriteria = detachedCriteria.add(Property.forName(subProperty).eqProperty(masterId));
            } else if (org.hibernate.criterion.Property.class.isInstance(criterion.getValue())) {
                detachedCriteria = detachedCriteria
                        .add(((org.hibernate.criterion.Property) criterion.getValue()).eqProperty(masterId));
            } else {
                detachedCriteria = detachedCriteria.add(toHibernateCriterion(criterion, alias));
            }
        }

        if (subquery.getSubqueryType() == Subquery.SubqueryType.TYPE_EXISTS) {
            return Subqueries.exists(detachedCriteria
                    .setProjection(Projections.property(alias + "." + subquery.getTarget().getIdentifierName())));
        } else {
            return Subqueries.notExists(detachedCriteria
                    .setProjection(Projections.property(alias + "." + subquery.getTarget().getIdentifierName())));
        }
    }
}