de.iteratec.iteraplan.persistence.dao.GenericBaseDAO.java Source code

Java tutorial

Introduction

Here is the source code for de.iteratec.iteraplan.persistence.dao.GenericBaseDAO.java

Source

/*
 * iteraplan is an IT Governance web application developed by iteratec, GmbH
 * Copyright (C) 2004 - 2014 iteratec, GmbH
 *
 * This program is free software; you can redistribute it and/or modify it under
 * the terms of the GNU Affero General Public License version 3 as published by
 * the Free Software Foundation with the addition of the following permission
 * added to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED
 * WORK IN WHICH THE COPYRIGHT IS OWNED BY ITERATEC, ITERATEC DISCLAIMS THE
 * WARRANTY OF NON INFRINGEMENT  OF THIRD PARTY RIGHTS.
 *
 * This program 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 General Public License for more
 * details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program; if not, see http://www.gnu.org/licenses or write to
 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 * MA 02110-1301 USA.
 *
 * You can contact iteratec GmbH headquarters at Inselkammerstr. 4
 * 82008 Munich - Unterhaching, Germany, or at email address info@iteratec.de.
 *
 * The interactive user interfaces in modified source and object code versions
 * of this program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU Affero General Public License version 3.
 *
 * In accordance with Section 7(b) of the GNU Affero General Public License
 * version 3, these Appropriate Legal Notices must retain the display of the
 * "iteraplan" logo. If the display of the logo is not reasonably
 * feasible for technical reasons, the Appropriate Legal Notices must display
 * the words "Powered by iteraplan".
 */
package de.iteratec.iteraplan.persistence.dao;

import java.io.Serializable;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Set;

import org.apache.commons.lang.StringUtils;
import org.hibernate.Criteria;
import org.hibernate.FetchMode;
import org.hibernate.Session;
import org.hibernate.criterion.DetachedCriteria;
import org.hibernate.criterion.Disjunction;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Projections;
import org.hibernate.criterion.Restrictions;
import org.springframework.dao.IncorrectResultSizeDataAccessException;
import org.springframework.orm.hibernate3.HibernateCallback;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;
import org.springframework.util.Assert;

import com.google.common.collect.Lists;

import de.iteratec.hibernate.criterion.IteraplanLikeExpression;
import de.iteratec.iteraplan.common.Logger;
import de.iteratec.iteraplan.common.UserContext;
import de.iteratec.iteraplan.common.error.IteraplanErrorMessages;
import de.iteratec.iteraplan.common.error.IteraplanTechnicalException;
import de.iteratec.iteraplan.common.util.Preconditions;
import de.iteratec.iteraplan.model.InformationSystemRelease;
import de.iteratec.iteraplan.persistence.util.CriteriaUtil;
import de.iteratec.iteraplan.persistence.util.SqlHqlStringUtils;

/**
 * Hibernate implementation of the DAO interface {@link DAOTemplate}.
 * 
 * @param <E>
 *          The type parameter for the concrete entity.
 * @param <T>
 *          The type parameter for the entity's identifier.
 */
public abstract class GenericBaseDAO<E, T extends Serializable> extends HibernateDaoSupport
        implements DAOTemplate<E, T> {

    private final Class<E> persistentClass;

    private static final Logger LOGGER = Logger.getIteraplanLogger(GenericBaseDAO.class);

    @SuppressWarnings({ "unchecked", "rawtypes" })
    public GenericBaseDAO() {
        Type type = getClass().getGenericSuperclass();
        while (!(type instanceof ParameterizedType)) {
            type = ((Class) type).getGenericSuperclass();
        }

        type = ((ParameterizedType) type).getActualTypeArguments()[0];
        this.persistentClass = (Class<E>) type;
    }

    /** {@inheritDoc} */
    public void delete(E entity) {
        Assert.notNull(entity);

        LOGGER.debug("Deleting: {0}", entity.getClass().getName());
        onBeforeDelete(entity);
        getHibernateTemplate().delete(entity);
    }

    /** {@inheritDoc} */
    public void deleteAll(Collection<? extends E> entities) {
        Preconditions.checkNotNull(entities);

        if (!entities.isEmpty()) {
            LOGGER.debug("Deleting: {0} of {1}", entities.size(),
                    entities.iterator().next().getClass().getSimpleName());
            getHibernateTemplate().deleteAll(entities);
        }
    }

    /** {@inheritDoc} */
    public boolean doesObjectWithDifferentIdExist(final T identifier, final String name) {
        Assert.notNull(name);

        HibernateCallback<Long> callback = new HibernateCallback<Long>() {
            public Long doInHibernate(Session session) {
                Criteria c = session.createCriteria(getPersistentClass());
                c.setProjection(Projections.count(getNameAttribute()));
                c.add(Restrictions.eq(getNameAttribute(), name.trim()).ignoreCase());
                if (identifier != null) {
                    c.add(Restrictions.ne("id", identifier));
                }
                Object result = c.uniqueResult();

                // if Hibernate returns an Integer, convert it to long
                if (result instanceof Integer) {
                    return Long.valueOf(((Integer) result).longValue());
                }
                // otherwise we expect a Long to be returned
                return (Long) result;
            }
        };

        Long count = getHibernateTemplate().execute(callback);

        return count.intValue() > 0 ? true : false;
    }

    /** {@inheritDoc} */
    @SuppressWarnings("unchecked")
    public List<E> executeNamedQuery(String namedQuery) {
        return getHibernateTemplate().findByNamedQuery(namedQuery);
    }

    /** {@inheritDoc} */
    @SuppressWarnings("unchecked")
    public List<E> executeNamedQuery(String namedQuery, String key, Object value) {
        return getHibernateTemplate().findByNamedQueryAndNamedParam(namedQuery, key, value);
    }

    /** {@inheritDoc} */
    @SuppressWarnings("unchecked")
    public List<E> executeNamedQuery(String namedQuery, String[] keys, Object[] values) {
        return getHibernateTemplate().findByNamedQueryAndNamedParam(namedQuery, keys, values);
    }

    /** {@inheritDoc} */
    @SuppressWarnings("unchecked")
    public List<E> findByCriteria(DetachedCriteria criteria) {
        return getHibernateTemplate().findByCriteria(criteria);
    }

    /** {@inheritDoc} */
    public E getFirstElement() {
        HibernateCallback<E> callback = new HibernateCallback<E>() {

            @SuppressWarnings("unchecked")
            public E doInHibernate(Session session) {
                Criteria c = session.createCriteria(getPersistentClass());
                c.addOrder(Order.asc(getNameAttribute()));
                c.setMaxResults(1);
                return (E) c.uniqueResult();
            }
        };

        return getHibernateTemplate().execute(callback);
    }

    /** {@inheritDoc} */
    @SuppressWarnings("unchecked")
    public List<E> loadElementList(final String orderByProperty) {

        HibernateCallback<List<E>> callback = new HibernateCallback<List<E>>() {
            public List<E> doInHibernate(Session session) {
                Criteria c = session.createCriteria(getPersistentClass());
                if (orderByProperty != null) {
                    c.addOrder(Order.asc(orderByProperty));
                }
                c.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);
                return c.list();
            }
        };

        return getHibernateTemplate().executeFind(callback);
    }

    /** {@inheritDoc} */
    @SuppressWarnings("unchecked")
    public List<E> loadElementListWithIds(final Set<T> identifiers) {
        if ((identifiers == null) || identifiers.isEmpty()) {
            return new ArrayList<E>();
        }

        HibernateCallback<List<E>> callback = new HibernateCallback<List<E>>() {
            public List<E> doInHibernate(Session session) {
                Criteria c = session.createCriteria(getPersistentClass());
                c.add(CriteriaUtil.createInRestrictions("id", identifiers));
                c.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);

                return c.list();
            }
        };

        return getHibernateTemplate().executeFind(callback);
    }

    /**
     * {@inheritDoc}
     */
    @SuppressWarnings("unchecked")
    public List<E> loadFilteredElementList(final String property, final Set<T> excludedIds) {

        HibernateCallback<List<E>> callback = new HibernateCallback<List<E>>() {
            public List<E> doInHibernate(Session session) {
                Criteria c = session.createCriteria(getPersistentClass());
                if ((excludedIds != null) && !excludedIds.isEmpty()) {
                    c.add(CriteriaUtil.createNotInRestrictions("id", excludedIds));
                }
                if (property != null) {
                    c.addOrder(Order.asc(property));
                }
                // without this for some reason multiple instances may be returned,
                // for example when loading AttributeTypeGroup. Strangely enough, when
                // loading AttributeTypeGroups by the HQL query "from AttributeTypeGroup",
                // only distinct instances are returned ?! Note that the distinct part is
                // done programatically by the Criteria implementation, not by the database!
                c.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);
                return c.list();
            }
        };

        return getHibernateTemplate().executeFind(callback);
    }

    /** {@inheritDoc} */
    public E loadObjectById(T id) {
        if (id == null) {
            return null;
        }

        return getHibernateTemplate().load(getPersistentClass(), id);
    }

    /**
     * {@inheritDoc}
     */
    public E loadObjectById(final T id, final String... associations) {
        Preconditions.checkNotNull(id);

        HibernateCallback<E> callback = new HibernateCallback<E>() {
            @SuppressWarnings("unchecked")
            public E doInHibernate(Session session) {
                Criteria criteria = session.createCriteria(getPersistentClass()).add(Restrictions.idEq(id));
                for (String association : associations) {
                    criteria.setFetchMode(association, FetchMode.JOIN);
                }
                return (E) criteria.uniqueResult();
            }
        };

        return getHibernateTemplate().execute(callback);
    }

    /** {@inheritDoc} */
    @SuppressWarnings("unchecked")
    public E loadObjectByIdIfExists(T id) {
        if (id == null) {
            return null;
        }

        Object entity = getHibernateTemplate().get(getPersistentClass(), id);
        if (entity == null) {
            return null;
        }
        if (!getPersistentClass().isAssignableFrom(entity.getClass())) {
            throw new IteraplanTechnicalException(IteraplanErrorMessages.ENTITY_NOT_FOUND_READ);
        }

        return (E) entity;
    }

    /** {@inheritDoc} */
    public E saveOrUpdate(E entity) {
        Assert.notNull(entity);

        LOGGER.debug("Updating: {0}", entity.getClass().getName());
        getHibernateTemplate().saveOrUpdate(entity);

        return entity;
    }

    /** {@inheritDoc} */
    public Collection<E> saveOrUpdate(Collection<E> entities) {
        Assert.notNull(entities);

        LOGGER.debug("Updating: {0}", entities);
        getHibernateTemplate().saveOrUpdateAll(entities);

        return entities;
    }

    /**
     * Convenience method to return a single instance that matches the query, or null if the query
     * returns no results. <br>
     * <br>
     * Semantic copied from Hibernate Criteria.uniqueResult()
     * 
     * @param detachedCriteria
     *          The detached Criteria that is forwarded to hibernateTemplate
     * @return The object or null if nothing matches the criteria
     */
    @SuppressWarnings("unchecked")
    protected E findByCriteriaUniqueResult(DetachedCriteria detachedCriteria) {
        List<E> list = getHibernateTemplate().findByCriteria(detachedCriteria);
        int size = list.size();
        if (size == 0) {
            return null;
        }

        // if the criteria is not precisely formed, the result list may contain duplicates
        // --> check that all results are equal, in case we got more than one
        E first = list.get(0);
        for (int i = 1; i < size; i++) {
            if (list.get(i) != first) {
                throw new IncorrectResultSizeDataAccessException(1, size);
            }
        }
        return first;
    }

    /**
     * @return The property name in the {@link #getPersistentClass() managed class} which represents the name of such entities.
     */
    protected abstract String getNameAttribute();

    /**
     * Returns the non-generic entity-class the concrete implementation of the DAO represents
     * 
     * @return The class of the entity that is handled by the DAO
     */
    protected Class<E> getPersistentClass() {
        return persistentClass;
    }

    /**
     * This method is called immediately prior to deleting the given entity. It allows for defining
     * additional operations such as manually deleting associated entities if needed. This method may
     * be overriden by subclasses to define specific behaviour. Note that this method should always be
     * called with a call to super().
     * 
     * @param entity The entity to delete.
     */
    protected void onBeforeDelete(E entity) {
        //do nothing
    }

    /** {@inheritDoc} */
    public List<E> findBySearchTerm(final String searchTerm, final String... attribute) {
        return findBySearchTerm(searchTerm, true, attribute);
    }

    /** {@inheritDoc} */
    @SuppressWarnings("unchecked")
    public List<E> findBySearchTerm(final String searchTerm, final boolean showInactive,
            final String... attribute) {

        List<Object> positionalQueryParams = Lists.newArrayList();

        // Build the Filter Statement if there is something to filter
        StringBuilder whereClause = new StringBuilder();
        if (StringUtils.isNotEmpty(searchTerm)) {
            whereClause.append(" WHERE (");
            for (int i = 0; i < attribute.length; i++) {
                whereClause.append("lower(" + attribute[i] + ") like ?");
                // add replacement value for the question mark placeholder
                positionalQueryParams.add(SqlHqlStringUtils.escapeSqlLikeSquareBrackets(
                        SqlHqlStringUtils.processGuiFilterForSql(searchTerm.toLowerCase()), getSession()));
                if (i < attribute.length - 1) {
                    whereClause.append(" OR ");
                }
            }
            whereClause.append(")");
        }

        if (!showInactive) {
            whereClause.append(whereClause.length() == 0 ? " WHERE" : " AND");
            whereClause.append(" typeOfStatus != '");
            whereClause.append(InformationSystemRelease.TypeOfStatus.INACTIVE);
            whereClause.append('\'');
        }

        // Build the Order Statement
        StringBuilder orderClause = new StringBuilder(" ORDER BY ");
        for (int i = 0; i < attribute.length; i++) {
            orderClause.append("entity." + attribute[i]);
            if (i < attribute.length - 1) {
                orderClause.append(", ");
            }
        }

        String className = persistentClass.getSimpleName();
        String query = "FROM " + className + " entity" + whereClause + orderClause;

        return getHibernateTemplate().find(query, positionalQueryParams.toArray());
    }

    /** {@inheritDoc} */
    @SuppressWarnings("unchecked")
    public List<E> getSubscribedElements() {
        HibernateCallback<List<E>> callback = new HibernateCallback<List<E>>() {
            public List<E> doInHibernate(Session session) {
                Criteria c = session.createCriteria(getPersistentClass());
                c.createCriteria("subscribedUsers")
                        .add(Restrictions.idEq(UserContext.getCurrentUserContext().getUser().getId()));

                return c.list();
            }
        };

        return getHibernateTemplate().executeFind(callback);
    }

    /** {@inheritDoc} */
    public E merge(E entity) {
        return getHibernateTemplate().merge(entity);
    }

    /** {@inheritDoc} */
    public List<E> findByNames(Set<String> names) {
        if (names.isEmpty()) {
            return Collections.emptyList();
        }

        DetachedCriteria criteria = DetachedCriteria.forClass(getPersistentClass());
        Disjunction disjunction = Restrictions.disjunction();
        for (String name : names) {
            //FIXME will eq do the trick here too or do we need like?
            //if like is needed we should use the IteraplanLikeExpression
            //      disjunction.add(Restrictions.like(getNameAttribute(), name, MatchMode.EXACT).ignoreCase());
            disjunction.add(new IteraplanLikeExpression(getNameAttribute(), name, true));
        }
        criteria.add(disjunction);

        return findByCriteria(criteria);
    }

    /** {@inheritDoc} */
    public void clearSession() {
        getHibernateTemplate().getSessionFactory().getCurrentSession().clear();
    }
}