All Downloads are FREE. Search and download functionalities are using the official Maven repository.

de.terrestris.shoguncore.dao.GenericHibernateDao Maven / Gradle / Ivy

There is a newer version: 5.3.13
Show newest version
package de.terrestris.shoguncore.dao;

import de.terrestris.shoguncore.model.PersistentObject;
import de.terrestris.shoguncore.model.User;
import de.terrestris.shoguncore.model.UserGroup;
import de.terrestris.shoguncore.model.security.PermissionCollection;
import de.terrestris.shoguncore.paging.PagingResult;
import de.terrestris.shoguncore.util.entity.EntityUtil;
import org.apache.logging.log4j.Logger;
import org.hibernate.*;
import org.hibernate.criterion.*;
import org.hibernate.proxy.HibernateProxy;
import org.hibernate.transform.DistinctRootEntityResultTransformer;
import org.hibernate.transform.Transformers;
import org.joda.time.DateTime;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Repository;

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

import static org.apache.logging.log4j.LogManager.getLogger;

/**
 * The superclass for all data access objects. Provides basic CRUD
 * functionality and a logger instance for all subclasses.
 *
 * @author Nils Bühner
 */
@Repository("genericDao")
public class GenericHibernateDao {

    /**
     * The LOGGER instance (that will be available in all subclasses)
     */
    protected static final Logger logger = getLogger(GenericHibernateDao.class);

    /**
     * Represents the class of the entity
     */
    private final Class entityClass;

    @Value("${hibernate.cache.use_query_cache}")
    private Boolean useQueryCache;
    /**
     * Hibernate SessionFactory
     */
    @Autowired
    private SessionFactory sessionFactory;

    /**
     * Default constructor
     */
    @SuppressWarnings("unchecked")
    public GenericHibernateDao() {
        this((Class) PersistentObject.class);
    }

    /**
     * Constructor
     *
     * @param clazz
     */
    protected GenericHibernateDao(Class clazz) {
        this.entityClass = clazz;
    }

    /**
     * Obtains the current session.
     *
     * @return
     */
    private Session getSession() {
        return sessionFactory.getCurrentSession();
    }

    /**
     * Return the real object from the database. Returns null if the object does
     * not exist.
     *
     * @param id
     * @return The object from the database or null if it does not exist
     * @see http://www.mkyong.com/hibernate/different-between-session-get-and-session-load/
     */
    public E findById(ID id) {
        logger.trace("Finding " + entityClass.getSimpleName() + " with ID " + id);
        return getSession().get(entityClass, id);
    }

    /**
     * Returns a list of entity objects that have field named
     * fieldName, which has an object fieldEntity
     * as value.
     *
     * @param fieldName   The name of the field
     * @param fieldEntity The element that should be set as value
     * @param criterion   Additional criterions to apply (optional)
     * @return The list of objects
     */
    @SuppressWarnings("unchecked")
    public List findAllWhereFieldEquals(String fieldName, Object fieldEntity,
                                           Criterion... criterion) {

        Class fieldEntityType = null;

        if (fieldEntity != null) {
            fieldEntityType = fieldEntity.getClass();
        }

        final boolean isField = EntityUtil.isField(entityClass, fieldName, fieldEntityType, true);

        if (!isField) {
            String errorMsg = String.format(
                "There is no field '%s' in the type '%s' that accepts instances of '%s'",
                fieldName,
                entityClass.getName(),
                fieldEntityType.getName()
            );
            throw new IllegalArgumentException(errorMsg);
        }

        Criteria criteria = createDistinctRootEntityCriteria(criterion);

        if (fieldEntity == null) {
            criteria.add(Restrictions.isNull(fieldName));
        } else {
            criteria.add(Restrictions.eq(fieldName, fieldEntity));
        }
        criteria.setCacheable(this.useQueryCache);

        return (List) criteria.list();
    }

    /**
     * Returns a list of entity objects that have a collection named
     * fieldName, which contains the passed
     * subElement.
     * 

* The can e.g. be used to return all applications that contain a certain layer. * * @param fieldName The name of the collection field * @param subElement The element that should be contained in the collection * @param criterion Additional criterions to apply (optional) * @return The list of objects */ @SuppressWarnings("unchecked") public List findAllWithCollectionContaining(String fieldName, PersistentObject subElement, Criterion... criterion) { final Class subElementType = subElement.getClass(); final boolean isCollectionField = EntityUtil.isCollectionField(entityClass, fieldName, subElementType, true); if (!isCollectionField) { String errorMsg = String.format( "There is no collection field '%s' with element type '%s' in the type '%s'", fieldName, subElementType.getName(), entityClass.getName() ); throw new IllegalArgumentException(errorMsg); } Criteria criteria = createDistinctRootEntityCriteria(criterion); criteria.createAlias(fieldName, "sub"); criteria.add(Restrictions.eq("sub.id", subElement.getId())); return (List) criteria.list(); } /** * Return a proxy of the object (without hitting the database). This should * only be used if it is assumed that the object really exists and where * non-existence would be an actual error. * * @param id * @return * @see http://www.mkyong.com/hibernate/different-between-session-get-and-session-load/ */ public E loadById(ID id) { logger.trace("Loading " + entityClass.getSimpleName() + " with ID " + id); return getSession().load(entityClass, id); } /** * Returns all Entities by calling findByCriteria(), i.e. without arguments. * * @return All entities * @see GenericHibernateDao#findByCriteria(Criterion...) */ public List findAll() throws HibernateException { logger.trace("Finding all instances of " + entityClass.getSimpleName()); return findByCriteria(); } /** * Saves or updates the passed entity. * * @param e The entity to save or update in the database. */ public void saveOrUpdate(E e) { final Integer id = e.getId(); final boolean hasId = id != null; String createOrUpdatePrefix = hasId ? "Updating" : "Creating a new"; String idSuffix = hasId ? " with ID " + id : ""; logger.trace(createOrUpdatePrefix + " instance of " + entityClass.getSimpleName() + idSuffix); e.setModified(DateTime.now()); getSession().saveOrUpdate(e); } /** * Deletes the passed entity. * * @param e The entity to remove from the database. */ public void delete(E e) { logger.trace("Deleting " + entityClass.getSimpleName() + " with ID " + e.getId()); getSession().delete(e); } /** * Unproxy the entity (and eagerly fetch properties). */ @SuppressWarnings("unchecked") public E unproxy(E e) { if (e == null) { throw new NullPointerException("Entity passed for initialization is null"); } Hibernate.initialize(e); if (e instanceof HibernateProxy) { e = (E) ((HibernateProxy) e).getHibernateLazyInitializer().getImplementation(); } return e; } /** * Detach an entity from the hibernate session * * @param e */ public void evict(E e) { logger.trace("Detaching " + entityClass.getSimpleName() + " with ID " + e.getId() + " from hibernate session"); getSession().evict(e); } /** * Gets the results, that match a variable number of passed criterions. Call * this method without arguments to find all entities. * * @param criterion A variable number of hibernate criterions * @return Entities matching the passed hibernate criterions */ @SuppressWarnings("unchecked") public List findByCriteria(Criterion... criterion) throws HibernateException { logger.trace("Finding instances of " + entityClass.getSimpleName() + " based on " + criterion.length + " criteria"); Criteria criteria = createDistinctRootEntityCriteria(criterion); return criteria.list(); } /** * Gets the results, that match a variable number of passed criterions, but return a * stripped version of the entities, where only the fieldNames in restrictFieldNames * have their actual values set. *

* You can call this with restrictFieldNames = null to get the full * entities back. *

* You can call this method without criterion arguments to find all entities (stripped down to * the restrictFieldNames). *

* If this is called as findByCriteriaRestricted(null) the return value equals the * return value of findByCriteria(). * * @param restrictFieldNames * @param criterion * @return * @throws HibernateException */ @SuppressWarnings("unchecked") public List findByCriteriaRestricted(List restrictFieldNames, Criterion... criterion) throws HibernateException { logger.trace("Finding instances of " + entityClass.getSimpleName() + " based on " + criterion.length + " criteria"); Criteria criteria = createDistinctRootEntityCriteria(criterion); if (restrictFieldNames != null) { ProjectionList projectionList = Projections.projectionList(); for (String restrictFieldName : restrictFieldNames) { PropertyProjection pp = Projections.property(restrictFieldName); projectionList.add(pp, restrictFieldName); } criteria.setProjection(projectionList); criteria.setResultTransformer( Transformers.aliasToBean(entityClass) ); } return criteria.list(); } /** * Gets the unique result, that matches a variable number of passed * criterions. * * @param criterion A variable number of hibernate criterions * @return Entity matching the passed hibernate criterions * @throws HibernateException if there is more than one matching result */ @SuppressWarnings("unchecked") public E findByUniqueCriteria(Criterion... criterion) throws HibernateException { logger.trace("Finding one unique " + entityClass.getSimpleName() + " based on " + criterion.length + " criteria"); Criteria criteria = createDistinctRootEntityCriteria(criterion); return (E) criteria.uniqueResult(); } /** * Gets the results, that match a variable number of passed criterions, * considering the paging- and sort-info at the same time. * * @param firstResult Starting index for the paging request. * @param maxResults Max number of result size. * @param criterion A variable number of hibernate criterions * @return */ @SuppressWarnings("unchecked") public PagingResult findByCriteriaWithSortingAndPaging(Integer firstResult, Integer maxResults, List sorters, Criterion... criterion) throws HibernateException { int nrOfSorters = sorters == null ? 0 : sorters.size(); logger.trace("Finding instances of " + entityClass.getSimpleName() + " based on " + criterion.length + " criteria" + " with " + nrOfSorters + " sorters"); Criteria criteria = createDistinctRootEntityCriteria(criterion); // add paging info if (maxResults != null) { logger.trace("Limiting result set size to " + maxResults); criteria.setMaxResults(maxResults); } if (firstResult != null) { logger.trace("Setting the first result to be retrieved to " + firstResult); criteria.setFirstResult(firstResult); } // add sort info if (sorters != null) { for (Order sortInfo : sorters) { criteria.addOrder(sortInfo); } } return new PagingResult(criteria.list(), getTotalCount(criterion)); } /** * This method returns a {@link Map} that maps {@link PersistentObject}s * to PermissionCollections for the passed {@link User}. I.e. the keySet * of the map is the collection of all {@link PersistentObject}s where the * user has at least one permission and the corresponding value contains * the {@link PermissionCollection} for the passed user on the entity. * * @param user * @return */ @SuppressWarnings({"unchecked"}) public Map findAllUserPermissionsOfUser(User user) { Criteria criteria = getSession().createCriteria(PersistentObject.class); // by only setting the alias, we will only get those entities where // there is at least one permission set... // it is hard (or even impossible in this scenario) to create a // restriction that filters for permissions of the given user only. // using HQL here is no option as the PersistentObject is // a MappedSuperclass (without table). // another efficient way would be a SQL query, but then the SQL // would be written in an explicit SQL dialect... criteria.createAlias("userPermissions", "up"); criteria.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY); List entitiesWithPermissions = criteria.list(); Map userPermissions = new HashMap(); // TODO find a better way than iterating over all entities of the system // that have at least one permission (for any user) (see comment above) for (PersistentObject entity : entitiesWithPermissions) { Map entityUserPermissions = entity.getUserPermissions(); if (entityUserPermissions.containsKey(user)) { userPermissions.put(entity, entityUserPermissions.get(user)); } } return userPermissions; } /** * This method returns a {@link Map} that maps {@link PersistentObject}s * to PermissionCollections for the passed {@link UserGroup}. I.e. the keySet * of the map is the collection of all {@link PersistentObject}s where the * user group has at least one permission and the corresponding value contains * the {@link PermissionCollection} for the passed user group on the entity. * * @param userGroup * @return */ @SuppressWarnings({"unchecked"}) public Map findAllUserGroupPermissionsOfUserGroup(UserGroup userGroup) { Criteria criteria = getSession().createCriteria(PersistentObject.class); // by only setting the alias, we will only get those entities where // there is at least one permission set... // it is hard (or even impossible in this scenario) to create a // restriction that filters for permissions of the given user group only. // using HQL here is no option as the PersistentObject is // a MappedSuperclass (without table). // another efficient way would be a SQL query, but then the SQL // would be written in an explicit SQL dialect... criteria.createAlias("groupPermissions", "gp"); criteria.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY); List entitiesWithPermissions = criteria.list(); Map userGroupPermissions = new HashMap(); // TODO find a better way than iterating over all entities of the system // that have at least one permission (for any user) (see comment above) for (PersistentObject entity : entitiesWithPermissions) { Map entityUserGroupPermissions = entity.getGroupPermissions(); if (entityUserGroupPermissions.containsKey(userGroup)) { userGroupPermissions.put(entity, entityUserGroupPermissions.get(userGroup)); } } return userGroupPermissions; } /** * Helper method: Creates a criteria for the {@link #entityClass} of this dao. * The query results will be handled with a * {@link DistinctRootEntityResultTransformer}. The criteria will contain * all passed criterions. * * @return */ protected Criteria createDistinctRootEntityCriteria(Criterion... criterion) { Criteria criteria = getSession().createCriteria(entityClass); addCriterionsToCriteria(criteria, criterion); criteria.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY); criteria.setCacheable(this.useQueryCache); return criteria; } /** * Returns the total count of db entries for the current type. * * @param criterion * @return */ public Number getTotalCount(Criterion... criterion) throws HibernateException { Criteria criteria = getSession().createCriteria(entityClass); addCriterionsToCriteria(criteria, criterion); criteria.setProjection(Projections.rowCount()); return (Long) criteria.uniqueResult(); } /** * Helper method: Adds all criterions to the criteria (if not null). * * @param criteria * @param criterion */ private void addCriterionsToCriteria(Criteria criteria, Criterion... criterion) { if (criteria != null) { for (Criterion c : criterion) { if (c != null) { criteria.add(c); } } } } /** * @return the entityClass */ public Class getEntityClass() { return entityClass; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy